1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/AbstractValidatingLambdaMetafactory.java Sat Aug 09 11:12:05 2014 +0200
1.3 @@ -0,0 +1,375 @@
1.4 +/*
1.5 + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1.7 + *
1.8 + * This code is free software; you can redistribute it and/or modify it
1.9 + * under the terms of the GNU General Public License version 2 only, as
1.10 + * published by the Free Software Foundation. Oracle designates this
1.11 + * particular file as subject to the "Classpath" exception as provided
1.12 + * by Oracle in the LICENSE file that accompanied this code.
1.13 + *
1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1.17 + * version 2 for more details (a copy is included in the LICENSE file that
1.18 + * accompanied this code).
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License version
1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1.23 + *
1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1.25 + * or visit www.oracle.com if you need additional information or have any
1.26 + * questions.
1.27 + */
1.28 +package java.lang.invoke;
1.29 +
1.30 +import sun.invoke.util.Wrapper;
1.31 +
1.32 +import static sun.invoke.util.Wrapper.forPrimitiveType;
1.33 +import static sun.invoke.util.Wrapper.forWrapperType;
1.34 +import static sun.invoke.util.Wrapper.isWrapperType;
1.35 +
1.36 +/**
1.37 + * Abstract implementation of a lambda metafactory which provides parameter
1.38 + * unrolling and input validation.
1.39 + *
1.40 + * @see LambdaMetafactory
1.41 + */
1.42 +/* package */ abstract class AbstractValidatingLambdaMetafactory {
1.43 +
1.44 + /*
1.45 + * For context, the comments for the following fields are marked in quotes
1.46 + * with their values, given this program:
1.47 + * interface II<T> { Object foo(T x); }
1.48 + * interface JJ<R extends Number> extends II<R> { }
1.49 + * class CC { String impl(int i) { return "impl:"+i; }}
1.50 + * class X {
1.51 + * public static void main(String[] args) {
1.52 + * JJ<Integer> iii = (new CC())::impl;
1.53 + * System.out.printf(">>> %s\n", iii.foo(44));
1.54 + * }}
1.55 + */
1.56 + final Class<?> targetClass; // The class calling the meta-factory via invokedynamic "class X"
1.57 + final MethodType invokedType; // The type of the invoked method "(CC)II"
1.58 + final Class<?> samBase; // The type of the returned instance "interface JJ"
1.59 + final String samMethodName; // Name of the SAM method "foo"
1.60 + final MethodType samMethodType; // Type of the SAM method "(Object)Object"
1.61 + final MethodHandle implMethod; // Raw method handle for the implementation method
1.62 + final MethodHandleInfo implInfo; // Info about the implementation method handle "MethodHandleInfo[5 CC.impl(int)String]"
1.63 + final int implKind; // Invocation kind for implementation "5"=invokevirtual
1.64 + final boolean implIsInstanceMethod; // Is the implementation an instance method "true"
1.65 + final Class<?> implDefiningClass; // Type defining the implementation "class CC"
1.66 + final MethodType implMethodType; // Type of the implementation method "(int)String"
1.67 + final MethodType instantiatedMethodType; // Instantiated erased functional interface method type "(Integer)Object"
1.68 + final boolean isSerializable; // Should the returned instance be serializable
1.69 + final Class<?>[] markerInterfaces; // Additional marker interfaces to be implemented
1.70 + final MethodType[] additionalBridges; // Signatures of additional methods to bridge
1.71 +
1.72 +
1.73 + /**
1.74 + * Meta-factory constructor.
1.75 + *
1.76 + * @param caller Stacked automatically by VM; represents a lookup context
1.77 + * with the accessibility privileges of the caller.
1.78 + * @param invokedType Stacked automatically by VM; the signature of the
1.79 + * invoked method, which includes the expected static
1.80 + * type of the returned lambda object, and the static
1.81 + * types of the captured arguments for the lambda. In
1.82 + * the event that the implementation method is an
1.83 + * instance method, the first argument in the invocation
1.84 + * signature will correspond to the receiver.
1.85 + * @param samMethodName Name of the method in the functional interface to
1.86 + * which the lambda or method reference is being
1.87 + * converted, represented as a String.
1.88 + * @param samMethodType Type of the method in the functional interface to
1.89 + * which the lambda or method reference is being
1.90 + * converted, represented as a MethodType.
1.91 + * @param implMethod The implementation method which should be called
1.92 + * (with suitable adaptation of argument types, return
1.93 + * types, and adjustment for captured arguments) when
1.94 + * methods of the resulting functional interface instance
1.95 + * are invoked.
1.96 + * @param instantiatedMethodType The signature of the primary functional
1.97 + * interface method after type variables are
1.98 + * substituted with their instantiation from
1.99 + * the capture site
1.100 + * @param isSerializable Should the lambda be made serializable? If set,
1.101 + * either the target type or one of the additional SAM
1.102 + * types must extend {@code Serializable}.
1.103 + * @param markerInterfaces Additional interfaces which the lambda object
1.104 + * should implement.
1.105 + * @param additionalBridges Method types for additional signatures to be
1.106 + * bridged to the implementation method
1.107 + * @throws LambdaConversionException If any of the meta-factory protocol
1.108 + * invariants are violated
1.109 + */
1.110 + AbstractValidatingLambdaMetafactory(MethodHandles.Lookup caller,
1.111 + MethodType invokedType,
1.112 + String samMethodName,
1.113 + MethodType samMethodType,
1.114 + MethodHandle implMethod,
1.115 + MethodType instantiatedMethodType,
1.116 + boolean isSerializable,
1.117 + Class<?>[] markerInterfaces,
1.118 + MethodType[] additionalBridges)
1.119 + throws LambdaConversionException {
1.120 + if ((caller.lookupModes() & MethodHandles.Lookup.PRIVATE) == 0) {
1.121 + throw new LambdaConversionException(String.format(
1.122 + "Invalid caller: %s",
1.123 + caller.lookupClass().getName()));
1.124 + }
1.125 + this.targetClass = caller.lookupClass();
1.126 + this.invokedType = invokedType;
1.127 +
1.128 + this.samBase = invokedType.returnType();
1.129 +
1.130 + this.samMethodName = samMethodName;
1.131 + this.samMethodType = samMethodType;
1.132 +
1.133 + this.implMethod = implMethod;
1.134 + this.implInfo = caller.revealDirect(implMethod);
1.135 + this.implKind = implInfo.getReferenceKind();
1.136 + this.implIsInstanceMethod =
1.137 + implKind == MethodHandleInfo.REF_invokeVirtual ||
1.138 + implKind == MethodHandleInfo.REF_invokeSpecial ||
1.139 + implKind == MethodHandleInfo.REF_invokeInterface;
1.140 + this.implDefiningClass = implInfo.getDeclaringClass();
1.141 + this.implMethodType = implInfo.getMethodType();
1.142 + this.instantiatedMethodType = instantiatedMethodType;
1.143 + this.isSerializable = isSerializable;
1.144 + this.markerInterfaces = markerInterfaces;
1.145 + this.additionalBridges = additionalBridges;
1.146 +
1.147 + if (!samBase.isInterface()) {
1.148 + throw new LambdaConversionException(String.format(
1.149 + "Functional interface %s is not an interface",
1.150 + samBase.getName()));
1.151 + }
1.152 +
1.153 + for (Class<?> c : markerInterfaces) {
1.154 + if (!c.isInterface()) {
1.155 + throw new LambdaConversionException(String.format(
1.156 + "Marker interface %s is not an interface",
1.157 + c.getName()));
1.158 + }
1.159 + }
1.160 + }
1.161 +
1.162 + /**
1.163 + * Build the CallSite.
1.164 + *
1.165 + * @return a CallSite, which, when invoked, will return an instance of the
1.166 + * functional interface
1.167 + * @throws ReflectiveOperationException
1.168 + */
1.169 + abstract CallSite buildCallSite()
1.170 + throws LambdaConversionException;
1.171 +
1.172 + /**
1.173 + * Check the meta-factory arguments for errors
1.174 + * @throws LambdaConversionException if there are improper conversions
1.175 + */
1.176 + void validateMetafactoryArgs() throws LambdaConversionException {
1.177 + switch (implKind) {
1.178 + case MethodHandleInfo.REF_invokeInterface:
1.179 + case MethodHandleInfo.REF_invokeVirtual:
1.180 + case MethodHandleInfo.REF_invokeStatic:
1.181 + case MethodHandleInfo.REF_newInvokeSpecial:
1.182 + case MethodHandleInfo.REF_invokeSpecial:
1.183 + break;
1.184 + default:
1.185 + throw new LambdaConversionException(String.format("Unsupported MethodHandle kind: %s", implInfo));
1.186 + }
1.187 +
1.188 + // Check arity: optional-receiver + captured + SAM == impl
1.189 + final int implArity = implMethodType.parameterCount();
1.190 + final int receiverArity = implIsInstanceMethod ? 1 : 0;
1.191 + final int capturedArity = invokedType.parameterCount();
1.192 + final int samArity = samMethodType.parameterCount();
1.193 + final int instantiatedArity = instantiatedMethodType.parameterCount();
1.194 + if (implArity + receiverArity != capturedArity + samArity) {
1.195 + throw new LambdaConversionException(
1.196 + String.format("Incorrect number of parameters for %s method %s; %d captured parameters, %d functional interface method parameters, %d implementation parameters",
1.197 + implIsInstanceMethod ? "instance" : "static", implInfo,
1.198 + capturedArity, samArity, implArity));
1.199 + }
1.200 + if (instantiatedArity != samArity) {
1.201 + throw new LambdaConversionException(
1.202 + String.format("Incorrect number of parameters for %s method %s; %d instantiated parameters, %d functional interface method parameters",
1.203 + implIsInstanceMethod ? "instance" : "static", implInfo,
1.204 + instantiatedArity, samArity));
1.205 + }
1.206 + for (MethodType bridgeMT : additionalBridges) {
1.207 + if (bridgeMT.parameterCount() != samArity) {
1.208 + throw new LambdaConversionException(
1.209 + String.format("Incorrect number of parameters for bridge signature %s; incompatible with %s",
1.210 + bridgeMT, samMethodType));
1.211 + }
1.212 + }
1.213 +
1.214 + // If instance: first captured arg (receiver) must be subtype of class where impl method is defined
1.215 + final int capturedStart;
1.216 + final int samStart;
1.217 + if (implIsInstanceMethod) {
1.218 + final Class<?> receiverClass;
1.219 +
1.220 + // implementation is an instance method, adjust for receiver in captured variables / SAM arguments
1.221 + if (capturedArity == 0) {
1.222 + // receiver is function parameter
1.223 + capturedStart = 0;
1.224 + samStart = 1;
1.225 + receiverClass = instantiatedMethodType.parameterType(0);
1.226 + } else {
1.227 + // receiver is a captured variable
1.228 + capturedStart = 1;
1.229 + samStart = 0;
1.230 + receiverClass = invokedType.parameterType(0);
1.231 + }
1.232 +
1.233 + // check receiver type
1.234 + if (!implDefiningClass.isAssignableFrom(receiverClass)) {
1.235 + throw new LambdaConversionException(
1.236 + String.format("Invalid receiver type %s; not a subtype of implementation type %s",
1.237 + receiverClass, implDefiningClass));
1.238 + }
1.239 +
1.240 + Class<?> implReceiverClass = implMethod.type().parameterType(0);
1.241 + if (implReceiverClass != implDefiningClass && !implReceiverClass.isAssignableFrom(receiverClass)) {
1.242 + throw new LambdaConversionException(
1.243 + String.format("Invalid receiver type %s; not a subtype of implementation receiver type %s",
1.244 + receiverClass, implReceiverClass));
1.245 + }
1.246 + } else {
1.247 + // no receiver
1.248 + capturedStart = 0;
1.249 + samStart = 0;
1.250 + }
1.251 +
1.252 + // Check for exact match on non-receiver captured arguments
1.253 + final int implFromCaptured = capturedArity - capturedStart;
1.254 + for (int i=0; i<implFromCaptured; i++) {
1.255 + Class<?> implParamType = implMethodType.parameterType(i);
1.256 + Class<?> capturedParamType = invokedType.parameterType(i + capturedStart);
1.257 + if (!capturedParamType.equals(implParamType)) {
1.258 + throw new LambdaConversionException(
1.259 + String.format("Type mismatch in captured lambda parameter %d: expecting %s, found %s",
1.260 + i, capturedParamType, implParamType));
1.261 + }
1.262 + }
1.263 + // Check for adaptation match on SAM arguments
1.264 + final int samOffset = samStart - implFromCaptured;
1.265 + for (int i=implFromCaptured; i<implArity; i++) {
1.266 + Class<?> implParamType = implMethodType.parameterType(i);
1.267 + Class<?> instantiatedParamType = instantiatedMethodType.parameterType(i + samOffset);
1.268 + if (!isAdaptableTo(instantiatedParamType, implParamType, true)) {
1.269 + throw new LambdaConversionException(
1.270 + String.format("Type mismatch for lambda argument %d: %s is not convertible to %s",
1.271 + i, instantiatedParamType, implParamType));
1.272 + }
1.273 + }
1.274 +
1.275 + // Adaptation match: return type
1.276 + Class<?> expectedType = instantiatedMethodType.returnType();
1.277 + Class<?> actualReturnType =
1.278 + (implKind == MethodHandleInfo.REF_newInvokeSpecial)
1.279 + ? implDefiningClass
1.280 + : implMethodType.returnType();
1.281 + Class<?> samReturnType = samMethodType.returnType();
1.282 + if (!isAdaptableToAsReturn(actualReturnType, expectedType)) {
1.283 + throw new LambdaConversionException(
1.284 + String.format("Type mismatch for lambda return: %s is not convertible to %s",
1.285 + actualReturnType, expectedType));
1.286 + }
1.287 + if (!isAdaptableToAsReturnStrict(expectedType, samReturnType)) {
1.288 + throw new LambdaConversionException(
1.289 + String.format("Type mismatch for lambda expected return: %s is not convertible to %s",
1.290 + expectedType, samReturnType));
1.291 + }
1.292 + for (MethodType bridgeMT : additionalBridges) {
1.293 + if (!isAdaptableToAsReturnStrict(expectedType, bridgeMT.returnType())) {
1.294 + throw new LambdaConversionException(
1.295 + String.format("Type mismatch for lambda expected return: %s is not convertible to %s",
1.296 + expectedType, bridgeMT.returnType()));
1.297 + }
1.298 + }
1.299 + }
1.300 +
1.301 + /**
1.302 + * Check type adaptability for parameter types.
1.303 + * @param fromType Type to convert from
1.304 + * @param toType Type to convert to
1.305 + * @param strict If true, do strict checks, else allow that fromType may be parameterized
1.306 + * @return True if 'fromType' can be passed to an argument of 'toType'
1.307 + */
1.308 + private boolean isAdaptableTo(Class<?> fromType, Class<?> toType, boolean strict) {
1.309 + if (fromType.equals(toType)) {
1.310 + return true;
1.311 + }
1.312 + if (fromType.isPrimitive()) {
1.313 + Wrapper wfrom = forPrimitiveType(fromType);
1.314 + if (toType.isPrimitive()) {
1.315 + // both are primitive: widening
1.316 + Wrapper wto = forPrimitiveType(toType);
1.317 + return wto.isConvertibleFrom(wfrom);
1.318 + } else {
1.319 + // from primitive to reference: boxing
1.320 + return toType.isAssignableFrom(wfrom.wrapperType());
1.321 + }
1.322 + } else {
1.323 + if (toType.isPrimitive()) {
1.324 + // from reference to primitive: unboxing
1.325 + Wrapper wfrom;
1.326 + if (isWrapperType(fromType) && (wfrom = forWrapperType(fromType)).primitiveType().isPrimitive()) {
1.327 + // fromType is a primitive wrapper; unbox+widen
1.328 + Wrapper wto = forPrimitiveType(toType);
1.329 + return wto.isConvertibleFrom(wfrom);
1.330 + } else {
1.331 + // must be convertible to primitive
1.332 + return !strict;
1.333 + }
1.334 + } else {
1.335 + // both are reference types: fromType should be a superclass of toType.
1.336 + return !strict || toType.isAssignableFrom(fromType);
1.337 + }
1.338 + }
1.339 + }
1.340 +
1.341 + /**
1.342 + * Check type adaptability for return types --
1.343 + * special handling of void type) and parameterized fromType
1.344 + * @return True if 'fromType' can be converted to 'toType'
1.345 + */
1.346 + private boolean isAdaptableToAsReturn(Class<?> fromType, Class<?> toType) {
1.347 + return toType.equals(void.class)
1.348 + || !fromType.equals(void.class) && isAdaptableTo(fromType, toType, false);
1.349 + }
1.350 + private boolean isAdaptableToAsReturnStrict(Class<?> fromType, Class<?> toType) {
1.351 + if (fromType.equals(void.class)) return toType.equals(void.class);
1.352 + return isAdaptableTo(fromType, toType, true);
1.353 + }
1.354 +
1.355 +
1.356 + /*********** Logging support -- for debugging only, uncomment as needed
1.357 + static final Executor logPool = Executors.newSingleThreadExecutor();
1.358 + protected static void log(final String s) {
1.359 + MethodHandleProxyLambdaMetafactory.logPool.execute(new Runnable() {
1.360 + @Override
1.361 + public void run() {
1.362 + System.out.println(s);
1.363 + }
1.364 + });
1.365 + }
1.366 +
1.367 + protected static void log(final String s, final Throwable e) {
1.368 + MethodHandleProxyLambdaMetafactory.logPool.execute(new Runnable() {
1.369 + @Override
1.370 + public void run() {
1.371 + System.out.println(s);
1.372 + e.printStackTrace(System.out);
1.373 + }
1.374 + });
1.375 + }
1.376 + ***********************/
1.377 +
1.378 +}
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/BoundMethodHandle.java Sat Aug 09 11:12:05 2014 +0200
2.3 @@ -0,0 +1,864 @@
2.4 +/*
2.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
2.7 + *
2.8 + * This code is free software; you can redistribute it and/or modify it
2.9 + * under the terms of the GNU General Public License version 2 only, as
2.10 + * published by the Free Software Foundation. Oracle designates this
2.11 + * particular file as subject to the "Classpath" exception as provided
2.12 + * by Oracle in the LICENSE file that accompanied this code.
2.13 + *
2.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
2.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
2.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
2.17 + * version 2 for more details (a copy is included in the LICENSE file that
2.18 + * accompanied this code).
2.19 + *
2.20 + * You should have received a copy of the GNU General Public License version
2.21 + * 2 along with this work; if not, write to the Free Software Foundation,
2.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2.23 + *
2.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2.25 + * or visit www.oracle.com if you need additional information or have any
2.26 + * questions.
2.27 + */
2.28 +
2.29 +package java.lang.invoke;
2.30 +
2.31 +import static jdk.internal.org.objectweb.asm.Opcodes.*;
2.32 +import static java.lang.invoke.LambdaForm.basicTypes;
2.33 +import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
2.34 +import static java.lang.invoke.MethodHandleStatics.*;
2.35 +
2.36 +import java.lang.invoke.LambdaForm.Name;
2.37 +import java.lang.invoke.LambdaForm.NamedFunction;
2.38 +import java.lang.invoke.MethodHandles.Lookup;
2.39 +import java.lang.reflect.Field;
2.40 +import java.util.Arrays;
2.41 +import java.util.HashMap;
2.42 +
2.43 +import sun.invoke.util.ValueConversions;
2.44 +import sun.invoke.util.Wrapper;
2.45 +
2.46 +import jdk.internal.org.objectweb.asm.ClassWriter;
2.47 +import jdk.internal.org.objectweb.asm.MethodVisitor;
2.48 +import jdk.internal.org.objectweb.asm.Type;
2.49 +
2.50 +/**
2.51 + * The flavor of method handle which emulates an invoke instruction
2.52 + * on a predetermined argument. The JVM dispatches to the correct method
2.53 + * when the handle is created, not when it is invoked.
2.54 + *
2.55 + * All bound arguments are encapsulated in dedicated species.
2.56 + */
2.57 +/* non-public */ abstract class BoundMethodHandle extends MethodHandle {
2.58 +
2.59 + /* non-public */ BoundMethodHandle(MethodType type, LambdaForm form) {
2.60 + super(type, form);
2.61 + }
2.62 +
2.63 + //
2.64 + // BMH API and internals
2.65 + //
2.66 +
2.67 + static MethodHandle bindSingle(MethodType type, LambdaForm form, char xtype, Object x) {
2.68 + // for some type signatures, there exist pre-defined concrete BMH classes
2.69 + try {
2.70 + switch (xtype) {
2.71 + case 'L':
2.72 + if (true) return bindSingle(type, form, x); // Use known fast path.
2.73 + return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('L').constructor[0].invokeBasic(type, form, x);
2.74 + case 'I':
2.75 + return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('I').constructor[0].invokeBasic(type, form, ValueConversions.widenSubword(x));
2.76 + case 'J':
2.77 + return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('J').constructor[0].invokeBasic(type, form, (long) x);
2.78 + case 'F':
2.79 + return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('F').constructor[0].invokeBasic(type, form, (float) x);
2.80 + case 'D':
2.81 + return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('D').constructor[0].invokeBasic(type, form, (double) x);
2.82 + default : throw new InternalError("unexpected xtype: " + xtype);
2.83 + }
2.84 + } catch (Throwable t) {
2.85 + throw newInternalError(t);
2.86 + }
2.87 + }
2.88 +
2.89 + static MethodHandle bindSingle(MethodType type, LambdaForm form, Object x) {
2.90 + return new Species_L(type, form, x);
2.91 + }
2.92 +
2.93 + MethodHandle cloneExtend(MethodType type, LambdaForm form, char xtype, Object x) {
2.94 + try {
2.95 + switch (xtype) {
2.96 + case 'L': return cloneExtendL(type, form, x);
2.97 + case 'I': return cloneExtendI(type, form, ValueConversions.widenSubword(x));
2.98 + case 'J': return cloneExtendJ(type, form, (long) x);
2.99 + case 'F': return cloneExtendF(type, form, (float) x);
2.100 + case 'D': return cloneExtendD(type, form, (double) x);
2.101 + }
2.102 + } catch (Throwable t) {
2.103 + throw newInternalError(t);
2.104 + }
2.105 + throw new InternalError("unexpected type: " + xtype);
2.106 + }
2.107 +
2.108 + @Override
2.109 + MethodHandle bindArgument(int pos, char basicType, Object value) {
2.110 + MethodType type = type().dropParameterTypes(pos, pos+1);
2.111 + LambdaForm form = internalForm().bind(1+pos, speciesData());
2.112 + return cloneExtend(type, form, basicType, value);
2.113 + }
2.114 +
2.115 + @Override
2.116 + MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
2.117 + LambdaForm form = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos+drops));
2.118 + try {
2.119 + return clone(srcType, form);
2.120 + } catch (Throwable t) {
2.121 + throw newInternalError(t);
2.122 + }
2.123 + }
2.124 +
2.125 + @Override
2.126 + MethodHandle permuteArguments(MethodType newType, int[] reorder) {
2.127 + try {
2.128 + return clone(newType, form.permuteArguments(1, reorder, basicTypes(newType.parameterList())));
2.129 + } catch (Throwable t) {
2.130 + throw newInternalError(t);
2.131 + }
2.132 + }
2.133 +
2.134 + static final String EXTENSION_TYPES = "LIJFD";
2.135 + static final byte INDEX_L = 0, INDEX_I = 1, INDEX_J = 2, INDEX_F = 3, INDEX_D = 4;
2.136 + static byte extensionIndex(char type) {
2.137 + int i = EXTENSION_TYPES.indexOf(type);
2.138 + if (i < 0) throw new InternalError();
2.139 + return (byte) i;
2.140 + }
2.141 +
2.142 + /**
2.143 + * Return the {@link SpeciesData} instance representing this BMH species. All subclasses must provide a
2.144 + * static field containing this value, and they must accordingly implement this method.
2.145 + */
2.146 + protected abstract SpeciesData speciesData();
2.147 +
2.148 + @Override
2.149 + final Object internalProperties() {
2.150 + return "/BMH="+internalValues();
2.151 + }
2.152 +
2.153 + @Override
2.154 + final Object internalValues() {
2.155 + Object[] boundValues = new Object[speciesData().fieldCount()];
2.156 + for (int i = 0; i < boundValues.length; ++i) {
2.157 + boundValues[i] = arg(i);
2.158 + }
2.159 + return Arrays.asList(boundValues);
2.160 + }
2.161 +
2.162 + public final Object arg(int i) {
2.163 + try {
2.164 + switch (speciesData().fieldType(i)) {
2.165 + case 'L': return argL(i);
2.166 + case 'I': return argI(i);
2.167 + case 'F': return argF(i);
2.168 + case 'D': return argD(i);
2.169 + case 'J': return argJ(i);
2.170 + }
2.171 + } catch (Throwable ex) {
2.172 + throw newInternalError(ex);
2.173 + }
2.174 + throw new InternalError("unexpected type: " + speciesData().types+"."+i);
2.175 + }
2.176 + public final Object argL(int i) throws Throwable { return speciesData().getters[i].invokeBasic(this); }
2.177 + public final int argI(int i) throws Throwable { return (int) speciesData().getters[i].invokeBasic(this); }
2.178 + public final float argF(int i) throws Throwable { return (float) speciesData().getters[i].invokeBasic(this); }
2.179 + public final double argD(int i) throws Throwable { return (double) speciesData().getters[i].invokeBasic(this); }
2.180 + public final long argJ(int i) throws Throwable { return (long) speciesData().getters[i].invokeBasic(this); }
2.181 +
2.182 + //
2.183 + // cloning API
2.184 + //
2.185 +
2.186 + public abstract BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable;
2.187 + public abstract BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable;
2.188 + public abstract BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable;
2.189 + public abstract BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable;
2.190 + public abstract BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable;
2.191 + public abstract BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable;
2.192 +
2.193 + // The following is a grossly irregular hack:
2.194 + @Override MethodHandle reinvokerTarget() {
2.195 + try {
2.196 + return (MethodHandle) argL(0);
2.197 + } catch (Throwable ex) {
2.198 + throw newInternalError(ex);
2.199 + }
2.200 + }
2.201 +
2.202 + //
2.203 + // concrete BMH classes required to close bootstrap loops
2.204 + //
2.205 +
2.206 + private // make it private to force users to access the enclosing class first
2.207 + static final class Species_L extends BoundMethodHandle {
2.208 + final Object argL0;
2.209 + public Species_L(MethodType mt, LambdaForm lf, Object argL0) {
2.210 + super(mt, lf);
2.211 + this.argL0 = argL0;
2.212 + }
2.213 + // The following is a grossly irregular hack:
2.214 + @Override MethodHandle reinvokerTarget() { return (MethodHandle) argL0; }
2.215 + @Override
2.216 + public SpeciesData speciesData() {
2.217 + return SPECIES_DATA;
2.218 + }
2.219 + public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("L", Species_L.class);
2.220 + @Override
2.221 + public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
2.222 + return new Species_L(mt, lf, argL0);
2.223 + }
2.224 + @Override
2.225 + public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
2.226 + return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, narg);
2.227 + }
2.228 + @Override
2.229 + public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
2.230 + return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, narg);
2.231 + }
2.232 + @Override
2.233 + public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
2.234 + return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, narg);
2.235 + }
2.236 + @Override
2.237 + public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
2.238 + return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, narg);
2.239 + }
2.240 + @Override
2.241 + public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
2.242 + return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, narg);
2.243 + }
2.244 + }
2.245 +
2.246 +/*
2.247 + static final class Species_LL extends BoundMethodHandle {
2.248 + final Object argL0;
2.249 + final Object argL1;
2.250 + public Species_LL(MethodType mt, LambdaForm lf, Object argL0, Object argL1) {
2.251 + super(mt, lf);
2.252 + this.argL0 = argL0;
2.253 + this.argL1 = argL1;
2.254 + }
2.255 + @Override
2.256 + public SpeciesData speciesData() {
2.257 + return SPECIES_DATA;
2.258 + }
2.259 + public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LL", Species_LL.class);
2.260 + @Override
2.261 + public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
2.262 + return new Species_LL(mt, lf, argL0, argL1);
2.263 + }
2.264 + @Override
2.265 + public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
2.266 + return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
2.267 + }
2.268 + @Override
2.269 + public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
2.270 + return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
2.271 + }
2.272 + @Override
2.273 + public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
2.274 + return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
2.275 + }
2.276 + @Override
2.277 + public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
2.278 + return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
2.279 + }
2.280 + @Override
2.281 + public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
2.282 + return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
2.283 + }
2.284 + }
2.285 +
2.286 + static final class Species_JL extends BoundMethodHandle {
2.287 + final long argJ0;
2.288 + final Object argL1;
2.289 + public Species_JL(MethodType mt, LambdaForm lf, long argJ0, Object argL1) {
2.290 + super(mt, lf);
2.291 + this.argJ0 = argJ0;
2.292 + this.argL1 = argL1;
2.293 + }
2.294 + @Override
2.295 + public SpeciesData speciesData() {
2.296 + return SPECIES_DATA;
2.297 + }
2.298 + public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("JL", Species_JL.class);
2.299 + @Override public final long argJ0() { return argJ0; }
2.300 + @Override public final Object argL1() { return argL1; }
2.301 + @Override
2.302 + public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
2.303 + return new Species_JL(mt, lf, argJ0, argL1);
2.304 + }
2.305 + @Override
2.306 + public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
2.307 + return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
2.308 + }
2.309 + @Override
2.310 + public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
2.311 + return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
2.312 + }
2.313 + @Override
2.314 + public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
2.315 + return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
2.316 + }
2.317 + @Override
2.318 + public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
2.319 + return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
2.320 + }
2.321 + @Override
2.322 + public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
2.323 + return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
2.324 + }
2.325 + }
2.326 +*/
2.327 +
2.328 + //
2.329 + // BMH species meta-data
2.330 + //
2.331 +
2.332 + /**
2.333 + * Meta-data wrapper for concrete BMH classes.
2.334 + */
2.335 + static class SpeciesData {
2.336 + final String types;
2.337 + final Class<? extends BoundMethodHandle> clazz;
2.338 + // Bootstrapping requires circular relations MH -> BMH -> SpeciesData -> MH
2.339 + // Therefore, we need a non-final link in the chain. Use array elements.
2.340 + final MethodHandle[] constructor;
2.341 + final MethodHandle[] getters;
2.342 + final SpeciesData[] extensions;
2.343 +
2.344 + public int fieldCount() {
2.345 + return types.length();
2.346 + }
2.347 + public char fieldType(int i) {
2.348 + return types.charAt(i);
2.349 + }
2.350 +
2.351 + public String toString() {
2.352 + return "SpeciesData["+(isPlaceholder() ? "<placeholder>" : clazz.getSimpleName())+":"+types+"]";
2.353 + }
2.354 +
2.355 + /**
2.356 + * Return a {@link LambdaForm.Name} containing a {@link LambdaForm.NamedFunction} that
2.357 + * represents a MH bound to a generic invoker, which in turn forwards to the corresponding
2.358 + * getter.
2.359 + */
2.360 + Name getterName(Name mhName, int i) {
2.361 + MethodHandle mh = getters[i];
2.362 + assert(mh != null) : this+"."+i;
2.363 + return new Name(mh, mhName);
2.364 + }
2.365 +
2.366 + NamedFunction getterFunction(int i) {
2.367 + return new NamedFunction(getters[i]);
2.368 + }
2.369 +
2.370 + static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class);
2.371 +
2.372 + private SpeciesData(String types, Class<? extends BoundMethodHandle> clazz) {
2.373 + this.types = types;
2.374 + this.clazz = clazz;
2.375 + if (!INIT_DONE) {
2.376 + this.constructor = new MethodHandle[1];
2.377 + this.getters = new MethodHandle[types.length()];
2.378 + } else {
2.379 + this.constructor = Factory.makeCtors(clazz, types, null);
2.380 + this.getters = Factory.makeGetters(clazz, types, null);
2.381 + }
2.382 + this.extensions = new SpeciesData[EXTENSION_TYPES.length()];
2.383 + }
2.384 +
2.385 + private void initForBootstrap() {
2.386 + assert(!INIT_DONE);
2.387 + if (constructor[0] == null) {
2.388 + Factory.makeCtors(clazz, types, this.constructor);
2.389 + Factory.makeGetters(clazz, types, this.getters);
2.390 + }
2.391 + }
2.392 +
2.393 + private SpeciesData(String types) {
2.394 + // Placeholder only.
2.395 + this.types = types;
2.396 + this.clazz = null;
2.397 + this.constructor = null;
2.398 + this.getters = null;
2.399 + this.extensions = null;
2.400 + }
2.401 + private boolean isPlaceholder() { return clazz == null; }
2.402 +
2.403 + private static final HashMap<String, SpeciesData> CACHE = new HashMap<>();
2.404 + static { CACHE.put("", EMPTY); } // make bootstrap predictable
2.405 + private static final boolean INIT_DONE; // set after <clinit> finishes...
2.406 +
2.407 + SpeciesData extendWithType(char type) {
2.408 + int i = extensionIndex(type);
2.409 + SpeciesData d = extensions[i];
2.410 + if (d != null) return d;
2.411 + extensions[i] = d = get(types+type);
2.412 + return d;
2.413 + }
2.414 +
2.415 + SpeciesData extendWithIndex(byte index) {
2.416 + SpeciesData d = extensions[index];
2.417 + if (d != null) return d;
2.418 + extensions[index] = d = get(types+EXTENSION_TYPES.charAt(index));
2.419 + return d;
2.420 + }
2.421 +
2.422 + private static SpeciesData get(String types) {
2.423 + // Acquire cache lock for query.
2.424 + SpeciesData d = lookupCache(types);
2.425 + if (!d.isPlaceholder())
2.426 + return d;
2.427 + synchronized (d) {
2.428 + // Use synch. on the placeholder to prevent multiple instantiation of one species.
2.429 + // Creating this class forces a recursive call to getForClass.
2.430 + if (lookupCache(types).isPlaceholder())
2.431 + Factory.generateConcreteBMHClass(types);
2.432 + }
2.433 + // Reacquire cache lock.
2.434 + d = lookupCache(types);
2.435 + // Class loading must have upgraded the cache.
2.436 + assert(d != null && !d.isPlaceholder());
2.437 + return d;
2.438 + }
2.439 + static SpeciesData getForClass(String types, Class<? extends BoundMethodHandle> clazz) {
2.440 + // clazz is a new class which is initializing its SPECIES_DATA field
2.441 + return updateCache(types, new SpeciesData(types, clazz));
2.442 + }
2.443 + private static synchronized SpeciesData lookupCache(String types) {
2.444 + SpeciesData d = CACHE.get(types);
2.445 + if (d != null) return d;
2.446 + d = new SpeciesData(types);
2.447 + assert(d.isPlaceholder());
2.448 + CACHE.put(types, d);
2.449 + return d;
2.450 + }
2.451 + private static synchronized SpeciesData updateCache(String types, SpeciesData d) {
2.452 + SpeciesData d2;
2.453 + assert((d2 = CACHE.get(types)) == null || d2.isPlaceholder());
2.454 + assert(!d.isPlaceholder());
2.455 + CACHE.put(types, d);
2.456 + return d;
2.457 + }
2.458 +
2.459 + static {
2.460 + // pre-fill the BMH speciesdata cache with BMH's inner classes
2.461 + final Class<BoundMethodHandle> rootCls = BoundMethodHandle.class;
2.462 + SpeciesData d0 = BoundMethodHandle.SPECIES_DATA; // trigger class init
2.463 + assert(d0 == null || d0 == lookupCache("")) : d0;
2.464 + try {
2.465 + for (Class<?> c : rootCls.getDeclaredClasses()) {
2.466 + if (rootCls.isAssignableFrom(c)) {
2.467 + final Class<? extends BoundMethodHandle> cbmh = c.asSubclass(BoundMethodHandle.class);
2.468 + SpeciesData d = Factory.speciesDataFromConcreteBMHClass(cbmh);
2.469 + assert(d != null) : cbmh.getName();
2.470 + assert(d.clazz == cbmh);
2.471 + assert(d == lookupCache(d.types));
2.472 + }
2.473 + }
2.474 + } catch (Throwable e) {
2.475 + throw newInternalError(e);
2.476 + }
2.477 +
2.478 + for (SpeciesData d : CACHE.values()) {
2.479 + d.initForBootstrap();
2.480 + }
2.481 + // Note: Do not simplify this, because INIT_DONE must not be
2.482 + // a compile-time constant during bootstrapping.
2.483 + INIT_DONE = Boolean.TRUE;
2.484 + }
2.485 + }
2.486 +
2.487 + static SpeciesData getSpeciesData(String types) {
2.488 + return SpeciesData.get(types);
2.489 + }
2.490 +
2.491 + /**
2.492 + * Generation of concrete BMH classes.
2.493 + *
2.494 + * A concrete BMH species is fit for binding a number of values adhering to a
2.495 + * given type pattern. Reference types are erased.
2.496 + *
2.497 + * BMH species are cached by type pattern.
2.498 + *
2.499 + * A BMH species has a number of fields with the concrete (possibly erased) types of
2.500 + * bound values. Setters are provided as an API in BMH. Getters are exposed as MHs,
2.501 + * which can be included as names in lambda forms.
2.502 + */
2.503 + static class Factory {
2.504 +
2.505 + static final String JLO_SIG = "Ljava/lang/Object;";
2.506 + static final String JLS_SIG = "Ljava/lang/String;";
2.507 + static final String JLC_SIG = "Ljava/lang/Class;";
2.508 + static final String MH = "java/lang/invoke/MethodHandle";
2.509 + static final String MH_SIG = "L"+MH+";";
2.510 + static final String BMH = "java/lang/invoke/BoundMethodHandle";
2.511 + static final String BMH_SIG = "L"+BMH+";";
2.512 + static final String SPECIES_DATA = "java/lang/invoke/BoundMethodHandle$SpeciesData";
2.513 + static final String SPECIES_DATA_SIG = "L"+SPECIES_DATA+";";
2.514 +
2.515 + static final String SPECIES_PREFIX_NAME = "Species_";
2.516 + static final String SPECIES_PREFIX_PATH = BMH + "$" + SPECIES_PREFIX_NAME;
2.517 +
2.518 + static final String BMHSPECIES_DATA_EWI_SIG = "(B)" + SPECIES_DATA_SIG;
2.519 + static final String BMHSPECIES_DATA_GFC_SIG = "(" + JLS_SIG + JLC_SIG + ")" + SPECIES_DATA_SIG;
2.520 + static final String MYSPECIES_DATA_SIG = "()" + SPECIES_DATA_SIG;
2.521 + static final String VOID_SIG = "()V";
2.522 +
2.523 + static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
2.524 +
2.525 + static final Class<?>[] TYPES = new Class<?>[] { Object.class, int.class, long.class, float.class, double.class };
2.526 +
2.527 + static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
2.528 +
2.529 + /**
2.530 + * Generate a concrete subclass of BMH for a given combination of bound types.
2.531 + *
2.532 + * A concrete BMH species adheres to the following schema:
2.533 + *
2.534 + * <pre>
2.535 + * class Species_[[types]] extends BoundMethodHandle {
2.536 + * [[fields]]
2.537 + * final SpeciesData speciesData() { return SpeciesData.get("[[types]]"); }
2.538 + * }
2.539 + * </pre>
2.540 + *
2.541 + * The {@code [[types]]} signature is precisely the string that is passed to this
2.542 + * method.
2.543 + *
2.544 + * The {@code [[fields]]} section consists of one field definition per character in
2.545 + * the type signature, adhering to the naming schema described in the definition of
2.546 + * {@link #makeFieldName}.
2.547 + *
2.548 + * For example, a concrete BMH species for two reference and one integral bound values
2.549 + * would have the following shape:
2.550 + *
2.551 + * <pre>
2.552 + * class BoundMethodHandle { ... private static
2.553 + * final class Species_LLI extends BoundMethodHandle {
2.554 + * final Object argL0;
2.555 + * final Object argL1;
2.556 + * final int argI2;
2.557 + * public Species_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
2.558 + * super(mt, lf);
2.559 + * this.argL0 = argL0;
2.560 + * this.argL1 = argL1;
2.561 + * this.argI2 = argI2;
2.562 + * }
2.563 + * public final SpeciesData speciesData() { return SPECIES_DATA; }
2.564 + * public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LLI", Species_LLI.class);
2.565 + * public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) {
2.566 + * return SPECIES_DATA.constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2);
2.567 + * }
2.568 + * public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) {
2.569 + * return SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
2.570 + * }
2.571 + * public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) {
2.572 + * return SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
2.573 + * }
2.574 + * public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) {
2.575 + * return SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
2.576 + * }
2.577 + * public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) {
2.578 + * return SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
2.579 + * }
2.580 + * public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) {
2.581 + * return SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
2.582 + * }
2.583 + * }
2.584 + * </pre>
2.585 + *
2.586 + * @param types the type signature, wherein reference types are erased to 'L'
2.587 + * @return the generated concrete BMH class
2.588 + */
2.589 + static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
2.590 + final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
2.591 +
2.592 + final String className = SPECIES_PREFIX_PATH + types;
2.593 + final String sourceFile = SPECIES_PREFIX_NAME + types;
2.594 + cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null);
2.595 + cw.visitSource(sourceFile, null);
2.596 +
2.597 + // emit static types and SPECIES_DATA fields
2.598 + cw.visitField(ACC_PUBLIC + ACC_STATIC, "SPECIES_DATA", SPECIES_DATA_SIG, null, null).visitEnd();
2.599 +
2.600 + // emit bound argument fields
2.601 + for (int i = 0; i < types.length(); ++i) {
2.602 + final char t = types.charAt(i);
2.603 + final String fieldName = makeFieldName(types, i);
2.604 + final String fieldDesc = t == 'L' ? JLO_SIG : String.valueOf(t);
2.605 + cw.visitField(ACC_FINAL, fieldName, fieldDesc, null, null).visitEnd();
2.606 + }
2.607 +
2.608 + MethodVisitor mv;
2.609 +
2.610 + // emit constructor
2.611 + mv = cw.visitMethod(ACC_PUBLIC, "<init>", makeSignature(types, true), null, null);
2.612 + mv.visitCode();
2.613 + mv.visitVarInsn(ALOAD, 0);
2.614 + mv.visitVarInsn(ALOAD, 1);
2.615 + mv.visitVarInsn(ALOAD, 2);
2.616 +
2.617 + mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true));
2.618 +
2.619 + for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
2.620 + // i counts the arguments, j counts corresponding argument slots
2.621 + char t = types.charAt(i);
2.622 + mv.visitVarInsn(ALOAD, 0);
2.623 + mv.visitVarInsn(typeLoadOp(t), j + 3); // parameters start at 3
2.624 + mv.visitFieldInsn(PUTFIELD, className, makeFieldName(types, i), typeSig(t));
2.625 + if (t == 'J' || t == 'D') {
2.626 + ++j; // adjust argument register access
2.627 + }
2.628 + }
2.629 +
2.630 + mv.visitInsn(RETURN);
2.631 + mv.visitMaxs(0, 0);
2.632 + mv.visitEnd();
2.633 +
2.634 + // emit implementation of reinvokerTarget()
2.635 + mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "reinvokerTarget", "()" + MH_SIG, null, null);
2.636 + mv.visitCode();
2.637 + mv.visitVarInsn(ALOAD, 0);
2.638 + mv.visitFieldInsn(GETFIELD, className, "argL0", JLO_SIG);
2.639 + mv.visitTypeInsn(CHECKCAST, MH);
2.640 + mv.visitInsn(ARETURN);
2.641 + mv.visitMaxs(0, 0);
2.642 + mv.visitEnd();
2.643 +
2.644 + // emit implementation of speciesData()
2.645 + mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "speciesData", MYSPECIES_DATA_SIG, null, null);
2.646 + mv.visitCode();
2.647 + mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
2.648 + mv.visitInsn(ARETURN);
2.649 + mv.visitMaxs(0, 0);
2.650 + mv.visitEnd();
2.651 +
2.652 + // emit clone()
2.653 + mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "clone", makeSignature("", false), null, E_THROWABLE);
2.654 + mv.visitCode();
2.655 + // return speciesData().constructor[0].invokeBasic(mt, lf, argL0, ...)
2.656 + // obtain constructor
2.657 + mv.visitVarInsn(ALOAD, 0);
2.658 + mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
2.659 + mv.visitFieldInsn(GETFIELD, SPECIES_DATA, "constructor", "[" + MH_SIG);
2.660 + mv.visitInsn(ICONST_0);
2.661 + mv.visitInsn(AALOAD);
2.662 + // load mt, lf
2.663 + mv.visitVarInsn(ALOAD, 1);
2.664 + mv.visitVarInsn(ALOAD, 2);
2.665 + // put fields on the stack
2.666 + emitPushFields(types, className, mv);
2.667 + // finally, invoke the constructor and return
2.668 + mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types, false));
2.669 + mv.visitInsn(ARETURN);
2.670 + mv.visitMaxs(0, 0);
2.671 + mv.visitEnd();
2.672 +
2.673 + // for each type, emit cloneExtendT()
2.674 + for (Class<?> c : TYPES) {
2.675 + char t = Wrapper.basicTypeChar(c);
2.676 + mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "cloneExtend" + t, makeSignature(String.valueOf(t), false), null, E_THROWABLE);
2.677 + mv.visitCode();
2.678 + // return SPECIES_DATA.extendWithIndex(extensionIndex(t)).constructor[0].invokeBasic(mt, lf, argL0, ..., narg)
2.679 + // obtain constructor
2.680 + mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
2.681 + int iconstInsn = ICONST_0 + extensionIndex(t);
2.682 + assert(iconstInsn <= ICONST_5);
2.683 + mv.visitInsn(iconstInsn);
2.684 + mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWithIndex", BMHSPECIES_DATA_EWI_SIG);
2.685 + mv.visitFieldInsn(GETFIELD, SPECIES_DATA, "constructor", "[" + MH_SIG);
2.686 + mv.visitInsn(ICONST_0);
2.687 + mv.visitInsn(AALOAD);
2.688 + // load mt, lf
2.689 + mv.visitVarInsn(ALOAD, 1);
2.690 + mv.visitVarInsn(ALOAD, 2);
2.691 + // put fields on the stack
2.692 + emitPushFields(types, className, mv);
2.693 + // put narg on stack
2.694 + mv.visitVarInsn(typeLoadOp(t), 3);
2.695 + // finally, invoke the constructor and return
2.696 + mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types + t, false));
2.697 + mv.visitInsn(ARETURN);
2.698 + mv.visitMaxs(0, 0);
2.699 + mv.visitEnd();
2.700 + }
2.701 +
2.702 + // emit class initializer
2.703 + mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "<clinit>", VOID_SIG, null, null);
2.704 + mv.visitCode();
2.705 + mv.visitLdcInsn(types);
2.706 + mv.visitLdcInsn(Type.getObjectType(className));
2.707 + mv.visitMethodInsn(INVOKESTATIC, SPECIES_DATA, "getForClass", BMHSPECIES_DATA_GFC_SIG);
2.708 + mv.visitFieldInsn(PUTSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
2.709 + mv.visitInsn(RETURN);
2.710 + mv.visitMaxs(0, 0);
2.711 + mv.visitEnd();
2.712 +
2.713 + cw.visitEnd();
2.714 +
2.715 + // load class
2.716 + final byte[] classFile = cw.toByteArray();
2.717 + InvokerBytecodeGenerator.maybeDump(className, classFile);
2.718 + Class<? extends BoundMethodHandle> bmhClass =
2.719 + //UNSAFE.defineAnonymousClass(BoundMethodHandle.class, classFile, null).asSubclass(BoundMethodHandle.class);
2.720 + UNSAFE.defineClass(className, classFile, 0, classFile.length,
2.721 + BoundMethodHandle.class.getClassLoader(), null)
2.722 + .asSubclass(BoundMethodHandle.class);
2.723 + UNSAFE.ensureClassInitialized(bmhClass);
2.724 +
2.725 + return bmhClass;
2.726 + }
2.727 +
2.728 + private static int typeLoadOp(char t) {
2.729 + switch (t) {
2.730 + case 'L': return ALOAD;
2.731 + case 'I': return ILOAD;
2.732 + case 'J': return LLOAD;
2.733 + case 'F': return FLOAD;
2.734 + case 'D': return DLOAD;
2.735 + default : throw new InternalError("unrecognized type " + t);
2.736 + }
2.737 + }
2.738 +
2.739 + private static void emitPushFields(String types, String className, MethodVisitor mv) {
2.740 + for (int i = 0; i < types.length(); ++i) {
2.741 + char tc = types.charAt(i);
2.742 + mv.visitVarInsn(ALOAD, 0);
2.743 + mv.visitFieldInsn(GETFIELD, className, makeFieldName(types, i), typeSig(tc));
2.744 + }
2.745 + }
2.746 +
2.747 + static String typeSig(char t) {
2.748 + return t == 'L' ? JLO_SIG : String.valueOf(t);
2.749 + }
2.750 +
2.751 + //
2.752 + // Getter MH generation.
2.753 + //
2.754 +
2.755 + private static MethodHandle makeGetter(Class<?> cbmhClass, String types, int index) {
2.756 + String fieldName = makeFieldName(types, index);
2.757 + Class<?> fieldType = Wrapper.forBasicType(types.charAt(index)).primitiveType();
2.758 + try {
2.759 + return LOOKUP.findGetter(cbmhClass, fieldName, fieldType);
2.760 + } catch (NoSuchFieldException | IllegalAccessException e) {
2.761 + throw newInternalError(e);
2.762 + }
2.763 + }
2.764 +
2.765 + static MethodHandle[] makeGetters(Class<?> cbmhClass, String types, MethodHandle[] mhs) {
2.766 + if (mhs == null) mhs = new MethodHandle[types.length()];
2.767 + for (int i = 0; i < mhs.length; ++i) {
2.768 + mhs[i] = makeGetter(cbmhClass, types, i);
2.769 + assert(mhs[i].internalMemberName().getDeclaringClass() == cbmhClass);
2.770 + }
2.771 + return mhs;
2.772 + }
2.773 +
2.774 + static MethodHandle[] makeCtors(Class<? extends BoundMethodHandle> cbmh, String types, MethodHandle mhs[]) {
2.775 + if (mhs == null) mhs = new MethodHandle[1];
2.776 + mhs[0] = makeCbmhCtor(cbmh, types);
2.777 + return mhs;
2.778 + }
2.779 +
2.780 + //
2.781 + // Auxiliary methods.
2.782 + //
2.783 +
2.784 + static SpeciesData speciesDataFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
2.785 + try {
2.786 + Field F_SPECIES_DATA = cbmh.getDeclaredField("SPECIES_DATA");
2.787 + return (SpeciesData) F_SPECIES_DATA.get(null);
2.788 + } catch (ReflectiveOperationException ex) {
2.789 + throw newInternalError(ex);
2.790 + }
2.791 + }
2.792 +
2.793 + /**
2.794 + * Field names in concrete BMHs adhere to this pattern:
2.795 + * arg + type + index
2.796 + * where type is a single character (L, I, J, F, D).
2.797 + */
2.798 + private static String makeFieldName(String types, int index) {
2.799 + assert index >= 0 && index < types.length();
2.800 + return "arg" + types.charAt(index) + index;
2.801 + }
2.802 +
2.803 + private static String makeSignature(String types, boolean ctor) {
2.804 + StringBuilder buf = new StringBuilder(SIG_INCIPIT);
2.805 + for (char c : types.toCharArray()) {
2.806 + buf.append(typeSig(c));
2.807 + }
2.808 + return buf.append(')').append(ctor ? "V" : BMH_SIG).toString();
2.809 + }
2.810 +
2.811 + static MethodHandle makeCbmhCtor(Class<? extends BoundMethodHandle> cbmh, String types) {
2.812 + try {
2.813 + return linkConstructor(LOOKUP.findConstructor(cbmh, MethodType.fromMethodDescriptorString(makeSignature(types, true), null)));
2.814 + } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | TypeNotPresentException e) {
2.815 + throw newInternalError(e);
2.816 + }
2.817 + }
2.818 +
2.819 + /**
2.820 + * Wrap a constructor call in a {@link LambdaForm}.
2.821 + *
2.822 + * If constructors ({@code <init>} methods) are called in LFs, problems might arise if the LFs
2.823 + * are turned into bytecode, because the call to the allocator is routed through an MH, and the
2.824 + * verifier cannot find a {@code NEW} instruction preceding the {@code INVOKESPECIAL} to
2.825 + * {@code <init>}. To avoid this, we add an indirection by invoking {@code <init>} through
2.826 + * {@link MethodHandle#linkToSpecial}.
2.827 + *
2.828 + * The last {@link LambdaForm.Name Name} in the argument's form is expected to be the {@code void}
2.829 + * result of the {@code <init>} invocation. This entry is replaced.
2.830 + */
2.831 + private static MethodHandle linkConstructor(MethodHandle cmh) {
2.832 + final LambdaForm lf = cmh.form;
2.833 + final int initNameIndex = lf.names.length - 1;
2.834 + final Name initName = lf.names[initNameIndex];
2.835 + final MemberName ctorMN = initName.function.member;
2.836 + final MethodType ctorMT = ctorMN.getInvocationType();
2.837 +
2.838 + // obtain function member (call target)
2.839 + // linker method type replaces initial parameter (BMH species) with BMH to avoid naming a species (anonymous class!)
2.840 + final MethodType linkerMT = ctorMT.changeParameterType(0, BoundMethodHandle.class).appendParameterTypes(MemberName.class);
2.841 + MemberName linkerMN = new MemberName(MethodHandle.class, "linkToSpecial", linkerMT, REF_invokeStatic);
2.842 + try {
2.843 + linkerMN = MemberName.getFactory().resolveOrFail(REF_invokeStatic, linkerMN, null, NoSuchMethodException.class);
2.844 + assert(linkerMN.isStatic());
2.845 + } catch (ReflectiveOperationException ex) {
2.846 + throw newInternalError(ex);
2.847 + }
2.848 + // extend arguments array
2.849 + Object[] newArgs = Arrays.copyOf(initName.arguments, initName.arguments.length + 1);
2.850 + newArgs[newArgs.length - 1] = ctorMN;
2.851 + // replace function
2.852 + final NamedFunction nf = new NamedFunction(linkerMN);
2.853 + final Name linkedCtor = new Name(nf, newArgs);
2.854 + linkedCtor.initIndex(initNameIndex);
2.855 + lf.names[initNameIndex] = linkedCtor;
2.856 + return cmh;
2.857 + }
2.858 +
2.859 + }
2.860 +
2.861 + private static final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
2.862 +
2.863 + /**
2.864 + * All subclasses must provide such a value describing their type signature.
2.865 + */
2.866 + static final SpeciesData SPECIES_DATA = SpeciesData.EMPTY;
2.867 +}
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/CallSite.java Sat Aug 09 11:12:05 2014 +0200
3.3 @@ -0,0 +1,347 @@
3.4 +/*
3.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3.7 + *
3.8 + * This code is free software; you can redistribute it and/or modify it
3.9 + * under the terms of the GNU General Public License version 2 only, as
3.10 + * published by the Free Software Foundation. Oracle designates this
3.11 + * particular file as subject to the "Classpath" exception as provided
3.12 + * by Oracle in the LICENSE file that accompanied this code.
3.13 + *
3.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
3.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
3.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
3.17 + * version 2 for more details (a copy is included in the LICENSE file that
3.18 + * accompanied this code).
3.19 + *
3.20 + * You should have received a copy of the GNU General Public License version
3.21 + * 2 along with this work; if not, write to the Free Software Foundation,
3.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
3.23 + *
3.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
3.25 + * or visit www.oracle.com if you need additional information or have any
3.26 + * questions.
3.27 + */
3.28 +
3.29 +package java.lang.invoke;
3.30 +
3.31 +import sun.invoke.empty.Empty;
3.32 +import static java.lang.invoke.MethodHandleStatics.*;
3.33 +import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
3.34 +
3.35 +/**
3.36 + * A {@code CallSite} is a holder for a variable {@link MethodHandle},
3.37 + * which is called its {@code target}.
3.38 + * An {@code invokedynamic} instruction linked to a {@code CallSite} delegates
3.39 + * all calls to the site's current target.
3.40 + * A {@code CallSite} may be associated with several {@code invokedynamic}
3.41 + * instructions, or it may be "free floating", associated with none.
3.42 + * In any case, it may be invoked through an associated method handle
3.43 + * called its {@linkplain #dynamicInvoker dynamic invoker}.
3.44 + * <p>
3.45 + * {@code CallSite} is an abstract class which does not allow
3.46 + * direct subclassing by users. It has three immediate,
3.47 + * concrete subclasses that may be either instantiated or subclassed.
3.48 + * <ul>
3.49 + * <li>If a mutable target is not required, an {@code invokedynamic} instruction
3.50 + * may be permanently bound by means of a {@linkplain ConstantCallSite constant call site}.
3.51 + * <li>If a mutable target is required which has volatile variable semantics,
3.52 + * because updates to the target must be immediately and reliably witnessed by other threads,
3.53 + * a {@linkplain VolatileCallSite volatile call site} may be used.
3.54 + * <li>Otherwise, if a mutable target is required,
3.55 + * a {@linkplain MutableCallSite mutable call site} may be used.
3.56 + * </ul>
3.57 + * <p>
3.58 + * A non-constant call site may be <em>relinked</em> by changing its target.
3.59 + * The new target must have the same {@linkplain MethodHandle#type() type}
3.60 + * as the previous target.
3.61 + * Thus, though a call site can be relinked to a series of
3.62 + * successive targets, it cannot change its type.
3.63 + * <p>
3.64 + * Here is a sample use of call sites and bootstrap methods which links every
3.65 + * dynamic call site to print its arguments:
3.66 +<blockquote><pre>{@code
3.67 +static void test() throws Throwable {
3.68 + // THE FOLLOWING LINE IS PSEUDOCODE FOR A JVM INSTRUCTION
3.69 + InvokeDynamic[#bootstrapDynamic].baz("baz arg", 2, 3.14);
3.70 +}
3.71 +private static void printArgs(Object... args) {
3.72 + System.out.println(java.util.Arrays.deepToString(args));
3.73 +}
3.74 +private static final MethodHandle printArgs;
3.75 +static {
3.76 + MethodHandles.Lookup lookup = MethodHandles.lookup();
3.77 + Class thisClass = lookup.lookupClass(); // (who am I?)
3.78 + printArgs = lookup.findStatic(thisClass,
3.79 + "printArgs", MethodType.methodType(void.class, Object[].class));
3.80 +}
3.81 +private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String name, MethodType type) {
3.82 + // ignore caller and name, but match the type:
3.83 + return new ConstantCallSite(printArgs.asType(type));
3.84 +}
3.85 +}</pre></blockquote>
3.86 + * @author John Rose, JSR 292 EG
3.87 + */
3.88 +abstract
3.89 +public class CallSite {
3.90 + static { MethodHandleImpl.initStatics(); }
3.91 +
3.92 + // The actual payload of this call site:
3.93 + /*package-private*/
3.94 + MethodHandle target; // Note: This field is known to the JVM. Do not change.
3.95 +
3.96 + /**
3.97 + * Make a blank call site object with the given method type.
3.98 + * An initial target method is supplied which will throw
3.99 + * an {@link IllegalStateException} if called.
3.100 + * <p>
3.101 + * Before this {@code CallSite} object is returned from a bootstrap method,
3.102 + * it is usually provided with a more useful target method,
3.103 + * via a call to {@link CallSite#setTarget(MethodHandle) setTarget}.
3.104 + * @throws NullPointerException if the proposed type is null
3.105 + */
3.106 + /*package-private*/
3.107 + CallSite(MethodType type) {
3.108 + target = type.invokers().uninitializedCallSite();
3.109 + }
3.110 +
3.111 + /**
3.112 + * Make a call site object equipped with an initial target method handle.
3.113 + * @param target the method handle which will be the initial target of the call site
3.114 + * @throws NullPointerException if the proposed target is null
3.115 + */
3.116 + /*package-private*/
3.117 + CallSite(MethodHandle target) {
3.118 + target.type(); // null check
3.119 + this.target = target;
3.120 + }
3.121 +
3.122 + /**
3.123 + * Make a call site object equipped with an initial target method handle.
3.124 + * @param targetType the desired type of the call site
3.125 + * @param createTargetHook a hook which will bind the call site to the target method handle
3.126 + * @throws WrongMethodTypeException if the hook cannot be invoked on the required arguments,
3.127 + * or if the target returned by the hook is not of the given {@code targetType}
3.128 + * @throws NullPointerException if the hook returns a null value
3.129 + * @throws ClassCastException if the hook returns something other than a {@code MethodHandle}
3.130 + * @throws Throwable anything else thrown by the hook function
3.131 + */
3.132 + /*package-private*/
3.133 + CallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable {
3.134 + this(targetType);
3.135 + ConstantCallSite selfCCS = (ConstantCallSite) this;
3.136 + MethodHandle boundTarget = (MethodHandle) createTargetHook.invokeWithArguments(selfCCS);
3.137 + checkTargetChange(this.target, boundTarget);
3.138 + this.target = boundTarget;
3.139 + }
3.140 +
3.141 + /**
3.142 + * Returns the type of this call site's target.
3.143 + * Although targets may change, any call site's type is permanent, and can never change to an unequal type.
3.144 + * The {@code setTarget} method enforces this invariant by refusing any new target that does
3.145 + * not have the previous target's type.
3.146 + * @return the type of the current target, which is also the type of any future target
3.147 + */
3.148 + public MethodType type() {
3.149 + // warning: do not call getTarget here, because CCS.getTarget can throw IllegalStateException
3.150 + return target.type();
3.151 + }
3.152 +
3.153 + /**
3.154 + * Returns the target method of the call site, according to the
3.155 + * behavior defined by this call site's specific class.
3.156 + * The immediate subclasses of {@code CallSite} document the
3.157 + * class-specific behaviors of this method.
3.158 + *
3.159 + * @return the current linkage state of the call site, its target method handle
3.160 + * @see ConstantCallSite
3.161 + * @see VolatileCallSite
3.162 + * @see #setTarget
3.163 + * @see ConstantCallSite#getTarget
3.164 + * @see MutableCallSite#getTarget
3.165 + * @see VolatileCallSite#getTarget
3.166 + */
3.167 + public abstract MethodHandle getTarget();
3.168 +
3.169 + /**
3.170 + * Updates the target method of this call site, according to the
3.171 + * behavior defined by this call site's specific class.
3.172 + * The immediate subclasses of {@code CallSite} document the
3.173 + * class-specific behaviors of this method.
3.174 + * <p>
3.175 + * The type of the new target must be {@linkplain MethodType#equals equal to}
3.176 + * the type of the old target.
3.177 + *
3.178 + * @param newTarget the new target
3.179 + * @throws NullPointerException if the proposed new target is null
3.180 + * @throws WrongMethodTypeException if the proposed new target
3.181 + * has a method type that differs from the previous target
3.182 + * @see CallSite#getTarget
3.183 + * @see ConstantCallSite#setTarget
3.184 + * @see MutableCallSite#setTarget
3.185 + * @see VolatileCallSite#setTarget
3.186 + */
3.187 + public abstract void setTarget(MethodHandle newTarget);
3.188 +
3.189 + void checkTargetChange(MethodHandle oldTarget, MethodHandle newTarget) {
3.190 + MethodType oldType = oldTarget.type();
3.191 + MethodType newType = newTarget.type(); // null check!
3.192 + if (!newType.equals(oldType))
3.193 + throw wrongTargetType(newTarget, oldType);
3.194 + }
3.195 +
3.196 + private static WrongMethodTypeException wrongTargetType(MethodHandle target, MethodType type) {
3.197 + return new WrongMethodTypeException(String.valueOf(target)+" should be of type "+type);
3.198 + }
3.199 +
3.200 + /**
3.201 + * Produces a method handle equivalent to an invokedynamic instruction
3.202 + * which has been linked to this call site.
3.203 + * <p>
3.204 + * This method is equivalent to the following code:
3.205 + * <blockquote><pre>{@code
3.206 + * MethodHandle getTarget, invoker, result;
3.207 + * getTarget = MethodHandles.publicLookup().bind(this, "getTarget", MethodType.methodType(MethodHandle.class));
3.208 + * invoker = MethodHandles.exactInvoker(this.type());
3.209 + * result = MethodHandles.foldArguments(invoker, getTarget)
3.210 + * }</pre></blockquote>
3.211 + *
3.212 + * @return a method handle which always invokes this call site's current target
3.213 + */
3.214 + public abstract MethodHandle dynamicInvoker();
3.215 +
3.216 + /*non-public*/ MethodHandle makeDynamicInvoker() {
3.217 + MethodHandle getTarget = GET_TARGET.bindReceiver(this);
3.218 + MethodHandle invoker = MethodHandles.exactInvoker(this.type());
3.219 + return MethodHandles.foldArguments(invoker, getTarget);
3.220 + }
3.221 +
3.222 + private static final MethodHandle GET_TARGET;
3.223 + static {
3.224 + try {
3.225 + GET_TARGET = IMPL_LOOKUP.
3.226 + findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class));
3.227 + } catch (ReflectiveOperationException e) {
3.228 + throw newInternalError(e);
3.229 + }
3.230 + }
3.231 +
3.232 + /** This guy is rolled into the default target if a MethodType is supplied to the constructor. */
3.233 + /*package-private*/
3.234 + static Empty uninitializedCallSite() {
3.235 + throw new IllegalStateException("uninitialized call site");
3.236 + }
3.237 +
3.238 + // unsafe stuff:
3.239 + private static final long TARGET_OFFSET;
3.240 + static {
3.241 + try {
3.242 + TARGET_OFFSET = UNSAFE.objectFieldOffset(CallSite.class.getDeclaredField("target"));
3.243 + } catch (Exception ex) { throw new Error(ex); }
3.244 + }
3.245 +
3.246 + /*package-private*/
3.247 + void setTargetNormal(MethodHandle newTarget) {
3.248 + MethodHandleNatives.setCallSiteTargetNormal(this, newTarget);
3.249 + }
3.250 + /*package-private*/
3.251 + MethodHandle getTargetVolatile() {
3.252 + return (MethodHandle) UNSAFE.getObjectVolatile(this, TARGET_OFFSET);
3.253 + }
3.254 + /*package-private*/
3.255 + void setTargetVolatile(MethodHandle newTarget) {
3.256 + MethodHandleNatives.setCallSiteTargetVolatile(this, newTarget);
3.257 + }
3.258 +
3.259 + // this implements the upcall from the JVM, MethodHandleNatives.makeDynamicCallSite:
3.260 + static CallSite makeSite(MethodHandle bootstrapMethod,
3.261 + // Callee information:
3.262 + String name, MethodType type,
3.263 + // Extra arguments for BSM, if any:
3.264 + Object info,
3.265 + // Caller information:
3.266 + Class<?> callerClass) {
3.267 + MethodHandles.Lookup caller = IMPL_LOOKUP.in(callerClass);
3.268 + CallSite site;
3.269 + try {
3.270 + Object binding;
3.271 + info = maybeReBox(info);
3.272 + if (info == null) {
3.273 + binding = bootstrapMethod.invoke(caller, name, type);
3.274 + } else if (!info.getClass().isArray()) {
3.275 + binding = bootstrapMethod.invoke(caller, name, type, info);
3.276 + } else {
3.277 + Object[] argv = (Object[]) info;
3.278 + maybeReBoxElements(argv);
3.279 + switch (argv.length) {
3.280 + case 0:
3.281 + binding = bootstrapMethod.invoke(caller, name, type);
3.282 + break;
3.283 + case 1:
3.284 + binding = bootstrapMethod.invoke(caller, name, type,
3.285 + argv[0]);
3.286 + break;
3.287 + case 2:
3.288 + binding = bootstrapMethod.invoke(caller, name, type,
3.289 + argv[0], argv[1]);
3.290 + break;
3.291 + case 3:
3.292 + binding = bootstrapMethod.invoke(caller, name, type,
3.293 + argv[0], argv[1], argv[2]);
3.294 + break;
3.295 + case 4:
3.296 + binding = bootstrapMethod.invoke(caller, name, type,
3.297 + argv[0], argv[1], argv[2], argv[3]);
3.298 + break;
3.299 + case 5:
3.300 + binding = bootstrapMethod.invoke(caller, name, type,
3.301 + argv[0], argv[1], argv[2], argv[3], argv[4]);
3.302 + break;
3.303 + case 6:
3.304 + binding = bootstrapMethod.invoke(caller, name, type,
3.305 + argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
3.306 + break;
3.307 + default:
3.308 + final int NON_SPREAD_ARG_COUNT = 3; // (caller, name, type)
3.309 + if (NON_SPREAD_ARG_COUNT + argv.length > MethodType.MAX_MH_ARITY)
3.310 + throw new BootstrapMethodError("too many bootstrap method arguments");
3.311 + MethodType bsmType = bootstrapMethod.type();
3.312 + MethodType invocationType = MethodType.genericMethodType(NON_SPREAD_ARG_COUNT + argv.length);
3.313 + MethodHandle typedBSM = bootstrapMethod.asType(invocationType);
3.314 + MethodHandle spreader = invocationType.invokers().spreadInvoker(NON_SPREAD_ARG_COUNT);
3.315 + binding = spreader.invokeExact(typedBSM, (Object)caller, (Object)name, (Object)type, argv);
3.316 + }
3.317 + }
3.318 + //System.out.println("BSM for "+name+type+" => "+binding);
3.319 + if (binding instanceof CallSite) {
3.320 + site = (CallSite) binding;
3.321 + } else {
3.322 + throw new ClassCastException("bootstrap method failed to produce a CallSite");
3.323 + }
3.324 + if (!site.getTarget().type().equals(type))
3.325 + throw new WrongMethodTypeException("wrong type: "+site.getTarget());
3.326 + } catch (Throwable ex) {
3.327 + BootstrapMethodError bex;
3.328 + if (ex instanceof BootstrapMethodError)
3.329 + bex = (BootstrapMethodError) ex;
3.330 + else
3.331 + bex = new BootstrapMethodError("call site initialization exception", ex);
3.332 + throw bex;
3.333 + }
3.334 + return site;
3.335 + }
3.336 +
3.337 + private static Object maybeReBox(Object x) {
3.338 + if (x instanceof Integer) {
3.339 + int xi = (int) x;
3.340 + if (xi == (byte) xi)
3.341 + x = xi; // must rebox; see JLS 5.1.7
3.342 + }
3.343 + return x;
3.344 + }
3.345 + private static void maybeReBoxElements(Object[] xa) {
3.346 + for (int i = 0; i < xa.length; i++) {
3.347 + xa[i] = maybeReBox(xa[i]);
3.348 + }
3.349 + }
3.350 +}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/ConstantCallSite.java Sat Aug 09 11:12:05 2014 +0200
4.3 @@ -0,0 +1,120 @@
4.4 +/*
4.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
4.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4.7 + *
4.8 + * This code is free software; you can redistribute it and/or modify it
4.9 + * under the terms of the GNU General Public License version 2 only, as
4.10 + * published by the Free Software Foundation. Oracle designates this
4.11 + * particular file as subject to the "Classpath" exception as provided
4.12 + * by Oracle in the LICENSE file that accompanied this code.
4.13 + *
4.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
4.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
4.17 + * version 2 for more details (a copy is included in the LICENSE file that
4.18 + * accompanied this code).
4.19 + *
4.20 + * You should have received a copy of the GNU General Public License version
4.21 + * 2 along with this work; if not, write to the Free Software Foundation,
4.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
4.23 + *
4.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
4.25 + * or visit www.oracle.com if you need additional information or have any
4.26 + * questions.
4.27 + */
4.28 +
4.29 +package java.lang.invoke;
4.30 +
4.31 +/**
4.32 + * A {@code ConstantCallSite} is a {@link CallSite} whose target is permanent, and can never be changed.
4.33 + * An {@code invokedynamic} instruction linked to a {@code ConstantCallSite} is permanently
4.34 + * bound to the call site's target.
4.35 + * @author John Rose, JSR 292 EG
4.36 + */
4.37 +public class ConstantCallSite extends CallSite {
4.38 + private final boolean isFrozen;
4.39 +
4.40 + /**
4.41 + * Creates a call site with a permanent target.
4.42 + * @param target the target to be permanently associated with this call site
4.43 + * @throws NullPointerException if the proposed target is null
4.44 + */
4.45 + public ConstantCallSite(MethodHandle target) {
4.46 + super(target);
4.47 + isFrozen = true;
4.48 + }
4.49 +
4.50 + /**
4.51 + * Creates a call site with a permanent target, possibly bound to the call site itself.
4.52 + * <p>
4.53 + * During construction of the call site, the {@code createTargetHook} is invoked to
4.54 + * produce the actual target, as if by a call of the form
4.55 + * {@code (MethodHandle) createTargetHook.invoke(this)}.
4.56 + * <p>
4.57 + * Note that user code cannot perform such an action directly in a subclass constructor,
4.58 + * since the target must be fixed before the {@code ConstantCallSite} constructor returns.
4.59 + * <p>
4.60 + * The hook is said to bind the call site to a target method handle,
4.61 + * and a typical action would be {@code someTarget.bindTo(this)}.
4.62 + * However, the hook is free to take any action whatever,
4.63 + * including ignoring the call site and returning a constant target.
4.64 + * <p>
4.65 + * The result returned by the hook must be a method handle of exactly
4.66 + * the same type as the call site.
4.67 + * <p>
4.68 + * While the hook is being called, the new {@code ConstantCallSite}
4.69 + * object is in a partially constructed state.
4.70 + * In this state,
4.71 + * a call to {@code getTarget}, or any other attempt to use the target,
4.72 + * will result in an {@code IllegalStateException}.
4.73 + * It is legal at all times to obtain the call site's type using the {@code type} method.
4.74 + *
4.75 + * @param targetType the type of the method handle to be permanently associated with this call site
4.76 + * @param createTargetHook a method handle to invoke (on the call site) to produce the call site's target
4.77 + * @throws WrongMethodTypeException if the hook cannot be invoked on the required arguments,
4.78 + * or if the target returned by the hook is not of the given {@code targetType}
4.79 + * @throws NullPointerException if the hook returns a null value
4.80 + * @throws ClassCastException if the hook returns something other than a {@code MethodHandle}
4.81 + * @throws Throwable anything else thrown by the hook function
4.82 + */
4.83 + protected ConstantCallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable {
4.84 + super(targetType, createTargetHook);
4.85 + isFrozen = true;
4.86 + }
4.87 +
4.88 + /**
4.89 + * Returns the target method of the call site, which behaves
4.90 + * like a {@code final} field of the {@code ConstantCallSite}.
4.91 + * That is, the target is always the original value passed
4.92 + * to the constructor call which created this instance.
4.93 + *
4.94 + * @return the immutable linkage state of this call site, a constant method handle
4.95 + * @throws IllegalStateException if the {@code ConstantCallSite} constructor has not completed
4.96 + */
4.97 + @Override public final MethodHandle getTarget() {
4.98 + if (!isFrozen) throw new IllegalStateException();
4.99 + return target;
4.100 + }
4.101 +
4.102 + /**
4.103 + * Always throws an {@link UnsupportedOperationException}.
4.104 + * This kind of call site cannot change its target.
4.105 + * @param ignore a new target proposed for the call site, which is ignored
4.106 + * @throws UnsupportedOperationException because this kind of call site cannot change its target
4.107 + */
4.108 + @Override public final void setTarget(MethodHandle ignore) {
4.109 + throw new UnsupportedOperationException();
4.110 + }
4.111 +
4.112 + /**
4.113 + * Returns this call site's permanent target.
4.114 + * Since that target will never change, this is a correct implementation
4.115 + * of {@link CallSite#dynamicInvoker CallSite.dynamicInvoker}.
4.116 + * @return the immutable linkage state of this call site, a constant method handle
4.117 + * @throws IllegalStateException if the {@code ConstantCallSite} constructor has not completed
4.118 + */
4.119 + @Override
4.120 + public final MethodHandle dynamicInvoker() {
4.121 + return getTarget();
4.122 + }
4.123 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/DirectMethodHandle.java Sat Aug 09 11:12:05 2014 +0200
5.3 @@ -0,0 +1,718 @@
5.4 +/*
5.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5.7 + *
5.8 + * This code is free software; you can redistribute it and/or modify it
5.9 + * under the terms of the GNU General Public License version 2 only, as
5.10 + * published by the Free Software Foundation. Oracle designates this
5.11 + * particular file as subject to the "Classpath" exception as provided
5.12 + * by Oracle in the LICENSE file that accompanied this code.
5.13 + *
5.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
5.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
5.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5.17 + * version 2 for more details (a copy is included in the LICENSE file that
5.18 + * accompanied this code).
5.19 + *
5.20 + * You should have received a copy of the GNU General Public License version
5.21 + * 2 along with this work; if not, write to the Free Software Foundation,
5.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
5.23 + *
5.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
5.25 + * or visit www.oracle.com if you need additional information or have any
5.26 + * questions.
5.27 + */
5.28 +
5.29 +package java.lang.invoke;
5.30 +
5.31 +import sun.misc.Unsafe;
5.32 +import java.lang.reflect.Method;
5.33 +import java.util.Arrays;
5.34 +import sun.invoke.util.VerifyAccess;
5.35 +import static java.lang.invoke.MethodHandleNatives.Constants.*;
5.36 +import static java.lang.invoke.LambdaForm.*;
5.37 +import static java.lang.invoke.MethodTypeForm.*;
5.38 +import static java.lang.invoke.MethodHandleStatics.*;
5.39 +import java.lang.ref.WeakReference;
5.40 +import java.lang.reflect.Field;
5.41 +import sun.invoke.util.ValueConversions;
5.42 +import sun.invoke.util.VerifyType;
5.43 +import sun.invoke.util.Wrapper;
5.44 +
5.45 +/**
5.46 + * The flavor of method handle which implements a constant reference
5.47 + * to a class member.
5.48 + * @author jrose
5.49 + */
5.50 +class DirectMethodHandle extends MethodHandle {
5.51 + final MemberName member;
5.52 +
5.53 + // Constructors and factory methods in this class *must* be package scoped or private.
5.54 + private DirectMethodHandle(MethodType mtype, LambdaForm form, MemberName member) {
5.55 + super(mtype, form);
5.56 + if (!member.isResolved()) throw new InternalError();
5.57 +
5.58 + if (member.getDeclaringClass().isInterface() &&
5.59 + member.isMethod() && !member.isAbstract()) {
5.60 + // Check for corner case: invokeinterface of Object method
5.61 + MemberName m = new MemberName(Object.class, member.getName(), member.getMethodType(), member.getReferenceKind());
5.62 + m = MemberName.getFactory().resolveOrNull(m.getReferenceKind(), m, null);
5.63 + if (m != null && m.isPublic()) {
5.64 + member = m;
5.65 + }
5.66 + }
5.67 +
5.68 + this.member = member;
5.69 + }
5.70 +
5.71 + // Factory methods:
5.72 + static DirectMethodHandle make(byte refKind, Class<?> receiver, MemberName member) {
5.73 + MethodType mtype = member.getMethodOrFieldType();
5.74 + if (!member.isStatic()) {
5.75 + if (!member.getDeclaringClass().isAssignableFrom(receiver) || member.isConstructor())
5.76 + throw new InternalError(member.toString());
5.77 + mtype = mtype.insertParameterTypes(0, receiver);
5.78 + }
5.79 + if (!member.isField()) {
5.80 + if (refKind == REF_invokeSpecial) {
5.81 + member = member.asSpecial();
5.82 + LambdaForm lform = preparedLambdaForm(member);
5.83 + return new Special(mtype, lform, member);
5.84 + } else {
5.85 + LambdaForm lform = preparedLambdaForm(member);
5.86 + return new DirectMethodHandle(mtype, lform, member);
5.87 + }
5.88 + } else {
5.89 + LambdaForm lform = preparedFieldLambdaForm(member);
5.90 + if (member.isStatic()) {
5.91 + long offset = MethodHandleNatives.staticFieldOffset(member);
5.92 + Object base = MethodHandleNatives.staticFieldBase(member);
5.93 + return new StaticAccessor(mtype, lform, member, base, offset);
5.94 + } else {
5.95 + long offset = MethodHandleNatives.objectFieldOffset(member);
5.96 + assert(offset == (int)offset);
5.97 + return new Accessor(mtype, lform, member, (int)offset);
5.98 + }
5.99 + }
5.100 + }
5.101 + static DirectMethodHandle make(Class<?> receiver, MemberName member) {
5.102 + byte refKind = member.getReferenceKind();
5.103 + if (refKind == REF_invokeSpecial)
5.104 + refKind = REF_invokeVirtual;
5.105 + return make(refKind, receiver, member);
5.106 + }
5.107 + static DirectMethodHandle make(MemberName member) {
5.108 + if (member.isConstructor())
5.109 + return makeAllocator(member);
5.110 + return make(member.getDeclaringClass(), member);
5.111 + }
5.112 + static DirectMethodHandle make(Method method) {
5.113 + return make(method.getDeclaringClass(), new MemberName(method));
5.114 + }
5.115 + static DirectMethodHandle make(Field field) {
5.116 + return make(field.getDeclaringClass(), new MemberName(field));
5.117 + }
5.118 + private static DirectMethodHandle makeAllocator(MemberName ctor) {
5.119 + assert(ctor.isConstructor() && ctor.getName().equals("<init>"));
5.120 + Class<?> instanceClass = ctor.getDeclaringClass();
5.121 + ctor = ctor.asConstructor();
5.122 + assert(ctor.isConstructor() && ctor.getReferenceKind() == REF_newInvokeSpecial) : ctor;
5.123 + MethodType mtype = ctor.getMethodType().changeReturnType(instanceClass);
5.124 + LambdaForm lform = preparedLambdaForm(ctor);
5.125 + MemberName init = ctor.asSpecial();
5.126 + assert(init.getMethodType().returnType() == void.class);
5.127 + return new Constructor(mtype, lform, ctor, init, instanceClass);
5.128 + }
5.129 +
5.130 + @Override
5.131 + MethodHandle copyWith(MethodType mt, LambdaForm lf) {
5.132 + return new DirectMethodHandle(mt, lf, member);
5.133 + }
5.134 +
5.135 + @Override
5.136 + String internalProperties() {
5.137 + return "/DMH="+member.toString();
5.138 + }
5.139 +
5.140 + //// Implementation methods.
5.141 + @Override
5.142 + MethodHandle viewAsType(MethodType newType) {
5.143 + return new DirectMethodHandle(newType, form, member);
5.144 + }
5.145 + @Override
5.146 + @ForceInline
5.147 + MemberName internalMemberName() {
5.148 + return member;
5.149 + }
5.150 +
5.151 + @Override
5.152 + MethodHandle bindArgument(int pos, char basicType, Object value) {
5.153 + // If the member needs dispatching, do so.
5.154 + if (pos == 0 && basicType == 'L') {
5.155 + DirectMethodHandle concrete = maybeRebind(value);
5.156 + if (concrete != null)
5.157 + return concrete.bindReceiver(value);
5.158 + }
5.159 + return super.bindArgument(pos, basicType, value);
5.160 + }
5.161 +
5.162 + @Override
5.163 + MethodHandle bindReceiver(Object receiver) {
5.164 + // If the member needs dispatching, do so.
5.165 + DirectMethodHandle concrete = maybeRebind(receiver);
5.166 + if (concrete != null)
5.167 + return concrete.bindReceiver(receiver);
5.168 + return super.bindReceiver(receiver);
5.169 + }
5.170 +
5.171 + private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
5.172 +
5.173 + private DirectMethodHandle maybeRebind(Object receiver) {
5.174 + if (receiver != null) {
5.175 + switch (member.getReferenceKind()) {
5.176 + case REF_invokeInterface:
5.177 + case REF_invokeVirtual:
5.178 + // Pre-dispatch the member.
5.179 + Class<?> concreteClass = receiver.getClass();
5.180 + MemberName concrete = new MemberName(concreteClass, member.getName(), member.getMethodType(), REF_invokeSpecial);
5.181 + concrete = IMPL_NAMES.resolveOrNull(REF_invokeSpecial, concrete, concreteClass);
5.182 + if (concrete != null)
5.183 + return new DirectMethodHandle(type(), preparedLambdaForm(concrete), concrete);
5.184 + break;
5.185 + }
5.186 + }
5.187 + return null;
5.188 + }
5.189 +
5.190 + /**
5.191 + * Create a LF which can invoke the given method.
5.192 + * Cache and share this structure among all methods with
5.193 + * the same basicType and refKind.
5.194 + */
5.195 + private static LambdaForm preparedLambdaForm(MemberName m) {
5.196 + assert(m.isInvocable()) : m; // call preparedFieldLambdaForm instead
5.197 + MethodType mtype = m.getInvocationType().basicType();
5.198 + assert(!m.isMethodHandleInvoke() || "invokeBasic".equals(m.getName())) : m;
5.199 + int which;
5.200 + switch (m.getReferenceKind()) {
5.201 + case REF_invokeVirtual: which = LF_INVVIRTUAL; break;
5.202 + case REF_invokeStatic: which = LF_INVSTATIC; break;
5.203 + case REF_invokeSpecial: which = LF_INVSPECIAL; break;
5.204 + case REF_invokeInterface: which = LF_INVINTERFACE; break;
5.205 + case REF_newInvokeSpecial: which = LF_NEWINVSPECIAL; break;
5.206 + default: throw new InternalError(m.toString());
5.207 + }
5.208 + if (which == LF_INVSTATIC && shouldBeInitialized(m)) {
5.209 + // precompute the barrier-free version:
5.210 + preparedLambdaForm(mtype, which);
5.211 + which = LF_INVSTATIC_INIT;
5.212 + }
5.213 + LambdaForm lform = preparedLambdaForm(mtype, which);
5.214 + maybeCompile(lform, m);
5.215 + assert(lform.methodType().dropParameterTypes(0, 1)
5.216 + .equals(m.getInvocationType().basicType()))
5.217 + : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
5.218 + return lform;
5.219 + }
5.220 +
5.221 + private static LambdaForm preparedLambdaForm(MethodType mtype, int which) {
5.222 + LambdaForm lform = mtype.form().cachedLambdaForm(which);
5.223 + if (lform != null) return lform;
5.224 + lform = makePreparedLambdaForm(mtype, which);
5.225 + return mtype.form().setCachedLambdaForm(which, lform);
5.226 + }
5.227 +
5.228 + private static LambdaForm makePreparedLambdaForm(MethodType mtype, int which) {
5.229 + boolean needsInit = (which == LF_INVSTATIC_INIT);
5.230 + boolean doesAlloc = (which == LF_NEWINVSPECIAL);
5.231 + String linkerName, lambdaName;
5.232 + switch (which) {
5.233 + case LF_INVVIRTUAL: linkerName = "linkToVirtual"; lambdaName = "DMH.invokeVirtual"; break;
5.234 + case LF_INVSTATIC: linkerName = "linkToStatic"; lambdaName = "DMH.invokeStatic"; break;
5.235 + case LF_INVSTATIC_INIT:linkerName = "linkToStatic"; lambdaName = "DMH.invokeStaticInit"; break;
5.236 + case LF_INVSPECIAL: linkerName = "linkToSpecial"; lambdaName = "DMH.invokeSpecial"; break;
5.237 + case LF_INVINTERFACE: linkerName = "linkToInterface"; lambdaName = "DMH.invokeInterface"; break;
5.238 + case LF_NEWINVSPECIAL: linkerName = "linkToSpecial"; lambdaName = "DMH.newInvokeSpecial"; break;
5.239 + default: throw new InternalError("which="+which);
5.240 + }
5.241 + MethodType mtypeWithArg = mtype.appendParameterTypes(MemberName.class);
5.242 + if (doesAlloc)
5.243 + mtypeWithArg = mtypeWithArg
5.244 + .insertParameterTypes(0, Object.class) // insert newly allocated obj
5.245 + .changeReturnType(void.class); // <init> returns void
5.246 + MemberName linker = new MemberName(MethodHandle.class, linkerName, mtypeWithArg, REF_invokeStatic);
5.247 + try {
5.248 + linker = IMPL_NAMES.resolveOrFail(REF_invokeStatic, linker, null, NoSuchMethodException.class);
5.249 + } catch (ReflectiveOperationException ex) {
5.250 + throw newInternalError(ex);
5.251 + }
5.252 + final int DMH_THIS = 0;
5.253 + final int ARG_BASE = 1;
5.254 + final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
5.255 + int nameCursor = ARG_LIMIT;
5.256 + final int NEW_OBJ = (doesAlloc ? nameCursor++ : -1);
5.257 + final int GET_MEMBER = nameCursor++;
5.258 + final int LINKER_CALL = nameCursor++;
5.259 + Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
5.260 + assert(names.length == nameCursor);
5.261 + if (doesAlloc) {
5.262 + // names = { argx,y,z,... new C, init method }
5.263 + names[NEW_OBJ] = new Name(Lazy.NF_allocateInstance, names[DMH_THIS]);
5.264 + names[GET_MEMBER] = new Name(Lazy.NF_constructorMethod, names[DMH_THIS]);
5.265 + } else if (needsInit) {
5.266 + names[GET_MEMBER] = new Name(Lazy.NF_internalMemberNameEnsureInit, names[DMH_THIS]);
5.267 + } else {
5.268 + names[GET_MEMBER] = new Name(Lazy.NF_internalMemberName, names[DMH_THIS]);
5.269 + }
5.270 + Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER+1, Object[].class);
5.271 + assert(outArgs[outArgs.length-1] == names[GET_MEMBER]); // look, shifted args!
5.272 + int result = LambdaForm.LAST_RESULT;
5.273 + if (doesAlloc) {
5.274 + assert(outArgs[outArgs.length-2] == names[NEW_OBJ]); // got to move this one
5.275 + System.arraycopy(outArgs, 0, outArgs, 1, outArgs.length-2);
5.276 + outArgs[0] = names[NEW_OBJ];
5.277 + result = NEW_OBJ;
5.278 + }
5.279 + names[LINKER_CALL] = new Name(linker, outArgs);
5.280 + lambdaName += "_" + LambdaForm.basicTypeSignature(mtype);
5.281 + LambdaForm lform = new LambdaForm(lambdaName, ARG_LIMIT, names, result);
5.282 + // This is a tricky bit of code. Don't send it through the LF interpreter.
5.283 + lform.compileToBytecode();
5.284 + return lform;
5.285 + }
5.286 +
5.287 + private static void maybeCompile(LambdaForm lform, MemberName m) {
5.288 + if (VerifyAccess.isSamePackage(m.getDeclaringClass(), MethodHandle.class))
5.289 + // Help along bootstrapping...
5.290 + lform.compileToBytecode();
5.291 + }
5.292 +
5.293 + /** Static wrapper for DirectMethodHandle.internalMemberName. */
5.294 + @ForceInline
5.295 + /*non-public*/ static Object internalMemberName(Object mh) {
5.296 + return ((DirectMethodHandle)mh).member;
5.297 + }
5.298 +
5.299 + /** Static wrapper for DirectMethodHandle.internalMemberName.
5.300 + * This one also forces initialization.
5.301 + */
5.302 + /*non-public*/ static Object internalMemberNameEnsureInit(Object mh) {
5.303 + DirectMethodHandle dmh = (DirectMethodHandle)mh;
5.304 + dmh.ensureInitialized();
5.305 + return dmh.member;
5.306 + }
5.307 +
5.308 + /*non-public*/ static
5.309 + boolean shouldBeInitialized(MemberName member) {
5.310 + switch (member.getReferenceKind()) {
5.311 + case REF_invokeStatic:
5.312 + case REF_getStatic:
5.313 + case REF_putStatic:
5.314 + case REF_newInvokeSpecial:
5.315 + break;
5.316 + default:
5.317 + // No need to initialize the class on this kind of member.
5.318 + return false;
5.319 + }
5.320 + Class<?> cls = member.getDeclaringClass();
5.321 + if (cls == ValueConversions.class ||
5.322 + cls == MethodHandleImpl.class ||
5.323 + cls == Invokers.class) {
5.324 + // These guys have lots of <clinit> DMH creation but we know
5.325 + // the MHs will not be used until the system is booted.
5.326 + return false;
5.327 + }
5.328 + if (VerifyAccess.isSamePackage(MethodHandle.class, cls) ||
5.329 + VerifyAccess.isSamePackage(ValueConversions.class, cls)) {
5.330 + // It is a system class. It is probably in the process of
5.331 + // being initialized, but we will help it along just to be safe.
5.332 + if (UNSAFE.shouldBeInitialized(cls)) {
5.333 + UNSAFE.ensureClassInitialized(cls);
5.334 + }
5.335 + return false;
5.336 + }
5.337 + return UNSAFE.shouldBeInitialized(cls);
5.338 + }
5.339 +
5.340 + private static class EnsureInitialized extends ClassValue<WeakReference<Thread>> {
5.341 + @Override
5.342 + protected WeakReference<Thread> computeValue(Class<?> type) {
5.343 + UNSAFE.ensureClassInitialized(type);
5.344 + if (UNSAFE.shouldBeInitialized(type))
5.345 + // If the previous call didn't block, this can happen.
5.346 + // We are executing inside <clinit>.
5.347 + return new WeakReference<>(Thread.currentThread());
5.348 + return null;
5.349 + }
5.350 + static final EnsureInitialized INSTANCE = new EnsureInitialized();
5.351 + }
5.352 +
5.353 + private void ensureInitialized() {
5.354 + if (checkInitialized(member)) {
5.355 + // The coast is clear. Delete the <clinit> barrier.
5.356 + if (member.isField())
5.357 + updateForm(preparedFieldLambdaForm(member));
5.358 + else
5.359 + updateForm(preparedLambdaForm(member));
5.360 + }
5.361 + }
5.362 + private static boolean checkInitialized(MemberName member) {
5.363 + Class<?> defc = member.getDeclaringClass();
5.364 + WeakReference<Thread> ref = EnsureInitialized.INSTANCE.get(defc);
5.365 + if (ref == null) {
5.366 + return true; // the final state
5.367 + }
5.368 + Thread clinitThread = ref.get();
5.369 + // Somebody may still be running defc.<clinit>.
5.370 + if (clinitThread == Thread.currentThread()) {
5.371 + // If anybody is running defc.<clinit>, it is this thread.
5.372 + if (UNSAFE.shouldBeInitialized(defc))
5.373 + // Yes, we are running it; keep the barrier for now.
5.374 + return false;
5.375 + } else {
5.376 + // We are in a random thread. Block.
5.377 + UNSAFE.ensureClassInitialized(defc);
5.378 + }
5.379 + assert(!UNSAFE.shouldBeInitialized(defc));
5.380 + // put it into the final state
5.381 + EnsureInitialized.INSTANCE.remove(defc);
5.382 + return true;
5.383 + }
5.384 +
5.385 + /*non-public*/ static void ensureInitialized(Object mh) {
5.386 + ((DirectMethodHandle)mh).ensureInitialized();
5.387 + }
5.388 +
5.389 + /** This subclass represents invokespecial instructions. */
5.390 + static class Special extends DirectMethodHandle {
5.391 + private Special(MethodType mtype, LambdaForm form, MemberName member) {
5.392 + super(mtype, form, member);
5.393 + }
5.394 + @Override
5.395 + boolean isInvokeSpecial() {
5.396 + return true;
5.397 + }
5.398 + @Override
5.399 + MethodHandle viewAsType(MethodType newType) {
5.400 + return new Special(newType, form, member);
5.401 + }
5.402 + }
5.403 +
5.404 + /** This subclass handles constructor references. */
5.405 + static class Constructor extends DirectMethodHandle {
5.406 + final MemberName initMethod;
5.407 + final Class<?> instanceClass;
5.408 +
5.409 + private Constructor(MethodType mtype, LambdaForm form, MemberName constructor,
5.410 + MemberName initMethod, Class<?> instanceClass) {
5.411 + super(mtype, form, constructor);
5.412 + this.initMethod = initMethod;
5.413 + this.instanceClass = instanceClass;
5.414 + assert(initMethod.isResolved());
5.415 + }
5.416 + @Override
5.417 + MethodHandle viewAsType(MethodType newType) {
5.418 + return new Constructor(newType, form, member, initMethod, instanceClass);
5.419 + }
5.420 + }
5.421 +
5.422 + /*non-public*/ static Object constructorMethod(Object mh) {
5.423 + Constructor dmh = (Constructor)mh;
5.424 + return dmh.initMethod;
5.425 + }
5.426 +
5.427 + /*non-public*/ static Object allocateInstance(Object mh) throws InstantiationException {
5.428 + Constructor dmh = (Constructor)mh;
5.429 + return UNSAFE.allocateInstance(dmh.instanceClass);
5.430 + }
5.431 +
5.432 + /** This subclass handles non-static field references. */
5.433 + static class Accessor extends DirectMethodHandle {
5.434 + final Class<?> fieldType;
5.435 + final int fieldOffset;
5.436 + private Accessor(MethodType mtype, LambdaForm form, MemberName member,
5.437 + int fieldOffset) {
5.438 + super(mtype, form, member);
5.439 + this.fieldType = member.getFieldType();
5.440 + this.fieldOffset = fieldOffset;
5.441 + }
5.442 +
5.443 + @Override Object checkCast(Object obj) {
5.444 + return fieldType.cast(obj);
5.445 + }
5.446 + @Override
5.447 + MethodHandle viewAsType(MethodType newType) {
5.448 + return new Accessor(newType, form, member, fieldOffset);
5.449 + }
5.450 + }
5.451 +
5.452 + @ForceInline
5.453 + /*non-public*/ static long fieldOffset(Object accessorObj) {
5.454 + // Note: We return a long because that is what Unsafe.getObject likes.
5.455 + // We store a plain int because it is more compact.
5.456 + return ((Accessor)accessorObj).fieldOffset;
5.457 + }
5.458 +
5.459 + @ForceInline
5.460 + /*non-public*/ static Object checkBase(Object obj) {
5.461 + // Note that the object's class has already been verified,
5.462 + // since the parameter type of the Accessor method handle
5.463 + // is either member.getDeclaringClass or a subclass.
5.464 + // This was verified in DirectMethodHandle.make.
5.465 + // Therefore, the only remaining check is for null.
5.466 + // Since this check is *not* guaranteed by Unsafe.getInt
5.467 + // and its siblings, we need to make an explicit one here.
5.468 + obj.getClass(); // maybe throw NPE
5.469 + return obj;
5.470 + }
5.471 +
5.472 + /** This subclass handles static field references. */
5.473 + static class StaticAccessor extends DirectMethodHandle {
5.474 + final private Class<?> fieldType;
5.475 + final private Object staticBase;
5.476 + final private long staticOffset;
5.477 +
5.478 + private StaticAccessor(MethodType mtype, LambdaForm form, MemberName member,
5.479 + Object staticBase, long staticOffset) {
5.480 + super(mtype, form, member);
5.481 + this.fieldType = member.getFieldType();
5.482 + this.staticBase = staticBase;
5.483 + this.staticOffset = staticOffset;
5.484 + }
5.485 +
5.486 + @Override Object checkCast(Object obj) {
5.487 + return fieldType.cast(obj);
5.488 + }
5.489 + @Override
5.490 + MethodHandle viewAsType(MethodType newType) {
5.491 + return new StaticAccessor(newType, form, member, staticBase, staticOffset);
5.492 + }
5.493 + }
5.494 +
5.495 + @ForceInline
5.496 + /*non-public*/ static Object nullCheck(Object obj) {
5.497 + obj.getClass();
5.498 + return obj;
5.499 + }
5.500 +
5.501 + @ForceInline
5.502 + /*non-public*/ static Object staticBase(Object accessorObj) {
5.503 + return ((StaticAccessor)accessorObj).staticBase;
5.504 + }
5.505 +
5.506 + @ForceInline
5.507 + /*non-public*/ static long staticOffset(Object accessorObj) {
5.508 + return ((StaticAccessor)accessorObj).staticOffset;
5.509 + }
5.510 +
5.511 + @ForceInline
5.512 + /*non-public*/ static Object checkCast(Object mh, Object obj) {
5.513 + return ((DirectMethodHandle) mh).checkCast(obj);
5.514 + }
5.515 +
5.516 + Object checkCast(Object obj) {
5.517 + return member.getReturnType().cast(obj);
5.518 + }
5.519 +
5.520 + // Caching machinery for field accessors:
5.521 + private static byte
5.522 + AF_GETFIELD = 0,
5.523 + AF_PUTFIELD = 1,
5.524 + AF_GETSTATIC = 2,
5.525 + AF_PUTSTATIC = 3,
5.526 + AF_GETSTATIC_INIT = 4,
5.527 + AF_PUTSTATIC_INIT = 5,
5.528 + AF_LIMIT = 6;
5.529 + // Enumerate the different field kinds using Wrapper,
5.530 + // with an extra case added for checked references.
5.531 + private static int
5.532 + FT_LAST_WRAPPER = Wrapper.values().length-1,
5.533 + FT_UNCHECKED_REF = Wrapper.OBJECT.ordinal(),
5.534 + FT_CHECKED_REF = FT_LAST_WRAPPER+1,
5.535 + FT_LIMIT = FT_LAST_WRAPPER+2;
5.536 + private static int afIndex(byte formOp, boolean isVolatile, int ftypeKind) {
5.537 + return ((formOp * FT_LIMIT * 2)
5.538 + + (isVolatile ? FT_LIMIT : 0)
5.539 + + ftypeKind);
5.540 + }
5.541 + private static final LambdaForm[] ACCESSOR_FORMS
5.542 + = new LambdaForm[afIndex(AF_LIMIT, false, 0)];
5.543 + private static int ftypeKind(Class<?> ftype) {
5.544 + if (ftype.isPrimitive())
5.545 + return Wrapper.forPrimitiveType(ftype).ordinal();
5.546 + else if (VerifyType.isNullReferenceConversion(Object.class, ftype))
5.547 + return FT_UNCHECKED_REF;
5.548 + else
5.549 + return FT_CHECKED_REF;
5.550 + }
5.551 +
5.552 + /**
5.553 + * Create a LF which can access the given field.
5.554 + * Cache and share this structure among all fields with
5.555 + * the same basicType and refKind.
5.556 + */
5.557 + private static LambdaForm preparedFieldLambdaForm(MemberName m) {
5.558 + Class<?> ftype = m.getFieldType();
5.559 + boolean isVolatile = m.isVolatile();
5.560 + byte formOp;
5.561 + switch (m.getReferenceKind()) {
5.562 + case REF_getField: formOp = AF_GETFIELD; break;
5.563 + case REF_putField: formOp = AF_PUTFIELD; break;
5.564 + case REF_getStatic: formOp = AF_GETSTATIC; break;
5.565 + case REF_putStatic: formOp = AF_PUTSTATIC; break;
5.566 + default: throw new InternalError(m.toString());
5.567 + }
5.568 + if (shouldBeInitialized(m)) {
5.569 + // precompute the barrier-free version:
5.570 + preparedFieldLambdaForm(formOp, isVolatile, ftype);
5.571 + assert((AF_GETSTATIC_INIT - AF_GETSTATIC) ==
5.572 + (AF_PUTSTATIC_INIT - AF_PUTSTATIC));
5.573 + formOp += (AF_GETSTATIC_INIT - AF_GETSTATIC);
5.574 + }
5.575 + LambdaForm lform = preparedFieldLambdaForm(formOp, isVolatile, ftype);
5.576 + maybeCompile(lform, m);
5.577 + assert(lform.methodType().dropParameterTypes(0, 1)
5.578 + .equals(m.getInvocationType().basicType()))
5.579 + : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
5.580 + return lform;
5.581 + }
5.582 + private static LambdaForm preparedFieldLambdaForm(byte formOp, boolean isVolatile, Class<?> ftype) {
5.583 + int afIndex = afIndex(formOp, isVolatile, ftypeKind(ftype));
5.584 + LambdaForm lform = ACCESSOR_FORMS[afIndex];
5.585 + if (lform != null) return lform;
5.586 + lform = makePreparedFieldLambdaForm(formOp, isVolatile, ftypeKind(ftype));
5.587 + ACCESSOR_FORMS[afIndex] = lform; // don't bother with a CAS
5.588 + return lform;
5.589 + }
5.590 +
5.591 + private static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, int ftypeKind) {
5.592 + boolean isGetter = (formOp & 1) == (AF_GETFIELD & 1);
5.593 + boolean isStatic = (formOp >= AF_GETSTATIC);
5.594 + boolean needsInit = (formOp >= AF_GETSTATIC_INIT);
5.595 + boolean needsCast = (ftypeKind == FT_CHECKED_REF);
5.596 + Wrapper fw = (needsCast ? Wrapper.OBJECT : Wrapper.values()[ftypeKind]);
5.597 + Class<?> ft = fw.primitiveType();
5.598 + assert(ftypeKind(needsCast ? String.class : ft) == ftypeKind);
5.599 + String tname = fw.primitiveSimpleName();
5.600 + String ctname = Character.toUpperCase(tname.charAt(0)) + tname.substring(1);
5.601 + if (isVolatile) ctname += "Volatile";
5.602 + String getOrPut = (isGetter ? "get" : "put");
5.603 + String linkerName = (getOrPut + ctname); // getObject, putIntVolatile, etc.
5.604 + MethodType linkerType;
5.605 + if (isGetter)
5.606 + linkerType = MethodType.methodType(ft, Object.class, long.class);
5.607 + else
5.608 + linkerType = MethodType.methodType(void.class, Object.class, long.class, ft);
5.609 + MemberName linker = new MemberName(Unsafe.class, linkerName, linkerType, REF_invokeVirtual);
5.610 + try {
5.611 + linker = IMPL_NAMES.resolveOrFail(REF_invokeVirtual, linker, null, NoSuchMethodException.class);
5.612 + } catch (ReflectiveOperationException ex) {
5.613 + throw newInternalError(ex);
5.614 + }
5.615 +
5.616 + // What is the external type of the lambda form?
5.617 + MethodType mtype;
5.618 + if (isGetter)
5.619 + mtype = MethodType.methodType(ft);
5.620 + else
5.621 + mtype = MethodType.methodType(void.class, ft);
5.622 + mtype = mtype.basicType(); // erase short to int, etc.
5.623 + if (!isStatic)
5.624 + mtype = mtype.insertParameterTypes(0, Object.class);
5.625 + final int DMH_THIS = 0;
5.626 + final int ARG_BASE = 1;
5.627 + final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
5.628 + // if this is for non-static access, the base pointer is stored at this index:
5.629 + final int OBJ_BASE = isStatic ? -1 : ARG_BASE;
5.630 + // if this is for write access, the value to be written is stored at this index:
5.631 + final int SET_VALUE = isGetter ? -1 : ARG_LIMIT - 1;
5.632 + int nameCursor = ARG_LIMIT;
5.633 + final int F_HOLDER = (isStatic ? nameCursor++ : -1); // static base if any
5.634 + final int F_OFFSET = nameCursor++; // Either static offset or field offset.
5.635 + final int OBJ_CHECK = (OBJ_BASE >= 0 ? nameCursor++ : -1);
5.636 + final int INIT_BAR = (needsInit ? nameCursor++ : -1);
5.637 + final int PRE_CAST = (needsCast && !isGetter ? nameCursor++ : -1);
5.638 + final int LINKER_CALL = nameCursor++;
5.639 + final int POST_CAST = (needsCast && isGetter ? nameCursor++ : -1);
5.640 + final int RESULT = nameCursor-1; // either the call or the cast
5.641 + Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
5.642 + if (needsInit)
5.643 + names[INIT_BAR] = new Name(Lazy.NF_ensureInitialized, names[DMH_THIS]);
5.644 + if (needsCast && !isGetter)
5.645 + names[PRE_CAST] = new Name(Lazy.NF_checkCast, names[DMH_THIS], names[SET_VALUE]);
5.646 + Object[] outArgs = new Object[1 + linkerType.parameterCount()];
5.647 + assert(outArgs.length == (isGetter ? 3 : 4));
5.648 + outArgs[0] = UNSAFE;
5.649 + if (isStatic) {
5.650 + outArgs[1] = names[F_HOLDER] = new Name(Lazy.NF_staticBase, names[DMH_THIS]);
5.651 + outArgs[2] = names[F_OFFSET] = new Name(Lazy.NF_staticOffset, names[DMH_THIS]);
5.652 + } else {
5.653 + outArgs[1] = names[OBJ_CHECK] = new Name(Lazy.NF_checkBase, names[OBJ_BASE]);
5.654 + outArgs[2] = names[F_OFFSET] = new Name(Lazy.NF_fieldOffset, names[DMH_THIS]);
5.655 + }
5.656 + if (!isGetter) {
5.657 + outArgs[3] = (needsCast ? names[PRE_CAST] : names[SET_VALUE]);
5.658 + }
5.659 + for (Object a : outArgs) assert(a != null);
5.660 + names[LINKER_CALL] = new Name(linker, outArgs);
5.661 + if (needsCast && isGetter)
5.662 + names[POST_CAST] = new Name(Lazy.NF_checkCast, names[DMH_THIS], names[LINKER_CALL]);
5.663 + for (Name n : names) assert(n != null);
5.664 + String fieldOrStatic = (isStatic ? "Static" : "Field");
5.665 + String lambdaName = (linkerName + fieldOrStatic); // significant only for debugging
5.666 + if (needsCast) lambdaName += "Cast";
5.667 + if (needsInit) lambdaName += "Init";
5.668 + return new LambdaForm(lambdaName, ARG_LIMIT, names, RESULT);
5.669 + }
5.670 +
5.671 + /**
5.672 + * Pre-initialized NamedFunctions for bootstrapping purposes.
5.673 + * Factored in an inner class to delay initialization until first usage.
5.674 + */
5.675 + private static class Lazy {
5.676 + static final NamedFunction
5.677 + NF_internalMemberName,
5.678 + NF_internalMemberNameEnsureInit,
5.679 + NF_ensureInitialized,
5.680 + NF_fieldOffset,
5.681 + NF_checkBase,
5.682 + NF_staticBase,
5.683 + NF_staticOffset,
5.684 + NF_checkCast,
5.685 + NF_allocateInstance,
5.686 + NF_constructorMethod;
5.687 + static {
5.688 + try {
5.689 + NamedFunction nfs[] = {
5.690 + NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
5.691 + .getDeclaredMethod("internalMemberName", Object.class)),
5.692 + NF_internalMemberNameEnsureInit = new NamedFunction(DirectMethodHandle.class
5.693 + .getDeclaredMethod("internalMemberNameEnsureInit", Object.class)),
5.694 + NF_ensureInitialized = new NamedFunction(DirectMethodHandle.class
5.695 + .getDeclaredMethod("ensureInitialized", Object.class)),
5.696 + NF_fieldOffset = new NamedFunction(DirectMethodHandle.class
5.697 + .getDeclaredMethod("fieldOffset", Object.class)),
5.698 + NF_checkBase = new NamedFunction(DirectMethodHandle.class
5.699 + .getDeclaredMethod("checkBase", Object.class)),
5.700 + NF_staticBase = new NamedFunction(DirectMethodHandle.class
5.701 + .getDeclaredMethod("staticBase", Object.class)),
5.702 + NF_staticOffset = new NamedFunction(DirectMethodHandle.class
5.703 + .getDeclaredMethod("staticOffset", Object.class)),
5.704 + NF_checkCast = new NamedFunction(DirectMethodHandle.class
5.705 + .getDeclaredMethod("checkCast", Object.class, Object.class)),
5.706 + NF_allocateInstance = new NamedFunction(DirectMethodHandle.class
5.707 + .getDeclaredMethod("allocateInstance", Object.class)),
5.708 + NF_constructorMethod = new NamedFunction(DirectMethodHandle.class
5.709 + .getDeclaredMethod("constructorMethod", Object.class))
5.710 + };
5.711 + for (NamedFunction nf : nfs) {
5.712 + // Each nf must be statically invocable or we get tied up in our bootstraps.
5.713 + assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
5.714 + nf.resolve();
5.715 + }
5.716 + } catch (ReflectiveOperationException ex) {
5.717 + throw newInternalError(ex);
5.718 + }
5.719 + }
5.720 + }
5.721 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/DontInline.java Sat Aug 09 11:12:05 2014 +0200
6.3 @@ -0,0 +1,37 @@
6.4 +/*
6.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
6.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6.7 + *
6.8 + * This code is free software; you can redistribute it and/or modify it
6.9 + * under the terms of the GNU General Public License version 2 only, as
6.10 + * published by the Free Software Foundation. Oracle designates this
6.11 + * particular file as subject to the "Classpath" exception as provided
6.12 + * by Oracle in the LICENSE file that accompanied this code.
6.13 + *
6.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
6.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
6.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
6.17 + * version 2 for more details (a copy is included in the LICENSE file that
6.18 + * accompanied this code).
6.19 + *
6.20 + * You should have received a copy of the GNU General Public License version
6.21 + * 2 along with this work; if not, write to the Free Software Foundation,
6.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
6.23 + *
6.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
6.25 + * or visit www.oracle.com if you need additional information or have any
6.26 + * questions.
6.27 + */
6.28 +
6.29 +package java.lang.invoke;
6.30 +
6.31 +import java.lang.annotation.*;
6.32 +
6.33 +/**
6.34 + * Internal marker for some methods in the JSR 292 implementation.
6.35 + */
6.36 +/*non-public*/
6.37 +@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
6.38 +@Retention(RetentionPolicy.RUNTIME)
6.39 +@interface DontInline {
6.40 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/ForceInline.java Sat Aug 09 11:12:05 2014 +0200
7.3 @@ -0,0 +1,37 @@
7.4 +/*
7.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
7.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7.7 + *
7.8 + * This code is free software; you can redistribute it and/or modify it
7.9 + * under the terms of the GNU General Public License version 2 only, as
7.10 + * published by the Free Software Foundation. Oracle designates this
7.11 + * particular file as subject to the "Classpath" exception as provided
7.12 + * by Oracle in the LICENSE file that accompanied this code.
7.13 + *
7.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
7.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
7.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
7.17 + * version 2 for more details (a copy is included in the LICENSE file that
7.18 + * accompanied this code).
7.19 + *
7.20 + * You should have received a copy of the GNU General Public License version
7.21 + * 2 along with this work; if not, write to the Free Software Foundation,
7.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
7.23 + *
7.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
7.25 + * or visit www.oracle.com if you need additional information or have any
7.26 + * questions.
7.27 + */
7.28 +
7.29 +package java.lang.invoke;
7.30 +
7.31 +import java.lang.annotation.*;
7.32 +
7.33 +/**
7.34 + * Internal marker for some methods in the JSR 292 implementation.
7.35 + */
7.36 +/*non-public*/
7.37 +@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
7.38 +@Retention(RetentionPolicy.RUNTIME)
7.39 +@interface ForceInline {
7.40 +}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/InfoFromMemberName.java Sat Aug 09 11:12:05 2014 +0200
8.3 @@ -0,0 +1,145 @@
8.4 +/*
8.5 + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
8.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8.7 + *
8.8 + * This code is free software; you can redistribute it and/or modify it
8.9 + * under the terms of the GNU General Public License version 2 only, as
8.10 + * published by the Free Software Foundation. Oracle designates this
8.11 + * particular file as subject to the "Classpath" exception as provided
8.12 + * by Oracle in the LICENSE file that accompanied this code.
8.13 + *
8.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
8.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
8.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
8.17 + * version 2 for more details (a copy is included in the LICENSE file that
8.18 + * accompanied this code).
8.19 + *
8.20 + * You should have received a copy of the GNU General Public License version
8.21 + * 2 along with this work; if not, write to the Free Software Foundation,
8.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
8.23 + *
8.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
8.25 + * or visit www.oracle.com if you need additional information or have any
8.26 + * questions.
8.27 + */
8.28 +
8.29 +package java.lang.invoke;
8.30 +
8.31 +import java.security.*;
8.32 +import java.lang.reflect.*;
8.33 +import java.lang.invoke.MethodHandleNatives.Constants;
8.34 +import java.lang.invoke.MethodHandles.Lookup;
8.35 +import static java.lang.invoke.MethodHandleStatics.*;
8.36 +
8.37 +/*
8.38 + * Auxiliary to MethodHandleInfo, wants to nest in MethodHandleInfo but must be non-public.
8.39 + */
8.40 +/*non-public*/
8.41 +final
8.42 +class InfoFromMemberName implements MethodHandleInfo {
8.43 + private final MemberName member;
8.44 + private final int referenceKind;
8.45 +
8.46 + InfoFromMemberName(Lookup lookup, MemberName member, byte referenceKind) {
8.47 + assert(member.isResolved() || member.isMethodHandleInvoke());
8.48 + assert(member.referenceKindIsConsistentWith(referenceKind));
8.49 + this.member = member;
8.50 + this.referenceKind = referenceKind;
8.51 + }
8.52 +
8.53 + @Override
8.54 + public Class<?> getDeclaringClass() {
8.55 + return member.getDeclaringClass();
8.56 + }
8.57 +
8.58 + @Override
8.59 + public String getName() {
8.60 + return member.getName();
8.61 + }
8.62 +
8.63 + @Override
8.64 + public MethodType getMethodType() {
8.65 + return member.getMethodOrFieldType();
8.66 + }
8.67 +
8.68 + @Override
8.69 + public int getModifiers() {
8.70 + return member.getModifiers();
8.71 + }
8.72 +
8.73 + @Override
8.74 + public int getReferenceKind() {
8.75 + return referenceKind;
8.76 + }
8.77 +
8.78 + @Override
8.79 + public String toString() {
8.80 + return MethodHandleInfo.toString(getReferenceKind(), getDeclaringClass(), getName(), getMethodType());
8.81 + }
8.82 +
8.83 + @Override
8.84 + public <T extends Member> T reflectAs(Class<T> expected, Lookup lookup) {
8.85 + if (member.isMethodHandleInvoke() && !member.isVarargs()) {
8.86 + // This member is an instance of a signature-polymorphic method, which cannot be reflected
8.87 + // A method handle invoker can come in either of two forms:
8.88 + // A generic placeholder (present in the source code, and varargs)
8.89 + // and a signature-polymorphic instance (synthetic and not varargs).
8.90 + // For more information see comments on {@link MethodHandleNatives#linkMethod}.
8.91 + throw new IllegalArgumentException("cannot reflect signature polymorphic method");
8.92 + }
8.93 + Member mem = AccessController.doPrivileged(new PrivilegedAction<Member>() {
8.94 + public Member run() {
8.95 + try {
8.96 + return reflectUnchecked();
8.97 + } catch (ReflectiveOperationException ex) {
8.98 + throw new IllegalArgumentException(ex);
8.99 + }
8.100 + }
8.101 + });
8.102 + try {
8.103 + Class<?> defc = getDeclaringClass();
8.104 + byte refKind = (byte) getReferenceKind();
8.105 + lookup.checkAccess(refKind, defc, convertToMemberName(refKind, mem));
8.106 + } catch (IllegalAccessException ex) {
8.107 + throw new IllegalArgumentException(ex);
8.108 + }
8.109 + return expected.cast(mem);
8.110 + }
8.111 +
8.112 + private Member reflectUnchecked() throws ReflectiveOperationException {
8.113 + byte refKind = (byte) getReferenceKind();
8.114 + Class<?> defc = getDeclaringClass();
8.115 + boolean isPublic = Modifier.isPublic(getModifiers());
8.116 + if (MethodHandleNatives.refKindIsMethod(refKind)) {
8.117 + if (isPublic)
8.118 + return defc.getMethod(getName(), getMethodType().parameterArray());
8.119 + else
8.120 + return defc.getDeclaredMethod(getName(), getMethodType().parameterArray());
8.121 + } else if (MethodHandleNatives.refKindIsConstructor(refKind)) {
8.122 + if (isPublic)
8.123 + return defc.getConstructor(getMethodType().parameterArray());
8.124 + else
8.125 + return defc.getDeclaredConstructor(getMethodType().parameterArray());
8.126 + } else if (MethodHandleNatives.refKindIsField(refKind)) {
8.127 + if (isPublic)
8.128 + return defc.getField(getName());
8.129 + else
8.130 + return defc.getDeclaredField(getName());
8.131 + } else {
8.132 + throw new IllegalArgumentException("referenceKind="+refKind);
8.133 + }
8.134 + }
8.135 +
8.136 + private static MemberName convertToMemberName(byte refKind, Member mem) throws IllegalAccessException {
8.137 + if (mem instanceof Method) {
8.138 + boolean wantSpecial = (refKind == REF_invokeSpecial);
8.139 + return new MemberName((Method) mem, wantSpecial);
8.140 + } else if (mem instanceof Constructor) {
8.141 + return new MemberName((Constructor) mem);
8.142 + } else if (mem instanceof Field) {
8.143 + boolean isSetter = (refKind == REF_putField || refKind == REF_putStatic);
8.144 + return new MemberName((Field) mem, isSetter);
8.145 + }
8.146 + throw new InternalError(mem.getClass().getName());
8.147 + }
8.148 +}
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/InnerClassLambdaMetafactory.java Sat Aug 09 11:12:05 2014 +0200
9.3 @@ -0,0 +1,561 @@
9.4 +/*
9.5 + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
9.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
9.7 + *
9.8 + * This code is free software; you can redistribute it and/or modify it
9.9 + * under the terms of the GNU General Public License version 2 only, as
9.10 + * published by the Free Software Foundation. Oracle designates this
9.11 + * particular file as subject to the "Classpath" exception as provided
9.12 + * by Oracle in the LICENSE file that accompanied this code.
9.13 + *
9.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
9.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
9.17 + * version 2 for more details (a copy is included in the LICENSE file that
9.18 + * accompanied this code).
9.19 + *
9.20 + * You should have received a copy of the GNU General Public License version
9.21 + * 2 along with this work; if not, write to the Free Software Foundation,
9.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
9.23 + *
9.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
9.25 + * or visit www.oracle.com if you need additional information or have any
9.26 + * questions.
9.27 + */
9.28 +
9.29 +package java.lang.invoke;
9.30 +
9.31 +import jdk.internal.org.objectweb.asm.*;
9.32 +import sun.invoke.util.BytecodeDescriptor;
9.33 +import sun.misc.Unsafe;
9.34 +import sun.security.action.GetPropertyAction;
9.35 +
9.36 +import java.io.FilePermission;
9.37 +import java.io.Serializable;
9.38 +import java.lang.reflect.Constructor;
9.39 +import java.security.AccessController;
9.40 +import java.security.PrivilegedAction;
9.41 +import java.util.LinkedHashSet;
9.42 +import java.util.concurrent.atomic.AtomicInteger;
9.43 +import java.util.PropertyPermission;
9.44 +import java.util.Set;
9.45 +
9.46 +import static jdk.internal.org.objectweb.asm.Opcodes.*;
9.47 +
9.48 +/**
9.49 + * Lambda metafactory implementation which dynamically creates an
9.50 + * inner-class-like class per lambda callsite.
9.51 + *
9.52 + * @see LambdaMetafactory
9.53 + */
9.54 +/* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
9.55 + private static final Unsafe UNSAFE = Unsafe.getUnsafe();
9.56 +
9.57 + private static final int CLASSFILE_VERSION = 52;
9.58 + private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
9.59 + private static final String JAVA_LANG_OBJECT = "java/lang/Object";
9.60 + private static final String NAME_CTOR = "<init>";
9.61 + private static final String NAME_FACTORY = "get$Lambda";
9.62 +
9.63 + //Serialization support
9.64 + private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda";
9.65 + private static final String NAME_NOT_SERIALIZABLE_EXCEPTION = "java/io/NotSerializableException";
9.66 + private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;";
9.67 + private static final String DESCR_METHOD_WRITE_OBJECT = "(Ljava/io/ObjectOutputStream;)V";
9.68 + private static final String DESCR_METHOD_READ_OBJECT = "(Ljava/io/ObjectInputStream;)V";
9.69 + private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace";
9.70 + private static final String NAME_METHOD_READ_OBJECT = "readObject";
9.71 + private static final String NAME_METHOD_WRITE_OBJECT = "writeObject";
9.72 + private static final String DESCR_CTOR_SERIALIZED_LAMBDA
9.73 + = MethodType.methodType(void.class,
9.74 + Class.class,
9.75 + String.class, String.class, String.class,
9.76 + int.class, String.class, String.class, String.class,
9.77 + String.class,
9.78 + Object[].class).toMethodDescriptorString();
9.79 + private static final String DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION
9.80 + = MethodType.methodType(void.class, String.class).toMethodDescriptorString();
9.81 + private static final String[] SER_HOSTILE_EXCEPTIONS = new String[] {NAME_NOT_SERIALIZABLE_EXCEPTION};
9.82 +
9.83 +
9.84 + private static final String[] EMPTY_STRING_ARRAY = new String[0];
9.85 +
9.86 + // Used to ensure that each spun class name is unique
9.87 + private static final AtomicInteger counter = new AtomicInteger(0);
9.88 +
9.89 + // For dumping generated classes to disk, for debugging purposes
9.90 + private static final ProxyClassesDumper dumper;
9.91 +
9.92 + static {
9.93 + final String key = "jdk.internal.lambda.dumpProxyClasses";
9.94 + String path = AccessController.doPrivileged(
9.95 + new GetPropertyAction(key), null,
9.96 + new PropertyPermission(key , "read"));
9.97 + dumper = (null == path) ? null : ProxyClassesDumper.getInstance(path);
9.98 + }
9.99 +
9.100 + // See context values in AbstractValidatingLambdaMetafactory
9.101 + private final String implMethodClassName; // Name of type containing implementation "CC"
9.102 + private final String implMethodName; // Name of implementation method "impl"
9.103 + private final String implMethodDesc; // Type descriptor for implementation methods "(I)Ljava/lang/String;"
9.104 + private final Class<?> implMethodReturnClass; // class for implementaion method return type "Ljava/lang/String;"
9.105 + private final MethodType constructorType; // Generated class constructor type "(CC)void"
9.106 + private final ClassWriter cw; // ASM class writer
9.107 + private final String[] argNames; // Generated names for the constructor arguments
9.108 + private final String[] argDescs; // Type descriptors for the constructor arguments
9.109 + private final String lambdaClassName; // Generated name for the generated class "X$$Lambda$1"
9.110 +
9.111 + /**
9.112 + * General meta-factory constructor, supporting both standard cases and
9.113 + * allowing for uncommon options such as serialization or bridging.
9.114 + *
9.115 + * @param caller Stacked automatically by VM; represents a lookup context
9.116 + * with the accessibility privileges of the caller.
9.117 + * @param invokedType Stacked automatically by VM; the signature of the
9.118 + * invoked method, which includes the expected static
9.119 + * type of the returned lambda object, and the static
9.120 + * types of the captured arguments for the lambda. In
9.121 + * the event that the implementation method is an
9.122 + * instance method, the first argument in the invocation
9.123 + * signature will correspond to the receiver.
9.124 + * @param samMethodName Name of the method in the functional interface to
9.125 + * which the lambda or method reference is being
9.126 + * converted, represented as a String.
9.127 + * @param samMethodType Type of the method in the functional interface to
9.128 + * which the lambda or method reference is being
9.129 + * converted, represented as a MethodType.
9.130 + * @param implMethod The implementation method which should be called (with
9.131 + * suitable adaptation of argument types, return types,
9.132 + * and adjustment for captured arguments) when methods of
9.133 + * the resulting functional interface instance are invoked.
9.134 + * @param instantiatedMethodType The signature of the primary functional
9.135 + * interface method after type variables are
9.136 + * substituted with their instantiation from
9.137 + * the capture site
9.138 + * @param isSerializable Should the lambda be made serializable? If set,
9.139 + * either the target type or one of the additional SAM
9.140 + * types must extend {@code Serializable}.
9.141 + * @param markerInterfaces Additional interfaces which the lambda object
9.142 + * should implement.
9.143 + * @param additionalBridges Method types for additional signatures to be
9.144 + * bridged to the implementation method
9.145 + * @throws LambdaConversionException If any of the meta-factory protocol
9.146 + * invariants are violated
9.147 + */
9.148 + public InnerClassLambdaMetafactory(MethodHandles.Lookup caller,
9.149 + MethodType invokedType,
9.150 + String samMethodName,
9.151 + MethodType samMethodType,
9.152 + MethodHandle implMethod,
9.153 + MethodType instantiatedMethodType,
9.154 + boolean isSerializable,
9.155 + Class<?>[] markerInterfaces,
9.156 + MethodType[] additionalBridges)
9.157 + throws LambdaConversionException {
9.158 + super(caller, invokedType, samMethodName, samMethodType,
9.159 + implMethod, instantiatedMethodType,
9.160 + isSerializable, markerInterfaces, additionalBridges);
9.161 + implMethodClassName = implDefiningClass.getName().replace('.', '/');
9.162 + implMethodName = implInfo.getName();
9.163 + implMethodDesc = implMethodType.toMethodDescriptorString();
9.164 + implMethodReturnClass = (implKind == MethodHandleInfo.REF_newInvokeSpecial)
9.165 + ? implDefiningClass
9.166 + : implMethodType.returnType();
9.167 + constructorType = invokedType.changeReturnType(Void.TYPE);
9.168 + lambdaClassName = targetClass.getName().replace('.', '/') + "$$Lambda$" + counter.incrementAndGet();
9.169 + cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
9.170 + int parameterCount = invokedType.parameterCount();
9.171 + if (parameterCount > 0) {
9.172 + argNames = new String[parameterCount];
9.173 + argDescs = new String[parameterCount];
9.174 + for (int i = 0; i < parameterCount; i++) {
9.175 + argNames[i] = "arg$" + (i + 1);
9.176 + argDescs[i] = BytecodeDescriptor.unparse(invokedType.parameterType(i));
9.177 + }
9.178 + } else {
9.179 + argNames = argDescs = EMPTY_STRING_ARRAY;
9.180 + }
9.181 + }
9.182 +
9.183 + /**
9.184 + * Build the CallSite. Generate a class file which implements the functional
9.185 + * interface, define the class, if there are no parameters create an instance
9.186 + * of the class which the CallSite will return, otherwise, generate handles
9.187 + * which will call the class' constructor.
9.188 + *
9.189 + * @return a CallSite, which, when invoked, will return an instance of the
9.190 + * functional interface
9.191 + * @throws ReflectiveOperationException
9.192 + * @throws LambdaConversionException If properly formed functional interface
9.193 + * is not found
9.194 + */
9.195 + @Override
9.196 + CallSite buildCallSite() throws LambdaConversionException {
9.197 + final Class<?> innerClass = spinInnerClass();
9.198 + if (invokedType.parameterCount() == 0) {
9.199 + final Constructor[] ctrs = AccessController.doPrivileged(
9.200 + new PrivilegedAction<Constructor[]>() {
9.201 + @Override
9.202 + public Constructor[] run() {
9.203 + Constructor<?>[] ctrs = innerClass.getDeclaredConstructors();
9.204 + if (ctrs.length == 1) {
9.205 + // The lambda implementing inner class constructor is private, set
9.206 + // it accessible (by us) before creating the constant sole instance
9.207 + ctrs[0].setAccessible(true);
9.208 + }
9.209 + return ctrs;
9.210 + }
9.211 + });
9.212 + if (ctrs.length != 1) {
9.213 + throw new LambdaConversionException("Expected one lambda constructor for "
9.214 + + innerClass.getCanonicalName() + ", got " + ctrs.length);
9.215 + }
9.216 +
9.217 + try {
9.218 + Object inst = ctrs[0].newInstance();
9.219 + return new ConstantCallSite(MethodHandles.constant(samBase, inst));
9.220 + }
9.221 + catch (ReflectiveOperationException e) {
9.222 + throw new LambdaConversionException("Exception instantiating lambda object", e);
9.223 + }
9.224 + } else {
9.225 + try {
9.226 + UNSAFE.ensureClassInitialized(innerClass);
9.227 + return new ConstantCallSite(
9.228 + MethodHandles.Lookup.IMPL_LOOKUP
9.229 + .findStatic(innerClass, NAME_FACTORY, invokedType));
9.230 + }
9.231 + catch (ReflectiveOperationException e) {
9.232 + throw new LambdaConversionException("Exception finding constructor", e);
9.233 + }
9.234 + }
9.235 + }
9.236 +
9.237 + /**
9.238 + * Generate a class file which implements the functional
9.239 + * interface, define and return the class.
9.240 + *
9.241 + * @implNote The class that is generated does not include signature
9.242 + * information for exceptions that may be present on the SAM method.
9.243 + * This is to reduce classfile size, and is harmless as checked exceptions
9.244 + * are erased anyway, no one will ever compile against this classfile,
9.245 + * and we make no guarantees about the reflective properties of lambda
9.246 + * objects.
9.247 + *
9.248 + * @return a Class which implements the functional interface
9.249 + * @throws LambdaConversionException If properly formed functional interface
9.250 + * is not found
9.251 + */
9.252 + private Class<?> spinInnerClass() throws LambdaConversionException {
9.253 + String[] interfaces;
9.254 + String samIntf = samBase.getName().replace('.', '/');
9.255 + boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(samBase);
9.256 + if (markerInterfaces.length == 0) {
9.257 + interfaces = new String[]{samIntf};
9.258 + } else {
9.259 + // Assure no duplicate interfaces (ClassFormatError)
9.260 + Set<String> itfs = new LinkedHashSet<>(markerInterfaces.length + 1);
9.261 + itfs.add(samIntf);
9.262 + for (Class<?> markerInterface : markerInterfaces) {
9.263 + itfs.add(markerInterface.getName().replace('.', '/'));
9.264 + accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(markerInterface);
9.265 + }
9.266 + interfaces = itfs.toArray(new String[itfs.size()]);
9.267 + }
9.268 +
9.269 + cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
9.270 + lambdaClassName, null,
9.271 + JAVA_LANG_OBJECT, interfaces);
9.272 +
9.273 + // Generate final fields to be filled in by constructor
9.274 + for (int i = 0; i < argDescs.length; i++) {
9.275 + FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
9.276 + argNames[i],
9.277 + argDescs[i],
9.278 + null, null);
9.279 + fv.visitEnd();
9.280 + }
9.281 +
9.282 + generateConstructor();
9.283 +
9.284 + if (invokedType.parameterCount() != 0) {
9.285 + generateFactory();
9.286 + }
9.287 +
9.288 + // Forward the SAM method
9.289 + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName,
9.290 + samMethodType.toMethodDescriptorString(), null, null);
9.291 + new ForwardingMethodGenerator(mv).generate(samMethodType);
9.292 +
9.293 + // Forward the bridges
9.294 + if (additionalBridges != null) {
9.295 + for (MethodType mt : additionalBridges) {
9.296 + mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samMethodName,
9.297 + mt.toMethodDescriptorString(), null, null);
9.298 + new ForwardingMethodGenerator(mv).generate(mt);
9.299 + }
9.300 + }
9.301 +
9.302 + if (isSerializable)
9.303 + generateSerializationFriendlyMethods();
9.304 + else if (accidentallySerializable)
9.305 + generateSerializationHostileMethods();
9.306 +
9.307 + cw.visitEnd();
9.308 +
9.309 + // Define the generated class in this VM.
9.310 +
9.311 + final byte[] classBytes = cw.toByteArray();
9.312 +
9.313 + // If requested, dump out to a file for debugging purposes
9.314 + if (dumper != null) {
9.315 + AccessController.doPrivileged(new PrivilegedAction<Void>() {
9.316 + @Override
9.317 + public Void run() {
9.318 + dumper.dumpClass(lambdaClassName, classBytes);
9.319 + return null;
9.320 + }
9.321 + }, null,
9.322 + new FilePermission("<<ALL FILES>>", "read, write"),
9.323 + // createDirectories may need it
9.324 + new PropertyPermission("user.dir", "read"));
9.325 + }
9.326 +
9.327 + return UNSAFE.defineAnonymousClass(targetClass, classBytes, null);
9.328 + }
9.329 +
9.330 + /**
9.331 + * Generate the factory method for the class
9.332 + */
9.333 + private void generateFactory() {
9.334 + MethodVisitor m = cw.visitMethod(ACC_PRIVATE | ACC_STATIC, NAME_FACTORY, invokedType.toMethodDescriptorString(), null, null);
9.335 + m.visitCode();
9.336 + m.visitTypeInsn(NEW, lambdaClassName);
9.337 + m.visitInsn(Opcodes.DUP);
9.338 + int parameterCount = invokedType.parameterCount();
9.339 + for (int typeIndex = 0, varIndex = 0; typeIndex < parameterCount; typeIndex++) {
9.340 + Class<?> argType = invokedType.parameterType(typeIndex);
9.341 + m.visitVarInsn(getLoadOpcode(argType), varIndex);
9.342 + varIndex += getParameterSize(argType);
9.343 + }
9.344 + m.visitMethodInsn(INVOKESPECIAL, lambdaClassName, NAME_CTOR, constructorType.toMethodDescriptorString());
9.345 + m.visitInsn(ARETURN);
9.346 + m.visitMaxs(-1, -1);
9.347 + m.visitEnd();
9.348 + }
9.349 +
9.350 + /**
9.351 + * Generate the constructor for the class
9.352 + */
9.353 + private void generateConstructor() {
9.354 + // Generate constructor
9.355 + MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR,
9.356 + constructorType.toMethodDescriptorString(), null, null);
9.357 + ctor.visitCode();
9.358 + ctor.visitVarInsn(ALOAD, 0);
9.359 + ctor.visitMethodInsn(INVOKESPECIAL, JAVA_LANG_OBJECT, NAME_CTOR,
9.360 + METHOD_DESCRIPTOR_VOID);
9.361 + int parameterCount = invokedType.parameterCount();
9.362 + for (int i = 0, lvIndex = 0; i < parameterCount; i++) {
9.363 + ctor.visitVarInsn(ALOAD, 0);
9.364 + Class<?> argType = invokedType.parameterType(i);
9.365 + ctor.visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
9.366 + lvIndex += getParameterSize(argType);
9.367 + ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argDescs[i]);
9.368 + }
9.369 + ctor.visitInsn(RETURN);
9.370 + // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
9.371 + ctor.visitMaxs(-1, -1);
9.372 + ctor.visitEnd();
9.373 + }
9.374 +
9.375 + /**
9.376 + * Generate a writeReplace method that supports serialization
9.377 + */
9.378 + private void generateSerializationFriendlyMethods() {
9.379 + TypeConvertingMethodAdapter mv
9.380 + = new TypeConvertingMethodAdapter(
9.381 + cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
9.382 + NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE,
9.383 + null, null));
9.384 +
9.385 + mv.visitCode();
9.386 + mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
9.387 + mv.visitInsn(DUP);
9.388 + mv.visitLdcInsn(Type.getType(targetClass));
9.389 + mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/'));
9.390 + mv.visitLdcInsn(samMethodName);
9.391 + mv.visitLdcInsn(samMethodType.toMethodDescriptorString());
9.392 + mv.visitLdcInsn(implInfo.getReferenceKind());
9.393 + mv.visitLdcInsn(implInfo.getDeclaringClass().getName().replace('.', '/'));
9.394 + mv.visitLdcInsn(implInfo.getName());
9.395 + mv.visitLdcInsn(implInfo.getMethodType().toMethodDescriptorString());
9.396 + mv.visitLdcInsn(instantiatedMethodType.toMethodDescriptorString());
9.397 + mv.iconst(argDescs.length);
9.398 + mv.visitTypeInsn(ANEWARRAY, JAVA_LANG_OBJECT);
9.399 + for (int i = 0; i < argDescs.length; i++) {
9.400 + mv.visitInsn(DUP);
9.401 + mv.iconst(i);
9.402 + mv.visitVarInsn(ALOAD, 0);
9.403 + mv.visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
9.404 + mv.boxIfTypePrimitive(Type.getType(argDescs[i]));
9.405 + mv.visitInsn(AASTORE);
9.406 + }
9.407 + mv.visitMethodInsn(INVOKESPECIAL, NAME_SERIALIZED_LAMBDA, NAME_CTOR,
9.408 + DESCR_CTOR_SERIALIZED_LAMBDA);
9.409 + mv.visitInsn(ARETURN);
9.410 + // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
9.411 + mv.visitMaxs(-1, -1);
9.412 + mv.visitEnd();
9.413 + }
9.414 +
9.415 + /**
9.416 + * Generate a readObject/writeObject method that is hostile to serialization
9.417 + */
9.418 + private void generateSerializationHostileMethods() {
9.419 + MethodVisitor mv = cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
9.420 + NAME_METHOD_WRITE_OBJECT, DESCR_METHOD_WRITE_OBJECT,
9.421 + null, SER_HOSTILE_EXCEPTIONS);
9.422 + mv.visitCode();
9.423 + mv.visitTypeInsn(NEW, NAME_NOT_SERIALIZABLE_EXCEPTION);
9.424 + mv.visitInsn(DUP);
9.425 + mv.visitLdcInsn("Non-serializable lambda");
9.426 + mv.visitMethodInsn(INVOKESPECIAL, NAME_NOT_SERIALIZABLE_EXCEPTION, NAME_CTOR,
9.427 + DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION);
9.428 + mv.visitInsn(ATHROW);
9.429 + mv.visitMaxs(-1, -1);
9.430 + mv.visitEnd();
9.431 +
9.432 + mv = cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
9.433 + NAME_METHOD_READ_OBJECT, DESCR_METHOD_READ_OBJECT,
9.434 + null, SER_HOSTILE_EXCEPTIONS);
9.435 + mv.visitCode();
9.436 + mv.visitTypeInsn(NEW, NAME_NOT_SERIALIZABLE_EXCEPTION);
9.437 + mv.visitInsn(DUP);
9.438 + mv.visitLdcInsn("Non-serializable lambda");
9.439 + mv.visitMethodInsn(INVOKESPECIAL, NAME_NOT_SERIALIZABLE_EXCEPTION, NAME_CTOR,
9.440 + DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION);
9.441 + mv.visitInsn(ATHROW);
9.442 + mv.visitMaxs(-1, -1);
9.443 + mv.visitEnd();
9.444 + }
9.445 +
9.446 + /**
9.447 + * This class generates a method body which calls the lambda implementation
9.448 + * method, converting arguments, as needed.
9.449 + */
9.450 + private class ForwardingMethodGenerator extends TypeConvertingMethodAdapter {
9.451 +
9.452 + ForwardingMethodGenerator(MethodVisitor mv) {
9.453 + super(mv);
9.454 + }
9.455 +
9.456 + void generate(MethodType methodType) {
9.457 + visitCode();
9.458 +
9.459 + if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
9.460 + visitTypeInsn(NEW, implMethodClassName);
9.461 + visitInsn(DUP);
9.462 + }
9.463 + for (int i = 0; i < argNames.length; i++) {
9.464 + visitVarInsn(ALOAD, 0);
9.465 + visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
9.466 + }
9.467 +
9.468 + convertArgumentTypes(methodType);
9.469 +
9.470 + // Invoke the method we want to forward to
9.471 + visitMethodInsn(invocationOpcode(), implMethodClassName,
9.472 + implMethodName, implMethodDesc,
9.473 + implDefiningClass.isInterface());
9.474 +
9.475 + // Convert the return value (if any) and return it
9.476 + // Note: if adapting from non-void to void, the 'return'
9.477 + // instruction will pop the unneeded result
9.478 + Class<?> samReturnClass = methodType.returnType();
9.479 + convertType(implMethodReturnClass, samReturnClass, samReturnClass);
9.480 + visitInsn(getReturnOpcode(samReturnClass));
9.481 + // Maxs computed by ClassWriter.COMPUTE_MAXS,these arguments ignored
9.482 + visitMaxs(-1, -1);
9.483 + visitEnd();
9.484 + }
9.485 +
9.486 + private void convertArgumentTypes(MethodType samType) {
9.487 + int lvIndex = 0;
9.488 + boolean samIncludesReceiver = implIsInstanceMethod &&
9.489 + invokedType.parameterCount() == 0;
9.490 + int samReceiverLength = samIncludesReceiver ? 1 : 0;
9.491 + if (samIncludesReceiver) {
9.492 + // push receiver
9.493 + Class<?> rcvrType = samType.parameterType(0);
9.494 + visitVarInsn(getLoadOpcode(rcvrType), lvIndex + 1);
9.495 + lvIndex += getParameterSize(rcvrType);
9.496 + convertType(rcvrType, implDefiningClass, instantiatedMethodType.parameterType(0));
9.497 + }
9.498 + int samParametersLength = samType.parameterCount();
9.499 + int argOffset = implMethodType.parameterCount() - samParametersLength;
9.500 + for (int i = samReceiverLength; i < samParametersLength; i++) {
9.501 + Class<?> argType = samType.parameterType(i);
9.502 + visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
9.503 + lvIndex += getParameterSize(argType);
9.504 + convertType(argType, implMethodType.parameterType(argOffset + i), instantiatedMethodType.parameterType(i));
9.505 + }
9.506 + }
9.507 +
9.508 + private int invocationOpcode() throws InternalError {
9.509 + switch (implKind) {
9.510 + case MethodHandleInfo.REF_invokeStatic:
9.511 + return INVOKESTATIC;
9.512 + case MethodHandleInfo.REF_newInvokeSpecial:
9.513 + return INVOKESPECIAL;
9.514 + case MethodHandleInfo.REF_invokeVirtual:
9.515 + return INVOKEVIRTUAL;
9.516 + case MethodHandleInfo.REF_invokeInterface:
9.517 + return INVOKEINTERFACE;
9.518 + case MethodHandleInfo.REF_invokeSpecial:
9.519 + return INVOKESPECIAL;
9.520 + default:
9.521 + throw new InternalError("Unexpected invocation kind: " + implKind);
9.522 + }
9.523 + }
9.524 + }
9.525 +
9.526 + static int getParameterSize(Class<?> c) {
9.527 + if (c == Void.TYPE) {
9.528 + return 0;
9.529 + } else if (c == Long.TYPE || c == Double.TYPE) {
9.530 + return 2;
9.531 + }
9.532 + return 1;
9.533 + }
9.534 +
9.535 + static int getLoadOpcode(Class<?> c) {
9.536 + if(c == Void.TYPE) {
9.537 + throw new InternalError("Unexpected void type of load opcode");
9.538 + }
9.539 + return ILOAD + getOpcodeOffset(c);
9.540 + }
9.541 +
9.542 + static int getReturnOpcode(Class<?> c) {
9.543 + if(c == Void.TYPE) {
9.544 + return RETURN;
9.545 + }
9.546 + return IRETURN + getOpcodeOffset(c);
9.547 + }
9.548 +
9.549 + private static int getOpcodeOffset(Class<?> c) {
9.550 + if (c.isPrimitive()) {
9.551 + if (c == Long.TYPE) {
9.552 + return 1;
9.553 + } else if (c == Float.TYPE) {
9.554 + return 2;
9.555 + } else if (c == Double.TYPE) {
9.556 + return 3;
9.557 + }
9.558 + return 0;
9.559 + } else {
9.560 + return 4;
9.561 + }
9.562 + }
9.563 +
9.564 +}
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/InvokeDynamic.java Sat Aug 09 11:12:05 2014 +0200
10.3 @@ -0,0 +1,33 @@
10.4 +/*
10.5 + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
10.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
10.7 + *
10.8 + * This code is free software; you can redistribute it and/or modify it
10.9 + * under the terms of the GNU General Public License version 2 only, as
10.10 + * published by the Free Software Foundation. Oracle designates this
10.11 + * particular file as subject to the "Classpath" exception as provided
10.12 + * by Oracle in the LICENSE file that accompanied this code.
10.13 + *
10.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
10.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
10.17 + * version 2 for more details (a copy is included in the LICENSE file that
10.18 + * accompanied this code).
10.19 + *
10.20 + * You should have received a copy of the GNU General Public License version
10.21 + * 2 along with this work; if not, write to the Free Software Foundation,
10.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
10.23 + *
10.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
10.25 + * or visit www.oracle.com if you need additional information or have any
10.26 + * questions.
10.27 + */
10.28 +
10.29 +package java.lang.invoke;
10.30 +
10.31 +/**
10.32 + * This is a place-holder class. Some HotSpot implementations need to see it.
10.33 + */
10.34 +final class InvokeDynamic {
10.35 + private InvokeDynamic() { throw new InternalError(); } // do not instantiate
10.36 +}
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/InvokerBytecodeGenerator.java Sat Aug 09 11:12:05 2014 +0200
11.3 @@ -0,0 +1,1052 @@
11.4 +/*
11.5 + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
11.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
11.7 + *
11.8 + * This code is free software; you can redistribute it and/or modify it
11.9 + * under the terms of the GNU General Public License version 2 only, as
11.10 + * published by the Free Software Foundation. Oracle designates this
11.11 + * particular file as subject to the "Classpath" exception as provided
11.12 + * by Oracle in the LICENSE file that accompanied this code.
11.13 + *
11.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
11.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11.17 + * version 2 for more details (a copy is included in the LICENSE file that
11.18 + * accompanied this code).
11.19 + *
11.20 + * You should have received a copy of the GNU General Public License version
11.21 + * 2 along with this work; if not, write to the Free Software Foundation,
11.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
11.23 + *
11.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
11.25 + * or visit www.oracle.com if you need additional information or have any
11.26 + * questions.
11.27 + */
11.28 +
11.29 +package java.lang.invoke;
11.30 +
11.31 +import sun.invoke.util.VerifyAccess;
11.32 +import java.lang.invoke.LambdaForm.Name;
11.33 +import java.lang.invoke.MethodHandles.Lookup;
11.34 +
11.35 +import sun.invoke.util.Wrapper;
11.36 +
11.37 +import java.io.*;
11.38 +import java.util.*;
11.39 +
11.40 +import jdk.internal.org.objectweb.asm.*;
11.41 +
11.42 +import java.lang.reflect.*;
11.43 +import static java.lang.invoke.MethodHandleStatics.*;
11.44 +import static java.lang.invoke.MethodHandleNatives.Constants.*;
11.45 +import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
11.46 +import sun.invoke.util.ValueConversions;
11.47 +import sun.invoke.util.VerifyType;
11.48 +
11.49 +/**
11.50 + * Code generation backend for LambdaForm.
11.51 + * <p>
11.52 + * @author John Rose, JSR 292 EG
11.53 + */
11.54 +class InvokerBytecodeGenerator {
11.55 + /** Define class names for convenience. */
11.56 + private static final String MH = "java/lang/invoke/MethodHandle";
11.57 + private static final String BMH = "java/lang/invoke/BoundMethodHandle";
11.58 + private static final String LF = "java/lang/invoke/LambdaForm";
11.59 + private static final String LFN = "java/lang/invoke/LambdaForm$Name";
11.60 + private static final String CLS = "java/lang/Class";
11.61 + private static final String OBJ = "java/lang/Object";
11.62 + private static final String OBJARY = "[Ljava/lang/Object;";
11.63 +
11.64 + private static final String LF_SIG = "L" + LF + ";";
11.65 + private static final String LFN_SIG = "L" + LFN + ";";
11.66 + private static final String LL_SIG = "(L" + OBJ + ";)L" + OBJ + ";";
11.67 +
11.68 + /** Name of its super class*/
11.69 + private static final String superName = LF;
11.70 +
11.71 + /** Name of new class */
11.72 + private final String className;
11.73 +
11.74 + /** Name of the source file (for stack trace printing). */
11.75 + private final String sourceFile;
11.76 +
11.77 + private final LambdaForm lambdaForm;
11.78 + private final String invokerName;
11.79 + private final MethodType invokerType;
11.80 + private final int[] localsMap;
11.81 +
11.82 + /** ASM bytecode generation. */
11.83 + private ClassWriter cw;
11.84 + private MethodVisitor mv;
11.85 +
11.86 + private static final MemberName.Factory MEMBERNAME_FACTORY = MemberName.getFactory();
11.87 + private static final Class<?> HOST_CLASS = LambdaForm.class;
11.88 +
11.89 + private InvokerBytecodeGenerator(LambdaForm lambdaForm, int localsMapSize,
11.90 + String className, String invokerName, MethodType invokerType) {
11.91 + if (invokerName.contains(".")) {
11.92 + int p = invokerName.indexOf(".");
11.93 + className = invokerName.substring(0, p);
11.94 + invokerName = invokerName.substring(p+1);
11.95 + }
11.96 + if (DUMP_CLASS_FILES) {
11.97 + className = makeDumpableClassName(className);
11.98 + }
11.99 + this.className = superName + "$" + className;
11.100 + this.sourceFile = "LambdaForm$" + className;
11.101 + this.lambdaForm = lambdaForm;
11.102 + this.invokerName = invokerName;
11.103 + this.invokerType = invokerType;
11.104 + this.localsMap = new int[localsMapSize];
11.105 + }
11.106 +
11.107 + private InvokerBytecodeGenerator(String className, String invokerName, MethodType invokerType) {
11.108 + this(null, invokerType.parameterCount(),
11.109 + className, invokerName, invokerType);
11.110 + // Create an array to map name indexes to locals indexes.
11.111 + for (int i = 0; i < localsMap.length; i++) {
11.112 + localsMap[i] = invokerType.parameterSlotCount() - invokerType.parameterSlotDepth(i);
11.113 + }
11.114 + }
11.115 +
11.116 + private InvokerBytecodeGenerator(String className, LambdaForm form, MethodType invokerType) {
11.117 + this(form, form.names.length,
11.118 + className, form.debugName, invokerType);
11.119 + // Create an array to map name indexes to locals indexes.
11.120 + Name[] names = form.names;
11.121 + for (int i = 0, index = 0; i < localsMap.length; i++) {
11.122 + localsMap[i] = index;
11.123 + index += Wrapper.forBasicType(names[i].type).stackSlots();
11.124 + }
11.125 + }
11.126 +
11.127 +
11.128 + /** instance counters for dumped classes */
11.129 + private final static HashMap<String,Integer> DUMP_CLASS_FILES_COUNTERS;
11.130 + /** debugging flag for saving generated class files */
11.131 + private final static File DUMP_CLASS_FILES_DIR;
11.132 +
11.133 + static {
11.134 + if (DUMP_CLASS_FILES) {
11.135 + DUMP_CLASS_FILES_COUNTERS = new HashMap<>();
11.136 + try {
11.137 + File dumpDir = new File("DUMP_CLASS_FILES");
11.138 + if (!dumpDir.exists()) {
11.139 + dumpDir.mkdirs();
11.140 + }
11.141 + DUMP_CLASS_FILES_DIR = dumpDir;
11.142 + System.out.println("Dumping class files to "+DUMP_CLASS_FILES_DIR+"/...");
11.143 + } catch (Exception e) {
11.144 + throw newInternalError(e);
11.145 + }
11.146 + } else {
11.147 + DUMP_CLASS_FILES_COUNTERS = null;
11.148 + DUMP_CLASS_FILES_DIR = null;
11.149 + }
11.150 + }
11.151 +
11.152 + static void maybeDump(final String className, final byte[] classFile) {
11.153 + if (DUMP_CLASS_FILES) {
11.154 + System.out.println("dump: " + className);
11.155 + java.security.AccessController.doPrivileged(
11.156 + new java.security.PrivilegedAction<Void>() {
11.157 + public Void run() {
11.158 + try {
11.159 + String dumpName = className;
11.160 + //dumpName = dumpName.replace('/', '-');
11.161 + File dumpFile = new File(DUMP_CLASS_FILES_DIR, dumpName+".class");
11.162 + dumpFile.getParentFile().mkdirs();
11.163 + FileOutputStream file = new FileOutputStream(dumpFile);
11.164 + file.write(classFile);
11.165 + file.close();
11.166 + return null;
11.167 + } catch (IOException ex) {
11.168 + throw newInternalError(ex);
11.169 + }
11.170 + }
11.171 + });
11.172 + }
11.173 +
11.174 + }
11.175 +
11.176 + private static String makeDumpableClassName(String className) {
11.177 + Integer ctr;
11.178 + synchronized (DUMP_CLASS_FILES_COUNTERS) {
11.179 + ctr = DUMP_CLASS_FILES_COUNTERS.get(className);
11.180 + if (ctr == null) ctr = 0;
11.181 + DUMP_CLASS_FILES_COUNTERS.put(className, ctr+1);
11.182 + }
11.183 + String sfx = ctr.toString();
11.184 + while (sfx.length() < 3)
11.185 + sfx = "0"+sfx;
11.186 + className += sfx;
11.187 + return className;
11.188 + }
11.189 +
11.190 + class CpPatch {
11.191 + final int index;
11.192 + final String placeholder;
11.193 + final Object value;
11.194 + CpPatch(int index, String placeholder, Object value) {
11.195 + this.index = index;
11.196 + this.placeholder = placeholder;
11.197 + this.value = value;
11.198 + }
11.199 + public String toString() {
11.200 + return "CpPatch/index="+index+",placeholder="+placeholder+",value="+value;
11.201 + }
11.202 + }
11.203 +
11.204 + Map<Object, CpPatch> cpPatches = new HashMap<>();
11.205 +
11.206 + int cph = 0; // for counting constant placeholders
11.207 +
11.208 + String constantPlaceholder(Object arg) {
11.209 + String cpPlaceholder = "CONSTANT_PLACEHOLDER_" + cph++;
11.210 + if (DUMP_CLASS_FILES) cpPlaceholder += " <<" + arg.toString() + ">>"; // debugging aid
11.211 + if (cpPatches.containsKey(cpPlaceholder)) {
11.212 + throw new InternalError("observed CP placeholder twice: " + cpPlaceholder);
11.213 + }
11.214 + // insert placeholder in CP and remember the patch
11.215 + int index = cw.newConst((Object) cpPlaceholder); // TODO check if aready in the constant pool
11.216 + cpPatches.put(cpPlaceholder, new CpPatch(index, cpPlaceholder, arg));
11.217 + return cpPlaceholder;
11.218 + }
11.219 +
11.220 + Object[] cpPatches(byte[] classFile) {
11.221 + int size = getConstantPoolSize(classFile);
11.222 + Object[] res = new Object[size];
11.223 + for (CpPatch p : cpPatches.values()) {
11.224 + if (p.index >= size)
11.225 + throw new InternalError("in cpool["+size+"]: "+p+"\n"+Arrays.toString(Arrays.copyOf(classFile, 20)));
11.226 + res[p.index] = p.value;
11.227 + }
11.228 + return res;
11.229 + }
11.230 +
11.231 + /**
11.232 + * Extract the number of constant pool entries from a given class file.
11.233 + *
11.234 + * @param classFile the bytes of the class file in question.
11.235 + * @return the number of entries in the constant pool.
11.236 + */
11.237 + private static int getConstantPoolSize(byte[] classFile) {
11.238 + // The first few bytes:
11.239 + // u4 magic;
11.240 + // u2 minor_version;
11.241 + // u2 major_version;
11.242 + // u2 constant_pool_count;
11.243 + return ((classFile[8] & 0xFF) << 8) | (classFile[9] & 0xFF);
11.244 + }
11.245 +
11.246 + /**
11.247 + * Extract the MemberName of a newly-defined method.
11.248 + */
11.249 + private MemberName loadMethod(byte[] classFile) {
11.250 + Class<?> invokerClass = loadAndInitializeInvokerClass(classFile, cpPatches(classFile));
11.251 + return resolveInvokerMember(invokerClass, invokerName, invokerType);
11.252 + }
11.253 +
11.254 + /**
11.255 + * Define a given class as anonymous class in the runtime system.
11.256 + */
11.257 + private static Class<?> loadAndInitializeInvokerClass(byte[] classBytes, Object[] patches) {
11.258 + Class<?> invokerClass = UNSAFE.defineAnonymousClass(HOST_CLASS, classBytes, patches);
11.259 + UNSAFE.ensureClassInitialized(invokerClass); // Make sure the class is initialized; VM might complain.
11.260 + return invokerClass;
11.261 + }
11.262 +
11.263 + private static MemberName resolveInvokerMember(Class<?> invokerClass, String name, MethodType type) {
11.264 + MemberName member = new MemberName(invokerClass, name, type, REF_invokeStatic);
11.265 + //System.out.println("resolveInvokerMember => "+member);
11.266 + //for (Method m : invokerClass.getDeclaredMethods()) System.out.println(" "+m);
11.267 + try {
11.268 + member = MEMBERNAME_FACTORY.resolveOrFail(REF_invokeStatic, member, HOST_CLASS, ReflectiveOperationException.class);
11.269 + } catch (ReflectiveOperationException e) {
11.270 + throw newInternalError(e);
11.271 + }
11.272 + //System.out.println("resolveInvokerMember => "+member);
11.273 + return member;
11.274 + }
11.275 +
11.276 + /**
11.277 + * Set up class file generation.
11.278 + */
11.279 + private void classFilePrologue() {
11.280 + cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
11.281 + cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, className, null, superName, null);
11.282 + cw.visitSource(sourceFile, null);
11.283 +
11.284 + String invokerDesc = invokerType.toMethodDescriptorString();
11.285 + mv = cw.visitMethod(Opcodes.ACC_STATIC, invokerName, invokerDesc, null, null);
11.286 + }
11.287 +
11.288 + /**
11.289 + * Tear down class file generation.
11.290 + */
11.291 + private void classFileEpilogue() {
11.292 + mv.visitMaxs(0, 0);
11.293 + mv.visitEnd();
11.294 + }
11.295 +
11.296 + /*
11.297 + * Low-level emit helpers.
11.298 + */
11.299 + private void emitConst(Object con) {
11.300 + if (con == null) {
11.301 + mv.visitInsn(Opcodes.ACONST_NULL);
11.302 + return;
11.303 + }
11.304 + if (con instanceof Integer) {
11.305 + emitIconstInsn((int) con);
11.306 + return;
11.307 + }
11.308 + if (con instanceof Long) {
11.309 + long x = (long) con;
11.310 + if (x == (short) x) {
11.311 + emitIconstInsn((int) x);
11.312 + mv.visitInsn(Opcodes.I2L);
11.313 + return;
11.314 + }
11.315 + }
11.316 + if (con instanceof Float) {
11.317 + float x = (float) con;
11.318 + if (x == (short) x) {
11.319 + emitIconstInsn((int) x);
11.320 + mv.visitInsn(Opcodes.I2F);
11.321 + return;
11.322 + }
11.323 + }
11.324 + if (con instanceof Double) {
11.325 + double x = (double) con;
11.326 + if (x == (short) x) {
11.327 + emitIconstInsn((int) x);
11.328 + mv.visitInsn(Opcodes.I2D);
11.329 + return;
11.330 + }
11.331 + }
11.332 + if (con instanceof Boolean) {
11.333 + emitIconstInsn((boolean) con ? 1 : 0);
11.334 + return;
11.335 + }
11.336 + // fall through:
11.337 + mv.visitLdcInsn(con);
11.338 + }
11.339 +
11.340 + private void emitIconstInsn(int i) {
11.341 + int opcode;
11.342 + switch (i) {
11.343 + case 0: opcode = Opcodes.ICONST_0; break;
11.344 + case 1: opcode = Opcodes.ICONST_1; break;
11.345 + case 2: opcode = Opcodes.ICONST_2; break;
11.346 + case 3: opcode = Opcodes.ICONST_3; break;
11.347 + case 4: opcode = Opcodes.ICONST_4; break;
11.348 + case 5: opcode = Opcodes.ICONST_5; break;
11.349 + default:
11.350 + if (i == (byte) i) {
11.351 + mv.visitIntInsn(Opcodes.BIPUSH, i & 0xFF);
11.352 + } else if (i == (short) i) {
11.353 + mv.visitIntInsn(Opcodes.SIPUSH, (char) i);
11.354 + } else {
11.355 + mv.visitLdcInsn(i);
11.356 + }
11.357 + return;
11.358 + }
11.359 + mv.visitInsn(opcode);
11.360 + }
11.361 +
11.362 + /*
11.363 + * NOTE: These load/store methods use the localsMap to find the correct index!
11.364 + */
11.365 + private void emitLoadInsn(char type, int index) {
11.366 + int opcode;
11.367 + switch (type) {
11.368 + case 'I': opcode = Opcodes.ILOAD; break;
11.369 + case 'J': opcode = Opcodes.LLOAD; break;
11.370 + case 'F': opcode = Opcodes.FLOAD; break;
11.371 + case 'D': opcode = Opcodes.DLOAD; break;
11.372 + case 'L': opcode = Opcodes.ALOAD; break;
11.373 + default:
11.374 + throw new InternalError("unknown type: " + type);
11.375 + }
11.376 + mv.visitVarInsn(opcode, localsMap[index]);
11.377 + }
11.378 + private void emitAloadInsn(int index) {
11.379 + emitLoadInsn('L', index);
11.380 + }
11.381 +
11.382 + private void emitStoreInsn(char type, int index) {
11.383 + int opcode;
11.384 + switch (type) {
11.385 + case 'I': opcode = Opcodes.ISTORE; break;
11.386 + case 'J': opcode = Opcodes.LSTORE; break;
11.387 + case 'F': opcode = Opcodes.FSTORE; break;
11.388 + case 'D': opcode = Opcodes.DSTORE; break;
11.389 + case 'L': opcode = Opcodes.ASTORE; break;
11.390 + default:
11.391 + throw new InternalError("unknown type: " + type);
11.392 + }
11.393 + mv.visitVarInsn(opcode, localsMap[index]);
11.394 + }
11.395 + private void emitAstoreInsn(int index) {
11.396 + emitStoreInsn('L', index);
11.397 + }
11.398 +
11.399 + /**
11.400 + * Emit a boxing call.
11.401 + *
11.402 + * @param type primitive type class to box.
11.403 + */
11.404 + private void emitBoxing(Class<?> type) {
11.405 + Wrapper wrapper = Wrapper.forPrimitiveType(type);
11.406 + String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
11.407 + String name = "valueOf";
11.408 + String desc = "(" + wrapper.basicTypeChar() + ")L" + owner + ";";
11.409 + mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc);
11.410 + }
11.411 +
11.412 + /**
11.413 + * Emit an unboxing call (plus preceding checkcast).
11.414 + *
11.415 + * @param type wrapper type class to unbox.
11.416 + */
11.417 + private void emitUnboxing(Class<?> type) {
11.418 + Wrapper wrapper = Wrapper.forWrapperType(type);
11.419 + String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
11.420 + String name = wrapper.primitiveSimpleName() + "Value";
11.421 + String desc = "()" + wrapper.basicTypeChar();
11.422 + mv.visitTypeInsn(Opcodes.CHECKCAST, owner);
11.423 + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc);
11.424 + }
11.425 +
11.426 + /**
11.427 + * Emit an implicit conversion.
11.428 + *
11.429 + * @param ptype type of value present on stack
11.430 + * @param pclass type of value required on stack
11.431 + */
11.432 + private void emitImplicitConversion(char ptype, Class<?> pclass) {
11.433 + switch (ptype) {
11.434 + case 'L':
11.435 + if (VerifyType.isNullConversion(Object.class, pclass))
11.436 + return;
11.437 + if (isStaticallyNameable(pclass)) {
11.438 + mv.visitTypeInsn(Opcodes.CHECKCAST, getInternalName(pclass));
11.439 + } else {
11.440 + mv.visitLdcInsn(constantPlaceholder(pclass));
11.441 + mv.visitTypeInsn(Opcodes.CHECKCAST, CLS);
11.442 + mv.visitInsn(Opcodes.SWAP);
11.443 + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, CLS, "cast", LL_SIG);
11.444 + if (pclass.isArray())
11.445 + mv.visitTypeInsn(Opcodes.CHECKCAST, OBJARY);
11.446 + }
11.447 + return;
11.448 + case 'I':
11.449 + if (!VerifyType.isNullConversion(int.class, pclass))
11.450 + emitPrimCast(ptype, Wrapper.basicTypeChar(pclass));
11.451 + return;
11.452 + case 'J':
11.453 + assert(pclass == long.class);
11.454 + return;
11.455 + case 'F':
11.456 + assert(pclass == float.class);
11.457 + return;
11.458 + case 'D':
11.459 + assert(pclass == double.class);
11.460 + return;
11.461 + }
11.462 + throw new InternalError("bad implicit conversion: tc="+ptype+": "+pclass);
11.463 + }
11.464 +
11.465 + /**
11.466 + * Emits an actual return instruction conforming to the given return type.
11.467 + */
11.468 + private void emitReturnInsn(Class<?> type) {
11.469 + int opcode;
11.470 + switch (Wrapper.basicTypeChar(type)) {
11.471 + case 'I': opcode = Opcodes.IRETURN; break;
11.472 + case 'J': opcode = Opcodes.LRETURN; break;
11.473 + case 'F': opcode = Opcodes.FRETURN; break;
11.474 + case 'D': opcode = Opcodes.DRETURN; break;
11.475 + case 'L': opcode = Opcodes.ARETURN; break;
11.476 + case 'V': opcode = Opcodes.RETURN; break;
11.477 + default:
11.478 + throw new InternalError("unknown return type: " + type);
11.479 + }
11.480 + mv.visitInsn(opcode);
11.481 + }
11.482 +
11.483 + private static String getInternalName(Class<?> c) {
11.484 + assert(VerifyAccess.isTypeVisible(c, Object.class));
11.485 + return c.getName().replace('.', '/');
11.486 + }
11.487 +
11.488 + /**
11.489 + * Generate customized bytecode for a given LambdaForm.
11.490 + */
11.491 + static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) {
11.492 + InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("MH", form, invokerType);
11.493 + return g.loadMethod(g.generateCustomizedCodeBytes());
11.494 + }
11.495 +
11.496 + /**
11.497 + * Generate an invoker method for the passed {@link LambdaForm}.
11.498 + */
11.499 + private byte[] generateCustomizedCodeBytes() {
11.500 + classFilePrologue();
11.501 +
11.502 + // Suppress this method in backtraces displayed to the user.
11.503 + mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
11.504 +
11.505 + // Mark this method as a compiled LambdaForm
11.506 + mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Compiled;", true);
11.507 +
11.508 + // Force inlining of this invoker method.
11.509 + mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
11.510 +
11.511 + // iterate over the form's names, generating bytecode instructions for each
11.512 + // start iterating at the first name following the arguments
11.513 + for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
11.514 + Name name = lambdaForm.names[i];
11.515 + MemberName member = name.function.member();
11.516 +
11.517 + if (isSelectAlternative(member)) {
11.518 + // selectAlternative idiom
11.519 + // FIXME: make sure this idiom is really present!
11.520 + emitSelectAlternative(name, lambdaForm.names[i + 1]);
11.521 + i++; // skip MH.invokeBasic of the selectAlternative result
11.522 + } else if (isStaticallyInvocable(member)) {
11.523 + emitStaticInvoke(member, name);
11.524 + } else {
11.525 + emitInvoke(name);
11.526 + }
11.527 +
11.528 + // store the result from evaluating to the target name in a local if required
11.529 + // (if this is the last value, i.e., the one that is going to be returned,
11.530 + // avoid store/load/return and just return)
11.531 + if (i == lambdaForm.names.length - 1 && i == lambdaForm.result) {
11.532 + // return value - do nothing
11.533 + } else if (name.type != 'V') {
11.534 + // non-void: actually assign
11.535 + emitStoreInsn(name.type, name.index());
11.536 + }
11.537 + }
11.538 +
11.539 + // return statement
11.540 + emitReturn();
11.541 +
11.542 + classFileEpilogue();
11.543 + bogusMethod(lambdaForm);
11.544 +
11.545 + final byte[] classFile = cw.toByteArray();
11.546 + maybeDump(className, classFile);
11.547 + return classFile;
11.548 + }
11.549 +
11.550 + /**
11.551 + * Emit an invoke for the given name.
11.552 + */
11.553 + void emitInvoke(Name name) {
11.554 + if (true) {
11.555 + // push receiver
11.556 + MethodHandle target = name.function.resolvedHandle;
11.557 + assert(target != null) : name.exprString();
11.558 + mv.visitLdcInsn(constantPlaceholder(target));
11.559 + mv.visitTypeInsn(Opcodes.CHECKCAST, MH);
11.560 + } else {
11.561 + // load receiver
11.562 + emitAloadInsn(0);
11.563 + mv.visitTypeInsn(Opcodes.CHECKCAST, MH);
11.564 + mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", LF_SIG);
11.565 + mv.visitFieldInsn(Opcodes.GETFIELD, LF, "names", LFN_SIG);
11.566 + // TODO more to come
11.567 + }
11.568 +
11.569 + // push arguments
11.570 + for (int i = 0; i < name.arguments.length; i++) {
11.571 + emitPushArgument(name, i);
11.572 + }
11.573 +
11.574 + // invocation
11.575 + MethodType type = name.function.methodType();
11.576 + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString());
11.577 + }
11.578 +
11.579 + static private Class<?>[] STATICALLY_INVOCABLE_PACKAGES = {
11.580 + // Sample classes from each package we are willing to bind to statically:
11.581 + java.lang.Object.class,
11.582 + java.util.Arrays.class,
11.583 + sun.misc.Unsafe.class
11.584 + //MethodHandle.class already covered
11.585 + };
11.586 +
11.587 + static boolean isStaticallyInvocable(MemberName member) {
11.588 + if (member == null) return false;
11.589 + if (member.isConstructor()) return false;
11.590 + Class<?> cls = member.getDeclaringClass();
11.591 + if (cls.isArray() || cls.isPrimitive())
11.592 + return false; // FIXME
11.593 + if (cls.isAnonymousClass() || cls.isLocalClass())
11.594 + return false; // inner class of some sort
11.595 + if (cls.getClassLoader() != MethodHandle.class.getClassLoader())
11.596 + return false; // not on BCP
11.597 + MethodType mtype = member.getMethodOrFieldType();
11.598 + if (!isStaticallyNameable(mtype.returnType()))
11.599 + return false;
11.600 + for (Class<?> ptype : mtype.parameterArray())
11.601 + if (!isStaticallyNameable(ptype))
11.602 + return false;
11.603 + if (!member.isPrivate() && VerifyAccess.isSamePackage(MethodHandle.class, cls))
11.604 + return true; // in java.lang.invoke package
11.605 + if (member.isPublic() && isStaticallyNameable(cls))
11.606 + return true;
11.607 + return false;
11.608 + }
11.609 +
11.610 + static boolean isStaticallyNameable(Class<?> cls) {
11.611 + while (cls.isArray())
11.612 + cls = cls.getComponentType();
11.613 + if (cls.isPrimitive())
11.614 + return true; // int[].class, for example
11.615 + // could use VerifyAccess.isClassAccessible but the following is a safe approximation
11.616 + if (cls.getClassLoader() != Object.class.getClassLoader())
11.617 + return false;
11.618 + if (VerifyAccess.isSamePackage(MethodHandle.class, cls))
11.619 + return true;
11.620 + if (!Modifier.isPublic(cls.getModifiers()))
11.621 + return false;
11.622 + for (Class<?> pkgcls : STATICALLY_INVOCABLE_PACKAGES) {
11.623 + if (VerifyAccess.isSamePackage(pkgcls, cls))
11.624 + return true;
11.625 + }
11.626 + return false;
11.627 + }
11.628 +
11.629 + /**
11.630 + * Emit an invoke for the given name, using the MemberName directly.
11.631 + */
11.632 + void emitStaticInvoke(MemberName member, Name name) {
11.633 + assert(member.equals(name.function.member()));
11.634 + String cname = getInternalName(member.getDeclaringClass());
11.635 + String mname = member.getName();
11.636 + String mtype;
11.637 + byte refKind = member.getReferenceKind();
11.638 + if (refKind == REF_invokeSpecial) {
11.639 + // in order to pass the verifier, we need to convert this to invokevirtual in all cases
11.640 + assert(member.canBeStaticallyBound()) : member;
11.641 + refKind = REF_invokeVirtual;
11.642 + }
11.643 +
11.644 + if (member.getDeclaringClass().isInterface() && refKind == REF_invokeVirtual) {
11.645 + // Methods from Object declared in an interface can be resolved by JVM to invokevirtual kind.
11.646 + // Need to convert it back to invokeinterface to pass verification and make the invocation works as expected.
11.647 + refKind = REF_invokeInterface;
11.648 + }
11.649 +
11.650 + // push arguments
11.651 + for (int i = 0; i < name.arguments.length; i++) {
11.652 + emitPushArgument(name, i);
11.653 + }
11.654 +
11.655 + // invocation
11.656 + if (member.isMethod()) {
11.657 + mtype = member.getMethodType().toMethodDescriptorString();
11.658 + mv.visitMethodInsn(refKindOpcode(refKind), cname, mname, mtype,
11.659 + member.getDeclaringClass().isInterface());
11.660 + } else {
11.661 + mtype = MethodType.toFieldDescriptorString(member.getFieldType());
11.662 + mv.visitFieldInsn(refKindOpcode(refKind), cname, mname, mtype);
11.663 + }
11.664 + }
11.665 + int refKindOpcode(byte refKind) {
11.666 + switch (refKind) {
11.667 + case REF_invokeVirtual: return Opcodes.INVOKEVIRTUAL;
11.668 + case REF_invokeStatic: return Opcodes.INVOKESTATIC;
11.669 + case REF_invokeSpecial: return Opcodes.INVOKESPECIAL;
11.670 + case REF_invokeInterface: return Opcodes.INVOKEINTERFACE;
11.671 + case REF_getField: return Opcodes.GETFIELD;
11.672 + case REF_putField: return Opcodes.PUTFIELD;
11.673 + case REF_getStatic: return Opcodes.GETSTATIC;
11.674 + case REF_putStatic: return Opcodes.PUTSTATIC;
11.675 + }
11.676 + throw new InternalError("refKind="+refKind);
11.677 + }
11.678 +
11.679 + /**
11.680 + * Check if MemberName is a call to MethodHandleImpl.selectAlternative.
11.681 + */
11.682 + private boolean isSelectAlternative(MemberName member) {
11.683 + return member != null &&
11.684 + member.getDeclaringClass() == MethodHandleImpl.class &&
11.685 + member.getName().equals("selectAlternative");
11.686 + }
11.687 +
11.688 + /**
11.689 + * Emit bytecode for the selectAlternative idiom.
11.690 + *
11.691 + * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithTest):
11.692 + * <blockquote><pre>{@code
11.693 + * Lambda(a0:L,a1:I)=>{
11.694 + * t2:I=foo.test(a1:I);
11.695 + * t3:L=MethodHandleImpl.selectAlternative(t2:I,(MethodHandle(int)int),(MethodHandle(int)int));
11.696 + * t4:I=MethodHandle.invokeBasic(t3:L,a1:I);t4:I}
11.697 + * }</pre></blockquote>
11.698 + */
11.699 + private void emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) {
11.700 + MethodType type = selectAlternativeName.function.methodType();
11.701 +
11.702 + Name receiver = (Name) invokeBasicName.arguments[0];
11.703 +
11.704 + Label L_fallback = new Label();
11.705 + Label L_done = new Label();
11.706 +
11.707 + // load test result
11.708 + emitPushArgument(selectAlternativeName, 0);
11.709 + mv.visitInsn(Opcodes.ICONST_1);
11.710 +
11.711 + // if_icmpne L_fallback
11.712 + mv.visitJumpInsn(Opcodes.IF_ICMPNE, L_fallback);
11.713 +
11.714 + // invoke selectAlternativeName.arguments[1]
11.715 + MethodHandle target = (MethodHandle) selectAlternativeName.arguments[1];
11.716 + emitPushArgument(selectAlternativeName, 1); // get 2nd argument of selectAlternative
11.717 + emitAstoreInsn(receiver.index()); // store the MH in the receiver slot
11.718 + emitInvoke(invokeBasicName);
11.719 +
11.720 + // goto L_done
11.721 + mv.visitJumpInsn(Opcodes.GOTO, L_done);
11.722 +
11.723 + // L_fallback:
11.724 + mv.visitLabel(L_fallback);
11.725 +
11.726 + // invoke selectAlternativeName.arguments[2]
11.727 + MethodHandle fallback = (MethodHandle) selectAlternativeName.arguments[2];
11.728 + emitPushArgument(selectAlternativeName, 2); // get 3rd argument of selectAlternative
11.729 + emitAstoreInsn(receiver.index()); // store the MH in the receiver slot
11.730 + emitInvoke(invokeBasicName);
11.731 +
11.732 + // L_done:
11.733 + mv.visitLabel(L_done);
11.734 + }
11.735 +
11.736 + private void emitPushArgument(Name name, int paramIndex) {
11.737 + Object arg = name.arguments[paramIndex];
11.738 + char ptype = name.function.parameterType(paramIndex);
11.739 + MethodType mtype = name.function.methodType();
11.740 + if (arg instanceof Name) {
11.741 + Name n = (Name) arg;
11.742 + emitLoadInsn(n.type, n.index());
11.743 + emitImplicitConversion(n.type, mtype.parameterType(paramIndex));
11.744 + } else if ((arg == null || arg instanceof String) && ptype == 'L') {
11.745 + emitConst(arg);
11.746 + } else {
11.747 + if (Wrapper.isWrapperType(arg.getClass()) && ptype != 'L') {
11.748 + emitConst(arg);
11.749 + } else {
11.750 + mv.visitLdcInsn(constantPlaceholder(arg));
11.751 + emitImplicitConversion('L', mtype.parameterType(paramIndex));
11.752 + }
11.753 + }
11.754 + }
11.755 +
11.756 + /**
11.757 + * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type.
11.758 + */
11.759 + private void emitReturn() {
11.760 + // return statement
11.761 + if (lambdaForm.result == -1) {
11.762 + // void
11.763 + mv.visitInsn(Opcodes.RETURN);
11.764 + } else {
11.765 + LambdaForm.Name rn = lambdaForm.names[lambdaForm.result];
11.766 + char rtype = Wrapper.basicTypeChar(invokerType.returnType());
11.767 +
11.768 + // put return value on the stack if it is not already there
11.769 + if (lambdaForm.result != lambdaForm.names.length - 1) {
11.770 + emitLoadInsn(rn.type, lambdaForm.result);
11.771 + }
11.772 +
11.773 + // potentially generate cast
11.774 + // rtype is the return type of the invoker - generated code must conform to this
11.775 + // rn.type is the type of the result Name in the LF
11.776 + if (rtype != rn.type) {
11.777 + // need cast
11.778 + if (rtype == 'L') {
11.779 + // possibly cast the primitive to the correct type for boxing
11.780 + char boxedType = Wrapper.forWrapperType(invokerType.returnType()).basicTypeChar();
11.781 + if (boxedType != rn.type) {
11.782 + emitPrimCast(rn.type, boxedType);
11.783 + }
11.784 + // cast primitive to reference ("boxing")
11.785 + emitBoxing(invokerType.returnType());
11.786 + } else {
11.787 + // to-primitive cast
11.788 + if (rn.type != 'L') {
11.789 + // prim-to-prim cast
11.790 + emitPrimCast(rn.type, rtype);
11.791 + } else {
11.792 + // ref-to-prim cast ("unboxing")
11.793 + throw new InternalError("no ref-to-prim (unboxing) casts supported right now");
11.794 + }
11.795 + }
11.796 + }
11.797 +
11.798 + // generate actual return statement
11.799 + emitReturnInsn(invokerType.returnType());
11.800 + }
11.801 + }
11.802 +
11.803 + /**
11.804 + * Emit a type conversion bytecode casting from "from" to "to".
11.805 + */
11.806 + private void emitPrimCast(char from, char to) {
11.807 + // Here's how.
11.808 + // - indicates forbidden
11.809 + // <-> indicates implicit
11.810 + // to ----> boolean byte short char int long float double
11.811 + // from boolean <-> - - - - - - -
11.812 + // byte - <-> i2s i2c <-> i2l i2f i2d
11.813 + // short - i2b <-> i2c <-> i2l i2f i2d
11.814 + // char - i2b i2s <-> <-> i2l i2f i2d
11.815 + // int - i2b i2s i2c <-> i2l i2f i2d
11.816 + // long - l2i,i2b l2i,i2s l2i,i2c l2i <-> l2f l2d
11.817 + // float - f2i,i2b f2i,i2s f2i,i2c f2i f2l <-> f2d
11.818 + // double - d2i,i2b d2i,i2s d2i,i2c d2i d2l d2f <->
11.819 + if (from == to) {
11.820 + // no cast required, should be dead code anyway
11.821 + return;
11.822 + }
11.823 + Wrapper wfrom = Wrapper.forBasicType(from);
11.824 + Wrapper wto = Wrapper.forBasicType(to);
11.825 + if (wfrom.isSubwordOrInt()) {
11.826 + // cast from {byte,short,char,int} to anything
11.827 + emitI2X(to);
11.828 + } else {
11.829 + // cast from {long,float,double} to anything
11.830 + if (wto.isSubwordOrInt()) {
11.831 + // cast to {byte,short,char,int}
11.832 + emitX2I(from);
11.833 + if (wto.bitWidth() < 32) {
11.834 + // targets other than int require another conversion
11.835 + emitI2X(to);
11.836 + }
11.837 + } else {
11.838 + // cast to {long,float,double} - this is verbose
11.839 + boolean error = false;
11.840 + switch (from) {
11.841 + case 'J':
11.842 + if (to == 'F') { mv.visitInsn(Opcodes.L2F); }
11.843 + else if (to == 'D') { mv.visitInsn(Opcodes.L2D); }
11.844 + else error = true;
11.845 + break;
11.846 + case 'F':
11.847 + if (to == 'J') { mv.visitInsn(Opcodes.F2L); }
11.848 + else if (to == 'D') { mv.visitInsn(Opcodes.F2D); }
11.849 + else error = true;
11.850 + break;
11.851 + case 'D':
11.852 + if (to == 'J') { mv.visitInsn(Opcodes.D2L); }
11.853 + else if (to == 'F') { mv.visitInsn(Opcodes.D2F); }
11.854 + else error = true;
11.855 + break;
11.856 + default:
11.857 + error = true;
11.858 + break;
11.859 + }
11.860 + if (error) {
11.861 + throw new IllegalStateException("unhandled prim cast: " + from + "2" + to);
11.862 + }
11.863 + }
11.864 + }
11.865 + }
11.866 +
11.867 + private void emitI2X(char type) {
11.868 + switch (type) {
11.869 + case 'B': mv.visitInsn(Opcodes.I2B); break;
11.870 + case 'S': mv.visitInsn(Opcodes.I2S); break;
11.871 + case 'C': mv.visitInsn(Opcodes.I2C); break;
11.872 + case 'I': /* naught */ break;
11.873 + case 'J': mv.visitInsn(Opcodes.I2L); break;
11.874 + case 'F': mv.visitInsn(Opcodes.I2F); break;
11.875 + case 'D': mv.visitInsn(Opcodes.I2D); break;
11.876 + case 'Z':
11.877 + // For compatibility with ValueConversions and explicitCastArguments:
11.878 + mv.visitInsn(Opcodes.ICONST_1);
11.879 + mv.visitInsn(Opcodes.IAND);
11.880 + break;
11.881 + default: throw new InternalError("unknown type: " + type);
11.882 + }
11.883 + }
11.884 +
11.885 + private void emitX2I(char type) {
11.886 + switch (type) {
11.887 + case 'J': mv.visitInsn(Opcodes.L2I); break;
11.888 + case 'F': mv.visitInsn(Opcodes.F2I); break;
11.889 + case 'D': mv.visitInsn(Opcodes.D2I); break;
11.890 + default: throw new InternalError("unknown type: " + type);
11.891 + }
11.892 + }
11.893 +
11.894 + private static String basicTypeCharSignature(String prefix, MethodType type) {
11.895 + StringBuilder buf = new StringBuilder(prefix);
11.896 + for (Class<?> ptype : type.parameterList())
11.897 + buf.append(Wrapper.forBasicType(ptype).basicTypeChar());
11.898 + buf.append('_').append(Wrapper.forBasicType(type.returnType()).basicTypeChar());
11.899 + return buf.toString();
11.900 + }
11.901 +
11.902 + /**
11.903 + * Generate bytecode for a LambdaForm.vmentry which calls interpretWithArguments.
11.904 + */
11.905 + static MemberName generateLambdaFormInterpreterEntryPoint(String sig) {
11.906 + assert(LambdaForm.isValidSignature(sig));
11.907 + //System.out.println("generateExactInvoker "+sig);
11.908 + // compute method type
11.909 + // first parameter and return type
11.910 + char tret = LambdaForm.signatureReturn(sig);
11.911 + MethodType type = MethodType.methodType(LambdaForm.typeClass(tret), MethodHandle.class);
11.912 + // other parameter types
11.913 + int arity = LambdaForm.signatureArity(sig);
11.914 + for (int i = 1; i < arity; i++) {
11.915 + type = type.appendParameterTypes(LambdaForm.typeClass(sig.charAt(i)));
11.916 + }
11.917 + InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("LFI", "interpret_"+tret, type);
11.918 + return g.loadMethod(g.generateLambdaFormInterpreterEntryPointBytes());
11.919 + }
11.920 +
11.921 + private byte[] generateLambdaFormInterpreterEntryPointBytes() {
11.922 + classFilePrologue();
11.923 +
11.924 + // Suppress this method in backtraces displayed to the user.
11.925 + mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
11.926 +
11.927 + // Don't inline the interpreter entry.
11.928 + mv.visitAnnotation("Ljava/lang/invoke/DontInline;", true);
11.929 +
11.930 + // create parameter array
11.931 + emitIconstInsn(invokerType.parameterCount());
11.932 + mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
11.933 +
11.934 + // fill parameter array
11.935 + for (int i = 0; i < invokerType.parameterCount(); i++) {
11.936 + Class<?> ptype = invokerType.parameterType(i);
11.937 + mv.visitInsn(Opcodes.DUP);
11.938 + emitIconstInsn(i);
11.939 + emitLoadInsn(Wrapper.basicTypeChar(ptype), i);
11.940 + // box if primitive type
11.941 + if (ptype.isPrimitive()) {
11.942 + emitBoxing(ptype);
11.943 + }
11.944 + mv.visitInsn(Opcodes.AASTORE);
11.945 + }
11.946 + // invoke
11.947 + emitAloadInsn(0);
11.948 + mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", "Ljava/lang/invoke/LambdaForm;");
11.949 + mv.visitInsn(Opcodes.SWAP); // swap form and array; avoid local variable
11.950 + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, LF, "interpretWithArguments", "([Ljava/lang/Object;)Ljava/lang/Object;");
11.951 +
11.952 + // maybe unbox
11.953 + Class<?> rtype = invokerType.returnType();
11.954 + if (rtype.isPrimitive() && rtype != void.class) {
11.955 + emitUnboxing(Wrapper.asWrapperType(rtype));
11.956 + }
11.957 +
11.958 + // return statement
11.959 + emitReturnInsn(rtype);
11.960 +
11.961 + classFileEpilogue();
11.962 + bogusMethod(invokerType);
11.963 +
11.964 + final byte[] classFile = cw.toByteArray();
11.965 + maybeDump(className, classFile);
11.966 + return classFile;
11.967 + }
11.968 +
11.969 + /**
11.970 + * Generate bytecode for a NamedFunction invoker.
11.971 + */
11.972 + static MemberName generateNamedFunctionInvoker(MethodTypeForm typeForm) {
11.973 + MethodType invokerType = LambdaForm.NamedFunction.INVOKER_METHOD_TYPE;
11.974 + String invokerName = basicTypeCharSignature("invoke_", typeForm.erasedType());
11.975 + InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("NFI", invokerName, invokerType);
11.976 + return g.loadMethod(g.generateNamedFunctionInvokerImpl(typeForm));
11.977 + }
11.978 +
11.979 + static int nfi = 0;
11.980 +
11.981 + private byte[] generateNamedFunctionInvokerImpl(MethodTypeForm typeForm) {
11.982 + MethodType dstType = typeForm.erasedType();
11.983 + classFilePrologue();
11.984 +
11.985 + // Suppress this method in backtraces displayed to the user.
11.986 + mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
11.987 +
11.988 + // Force inlining of this invoker method.
11.989 + mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
11.990 +
11.991 + // Load receiver
11.992 + emitAloadInsn(0);
11.993 +
11.994 + // Load arguments from array
11.995 + for (int i = 0; i < dstType.parameterCount(); i++) {
11.996 + emitAloadInsn(1);
11.997 + emitIconstInsn(i);
11.998 + mv.visitInsn(Opcodes.AALOAD);
11.999 +
11.1000 + // Maybe unbox
11.1001 + Class<?> dptype = dstType.parameterType(i);
11.1002 + if (dptype.isPrimitive()) {
11.1003 + Class<?> sptype = dstType.basicType().wrap().parameterType(i);
11.1004 + Wrapper dstWrapper = Wrapper.forBasicType(dptype);
11.1005 + Wrapper srcWrapper = dstWrapper.isSubwordOrInt() ? Wrapper.INT : dstWrapper; // narrow subword from int
11.1006 + emitUnboxing(srcWrapper.wrapperType());
11.1007 + emitPrimCast(srcWrapper.basicTypeChar(), dstWrapper.basicTypeChar());
11.1008 + }
11.1009 + }
11.1010 +
11.1011 + // Invoke
11.1012 + String targetDesc = dstType.basicType().toMethodDescriptorString();
11.1013 + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", targetDesc);
11.1014 +
11.1015 + // Box primitive types
11.1016 + Class<?> rtype = dstType.returnType();
11.1017 + if (rtype != void.class && rtype.isPrimitive()) {
11.1018 + Wrapper srcWrapper = Wrapper.forBasicType(rtype);
11.1019 + Wrapper dstWrapper = srcWrapper.isSubwordOrInt() ? Wrapper.INT : srcWrapper; // widen subword to int
11.1020 + // boolean casts not allowed
11.1021 + emitPrimCast(srcWrapper.basicTypeChar(), dstWrapper.basicTypeChar());
11.1022 + emitBoxing(dstWrapper.primitiveType());
11.1023 + }
11.1024 +
11.1025 + // If the return type is void we return a null reference.
11.1026 + if (rtype == void.class) {
11.1027 + mv.visitInsn(Opcodes.ACONST_NULL);
11.1028 + }
11.1029 + emitReturnInsn(Object.class); // NOTE: NamedFunction invokers always return a reference value.
11.1030 +
11.1031 + classFileEpilogue();
11.1032 + bogusMethod(dstType);
11.1033 +
11.1034 + final byte[] classFile = cw.toByteArray();
11.1035 + maybeDump(className, classFile);
11.1036 + return classFile;
11.1037 + }
11.1038 +
11.1039 + /**
11.1040 + * Emit a bogus method that just loads some string constants. This is to get the constants into the constant pool
11.1041 + * for debugging purposes.
11.1042 + */
11.1043 + private void bogusMethod(Object... os) {
11.1044 + if (DUMP_CLASS_FILES) {
11.1045 + mv = cw.visitMethod(Opcodes.ACC_STATIC, "dummy", "()V", null, null);
11.1046 + for (Object o : os) {
11.1047 + mv.visitLdcInsn(o.toString());
11.1048 + mv.visitInsn(Opcodes.POP);
11.1049 + }
11.1050 + mv.visitInsn(Opcodes.RETURN);
11.1051 + mv.visitMaxs(0, 0);
11.1052 + mv.visitEnd();
11.1053 + }
11.1054 + }
11.1055 +}
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
12.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/Invokers.java Sat Aug 09 11:12:05 2014 +0200
12.3 @@ -0,0 +1,462 @@
12.4 +/*
12.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
12.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
12.7 + *
12.8 + * This code is free software; you can redistribute it and/or modify it
12.9 + * under the terms of the GNU General Public License version 2 only, as
12.10 + * published by the Free Software Foundation. Oracle designates this
12.11 + * particular file as subject to the "Classpath" exception as provided
12.12 + * by Oracle in the LICENSE file that accompanied this code.
12.13 + *
12.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
12.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12.17 + * version 2 for more details (a copy is included in the LICENSE file that
12.18 + * accompanied this code).
12.19 + *
12.20 + * You should have received a copy of the GNU General Public License version
12.21 + * 2 along with this work; if not, write to the Free Software Foundation,
12.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
12.23 + *
12.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
12.25 + * or visit www.oracle.com if you need additional information or have any
12.26 + * questions.
12.27 + */
12.28 +
12.29 +package java.lang.invoke;
12.30 +
12.31 +import java.util.Arrays;
12.32 +import sun.invoke.empty.Empty;
12.33 +import static java.lang.invoke.MethodHandleStatics.*;
12.34 +import static java.lang.invoke.MethodHandleNatives.Constants.*;
12.35 +import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
12.36 +import static java.lang.invoke.LambdaForm.*;
12.37 +
12.38 +/**
12.39 + * Construction and caching of often-used invokers.
12.40 + * @author jrose
12.41 + */
12.42 +class Invokers {
12.43 + // exact type (sans leading taget MH) for the outgoing call
12.44 + private final MethodType targetType;
12.45 +
12.46 + // FIXME: Get rid of the invokers that are not useful.
12.47 +
12.48 + // exact invoker for the outgoing call
12.49 + private /*lazy*/ MethodHandle exactInvoker;
12.50 + private /*lazy*/ MethodHandle basicInvoker; // invokeBasic (unchecked exact)
12.51 +
12.52 + // erased (partially untyped but with primitives) invoker for the outgoing call
12.53 + // FIXME: get rid of
12.54 + private /*lazy*/ MethodHandle erasedInvoker;
12.55 + // FIXME: get rid of
12.56 + /*lazy*/ MethodHandle erasedInvokerWithDrops; // for InvokeGeneric
12.57 +
12.58 + // general invoker for the outgoing call
12.59 + private /*lazy*/ MethodHandle generalInvoker;
12.60 +
12.61 + // general invoker for the outgoing call, uses varargs
12.62 + private /*lazy*/ MethodHandle varargsInvoker;
12.63 +
12.64 + // general invoker for the outgoing call; accepts a trailing Object[]
12.65 + private final /*lazy*/ MethodHandle[] spreadInvokers;
12.66 +
12.67 + // invoker for an unbound callsite
12.68 + private /*lazy*/ MethodHandle uninitializedCallSite;
12.69 +
12.70 + /** Compute and cache information common to all collecting adapters
12.71 + * that implement members of the erasure-family of the given erased type.
12.72 + */
12.73 + /*non-public*/ Invokers(MethodType targetType) {
12.74 + this.targetType = targetType;
12.75 + this.spreadInvokers = new MethodHandle[targetType.parameterCount()+1];
12.76 + }
12.77 +
12.78 + /*non-public*/ MethodHandle exactInvoker() {
12.79 + MethodHandle invoker = exactInvoker;
12.80 + if (invoker != null) return invoker;
12.81 + invoker = makeExactOrGeneralInvoker(true);
12.82 + exactInvoker = invoker;
12.83 + return invoker;
12.84 + }
12.85 +
12.86 + /*non-public*/ MethodHandle generalInvoker() {
12.87 + MethodHandle invoker = generalInvoker;
12.88 + if (invoker != null) return invoker;
12.89 + invoker = makeExactOrGeneralInvoker(false);
12.90 + generalInvoker = invoker;
12.91 + return invoker;
12.92 + }
12.93 +
12.94 + private MethodHandle makeExactOrGeneralInvoker(boolean isExact) {
12.95 + MethodType mtype = targetType;
12.96 + MethodType invokerType = mtype.invokerType();
12.97 + int which = (isExact ? MethodTypeForm.LF_EX_INVOKER : MethodTypeForm.LF_GEN_INVOKER);
12.98 + LambdaForm lform = invokeHandleForm(mtype, false, which);
12.99 + MethodHandle invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
12.100 + String whichName = (isExact ? "invokeExact" : "invoke");
12.101 + invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke(whichName, mtype));
12.102 + assert(checkInvoker(invoker));
12.103 + maybeCompileToBytecode(invoker);
12.104 + return invoker;
12.105 + }
12.106 +
12.107 + /** If the target type seems to be common enough, eagerly compile the invoker to bytecodes. */
12.108 + private void maybeCompileToBytecode(MethodHandle invoker) {
12.109 + final int EAGER_COMPILE_ARITY_LIMIT = 10;
12.110 + if (targetType == targetType.erase() &&
12.111 + targetType.parameterCount() < EAGER_COMPILE_ARITY_LIMIT) {
12.112 + invoker.form.compileToBytecode();
12.113 + }
12.114 + }
12.115 +
12.116 + /*non-public*/ MethodHandle basicInvoker() {
12.117 + MethodHandle invoker = basicInvoker;
12.118 + if (invoker != null) return invoker;
12.119 + MethodType basicType = targetType.basicType();
12.120 + if (basicType != targetType) {
12.121 + // double cache; not used significantly
12.122 + return basicInvoker = basicType.invokers().basicInvoker();
12.123 + }
12.124 + MemberName method = invokeBasicMethod(basicType);
12.125 + invoker = DirectMethodHandle.make(method);
12.126 + assert(checkInvoker(invoker));
12.127 + basicInvoker = invoker;
12.128 + return invoker;
12.129 + }
12.130 +
12.131 + // This next one is called from LambdaForm.NamedFunction.<init>.
12.132 + /*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) {
12.133 + assert(basicType == basicType.basicType());
12.134 + try {
12.135 + //Lookup.findVirtual(MethodHandle.class, name, type);
12.136 + return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType);
12.137 + } catch (ReflectiveOperationException ex) {
12.138 + throw newInternalError("JVM cannot find invoker for "+basicType, ex);
12.139 + }
12.140 + }
12.141 +
12.142 + private boolean checkInvoker(MethodHandle invoker) {
12.143 + assert(targetType.invokerType().equals(invoker.type()))
12.144 + : java.util.Arrays.asList(targetType, targetType.invokerType(), invoker);
12.145 + assert(invoker.internalMemberName() == null ||
12.146 + invoker.internalMemberName().getMethodType().equals(targetType));
12.147 + assert(!invoker.isVarargsCollector());
12.148 + return true;
12.149 + }
12.150 +
12.151 + // FIXME: get rid of
12.152 + /*non-public*/ MethodHandle erasedInvoker() {
12.153 + MethodHandle xinvoker = exactInvoker();
12.154 + MethodHandle invoker = erasedInvoker;
12.155 + if (invoker != null) return invoker;
12.156 + MethodType erasedType = targetType.erase();
12.157 + invoker = xinvoker.asType(erasedType.invokerType());
12.158 + erasedInvoker = invoker;
12.159 + return invoker;
12.160 + }
12.161 +
12.162 + /*non-public*/ MethodHandle spreadInvoker(int leadingArgCount) {
12.163 + MethodHandle vaInvoker = spreadInvokers[leadingArgCount];
12.164 + if (vaInvoker != null) return vaInvoker;
12.165 + int spreadArgCount = targetType.parameterCount() - leadingArgCount;
12.166 + MethodType spreadInvokerType = targetType
12.167 + .replaceParameterTypes(leadingArgCount, targetType.parameterCount(), Object[].class);
12.168 + if (targetType.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY) {
12.169 + // Factor sinvoker.invoke(mh, a) into ginvoker.asSpreader().invoke(mh, a)
12.170 + // where ginvoker.invoke(mh, a*) => mh.invoke(a*).
12.171 + MethodHandle genInvoker = generalInvoker();
12.172 + vaInvoker = genInvoker.asSpreader(Object[].class, spreadArgCount);
12.173 + } else {
12.174 + // Cannot build a general invoker here of type ginvoker.invoke(mh, a*[254]).
12.175 + // Instead, factor sinvoker.invoke(mh, a) into ainvoker.invoke(filter(mh), a)
12.176 + // where filter(mh) == mh.asSpreader(Object[], spreadArgCount)
12.177 + MethodHandle arrayInvoker = MethodHandles.exactInvoker(spreadInvokerType);
12.178 + MethodHandle makeSpreader;
12.179 + try {
12.180 + makeSpreader = IMPL_LOOKUP
12.181 + .findVirtual(MethodHandle.class, "asSpreader",
12.182 + MethodType.methodType(MethodHandle.class, Class.class, int.class));
12.183 + } catch (ReflectiveOperationException ex) {
12.184 + throw newInternalError(ex);
12.185 + }
12.186 + makeSpreader = MethodHandles.insertArguments(makeSpreader, 1, Object[].class, spreadArgCount);
12.187 + vaInvoker = MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader);
12.188 + }
12.189 + assert(vaInvoker.type().equals(spreadInvokerType.invokerType()));
12.190 + maybeCompileToBytecode(vaInvoker);
12.191 + spreadInvokers[leadingArgCount] = vaInvoker;
12.192 + return vaInvoker;
12.193 + }
12.194 +
12.195 + /*non-public*/ MethodHandle varargsInvoker() {
12.196 + MethodHandle vaInvoker = varargsInvoker;
12.197 + if (vaInvoker != null) return vaInvoker;
12.198 + vaInvoker = spreadInvoker(0).asType(MethodType.genericMethodType(0, true).invokerType());
12.199 + varargsInvoker = vaInvoker;
12.200 + return vaInvoker;
12.201 + }
12.202 +
12.203 + private static MethodHandle THROW_UCS = null;
12.204 +
12.205 + /*non-public*/ MethodHandle uninitializedCallSite() {
12.206 + MethodHandle invoker = uninitializedCallSite;
12.207 + if (invoker != null) return invoker;
12.208 + if (targetType.parameterCount() > 0) {
12.209 + MethodType type0 = targetType.dropParameterTypes(0, targetType.parameterCount());
12.210 + Invokers invokers0 = type0.invokers();
12.211 + invoker = MethodHandles.dropArguments(invokers0.uninitializedCallSite(),
12.212 + 0, targetType.parameterList());
12.213 + assert(invoker.type().equals(targetType));
12.214 + uninitializedCallSite = invoker;
12.215 + return invoker;
12.216 + }
12.217 + invoker = THROW_UCS;
12.218 + if (invoker == null) {
12.219 + try {
12.220 + THROW_UCS = invoker = IMPL_LOOKUP
12.221 + .findStatic(CallSite.class, "uninitializedCallSite",
12.222 + MethodType.methodType(Empty.class));
12.223 + } catch (ReflectiveOperationException ex) {
12.224 + throw newInternalError(ex);
12.225 + }
12.226 + }
12.227 + invoker = MethodHandles.explicitCastArguments(invoker, MethodType.methodType(targetType.returnType()));
12.228 + invoker = invoker.dropArguments(targetType, 0, targetType.parameterCount());
12.229 + assert(invoker.type().equals(targetType));
12.230 + uninitializedCallSite = invoker;
12.231 + return invoker;
12.232 + }
12.233 +
12.234 + public String toString() {
12.235 + return "Invokers"+targetType;
12.236 + }
12.237 +
12.238 + static MemberName methodHandleInvokeLinkerMethod(String name,
12.239 + MethodType mtype,
12.240 + Object[] appendixResult) {
12.241 + int which;
12.242 + switch (name) {
12.243 + case "invokeExact": which = MethodTypeForm.LF_EX_LINKER; break;
12.244 + case "invoke": which = MethodTypeForm.LF_GEN_LINKER; break;
12.245 + default: throw new InternalError("not invoker: "+name);
12.246 + }
12.247 + LambdaForm lform;
12.248 + if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MH_LINKER_ARG_APPENDED) {
12.249 + lform = invokeHandleForm(mtype, false, which);
12.250 + appendixResult[0] = mtype;
12.251 + } else {
12.252 + lform = invokeHandleForm(mtype, true, which);
12.253 + }
12.254 + return lform.vmentry;
12.255 + }
12.256 +
12.257 + // argument count to account for trailing "appendix value" (typically the mtype)
12.258 + private static final int MH_LINKER_ARG_APPENDED = 1;
12.259 +
12.260 + /** Returns an adapter for invokeExact or generic invoke, as a MH or constant pool linker.
12.261 + * If !customized, caller is responsible for supplying, during adapter execution,
12.262 + * a copy of the exact mtype. This is because the adapter might be generalized to
12.263 + * a basic type.
12.264 + * @param mtype the caller's method type (either basic or full-custom)
12.265 + * @param customized whether to use a trailing appendix argument (to carry the mtype)
12.266 + * @param which bit-encoded 0x01 whether it is a CP adapter ("linker") or MHs.invoker value ("invoker");
12.267 + * 0x02 whether it is for invokeExact or generic invoke
12.268 + */
12.269 + private static LambdaForm invokeHandleForm(MethodType mtype, boolean customized, int which) {
12.270 + boolean isCached;
12.271 + if (!customized) {
12.272 + mtype = mtype.basicType(); // normalize Z to I, String to Object, etc.
12.273 + isCached = true;
12.274 + } else {
12.275 + isCached = false; // maybe cache if mtype == mtype.basicType()
12.276 + }
12.277 + boolean isLinker, isGeneric;
12.278 + String debugName;
12.279 + switch (which) {
12.280 + case MethodTypeForm.LF_EX_LINKER: isLinker = true; isGeneric = false; debugName = "invokeExact_MT"; break;
12.281 + case MethodTypeForm.LF_EX_INVOKER: isLinker = false; isGeneric = false; debugName = "exactInvoker"; break;
12.282 + case MethodTypeForm.LF_GEN_LINKER: isLinker = true; isGeneric = true; debugName = "invoke_MT"; break;
12.283 + case MethodTypeForm.LF_GEN_INVOKER: isLinker = false; isGeneric = true; debugName = "invoker"; break;
12.284 + default: throw new InternalError();
12.285 + }
12.286 + LambdaForm lform;
12.287 + if (isCached) {
12.288 + lform = mtype.form().cachedLambdaForm(which);
12.289 + if (lform != null) return lform;
12.290 + }
12.291 + // exactInvokerForm (Object,Object)Object
12.292 + // link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial
12.293 + final int THIS_MH = 0;
12.294 + final int CALL_MH = THIS_MH + (isLinker ? 0 : 1);
12.295 + final int ARG_BASE = CALL_MH + 1;
12.296 + final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount();
12.297 + final int INARG_LIMIT = OUTARG_LIMIT + (isLinker && !customized ? 1 : 0);
12.298 + int nameCursor = OUTARG_LIMIT;
12.299 + final int MTYPE_ARG = customized ? -1 : nameCursor++; // might be last in-argument
12.300 + final int CHECK_TYPE = nameCursor++;
12.301 + final int LINKER_CALL = nameCursor++;
12.302 + MethodType invokerFormType = mtype.invokerType();
12.303 + if (isLinker) {
12.304 + if (!customized)
12.305 + invokerFormType = invokerFormType.appendParameterTypes(MemberName.class);
12.306 + } else {
12.307 + invokerFormType = invokerFormType.invokerType();
12.308 + }
12.309 + Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
12.310 + assert(names.length == nameCursor)
12.311 + : Arrays.asList(mtype, customized, which, nameCursor, names.length);
12.312 + if (MTYPE_ARG >= INARG_LIMIT) {
12.313 + assert(names[MTYPE_ARG] == null);
12.314 + NamedFunction getter = BoundMethodHandle.getSpeciesData("L").getterFunction(0);
12.315 + names[MTYPE_ARG] = new Name(getter, names[THIS_MH]);
12.316 + // else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM)
12.317 + }
12.318 +
12.319 + // Make the final call. If isGeneric, then prepend the result of type checking.
12.320 + MethodType outCallType = mtype.basicType();
12.321 + Object[] outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class);
12.322 + Object mtypeArg = (customized ? mtype : names[MTYPE_ARG]);
12.323 + if (!isGeneric) {
12.324 + names[CHECK_TYPE] = new Name(NF_checkExactType, names[CALL_MH], mtypeArg);
12.325 + // mh.invokeExact(a*):R => checkExactType(mh, TYPEOF(a*:R)); mh.invokeBasic(a*)
12.326 + } else {
12.327 + names[CHECK_TYPE] = new Name(NF_checkGenericType, names[CALL_MH], mtypeArg);
12.328 + // mh.invokeGeneric(a*):R => checkGenericType(mh, TYPEOF(a*:R)).invokeBasic(a*)
12.329 + outArgs[0] = names[CHECK_TYPE];
12.330 + }
12.331 + names[LINKER_CALL] = new Name(outCallType, outArgs);
12.332 + lform = new LambdaForm(debugName, INARG_LIMIT, names);
12.333 + if (isLinker)
12.334 + lform.compileToBytecode(); // JVM needs a real methodOop
12.335 + if (isCached)
12.336 + lform = mtype.form().setCachedLambdaForm(which, lform);
12.337 + return lform;
12.338 + }
12.339 +
12.340 + /*non-public*/ static
12.341 + WrongMethodTypeException newWrongMethodTypeException(MethodType actual, MethodType expected) {
12.342 + // FIXME: merge with JVM logic for throwing WMTE
12.343 + return new WrongMethodTypeException("expected "+expected+" but found "+actual);
12.344 + }
12.345 +
12.346 + /** Static definition of MethodHandle.invokeExact checking code. */
12.347 + /*non-public*/ static
12.348 + @ForceInline
12.349 + void checkExactType(Object mhObj, Object expectedObj) {
12.350 + MethodHandle mh = (MethodHandle) mhObj;
12.351 + MethodType expected = (MethodType) expectedObj;
12.352 + MethodType actual = mh.type();
12.353 + if (actual != expected)
12.354 + throw newWrongMethodTypeException(expected, actual);
12.355 + }
12.356 +
12.357 + /** Static definition of MethodHandle.invokeGeneric checking code.
12.358 + * Directly returns the type-adjusted MH to invoke, as follows:
12.359 + * {@code (R)MH.invoke(a*) => MH.asType(TYPEOF(a*:R)).invokeBasic(a*)}
12.360 + */
12.361 + /*non-public*/ static
12.362 + @ForceInline
12.363 + Object checkGenericType(Object mhObj, Object expectedObj) {
12.364 + MethodHandle mh = (MethodHandle) mhObj;
12.365 + MethodType expected = (MethodType) expectedObj;
12.366 + if (mh.type() == expected) return mh;
12.367 + MethodHandle atc = mh.asTypeCache;
12.368 + if (atc != null && atc.type() == expected) return atc;
12.369 + return mh.asType(expected);
12.370 + /* Maybe add more paths here. Possible optimizations:
12.371 + * for (R)MH.invoke(a*),
12.372 + * let MT0 = TYPEOF(a*:R), MT1 = MH.type
12.373 + *
12.374 + * if MT0==MT1 or MT1 can be safely called by MT0
12.375 + * => MH.invokeBasic(a*)
12.376 + * if MT1 can be safely called by MT0[R := Object]
12.377 + * => MH.invokeBasic(a*) & checkcast(R)
12.378 + * if MT1 can be safely called by MT0[* := Object]
12.379 + * => checkcast(A)* & MH.invokeBasic(a*) & checkcast(R)
12.380 + * if a big adapter BA can be pulled out of (MT0,MT1)
12.381 + * => BA.invokeBasic(MT0,MH,a*)
12.382 + * if a local adapter LA can cached on static CS0 = new GICS(MT0)
12.383 + * => CS0.LA.invokeBasic(MH,a*)
12.384 + * else
12.385 + * => MH.asType(MT0).invokeBasic(A*)
12.386 + */
12.387 + }
12.388 +
12.389 + static MemberName linkToCallSiteMethod(MethodType mtype) {
12.390 + LambdaForm lform = callSiteForm(mtype, false);
12.391 + return lform.vmentry;
12.392 + }
12.393 +
12.394 + static MemberName linkToTargetMethod(MethodType mtype) {
12.395 + LambdaForm lform = callSiteForm(mtype, true);
12.396 + return lform.vmentry;
12.397 + }
12.398 +
12.399 + // skipCallSite is true if we are optimizing a ConstantCallSite
12.400 + private static LambdaForm callSiteForm(MethodType mtype, boolean skipCallSite) {
12.401 + mtype = mtype.basicType(); // normalize Z to I, String to Object, etc.
12.402 + final int which = (skipCallSite ? MethodTypeForm.LF_MH_LINKER : MethodTypeForm.LF_CS_LINKER);
12.403 + LambdaForm lform = mtype.form().cachedLambdaForm(which);
12.404 + if (lform != null) return lform;
12.405 + // exactInvokerForm (Object,Object)Object
12.406 + // link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial
12.407 + final int ARG_BASE = 0;
12.408 + final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount();
12.409 + final int INARG_LIMIT = OUTARG_LIMIT + 1;
12.410 + int nameCursor = OUTARG_LIMIT;
12.411 + final int APPENDIX_ARG = nameCursor++; // the last in-argument
12.412 + final int CSITE_ARG = skipCallSite ? -1 : APPENDIX_ARG;
12.413 + final int CALL_MH = skipCallSite ? APPENDIX_ARG : nameCursor++; // result of getTarget
12.414 + final int LINKER_CALL = nameCursor++;
12.415 + MethodType invokerFormType = mtype.appendParameterTypes(skipCallSite ? MethodHandle.class : CallSite.class);
12.416 + Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
12.417 + assert(names.length == nameCursor);
12.418 + assert(names[APPENDIX_ARG] != null);
12.419 + if (!skipCallSite)
12.420 + names[CALL_MH] = new Name(NF_getCallSiteTarget, names[CSITE_ARG]);
12.421 + // (site.)invokedynamic(a*):R => mh = site.getTarget(); mh.invokeBasic(a*)
12.422 + final int PREPEND_MH = 0, PREPEND_COUNT = 1;
12.423 + Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, OUTARG_LIMIT + PREPEND_COUNT, Object[].class);
12.424 + // prepend MH argument:
12.425 + System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT);
12.426 + outArgs[PREPEND_MH] = names[CALL_MH];
12.427 + names[LINKER_CALL] = new Name(mtype, outArgs);
12.428 + lform = new LambdaForm((skipCallSite ? "linkToTargetMethod" : "linkToCallSite"), INARG_LIMIT, names);
12.429 + lform.compileToBytecode(); // JVM needs a real methodOop
12.430 + lform = mtype.form().setCachedLambdaForm(which, lform);
12.431 + return lform;
12.432 + }
12.433 +
12.434 + /** Static definition of MethodHandle.invokeGeneric checking code. */
12.435 + /*non-public*/ static
12.436 + @ForceInline
12.437 + Object getCallSiteTarget(Object site) {
12.438 + return ((CallSite)site).getTarget();
12.439 + }
12.440 +
12.441 + // Local constant functions:
12.442 + private static final NamedFunction NF_checkExactType;
12.443 + private static final NamedFunction NF_checkGenericType;
12.444 + private static final NamedFunction NF_asType;
12.445 + private static final NamedFunction NF_getCallSiteTarget;
12.446 + static {
12.447 + try {
12.448 + NF_checkExactType = new NamedFunction(Invokers.class
12.449 + .getDeclaredMethod("checkExactType", Object.class, Object.class));
12.450 + NF_checkGenericType = new NamedFunction(Invokers.class
12.451 + .getDeclaredMethod("checkGenericType", Object.class, Object.class));
12.452 + NF_asType = new NamedFunction(MethodHandle.class
12.453 + .getDeclaredMethod("asType", MethodType.class));
12.454 + NF_getCallSiteTarget = new NamedFunction(Invokers.class
12.455 + .getDeclaredMethod("getCallSiteTarget", Object.class));
12.456 + NF_checkExactType.resolve();
12.457 + NF_checkGenericType.resolve();
12.458 + NF_getCallSiteTarget.resolve();
12.459 + // bound
12.460 + } catch (ReflectiveOperationException ex) {
12.461 + throw newInternalError(ex);
12.462 + }
12.463 + }
12.464 +
12.465 +}
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
13.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/LambdaConversionException.java Sat Aug 09 11:12:05 2014 +0200
13.3 @@ -0,0 +1,76 @@
13.4 +/*
13.5 + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
13.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
13.7 + *
13.8 + * This code is free software; you can redistribute it and/or modify it
13.9 + * under the terms of the GNU General Public License version 2 only, as
13.10 + * published by the Free Software Foundation. Oracle designates this
13.11 + * particular file as subject to the "Classpath" exception as provided
13.12 + * by Oracle in the LICENSE file that accompanied this code.
13.13 + *
13.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
13.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13.17 + * version 2 for more details (a copy is included in the LICENSE file that
13.18 + * accompanied this code).
13.19 + *
13.20 + * You should have received a copy of the GNU General Public License version
13.21 + * 2 along with this work; if not, write to the Free Software Foundation,
13.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
13.23 + *
13.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
13.25 + * or visit www.oracle.com if you need additional information or have any
13.26 + * questions.
13.27 + */
13.28 +
13.29 +package java.lang.invoke;
13.30 +
13.31 +/**
13.32 + * LambdaConversionException
13.33 + */
13.34 +public class LambdaConversionException extends Exception {
13.35 + private static final long serialVersionUID = 292L + 8L;
13.36 +
13.37 + /**
13.38 + * Constructs a {@code LambdaConversionException}.
13.39 + */
13.40 + public LambdaConversionException() {
13.41 + }
13.42 +
13.43 + /**
13.44 + * Constructs a {@code LambdaConversionException} with a message.
13.45 + * @param message the detail message
13.46 + */
13.47 + public LambdaConversionException(String message) {
13.48 + super(message);
13.49 + }
13.50 +
13.51 + /**
13.52 + * Constructs a {@code LambdaConversionException} with a message and cause.
13.53 + * @param message the detail message
13.54 + * @param cause the cause
13.55 + */
13.56 + public LambdaConversionException(String message, Throwable cause) {
13.57 + super(message, cause);
13.58 + }
13.59 +
13.60 + /**
13.61 + * Constructs a {@code LambdaConversionException} with a cause.
13.62 + * @param cause the cause
13.63 + */
13.64 + public LambdaConversionException(Throwable cause) {
13.65 + super(cause);
13.66 + }
13.67 +
13.68 + /**
13.69 + * Constructs a {@code LambdaConversionException} with a message,
13.70 + * cause, and other settings.
13.71 + * @param message the detail message
13.72 + * @param cause the cause
13.73 + * @param enableSuppression whether or not suppressed exceptions are enabled
13.74 + * @param writableStackTrace whether or not the stack trace is writable
13.75 + */
13.76 + public LambdaConversionException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
13.77 + super(message, cause, enableSuppression, writableStackTrace);
13.78 + }
13.79 +}
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
14.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/LambdaForm.java Sat Aug 09 11:12:05 2014 +0200
14.3 @@ -0,0 +1,1646 @@
14.4 +/*
14.5 + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
14.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
14.7 + *
14.8 + * This code is free software; you can redistribute it and/or modify it
14.9 + * under the terms of the GNU General Public License version 2 only, as
14.10 + * published by the Free Software Foundation. Oracle designates this
14.11 + * particular file as subject to the "Classpath" exception as provided
14.12 + * by Oracle in the LICENSE file that accompanied this code.
14.13 + *
14.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
14.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14.17 + * version 2 for more details (a copy is included in the LICENSE file that
14.18 + * accompanied this code).
14.19 + *
14.20 + * You should have received a copy of the GNU General Public License version
14.21 + * 2 along with this work; if not, write to the Free Software Foundation,
14.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
14.23 + *
14.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
14.25 + * or visit www.oracle.com if you need additional information or have any
14.26 + * questions.
14.27 + */
14.28 +
14.29 +package java.lang.invoke;
14.30 +
14.31 +import java.lang.annotation.*;
14.32 +import java.lang.reflect.Method;
14.33 +import java.util.Map;
14.34 +import java.util.List;
14.35 +import java.util.Arrays;
14.36 +import java.util.ArrayList;
14.37 +import java.util.HashMap;
14.38 +import java.util.concurrent.ConcurrentHashMap;
14.39 +import sun.invoke.util.Wrapper;
14.40 +import static java.lang.invoke.MethodHandleStatics.*;
14.41 +import static java.lang.invoke.MethodHandleNatives.Constants.*;
14.42 +import java.lang.reflect.Field;
14.43 +import java.util.Objects;
14.44 +
14.45 +/**
14.46 + * The symbolic, non-executable form of a method handle's invocation semantics.
14.47 + * It consists of a series of names.
14.48 + * The first N (N=arity) names are parameters,
14.49 + * while any remaining names are temporary values.
14.50 + * Each temporary specifies the application of a function to some arguments.
14.51 + * The functions are method handles, while the arguments are mixes of
14.52 + * constant values and local names.
14.53 + * The result of the lambda is defined as one of the names, often the last one.
14.54 + * <p>
14.55 + * Here is an approximate grammar:
14.56 + * <blockquote><pre>{@code
14.57 + * LambdaForm = "(" ArgName* ")=>{" TempName* Result "}"
14.58 + * ArgName = "a" N ":" T
14.59 + * TempName = "t" N ":" T "=" Function "(" Argument* ");"
14.60 + * Function = ConstantValue
14.61 + * Argument = NameRef | ConstantValue
14.62 + * Result = NameRef | "void"
14.63 + * NameRef = "a" N | "t" N
14.64 + * N = (any whole number)
14.65 + * T = "L" | "I" | "J" | "F" | "D" | "V"
14.66 + * }</pre></blockquote>
14.67 + * Names are numbered consecutively from left to right starting at zero.
14.68 + * (The letters are merely a taste of syntax sugar.)
14.69 + * Thus, the first temporary (if any) is always numbered N (where N=arity).
14.70 + * Every occurrence of a name reference in an argument list must refer to
14.71 + * a name previously defined within the same lambda.
14.72 + * A lambda has a void result if and only if its result index is -1.
14.73 + * If a temporary has the type "V", it cannot be the subject of a NameRef,
14.74 + * even though possesses a number.
14.75 + * Note that all reference types are erased to "L", which stands for {@code Object}.
14.76 + * All subword types (boolean, byte, short, char) are erased to "I" which is {@code int}.
14.77 + * The other types stand for the usual primitive types.
14.78 + * <p>
14.79 + * Function invocation closely follows the static rules of the Java verifier.
14.80 + * Arguments and return values must exactly match when their "Name" types are
14.81 + * considered.
14.82 + * Conversions are allowed only if they do not change the erased type.
14.83 + * <ul>
14.84 + * <li>L = Object: casts are used freely to convert into and out of reference types
14.85 + * <li>I = int: subword types are forcibly narrowed when passed as arguments (see {@code explicitCastArguments})
14.86 + * <li>J = long: no implicit conversions
14.87 + * <li>F = float: no implicit conversions
14.88 + * <li>D = double: no implicit conversions
14.89 + * <li>V = void: a function result may be void if and only if its Name is of type "V"
14.90 + * </ul>
14.91 + * Although implicit conversions are not allowed, explicit ones can easily be
14.92 + * encoded by using temporary expressions which call type-transformed identity functions.
14.93 + * <p>
14.94 + * Examples:
14.95 + * <blockquote><pre>{@code
14.96 + * (a0:J)=>{ a0 }
14.97 + * == identity(long)
14.98 + * (a0:I)=>{ t1:V = System.out#println(a0); void }
14.99 + * == System.out#println(int)
14.100 + * (a0:L)=>{ t1:V = System.out#println(a0); a0 }
14.101 + * == identity, with printing side-effect
14.102 + * (a0:L, a1:L)=>{ t2:L = BoundMethodHandle#argument(a0);
14.103 + * t3:L = BoundMethodHandle#target(a0);
14.104 + * t4:L = MethodHandle#invoke(t3, t2, a1); t4 }
14.105 + * == general invoker for unary insertArgument combination
14.106 + * (a0:L, a1:L)=>{ t2:L = FilterMethodHandle#filter(a0);
14.107 + * t3:L = MethodHandle#invoke(t2, a1);
14.108 + * t4:L = FilterMethodHandle#target(a0);
14.109 + * t5:L = MethodHandle#invoke(t4, t3); t5 }
14.110 + * == general invoker for unary filterArgument combination
14.111 + * (a0:L, a1:L)=>{ ...(same as previous example)...
14.112 + * t5:L = MethodHandle#invoke(t4, t3, a1); t5 }
14.113 + * == general invoker for unary/unary foldArgument combination
14.114 + * (a0:L, a1:I)=>{ t2:I = identity(long).asType((int)->long)(a1); t2 }
14.115 + * == invoker for identity method handle which performs i2l
14.116 + * (a0:L, a1:L)=>{ t2:L = BoundMethodHandle#argument(a0);
14.117 + * t3:L = Class#cast(t2,a1); t3 }
14.118 + * == invoker for identity method handle which performs cast
14.119 + * }</pre></blockquote>
14.120 + * <p>
14.121 + * @author John Rose, JSR 292 EG
14.122 + */
14.123 +class LambdaForm {
14.124 + final int arity;
14.125 + final int result;
14.126 + @Stable final Name[] names;
14.127 + final String debugName;
14.128 + MemberName vmentry; // low-level behavior, or null if not yet prepared
14.129 + private boolean isCompiled;
14.130 +
14.131 + // Caches for common structural transforms:
14.132 + LambdaForm[] bindCache;
14.133 +
14.134 + public static final int VOID_RESULT = -1, LAST_RESULT = -2;
14.135 +
14.136 + LambdaForm(String debugName,
14.137 + int arity, Name[] names, int result) {
14.138 + assert(namesOK(arity, names));
14.139 + this.arity = arity;
14.140 + this.result = fixResult(result, names);
14.141 + this.names = names.clone();
14.142 + this.debugName = debugName;
14.143 + normalize();
14.144 + }
14.145 +
14.146 + LambdaForm(String debugName,
14.147 + int arity, Name[] names) {
14.148 + this(debugName,
14.149 + arity, names, LAST_RESULT);
14.150 + }
14.151 +
14.152 + LambdaForm(String debugName,
14.153 + Name[] formals, Name[] temps, Name result) {
14.154 + this(debugName,
14.155 + formals.length, buildNames(formals, temps, result), LAST_RESULT);
14.156 + }
14.157 +
14.158 + private static Name[] buildNames(Name[] formals, Name[] temps, Name result) {
14.159 + int arity = formals.length;
14.160 + int length = arity + temps.length + (result == null ? 0 : 1);
14.161 + Name[] names = Arrays.copyOf(formals, length);
14.162 + System.arraycopy(temps, 0, names, arity, temps.length);
14.163 + if (result != null)
14.164 + names[length - 1] = result;
14.165 + return names;
14.166 + }
14.167 +
14.168 + private LambdaForm(String sig) {
14.169 + // Make a blank lambda form, which returns a constant zero or null.
14.170 + // It is used as a template for managing the invocation of similar forms that are non-empty.
14.171 + // Called only from getPreparedForm.
14.172 + assert(isValidSignature(sig));
14.173 + this.arity = signatureArity(sig);
14.174 + this.result = (signatureReturn(sig) == 'V' ? -1 : arity);
14.175 + this.names = buildEmptyNames(arity, sig);
14.176 + this.debugName = "LF.zero";
14.177 + assert(nameRefsAreLegal());
14.178 + assert(isEmpty());
14.179 + assert(sig.equals(basicTypeSignature()));
14.180 + }
14.181 +
14.182 + private static Name[] buildEmptyNames(int arity, String basicTypeSignature) {
14.183 + assert(isValidSignature(basicTypeSignature));
14.184 + int resultPos = arity + 1; // skip '_'
14.185 + if (arity < 0 || basicTypeSignature.length() != resultPos+1)
14.186 + throw new IllegalArgumentException("bad arity for "+basicTypeSignature);
14.187 + int numRes = (basicTypeSignature.charAt(resultPos) == 'V' ? 0 : 1);
14.188 + Name[] names = arguments(numRes, basicTypeSignature.substring(0, arity));
14.189 + for (int i = 0; i < numRes; i++) {
14.190 + names[arity + i] = constantZero(arity + i, basicTypeSignature.charAt(resultPos + i));
14.191 + }
14.192 + return names;
14.193 + }
14.194 +
14.195 + private static int fixResult(int result, Name[] names) {
14.196 + if (result >= 0) {
14.197 + if (names[result].type == 'V')
14.198 + return -1;
14.199 + } else if (result == LAST_RESULT) {
14.200 + return names.length - 1;
14.201 + }
14.202 + return result;
14.203 + }
14.204 +
14.205 + private static boolean namesOK(int arity, Name[] names) {
14.206 + for (int i = 0; i < names.length; i++) {
14.207 + Name n = names[i];
14.208 + assert(n != null) : "n is null";
14.209 + if (i < arity)
14.210 + assert( n.isParam()) : n + " is not param at " + i;
14.211 + else
14.212 + assert(!n.isParam()) : n + " is param at " + i;
14.213 + }
14.214 + return true;
14.215 + }
14.216 +
14.217 + /** Renumber and/or replace params so that they are interned and canonically numbered. */
14.218 + private void normalize() {
14.219 + Name[] oldNames = null;
14.220 + int changesStart = 0;
14.221 + for (int i = 0; i < names.length; i++) {
14.222 + Name n = names[i];
14.223 + if (!n.initIndex(i)) {
14.224 + if (oldNames == null) {
14.225 + oldNames = names.clone();
14.226 + changesStart = i;
14.227 + }
14.228 + names[i] = n.cloneWithIndex(i);
14.229 + }
14.230 + }
14.231 + if (oldNames != null) {
14.232 + int startFixing = arity;
14.233 + if (startFixing <= changesStart)
14.234 + startFixing = changesStart+1;
14.235 + for (int i = startFixing; i < names.length; i++) {
14.236 + Name fixed = names[i].replaceNames(oldNames, names, changesStart, i);
14.237 + names[i] = fixed.newIndex(i);
14.238 + }
14.239 + }
14.240 + assert(nameRefsAreLegal());
14.241 + int maxInterned = Math.min(arity, INTERNED_ARGUMENT_LIMIT);
14.242 + boolean needIntern = false;
14.243 + for (int i = 0; i < maxInterned; i++) {
14.244 + Name n = names[i], n2 = internArgument(n);
14.245 + if (n != n2) {
14.246 + names[i] = n2;
14.247 + needIntern = true;
14.248 + }
14.249 + }
14.250 + if (needIntern) {
14.251 + for (int i = arity; i < names.length; i++) {
14.252 + names[i].internArguments();
14.253 + }
14.254 + assert(nameRefsAreLegal());
14.255 + }
14.256 + }
14.257 +
14.258 + /**
14.259 + * Check that all embedded Name references are localizable to this lambda,
14.260 + * and are properly ordered after their corresponding definitions.
14.261 + * <p>
14.262 + * Note that a Name can be local to multiple lambdas, as long as
14.263 + * it possesses the same index in each use site.
14.264 + * This allows Name references to be freely reused to construct
14.265 + * fresh lambdas, without confusion.
14.266 + */
14.267 + private boolean nameRefsAreLegal() {
14.268 + assert(arity >= 0 && arity <= names.length);
14.269 + assert(result >= -1 && result < names.length);
14.270 + // Do all names possess an index consistent with their local definition order?
14.271 + for (int i = 0; i < arity; i++) {
14.272 + Name n = names[i];
14.273 + assert(n.index() == i) : Arrays.asList(n.index(), i);
14.274 + assert(n.isParam());
14.275 + }
14.276 + // Also, do all local name references
14.277 + for (int i = arity; i < names.length; i++) {
14.278 + Name n = names[i];
14.279 + assert(n.index() == i);
14.280 + for (Object arg : n.arguments) {
14.281 + if (arg instanceof Name) {
14.282 + Name n2 = (Name) arg;
14.283 + int i2 = n2.index;
14.284 + assert(0 <= i2 && i2 < names.length) : n.debugString() + ": 0 <= i2 && i2 < names.length: 0 <= " + i2 + " < " + names.length;
14.285 + assert(names[i2] == n2) : Arrays.asList("-1-", i, "-2-", n.debugString(), "-3-", i2, "-4-", n2.debugString(), "-5-", names[i2].debugString(), "-6-", this);
14.286 + assert(i2 < i); // ref must come after def!
14.287 + }
14.288 + }
14.289 + }
14.290 + return true;
14.291 + }
14.292 +
14.293 + /** Invoke this form on the given arguments. */
14.294 + // final Object invoke(Object... args) throws Throwable {
14.295 + // // NYI: fit this into the fast path?
14.296 + // return interpretWithArguments(args);
14.297 + // }
14.298 +
14.299 + /** Report the return type. */
14.300 + char returnType() {
14.301 + if (result < 0) return 'V';
14.302 + Name n = names[result];
14.303 + return n.type;
14.304 + }
14.305 +
14.306 + /** Report the N-th argument type. */
14.307 + char parameterType(int n) {
14.308 + assert(n < arity);
14.309 + return names[n].type;
14.310 + }
14.311 +
14.312 + /** Report the arity. */
14.313 + int arity() {
14.314 + return arity;
14.315 + }
14.316 +
14.317 + /** Return the method type corresponding to my basic type signature. */
14.318 + MethodType methodType() {
14.319 + return signatureType(basicTypeSignature());
14.320 + }
14.321 + /** Return ABC_Z, where the ABC are parameter type characters, and Z is the return type character. */
14.322 + final String basicTypeSignature() {
14.323 + StringBuilder buf = new StringBuilder(arity() + 3);
14.324 + for (int i = 0, a = arity(); i < a; i++)
14.325 + buf.append(parameterType(i));
14.326 + return buf.append('_').append(returnType()).toString();
14.327 + }
14.328 + static int signatureArity(String sig) {
14.329 + assert(isValidSignature(sig));
14.330 + return sig.indexOf('_');
14.331 + }
14.332 + static char signatureReturn(String sig) {
14.333 + return sig.charAt(signatureArity(sig)+1);
14.334 + }
14.335 + static boolean isValidSignature(String sig) {
14.336 + int arity = sig.indexOf('_');
14.337 + if (arity < 0) return false; // must be of the form *_*
14.338 + int siglen = sig.length();
14.339 + if (siglen != arity + 2) return false; // *_X
14.340 + for (int i = 0; i < siglen; i++) {
14.341 + if (i == arity) continue; // skip '_'
14.342 + char c = sig.charAt(i);
14.343 + if (c == 'V')
14.344 + return (i == siglen - 1 && arity == siglen - 2);
14.345 + if (ALL_TYPES.indexOf(c) < 0) return false; // must be [LIJFD]
14.346 + }
14.347 + return true; // [LIJFD]*_[LIJFDV]
14.348 + }
14.349 + static Class<?> typeClass(char t) {
14.350 + switch (t) {
14.351 + case 'I': return int.class;
14.352 + case 'J': return long.class;
14.353 + case 'F': return float.class;
14.354 + case 'D': return double.class;
14.355 + case 'L': return Object.class;
14.356 + case 'V': return void.class;
14.357 + default: assert false;
14.358 + }
14.359 + return null;
14.360 + }
14.361 + static MethodType signatureType(String sig) {
14.362 + Class<?>[] ptypes = new Class<?>[signatureArity(sig)];
14.363 + for (int i = 0; i < ptypes.length; i++)
14.364 + ptypes[i] = typeClass(sig.charAt(i));
14.365 + Class<?> rtype = typeClass(signatureReturn(sig));
14.366 + return MethodType.methodType(rtype, ptypes);
14.367 + }
14.368 +
14.369 + /*
14.370 + * Code generation issues:
14.371 + *
14.372 + * Compiled LFs should be reusable in general.
14.373 + * The biggest issue is how to decide when to pull a name into
14.374 + * the bytecode, versus loading a reified form from the MH data.
14.375 + *
14.376 + * For example, an asType wrapper may require execution of a cast
14.377 + * after a call to a MH. The target type of the cast can be placed
14.378 + * as a constant in the LF itself. This will force the cast type
14.379 + * to be compiled into the bytecodes and native code for the MH.
14.380 + * Or, the target type of the cast can be erased in the LF, and
14.381 + * loaded from the MH data. (Later on, if the MH as a whole is
14.382 + * inlined, the data will flow into the inlined instance of the LF,
14.383 + * as a constant, and the end result will be an optimal cast.)
14.384 + *
14.385 + * This erasure of cast types can be done with any use of
14.386 + * reference types. It can also be done with whole method
14.387 + * handles. Erasing a method handle might leave behind
14.388 + * LF code that executes correctly for any MH of a given
14.389 + * type, and load the required MH from the enclosing MH's data.
14.390 + * Or, the erasure might even erase the expected MT.
14.391 + *
14.392 + * Also, for direct MHs, the MemberName of the target
14.393 + * could be erased, and loaded from the containing direct MH.
14.394 + * As a simple case, a LF for all int-valued non-static
14.395 + * field getters would perform a cast on its input argument
14.396 + * (to non-constant base type derived from the MemberName)
14.397 + * and load an integer value from the input object
14.398 + * (at a non-constant offset also derived from the MemberName).
14.399 + * Such MN-erased LFs would be inlinable back to optimized
14.400 + * code, whenever a constant enclosing DMH is available
14.401 + * to supply a constant MN from its data.
14.402 + *
14.403 + * The main problem here is to keep LFs reasonably generic,
14.404 + * while ensuring that hot spots will inline good instances.
14.405 + * "Reasonably generic" means that we don't end up with
14.406 + * repeated versions of bytecode or machine code that do
14.407 + * not differ in their optimized form. Repeated versions
14.408 + * of machine would have the undesirable overheads of
14.409 + * (a) redundant compilation work and (b) extra I$ pressure.
14.410 + * To control repeated versions, we need to be ready to
14.411 + * erase details from LFs and move them into MH data,
14.412 + * whevener those details are not relevant to significant
14.413 + * optimization. "Significant" means optimization of
14.414 + * code that is actually hot.
14.415 + *
14.416 + * Achieving this may require dynamic splitting of MHs, by replacing
14.417 + * a generic LF with a more specialized one, on the same MH,
14.418 + * if (a) the MH is frequently executed and (b) the MH cannot
14.419 + * be inlined into a containing caller, such as an invokedynamic.
14.420 + *
14.421 + * Compiled LFs that are no longer used should be GC-able.
14.422 + * If they contain non-BCP references, they should be properly
14.423 + * interlinked with the class loader(s) that their embedded types
14.424 + * depend on. This probably means that reusable compiled LFs
14.425 + * will be tabulated (indexed) on relevant class loaders,
14.426 + * or else that the tables that cache them will have weak links.
14.427 + */
14.428 +
14.429 + /**
14.430 + * Make this LF directly executable, as part of a MethodHandle.
14.431 + * Invariant: Every MH which is invoked must prepare its LF
14.432 + * before invocation.
14.433 + * (In principle, the JVM could do this very lazily,
14.434 + * as a sort of pre-invocation linkage step.)
14.435 + */
14.436 + public void prepare() {
14.437 + if (COMPILE_THRESHOLD == 0) {
14.438 + compileToBytecode();
14.439 + }
14.440 + if (this.vmentry != null) {
14.441 + // already prepared (e.g., a primitive DMH invoker form)
14.442 + return;
14.443 + }
14.444 + LambdaForm prep = getPreparedForm(basicTypeSignature());
14.445 + this.vmentry = prep.vmentry;
14.446 + // TO DO: Maybe add invokeGeneric, invokeWithArguments
14.447 + }
14.448 +
14.449 + /** Generate optimizable bytecode for this form. */
14.450 + MemberName compileToBytecode() {
14.451 + MethodType invokerType = methodType();
14.452 + assert(vmentry == null || vmentry.getMethodType().basicType().equals(invokerType));
14.453 + if (vmentry != null && isCompiled) {
14.454 + return vmentry; // already compiled somehow
14.455 + }
14.456 + try {
14.457 + vmentry = InvokerBytecodeGenerator.generateCustomizedCode(this, invokerType);
14.458 + if (TRACE_INTERPRETER)
14.459 + traceInterpreter("compileToBytecode", this);
14.460 + isCompiled = true;
14.461 + return vmentry;
14.462 + } catch (Error | Exception ex) {
14.463 + throw newInternalError("compileToBytecode", ex);
14.464 + }
14.465 + }
14.466 +
14.467 + private static final ConcurrentHashMap<String,LambdaForm> PREPARED_FORMS;
14.468 + static {
14.469 + int capacity = 512; // expect many distinct signatures over time
14.470 + float loadFactor = 0.75f; // normal default
14.471 + int writers = 1;
14.472 + PREPARED_FORMS = new ConcurrentHashMap<>(capacity, loadFactor, writers);
14.473 + }
14.474 +
14.475 + private static Map<String,LambdaForm> computeInitialPreparedForms() {
14.476 + // Find all predefined invokers and associate them with canonical empty lambda forms.
14.477 + HashMap<String,LambdaForm> forms = new HashMap<>();
14.478 + for (MemberName m : MemberName.getFactory().getMethods(LambdaForm.class, false, null, null, null)) {
14.479 + if (!m.isStatic() || !m.isPackage()) continue;
14.480 + MethodType mt = m.getMethodType();
14.481 + if (mt.parameterCount() > 0 &&
14.482 + mt.parameterType(0) == MethodHandle.class &&
14.483 + m.getName().startsWith("interpret_")) {
14.484 + String sig = basicTypeSignature(mt);
14.485 + assert(m.getName().equals("interpret" + sig.substring(sig.indexOf('_'))));
14.486 + LambdaForm form = new LambdaForm(sig);
14.487 + form.vmentry = m;
14.488 + mt.form().setCachedLambdaForm(MethodTypeForm.LF_COUNTER, form);
14.489 + // FIXME: get rid of PREPARED_FORMS; use MethodTypeForm cache only
14.490 + forms.put(sig, form);
14.491 + }
14.492 + }
14.493 + //System.out.println("computeInitialPreparedForms => "+forms);
14.494 + return forms;
14.495 + }
14.496 +
14.497 + // Set this false to disable use of the interpret_L methods defined in this file.
14.498 + private static final boolean USE_PREDEFINED_INTERPRET_METHODS = true;
14.499 +
14.500 + // The following are predefined exact invokers. The system must build
14.501 + // a separate invoker for each distinct signature.
14.502 + static Object interpret_L(MethodHandle mh) throws Throwable {
14.503 + Object[] av = {mh};
14.504 + String sig = null;
14.505 + assert(argumentTypesMatch(sig = "L_L", av));
14.506 + Object res = mh.form.interpretWithArguments(av);
14.507 + assert(returnTypesMatch(sig, av, res));
14.508 + return res;
14.509 + }
14.510 + static Object interpret_L(MethodHandle mh, Object x1) throws Throwable {
14.511 + Object[] av = {mh, x1};
14.512 + String sig = null;
14.513 + assert(argumentTypesMatch(sig = "LL_L", av));
14.514 + Object res = mh.form.interpretWithArguments(av);
14.515 + assert(returnTypesMatch(sig, av, res));
14.516 + return res;
14.517 + }
14.518 + static Object interpret_L(MethodHandle mh, Object x1, Object x2) throws Throwable {
14.519 + Object[] av = {mh, x1, x2};
14.520 + String sig = null;
14.521 + assert(argumentTypesMatch(sig = "LLL_L", av));
14.522 + Object res = mh.form.interpretWithArguments(av);
14.523 + assert(returnTypesMatch(sig, av, res));
14.524 + return res;
14.525 + }
14.526 + private static LambdaForm getPreparedForm(String sig) {
14.527 + MethodType mtype = signatureType(sig);
14.528 + //LambdaForm prep = PREPARED_FORMS.get(sig);
14.529 + LambdaForm prep = mtype.form().cachedLambdaForm(MethodTypeForm.LF_INTERPRET);
14.530 + if (prep != null) return prep;
14.531 + assert(isValidSignature(sig));
14.532 + prep = new LambdaForm(sig);
14.533 + prep.vmentry = InvokerBytecodeGenerator.generateLambdaFormInterpreterEntryPoint(sig);
14.534 + //LambdaForm prep2 = PREPARED_FORMS.putIfAbsent(sig.intern(), prep);
14.535 + return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_INTERPRET, prep);
14.536 + }
14.537 +
14.538 + // The next few routines are called only from assert expressions
14.539 + // They verify that the built-in invokers process the correct raw data types.
14.540 + private static boolean argumentTypesMatch(String sig, Object[] av) {
14.541 + int arity = signatureArity(sig);
14.542 + assert(av.length == arity) : "av.length == arity: av.length=" + av.length + ", arity=" + arity;
14.543 + assert(av[0] instanceof MethodHandle) : "av[0] not instace of MethodHandle: " + av[0];
14.544 + MethodHandle mh = (MethodHandle) av[0];
14.545 + MethodType mt = mh.type();
14.546 + assert(mt.parameterCount() == arity-1);
14.547 + for (int i = 0; i < av.length; i++) {
14.548 + Class<?> pt = (i == 0 ? MethodHandle.class : mt.parameterType(i-1));
14.549 + assert(valueMatches(sig.charAt(i), pt, av[i]));
14.550 + }
14.551 + return true;
14.552 + }
14.553 + private static boolean valueMatches(char tc, Class<?> type, Object x) {
14.554 + // The following line is needed because (...)void method handles can use non-void invokers
14.555 + if (type == void.class) tc = 'V'; // can drop any kind of value
14.556 + assert tc == basicType(type) : tc + " == basicType(" + type + ")=" + basicType(type);
14.557 + switch (tc) {
14.558 + case 'I': assert checkInt(type, x) : "checkInt(" + type + "," + x +")"; break;
14.559 + case 'J': assert x instanceof Long : "instanceof Long: " + x; break;
14.560 + case 'F': assert x instanceof Float : "instanceof Float: " + x; break;
14.561 + case 'D': assert x instanceof Double : "instanceof Double: " + x; break;
14.562 + case 'L': assert checkRef(type, x) : "checkRef(" + type + "," + x + ")"; break;
14.563 + case 'V': break; // allow anything here; will be dropped
14.564 + default: assert(false);
14.565 + }
14.566 + return true;
14.567 + }
14.568 + private static boolean returnTypesMatch(String sig, Object[] av, Object res) {
14.569 + MethodHandle mh = (MethodHandle) av[0];
14.570 + return valueMatches(signatureReturn(sig), mh.type().returnType(), res);
14.571 + }
14.572 + private static boolean checkInt(Class<?> type, Object x) {
14.573 + assert(x instanceof Integer);
14.574 + if (type == int.class) return true;
14.575 + Wrapper w = Wrapper.forBasicType(type);
14.576 + assert(w.isSubwordOrInt());
14.577 + Object x1 = Wrapper.INT.wrap(w.wrap(x));
14.578 + return x.equals(x1);
14.579 + }
14.580 + private static boolean checkRef(Class<?> type, Object x) {
14.581 + assert(!type.isPrimitive());
14.582 + if (x == null) return true;
14.583 + if (type.isInterface()) return true;
14.584 + return type.isInstance(x);
14.585 + }
14.586 +
14.587 + /** If the invocation count hits the threshold we spin bytecodes and call that subsequently. */
14.588 + private static final int COMPILE_THRESHOLD;
14.589 + static {
14.590 + if (MethodHandleStatics.COMPILE_THRESHOLD != null)
14.591 + COMPILE_THRESHOLD = MethodHandleStatics.COMPILE_THRESHOLD;
14.592 + else
14.593 + COMPILE_THRESHOLD = 30; // default value
14.594 + }
14.595 + private int invocationCounter = 0;
14.596 +
14.597 + @Hidden
14.598 + @DontInline
14.599 + /** Interpretively invoke this form on the given arguments. */
14.600 + Object interpretWithArguments(Object... argumentValues) throws Throwable {
14.601 + if (TRACE_INTERPRETER)
14.602 + return interpretWithArgumentsTracing(argumentValues);
14.603 + checkInvocationCounter();
14.604 + assert(arityCheck(argumentValues));
14.605 + Object[] values = Arrays.copyOf(argumentValues, names.length);
14.606 + for (int i = argumentValues.length; i < values.length; i++) {
14.607 + values[i] = interpretName(names[i], values);
14.608 + }
14.609 + return (result < 0) ? null : values[result];
14.610 + }
14.611 +
14.612 + @Hidden
14.613 + @DontInline
14.614 + /** Evaluate a single Name within this form, applying its function to its arguments. */
14.615 + Object interpretName(Name name, Object[] values) throws Throwable {
14.616 + if (TRACE_INTERPRETER)
14.617 + traceInterpreter("| interpretName", name.debugString(), (Object[]) null);
14.618 + Object[] arguments = Arrays.copyOf(name.arguments, name.arguments.length, Object[].class);
14.619 + for (int i = 0; i < arguments.length; i++) {
14.620 + Object a = arguments[i];
14.621 + if (a instanceof Name) {
14.622 + int i2 = ((Name)a).index();
14.623 + assert(names[i2] == a);
14.624 + a = values[i2];
14.625 + arguments[i] = a;
14.626 + }
14.627 + }
14.628 + return name.function.invokeWithArguments(arguments);
14.629 + }
14.630 +
14.631 + private void checkInvocationCounter() {
14.632 + if (COMPILE_THRESHOLD != 0 &&
14.633 + invocationCounter < COMPILE_THRESHOLD) {
14.634 + invocationCounter++; // benign race
14.635 + if (invocationCounter >= COMPILE_THRESHOLD) {
14.636 + // Replace vmentry with a bytecode version of this LF.
14.637 + compileToBytecode();
14.638 + }
14.639 + }
14.640 + }
14.641 + Object interpretWithArgumentsTracing(Object... argumentValues) throws Throwable {
14.642 + traceInterpreter("[ interpretWithArguments", this, argumentValues);
14.643 + if (invocationCounter < COMPILE_THRESHOLD) {
14.644 + int ctr = invocationCounter++; // benign race
14.645 + traceInterpreter("| invocationCounter", ctr);
14.646 + if (invocationCounter >= COMPILE_THRESHOLD) {
14.647 + compileToBytecode();
14.648 + }
14.649 + }
14.650 + Object rval;
14.651 + try {
14.652 + assert(arityCheck(argumentValues));
14.653 + Object[] values = Arrays.copyOf(argumentValues, names.length);
14.654 + for (int i = argumentValues.length; i < values.length; i++) {
14.655 + values[i] = interpretName(names[i], values);
14.656 + }
14.657 + rval = (result < 0) ? null : values[result];
14.658 + } catch (Throwable ex) {
14.659 + traceInterpreter("] throw =>", ex);
14.660 + throw ex;
14.661 + }
14.662 + traceInterpreter("] return =>", rval);
14.663 + return rval;
14.664 + }
14.665 +
14.666 + //** This transform is applied (statically) to every name.function. */
14.667 + /*
14.668 + private static MethodHandle eraseSubwordTypes(MethodHandle mh) {
14.669 + MethodType mt = mh.type();
14.670 + if (mt.hasPrimitives()) {
14.671 + mt = mt.changeReturnType(eraseSubwordType(mt.returnType()));
14.672 + for (int i = 0; i < mt.parameterCount(); i++) {
14.673 + mt = mt.changeParameterType(i, eraseSubwordType(mt.parameterType(i)));
14.674 + }
14.675 + mh = MethodHandles.explicitCastArguments(mh, mt);
14.676 + }
14.677 + return mh;
14.678 + }
14.679 + private static Class<?> eraseSubwordType(Class<?> type) {
14.680 + if (!type.isPrimitive()) return type;
14.681 + if (type == int.class) return type;
14.682 + Wrapper w = Wrapper.forPrimitiveType(type);
14.683 + if (w.isSubwordOrInt()) return int.class;
14.684 + return type;
14.685 + }
14.686 + */
14.687 +
14.688 + static void traceInterpreter(String event, Object obj, Object... args) {
14.689 + if (TRACE_INTERPRETER) {
14.690 + System.out.println("LFI: "+event+" "+(obj != null ? obj : "")+(args != null && args.length != 0 ? Arrays.asList(args) : ""));
14.691 + }
14.692 + }
14.693 + static void traceInterpreter(String event, Object obj) {
14.694 + traceInterpreter(event, obj, (Object[])null);
14.695 + }
14.696 + private boolean arityCheck(Object[] argumentValues) {
14.697 + assert(argumentValues.length == arity) : arity+"!="+Arrays.asList(argumentValues)+".length";
14.698 + // also check that the leading (receiver) argument is somehow bound to this LF:
14.699 + assert(argumentValues[0] instanceof MethodHandle) : "not MH: " + argumentValues[0];
14.700 + assert(((MethodHandle)argumentValues[0]).internalForm() == this);
14.701 + // note: argument #0 could also be an interface wrapper, in the future
14.702 + return true;
14.703 + }
14.704 +
14.705 + private boolean isEmpty() {
14.706 + if (result < 0)
14.707 + return (names.length == arity);
14.708 + else if (result == arity && names.length == arity + 1)
14.709 + return names[arity].isConstantZero();
14.710 + else
14.711 + return false;
14.712 + }
14.713 +
14.714 + public String toString() {
14.715 + StringBuilder buf = new StringBuilder(debugName+"=Lambda(");
14.716 + for (int i = 0; i < names.length; i++) {
14.717 + if (i == arity) buf.append(")=>{");
14.718 + Name n = names[i];
14.719 + if (i >= arity) buf.append("\n ");
14.720 + buf.append(n);
14.721 + if (i < arity) {
14.722 + if (i+1 < arity) buf.append(",");
14.723 + continue;
14.724 + }
14.725 + buf.append("=").append(n.exprString());
14.726 + buf.append(";");
14.727 + }
14.728 + buf.append(result < 0 ? "void" : names[result]).append("}");
14.729 + if (TRACE_INTERPRETER) {
14.730 + // Extra verbosity:
14.731 + buf.append(":").append(basicTypeSignature());
14.732 + buf.append("/").append(vmentry);
14.733 + }
14.734 + return buf.toString();
14.735 + }
14.736 +
14.737 + /**
14.738 + * Apply immediate binding for a Name in this form indicated by its position relative to the form.
14.739 + * The first parameter to a LambdaForm, a0:L, always represents the form's method handle, so 0 is not
14.740 + * accepted as valid.
14.741 + */
14.742 + LambdaForm bindImmediate(int pos, char basicType, Object value) {
14.743 + // must be an argument, and the types must match
14.744 + assert pos > 0 && pos < arity && names[pos].type == basicType && Name.typesMatch(basicType, value);
14.745 +
14.746 + int arity2 = arity - 1;
14.747 + Name[] names2 = new Name[names.length - 1];
14.748 + for (int r = 0, w = 0; r < names.length; ++r, ++w) { // (r)ead from names, (w)rite to names2
14.749 + Name n = names[r];
14.750 + if (n.isParam()) {
14.751 + if (n.index == pos) {
14.752 + // do not copy over the argument that is to be replaced with a literal,
14.753 + // but adjust the write index
14.754 + --w;
14.755 + } else {
14.756 + names2[w] = new Name(w, n.type);
14.757 + }
14.758 + } else {
14.759 + Object[] arguments2 = new Object[n.arguments.length];
14.760 + for (int i = 0; i < n.arguments.length; ++i) {
14.761 + Object arg = n.arguments[i];
14.762 + if (arg instanceof Name) {
14.763 + int ni = ((Name) arg).index;
14.764 + if (ni == pos) {
14.765 + arguments2[i] = value;
14.766 + } else if (ni < pos) {
14.767 + // replacement position not yet passed
14.768 + arguments2[i] = names2[ni];
14.769 + } else {
14.770 + // replacement position passed
14.771 + arguments2[i] = names2[ni - 1];
14.772 + }
14.773 + } else {
14.774 + arguments2[i] = arg;
14.775 + }
14.776 + }
14.777 + names2[w] = new Name(n.function, arguments2);
14.778 + names2[w].initIndex(w);
14.779 + }
14.780 + }
14.781 +
14.782 + int result2 = result == -1 ? -1 : result - 1;
14.783 + return new LambdaForm(debugName, arity2, names2, result2);
14.784 + }
14.785 +
14.786 + LambdaForm bind(int namePos, BoundMethodHandle.SpeciesData oldData) {
14.787 + Name name = names[namePos];
14.788 + BoundMethodHandle.SpeciesData newData = oldData.extendWithType(name.type);
14.789 + return bind(name, newData.getterName(names[0], oldData.fieldCount()), oldData, newData);
14.790 + }
14.791 + LambdaForm bind(Name name, Name binding,
14.792 + BoundMethodHandle.SpeciesData oldData,
14.793 + BoundMethodHandle.SpeciesData newData) {
14.794 + int pos = name.index;
14.795 + assert(name.isParam());
14.796 + assert(!binding.isParam());
14.797 + assert(name.type == binding.type);
14.798 + assert(0 <= pos && pos < arity && names[pos] == name);
14.799 + assert(binding.function.memberDeclaringClassOrNull() == newData.clazz);
14.800 + assert(oldData.getters.length == newData.getters.length-1);
14.801 + if (bindCache != null) {
14.802 + LambdaForm form = bindCache[pos];
14.803 + if (form != null) {
14.804 + assert(form.contains(binding)) : "form << " + form + " >> does not contain binding << " + binding + " >>";
14.805 + return form;
14.806 + }
14.807 + } else {
14.808 + bindCache = new LambdaForm[arity];
14.809 + }
14.810 + assert(nameRefsAreLegal());
14.811 + int arity2 = arity-1;
14.812 + Name[] names2 = names.clone();
14.813 + names2[pos] = binding; // we might move this in a moment
14.814 +
14.815 + // The newly created LF will run with a different BMH.
14.816 + // Switch over any pre-existing BMH field references to the new BMH class.
14.817 + int firstOldRef = -1;
14.818 + for (int i = 0; i < names2.length; i++) {
14.819 + Name n = names[i];
14.820 + if (n.function != null &&
14.821 + n.function.memberDeclaringClassOrNull() == oldData.clazz) {
14.822 + MethodHandle oldGetter = n.function.resolvedHandle;
14.823 + MethodHandle newGetter = null;
14.824 + for (int j = 0; j < oldData.getters.length; j++) {
14.825 + if (oldGetter == oldData.getters[j])
14.826 + newGetter = newData.getters[j];
14.827 + }
14.828 + if (newGetter != null) {
14.829 + if (firstOldRef < 0) firstOldRef = i;
14.830 + Name n2 = new Name(newGetter, n.arguments);
14.831 + names2[i] = n2;
14.832 + }
14.833 + }
14.834 + }
14.835 +
14.836 + // Walk over the new list of names once, in forward order.
14.837 + // Replace references to 'name' with 'binding'.
14.838 + // Replace data structure references to the old BMH species with the new.
14.839 + // This might cause a ripple effect, but it will settle in one pass.
14.840 + assert(firstOldRef < 0 || firstOldRef > pos);
14.841 + for (int i = pos+1; i < names2.length; i++) {
14.842 + if (i <= arity2) continue;
14.843 + names2[i] = names2[i].replaceNames(names, names2, pos, i);
14.844 + }
14.845 +
14.846 + // (a0, a1, name=a2, a3, a4) => (a0, a1, a3, a4, binding)
14.847 + int insPos = pos;
14.848 + for (; insPos+1 < names2.length; insPos++) {
14.849 + Name n = names2[insPos+1];
14.850 + if (n.isSiblingBindingBefore(binding)) {
14.851 + names2[insPos] = n;
14.852 + } else {
14.853 + break;
14.854 + }
14.855 + }
14.856 + names2[insPos] = binding;
14.857 +
14.858 + // Since we moved some stuff, maybe update the result reference:
14.859 + int result2 = result;
14.860 + if (result2 == pos)
14.861 + result2 = insPos;
14.862 + else if (result2 > pos && result2 <= insPos)
14.863 + result2 -= 1;
14.864 +
14.865 + return bindCache[pos] = new LambdaForm(debugName, arity2, names2, result2);
14.866 + }
14.867 +
14.868 + boolean contains(Name name) {
14.869 + int pos = name.index();
14.870 + if (pos >= 0) {
14.871 + return pos < names.length && name.equals(names[pos]);
14.872 + }
14.873 + for (int i = arity; i < names.length; i++) {
14.874 + if (name.equals(names[i]))
14.875 + return true;
14.876 + }
14.877 + return false;
14.878 + }
14.879 +
14.880 + LambdaForm addArguments(int pos, char... types) {
14.881 + assert(pos <= arity);
14.882 + int length = names.length;
14.883 + int inTypes = types.length;
14.884 + Name[] names2 = Arrays.copyOf(names, length + inTypes);
14.885 + int arity2 = arity + inTypes;
14.886 + int result2 = result;
14.887 + if (result2 >= arity)
14.888 + result2 += inTypes;
14.889 + // names array has MH in slot 0; skip it.
14.890 + int argpos = pos + 1;
14.891 + // Note: The LF constructor will rename names2[argpos...].
14.892 + // Make space for new arguments (shift temporaries).
14.893 + System.arraycopy(names, argpos, names2, argpos + inTypes, length - argpos);
14.894 + for (int i = 0; i < inTypes; i++) {
14.895 + names2[argpos + i] = new Name(types[i]);
14.896 + }
14.897 + return new LambdaForm(debugName, arity2, names2, result2);
14.898 + }
14.899 +
14.900 + LambdaForm addArguments(int pos, List<Class<?>> types) {
14.901 + char[] basicTypes = new char[types.size()];
14.902 + for (int i = 0; i < basicTypes.length; i++)
14.903 + basicTypes[i] = basicType(types.get(i));
14.904 + return addArguments(pos, basicTypes);
14.905 + }
14.906 +
14.907 + LambdaForm permuteArguments(int skip, int[] reorder, char[] types) {
14.908 + // Note: When inArg = reorder[outArg], outArg is fed by a copy of inArg.
14.909 + // The types are the types of the new (incoming) arguments.
14.910 + int length = names.length;
14.911 + int inTypes = types.length;
14.912 + int outArgs = reorder.length;
14.913 + assert(skip+outArgs == arity);
14.914 + assert(permutedTypesMatch(reorder, types, names, skip));
14.915 + int pos = 0;
14.916 + // skip trivial first part of reordering:
14.917 + while (pos < outArgs && reorder[pos] == pos) pos += 1;
14.918 + Name[] names2 = new Name[length - outArgs + inTypes];
14.919 + System.arraycopy(names, 0, names2, 0, skip+pos);
14.920 + // copy the body:
14.921 + int bodyLength = length - arity;
14.922 + System.arraycopy(names, skip+outArgs, names2, skip+inTypes, bodyLength);
14.923 + int arity2 = names2.length - bodyLength;
14.924 + int result2 = result;
14.925 + if (result2 >= 0) {
14.926 + if (result2 < skip+outArgs) {
14.927 + // return the corresponding inArg
14.928 + result2 = reorder[result2-skip];
14.929 + } else {
14.930 + result2 = result2 - outArgs + inTypes;
14.931 + }
14.932 + }
14.933 + // rework names in the body:
14.934 + for (int j = pos; j < outArgs; j++) {
14.935 + Name n = names[skip+j];
14.936 + int i = reorder[j];
14.937 + // replace names[skip+j] by names2[skip+i]
14.938 + Name n2 = names2[skip+i];
14.939 + if (n2 == null)
14.940 + names2[skip+i] = n2 = new Name(types[i]);
14.941 + else
14.942 + assert(n2.type == types[i]);
14.943 + for (int k = arity2; k < names2.length; k++) {
14.944 + names2[k] = names2[k].replaceName(n, n2);
14.945 + }
14.946 + }
14.947 + // some names are unused, but must be filled in
14.948 + for (int i = skip+pos; i < arity2; i++) {
14.949 + if (names2[i] == null)
14.950 + names2[i] = argument(i, types[i - skip]);
14.951 + }
14.952 + for (int j = arity; j < names.length; j++) {
14.953 + int i = j - arity + arity2;
14.954 + // replace names2[i] by names[j]
14.955 + Name n = names[j];
14.956 + Name n2 = names2[i];
14.957 + if (n != n2) {
14.958 + for (int k = i+1; k < names2.length; k++) {
14.959 + names2[k] = names2[k].replaceName(n, n2);
14.960 + }
14.961 + }
14.962 + }
14.963 + return new LambdaForm(debugName, arity2, names2, result2);
14.964 + }
14.965 +
14.966 + static boolean permutedTypesMatch(int[] reorder, char[] types, Name[] names, int skip) {
14.967 + int inTypes = types.length;
14.968 + int outArgs = reorder.length;
14.969 + for (int i = 0; i < outArgs; i++) {
14.970 + assert(names[skip+i].isParam());
14.971 + assert(names[skip+i].type == types[reorder[i]]);
14.972 + }
14.973 + return true;
14.974 + }
14.975 +
14.976 + static class NamedFunction {
14.977 + final MemberName member;
14.978 + @Stable MethodHandle resolvedHandle;
14.979 + @Stable MethodHandle invoker;
14.980 +
14.981 + NamedFunction(MethodHandle resolvedHandle) {
14.982 + this(resolvedHandle.internalMemberName(), resolvedHandle);
14.983 + }
14.984 + NamedFunction(MemberName member, MethodHandle resolvedHandle) {
14.985 + this.member = member;
14.986 + //resolvedHandle = eraseSubwordTypes(resolvedHandle);
14.987 + this.resolvedHandle = resolvedHandle;
14.988 + }
14.989 + NamedFunction(MethodType basicInvokerType) {
14.990 + assert(basicInvokerType == basicInvokerType.basicType()) : basicInvokerType;
14.991 + if (basicInvokerType.parameterSlotCount() < MethodType.MAX_MH_INVOKER_ARITY) {
14.992 + this.resolvedHandle = basicInvokerType.invokers().basicInvoker();
14.993 + this.member = resolvedHandle.internalMemberName();
14.994 + } else {
14.995 + // necessary to pass BigArityTest
14.996 + this.member = Invokers.invokeBasicMethod(basicInvokerType);
14.997 + }
14.998 + }
14.999 +
14.1000 + // The next 3 constructors are used to break circular dependencies on MH.invokeStatic, etc.
14.1001 + // Any LambdaForm containing such a member is not interpretable.
14.1002 + // This is OK, since all such LFs are prepared with special primitive vmentry points.
14.1003 + // And even without the resolvedHandle, the name can still be compiled and optimized.
14.1004 + NamedFunction(Method method) {
14.1005 + this(new MemberName(method));
14.1006 + }
14.1007 + NamedFunction(Field field) {
14.1008 + this(new MemberName(field));
14.1009 + }
14.1010 + NamedFunction(MemberName member) {
14.1011 + this.member = member;
14.1012 + this.resolvedHandle = null;
14.1013 + }
14.1014 +
14.1015 + MethodHandle resolvedHandle() {
14.1016 + if (resolvedHandle == null) resolve();
14.1017 + return resolvedHandle;
14.1018 + }
14.1019 +
14.1020 + void resolve() {
14.1021 + resolvedHandle = DirectMethodHandle.make(member);
14.1022 + }
14.1023 +
14.1024 + @Override
14.1025 + public boolean equals(Object other) {
14.1026 + if (this == other) return true;
14.1027 + if (other == null) return false;
14.1028 + if (!(other instanceof NamedFunction)) return false;
14.1029 + NamedFunction that = (NamedFunction) other;
14.1030 + return this.member != null && this.member.equals(that.member);
14.1031 + }
14.1032 +
14.1033 + @Override
14.1034 + public int hashCode() {
14.1035 + if (member != null)
14.1036 + return member.hashCode();
14.1037 + return super.hashCode();
14.1038 + }
14.1039 +
14.1040 + // Put the predefined NamedFunction invokers into the table.
14.1041 + static void initializeInvokers() {
14.1042 + for (MemberName m : MemberName.getFactory().getMethods(NamedFunction.class, false, null, null, null)) {
14.1043 + if (!m.isStatic() || !m.isPackage()) continue;
14.1044 + MethodType type = m.getMethodType();
14.1045 + if (type.equals(INVOKER_METHOD_TYPE) &&
14.1046 + m.getName().startsWith("invoke_")) {
14.1047 + String sig = m.getName().substring("invoke_".length());
14.1048 + int arity = LambdaForm.signatureArity(sig);
14.1049 + MethodType srcType = MethodType.genericMethodType(arity);
14.1050 + if (LambdaForm.signatureReturn(sig) == 'V')
14.1051 + srcType = srcType.changeReturnType(void.class);
14.1052 + MethodTypeForm typeForm = srcType.form();
14.1053 + typeForm.namedFunctionInvoker = DirectMethodHandle.make(m);
14.1054 + }
14.1055 + }
14.1056 + }
14.1057 +
14.1058 + // The following are predefined NamedFunction invokers. The system must build
14.1059 + // a separate invoker for each distinct signature.
14.1060 + /** void return type invokers. */
14.1061 + @Hidden
14.1062 + static Object invoke__V(MethodHandle mh, Object[] a) throws Throwable {
14.1063 + assert(a.length == 0);
14.1064 + mh.invokeBasic();
14.1065 + return null;
14.1066 + }
14.1067 + @Hidden
14.1068 + static Object invoke_L_V(MethodHandle mh, Object[] a) throws Throwable {
14.1069 + assert(a.length == 1);
14.1070 + mh.invokeBasic(a[0]);
14.1071 + return null;
14.1072 + }
14.1073 + @Hidden
14.1074 + static Object invoke_LL_V(MethodHandle mh, Object[] a) throws Throwable {
14.1075 + assert(a.length == 2);
14.1076 + mh.invokeBasic(a[0], a[1]);
14.1077 + return null;
14.1078 + }
14.1079 + @Hidden
14.1080 + static Object invoke_LLL_V(MethodHandle mh, Object[] a) throws Throwable {
14.1081 + assert(a.length == 3);
14.1082 + mh.invokeBasic(a[0], a[1], a[2]);
14.1083 + return null;
14.1084 + }
14.1085 + @Hidden
14.1086 + static Object invoke_LLLL_V(MethodHandle mh, Object[] a) throws Throwable {
14.1087 + assert(a.length == 4);
14.1088 + mh.invokeBasic(a[0], a[1], a[2], a[3]);
14.1089 + return null;
14.1090 + }
14.1091 + @Hidden
14.1092 + static Object invoke_LLLLL_V(MethodHandle mh, Object[] a) throws Throwable {
14.1093 + assert(a.length == 5);
14.1094 + mh.invokeBasic(a[0], a[1], a[2], a[3], a[4]);
14.1095 + return null;
14.1096 + }
14.1097 + /** Object return type invokers. */
14.1098 + @Hidden
14.1099 + static Object invoke__L(MethodHandle mh, Object[] a) throws Throwable {
14.1100 + assert(a.length == 0);
14.1101 + return mh.invokeBasic();
14.1102 + }
14.1103 + @Hidden
14.1104 + static Object invoke_L_L(MethodHandle mh, Object[] a) throws Throwable {
14.1105 + assert(a.length == 1);
14.1106 + return mh.invokeBasic(a[0]);
14.1107 + }
14.1108 + @Hidden
14.1109 + static Object invoke_LL_L(MethodHandle mh, Object[] a) throws Throwable {
14.1110 + assert(a.length == 2);
14.1111 + return mh.invokeBasic(a[0], a[1]);
14.1112 + }
14.1113 + @Hidden
14.1114 + static Object invoke_LLL_L(MethodHandle mh, Object[] a) throws Throwable {
14.1115 + assert(a.length == 3);
14.1116 + return mh.invokeBasic(a[0], a[1], a[2]);
14.1117 + }
14.1118 + @Hidden
14.1119 + static Object invoke_LLLL_L(MethodHandle mh, Object[] a) throws Throwable {
14.1120 + assert(a.length == 4);
14.1121 + return mh.invokeBasic(a[0], a[1], a[2], a[3]);
14.1122 + }
14.1123 + @Hidden
14.1124 + static Object invoke_LLLLL_L(MethodHandle mh, Object[] a) throws Throwable {
14.1125 + assert(a.length == 5);
14.1126 + return mh.invokeBasic(a[0], a[1], a[2], a[3], a[4]);
14.1127 + }
14.1128 +
14.1129 + static final MethodType INVOKER_METHOD_TYPE =
14.1130 + MethodType.methodType(Object.class, MethodHandle.class, Object[].class);
14.1131 +
14.1132 + private static MethodHandle computeInvoker(MethodTypeForm typeForm) {
14.1133 + MethodHandle mh = typeForm.namedFunctionInvoker;
14.1134 + if (mh != null) return mh;
14.1135 + MemberName invoker = InvokerBytecodeGenerator.generateNamedFunctionInvoker(typeForm); // this could take a while
14.1136 + mh = DirectMethodHandle.make(invoker);
14.1137 + MethodHandle mh2 = typeForm.namedFunctionInvoker;
14.1138 + if (mh2 != null) return mh2; // benign race
14.1139 + if (!mh.type().equals(INVOKER_METHOD_TYPE))
14.1140 + throw new InternalError(mh.debugString());
14.1141 + return typeForm.namedFunctionInvoker = mh;
14.1142 + }
14.1143 +
14.1144 + @Hidden
14.1145 + Object invokeWithArguments(Object... arguments) throws Throwable {
14.1146 + // If we have a cached invoker, call it right away.
14.1147 + // NOTE: The invoker always returns a reference value.
14.1148 + if (TRACE_INTERPRETER) return invokeWithArgumentsTracing(arguments);
14.1149 + assert(checkArgumentTypes(arguments, methodType()));
14.1150 + return invoker().invokeBasic(resolvedHandle(), arguments);
14.1151 + }
14.1152 +
14.1153 + @Hidden
14.1154 + Object invokeWithArgumentsTracing(Object[] arguments) throws Throwable {
14.1155 + Object rval;
14.1156 + try {
14.1157 + traceInterpreter("[ call", this, arguments);
14.1158 + if (invoker == null) {
14.1159 + traceInterpreter("| getInvoker", this);
14.1160 + invoker();
14.1161 + }
14.1162 + if (resolvedHandle == null) {
14.1163 + traceInterpreter("| resolve", this);
14.1164 + resolvedHandle();
14.1165 + }
14.1166 + assert(checkArgumentTypes(arguments, methodType()));
14.1167 + rval = invoker().invokeBasic(resolvedHandle(), arguments);
14.1168 + } catch (Throwable ex) {
14.1169 + traceInterpreter("] throw =>", ex);
14.1170 + throw ex;
14.1171 + }
14.1172 + traceInterpreter("] return =>", rval);
14.1173 + return rval;
14.1174 + }
14.1175 +
14.1176 + private MethodHandle invoker() {
14.1177 + if (invoker != null) return invoker;
14.1178 + // Get an invoker and cache it.
14.1179 + return invoker = computeInvoker(methodType().form());
14.1180 + }
14.1181 +
14.1182 + private static boolean checkArgumentTypes(Object[] arguments, MethodType methodType) {
14.1183 + if (true) return true; // FIXME
14.1184 + MethodType dstType = methodType.form().erasedType();
14.1185 + MethodType srcType = dstType.basicType().wrap();
14.1186 + Class<?>[] ptypes = new Class<?>[arguments.length];
14.1187 + for (int i = 0; i < arguments.length; i++) {
14.1188 + Object arg = arguments[i];
14.1189 + Class<?> ptype = arg == null ? Object.class : arg.getClass();
14.1190 + // If the dest. type is a primitive we keep the
14.1191 + // argument type.
14.1192 + ptypes[i] = dstType.parameterType(i).isPrimitive() ? ptype : Object.class;
14.1193 + }
14.1194 + MethodType argType = MethodType.methodType(srcType.returnType(), ptypes).wrap();
14.1195 + assert(argType.isConvertibleTo(srcType)) : "wrong argument types: cannot convert " + argType + " to " + srcType;
14.1196 + return true;
14.1197 + }
14.1198 +
14.1199 + String basicTypeSignature() {
14.1200 + //return LambdaForm.basicTypeSignature(resolvedHandle.type());
14.1201 + return LambdaForm.basicTypeSignature(methodType());
14.1202 + }
14.1203 +
14.1204 + MethodType methodType() {
14.1205 + if (resolvedHandle != null)
14.1206 + return resolvedHandle.type();
14.1207 + else
14.1208 + // only for certain internal LFs during bootstrapping
14.1209 + return member.getInvocationType();
14.1210 + }
14.1211 +
14.1212 + MemberName member() {
14.1213 + assert(assertMemberIsConsistent());
14.1214 + return member;
14.1215 + }
14.1216 +
14.1217 + // Called only from assert.
14.1218 + private boolean assertMemberIsConsistent() {
14.1219 + if (resolvedHandle instanceof DirectMethodHandle) {
14.1220 + MemberName m = resolvedHandle.internalMemberName();
14.1221 + assert(m.equals(member));
14.1222 + }
14.1223 + return true;
14.1224 + }
14.1225 +
14.1226 + Class<?> memberDeclaringClassOrNull() {
14.1227 + return (member == null) ? null : member.getDeclaringClass();
14.1228 + }
14.1229 +
14.1230 + char returnType() {
14.1231 + return basicType(methodType().returnType());
14.1232 + }
14.1233 +
14.1234 + char parameterType(int n) {
14.1235 + return basicType(methodType().parameterType(n));
14.1236 + }
14.1237 +
14.1238 + int arity() {
14.1239 + //int siglen = member.getMethodType().parameterCount();
14.1240 + //if (!member.isStatic()) siglen += 1;
14.1241 + //return siglen;
14.1242 + return methodType().parameterCount();
14.1243 + }
14.1244 +
14.1245 + public String toString() {
14.1246 + if (member == null) return String.valueOf(resolvedHandle);
14.1247 + return member.getDeclaringClass().getSimpleName()+"."+member.getName();
14.1248 + }
14.1249 + }
14.1250 +
14.1251 + void resolve() {
14.1252 + for (Name n : names) n.resolve();
14.1253 + }
14.1254 +
14.1255 + public static char basicType(Class<?> type) {
14.1256 + char c = Wrapper.basicTypeChar(type);
14.1257 + if ("ZBSC".indexOf(c) >= 0) c = 'I';
14.1258 + assert("LIJFDV".indexOf(c) >= 0);
14.1259 + return c;
14.1260 + }
14.1261 + public static char[] basicTypes(List<Class<?>> types) {
14.1262 + char[] btypes = new char[types.size()];
14.1263 + for (int i = 0; i < btypes.length; i++) {
14.1264 + btypes[i] = basicType(types.get(i));
14.1265 + }
14.1266 + return btypes;
14.1267 + }
14.1268 + public static String basicTypeSignature(MethodType type) {
14.1269 + char[] sig = new char[type.parameterCount() + 2];
14.1270 + int sigp = 0;
14.1271 + for (Class<?> pt : type.parameterList()) {
14.1272 + sig[sigp++] = basicType(pt);
14.1273 + }
14.1274 + sig[sigp++] = '_';
14.1275 + sig[sigp++] = basicType(type.returnType());
14.1276 + assert(sigp == sig.length);
14.1277 + return String.valueOf(sig);
14.1278 + }
14.1279 +
14.1280 + static final class Name {
14.1281 + final char type;
14.1282 + private short index;
14.1283 + final NamedFunction function;
14.1284 + @Stable final Object[] arguments;
14.1285 +
14.1286 + private Name(int index, char type, NamedFunction function, Object[] arguments) {
14.1287 + this.index = (short)index;
14.1288 + this.type = type;
14.1289 + this.function = function;
14.1290 + this.arguments = arguments;
14.1291 + assert(this.index == index);
14.1292 + }
14.1293 + Name(MethodHandle function, Object... arguments) {
14.1294 + this(new NamedFunction(function), arguments);
14.1295 + }
14.1296 + Name(MethodType functionType, Object... arguments) {
14.1297 + this(new NamedFunction(functionType), arguments);
14.1298 + assert(arguments[0] instanceof Name && ((Name)arguments[0]).type == 'L');
14.1299 + }
14.1300 + Name(MemberName function, Object... arguments) {
14.1301 + this(new NamedFunction(function), arguments);
14.1302 + }
14.1303 + Name(NamedFunction function, Object... arguments) {
14.1304 + this(-1, function.returnType(), function, arguments = arguments.clone());
14.1305 + assert(arguments.length == function.arity()) : "arity mismatch: arguments.length=" + arguments.length + " == function.arity()=" + function.arity() + " in " + debugString();
14.1306 + for (int i = 0; i < arguments.length; i++)
14.1307 + assert(typesMatch(function.parameterType(i), arguments[i])) : "types don't match: function.parameterType(" + i + ")=" + function.parameterType(i) + ", arguments[" + i + "]=" + arguments[i] + " in " + debugString();
14.1308 + }
14.1309 + Name(int index, char type) {
14.1310 + this(index, type, null, null);
14.1311 + }
14.1312 + Name(char type) {
14.1313 + this(-1, type);
14.1314 + }
14.1315 +
14.1316 + char type() { return type; }
14.1317 + int index() { return index; }
14.1318 + boolean initIndex(int i) {
14.1319 + if (index != i) {
14.1320 + if (index != -1) return false;
14.1321 + index = (short)i;
14.1322 + }
14.1323 + return true;
14.1324 + }
14.1325 +
14.1326 +
14.1327 + void resolve() {
14.1328 + if (function != null)
14.1329 + function.resolve();
14.1330 + }
14.1331 +
14.1332 + Name newIndex(int i) {
14.1333 + if (initIndex(i)) return this;
14.1334 + return cloneWithIndex(i);
14.1335 + }
14.1336 + Name cloneWithIndex(int i) {
14.1337 + Object[] newArguments = (arguments == null) ? null : arguments.clone();
14.1338 + return new Name(i, type, function, newArguments);
14.1339 + }
14.1340 + Name replaceName(Name oldName, Name newName) { // FIXME: use replaceNames uniformly
14.1341 + if (oldName == newName) return this;
14.1342 + @SuppressWarnings("LocalVariableHidesMemberVariable")
14.1343 + Object[] arguments = this.arguments;
14.1344 + if (arguments == null) return this;
14.1345 + boolean replaced = false;
14.1346 + for (int j = 0; j < arguments.length; j++) {
14.1347 + if (arguments[j] == oldName) {
14.1348 + if (!replaced) {
14.1349 + replaced = true;
14.1350 + arguments = arguments.clone();
14.1351 + }
14.1352 + arguments[j] = newName;
14.1353 + }
14.1354 + }
14.1355 + if (!replaced) return this;
14.1356 + return new Name(function, arguments);
14.1357 + }
14.1358 + Name replaceNames(Name[] oldNames, Name[] newNames, int start, int end) {
14.1359 + @SuppressWarnings("LocalVariableHidesMemberVariable")
14.1360 + Object[] arguments = this.arguments;
14.1361 + boolean replaced = false;
14.1362 + eachArg:
14.1363 + for (int j = 0; j < arguments.length; j++) {
14.1364 + if (arguments[j] instanceof Name) {
14.1365 + Name n = (Name) arguments[j];
14.1366 + int check = n.index;
14.1367 + // harmless check to see if the thing is already in newNames:
14.1368 + if (check >= 0 && check < newNames.length && n == newNames[check])
14.1369 + continue eachArg;
14.1370 + // n might not have the correct index: n != oldNames[n.index].
14.1371 + for (int i = start; i < end; i++) {
14.1372 + if (n == oldNames[i]) {
14.1373 + if (n == newNames[i])
14.1374 + continue eachArg;
14.1375 + if (!replaced) {
14.1376 + replaced = true;
14.1377 + arguments = arguments.clone();
14.1378 + }
14.1379 + arguments[j] = newNames[i];
14.1380 + continue eachArg;
14.1381 + }
14.1382 + }
14.1383 + }
14.1384 + }
14.1385 + if (!replaced) return this;
14.1386 + return new Name(function, arguments);
14.1387 + }
14.1388 + void internArguments() {
14.1389 + @SuppressWarnings("LocalVariableHidesMemberVariable")
14.1390 + Object[] arguments = this.arguments;
14.1391 + for (int j = 0; j < arguments.length; j++) {
14.1392 + if (arguments[j] instanceof Name) {
14.1393 + Name n = (Name) arguments[j];
14.1394 + if (n.isParam() && n.index < INTERNED_ARGUMENT_LIMIT)
14.1395 + arguments[j] = internArgument(n);
14.1396 + }
14.1397 + }
14.1398 + }
14.1399 + boolean isParam() {
14.1400 + return function == null;
14.1401 + }
14.1402 + boolean isConstantZero() {
14.1403 + return !isParam() && arguments.length == 0 && function.equals(constantZero(0, type).function);
14.1404 + }
14.1405 +
14.1406 + public String toString() {
14.1407 + return (isParam()?"a":"t")+(index >= 0 ? index : System.identityHashCode(this))+":"+type;
14.1408 + }
14.1409 + public String debugString() {
14.1410 + String s = toString();
14.1411 + return (function == null) ? s : s + "=" + exprString();
14.1412 + }
14.1413 + public String exprString() {
14.1414 + if (function == null) return "null";
14.1415 + StringBuilder buf = new StringBuilder(function.toString());
14.1416 + buf.append("(");
14.1417 + String cma = "";
14.1418 + for (Object a : arguments) {
14.1419 + buf.append(cma); cma = ",";
14.1420 + if (a instanceof Name || a instanceof Integer)
14.1421 + buf.append(a);
14.1422 + else
14.1423 + buf.append("(").append(a).append(")");
14.1424 + }
14.1425 + buf.append(")");
14.1426 + return buf.toString();
14.1427 + }
14.1428 +
14.1429 + private static boolean typesMatch(char parameterType, Object object) {
14.1430 + if (object instanceof Name) {
14.1431 + return ((Name)object).type == parameterType;
14.1432 + }
14.1433 + switch (parameterType) {
14.1434 + case 'I': return object instanceof Integer;
14.1435 + case 'J': return object instanceof Long;
14.1436 + case 'F': return object instanceof Float;
14.1437 + case 'D': return object instanceof Double;
14.1438 + }
14.1439 + assert(parameterType == 'L');
14.1440 + return true;
14.1441 + }
14.1442 +
14.1443 + /**
14.1444 + * Does this Name precede the given binding node in some canonical order?
14.1445 + * This predicate is used to order data bindings (via insertion sort)
14.1446 + * with some stability.
14.1447 + */
14.1448 + boolean isSiblingBindingBefore(Name binding) {
14.1449 + assert(!binding.isParam());
14.1450 + if (isParam()) return true;
14.1451 + if (function.equals(binding.function) &&
14.1452 + arguments.length == binding.arguments.length) {
14.1453 + boolean sawInt = false;
14.1454 + for (int i = 0; i < arguments.length; i++) {
14.1455 + Object a1 = arguments[i];
14.1456 + Object a2 = binding.arguments[i];
14.1457 + if (!a1.equals(a2)) {
14.1458 + if (a1 instanceof Integer && a2 instanceof Integer) {
14.1459 + if (sawInt) continue;
14.1460 + sawInt = true;
14.1461 + if ((int)a1 < (int)a2) continue; // still might be true
14.1462 + }
14.1463 + return false;
14.1464 + }
14.1465 + }
14.1466 + return sawInt;
14.1467 + }
14.1468 + return false;
14.1469 + }
14.1470 +
14.1471 + public boolean equals(Name that) {
14.1472 + if (this == that) return true;
14.1473 + if (isParam())
14.1474 + // each parameter is a unique atom
14.1475 + return false; // this != that
14.1476 + return
14.1477 + //this.index == that.index &&
14.1478 + this.type == that.type &&
14.1479 + this.function.equals(that.function) &&
14.1480 + Arrays.equals(this.arguments, that.arguments);
14.1481 + }
14.1482 + @Override
14.1483 + public boolean equals(Object x) {
14.1484 + return x instanceof Name && equals((Name)x);
14.1485 + }
14.1486 + @Override
14.1487 + public int hashCode() {
14.1488 + if (isParam())
14.1489 + return index | (type << 8);
14.1490 + return function.hashCode() ^ Arrays.hashCode(arguments);
14.1491 + }
14.1492 + }
14.1493 +
14.1494 + static Name argument(int which, char type) {
14.1495 + int tn = ALL_TYPES.indexOf(type);
14.1496 + if (tn < 0 || which >= INTERNED_ARGUMENT_LIMIT)
14.1497 + return new Name(which, type);
14.1498 + return INTERNED_ARGUMENTS[tn][which];
14.1499 + }
14.1500 + static Name internArgument(Name n) {
14.1501 + assert(n.isParam()) : "not param: " + n;
14.1502 + assert(n.index < INTERNED_ARGUMENT_LIMIT);
14.1503 + return argument(n.index, n.type);
14.1504 + }
14.1505 + static Name[] arguments(int extra, String types) {
14.1506 + int length = types.length();
14.1507 + Name[] names = new Name[length + extra];
14.1508 + for (int i = 0; i < length; i++)
14.1509 + names[i] = argument(i, types.charAt(i));
14.1510 + return names;
14.1511 + }
14.1512 + static Name[] arguments(int extra, char... types) {
14.1513 + int length = types.length;
14.1514 + Name[] names = new Name[length + extra];
14.1515 + for (int i = 0; i < length; i++)
14.1516 + names[i] = argument(i, types[i]);
14.1517 + return names;
14.1518 + }
14.1519 + static Name[] arguments(int extra, List<Class<?>> types) {
14.1520 + int length = types.size();
14.1521 + Name[] names = new Name[length + extra];
14.1522 + for (int i = 0; i < length; i++)
14.1523 + names[i] = argument(i, basicType(types.get(i)));
14.1524 + return names;
14.1525 + }
14.1526 + static Name[] arguments(int extra, Class<?>... types) {
14.1527 + int length = types.length;
14.1528 + Name[] names = new Name[length + extra];
14.1529 + for (int i = 0; i < length; i++)
14.1530 + names[i] = argument(i, basicType(types[i]));
14.1531 + return names;
14.1532 + }
14.1533 + static Name[] arguments(int extra, MethodType types) {
14.1534 + int length = types.parameterCount();
14.1535 + Name[] names = new Name[length + extra];
14.1536 + for (int i = 0; i < length; i++)
14.1537 + names[i] = argument(i, basicType(types.parameterType(i)));
14.1538 + return names;
14.1539 + }
14.1540 + static final String ALL_TYPES = "LIJFD"; // omit V, not an argument type
14.1541 + static final int INTERNED_ARGUMENT_LIMIT = 10;
14.1542 + private static final Name[][] INTERNED_ARGUMENTS
14.1543 + = new Name[ALL_TYPES.length()][INTERNED_ARGUMENT_LIMIT];
14.1544 + static {
14.1545 + for (int tn = 0; tn < ALL_TYPES.length(); tn++) {
14.1546 + for (int i = 0; i < INTERNED_ARGUMENTS[tn].length; i++) {
14.1547 + char type = ALL_TYPES.charAt(tn);
14.1548 + INTERNED_ARGUMENTS[tn][i] = new Name(i, type);
14.1549 + }
14.1550 + }
14.1551 + }
14.1552 +
14.1553 + private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
14.1554 +
14.1555 + static Name constantZero(int which, char type) {
14.1556 + return CONSTANT_ZERO[ALL_TYPES.indexOf(type)].newIndex(which);
14.1557 + }
14.1558 + private static final Name[] CONSTANT_ZERO
14.1559 + = new Name[ALL_TYPES.length()];
14.1560 + static {
14.1561 + for (int tn = 0; tn < ALL_TYPES.length(); tn++) {
14.1562 + char bt = ALL_TYPES.charAt(tn);
14.1563 + Wrapper wrap = Wrapper.forBasicType(bt);
14.1564 + MemberName zmem = new MemberName(LambdaForm.class, "zero"+bt, MethodType.methodType(wrap.primitiveType()), REF_invokeStatic);
14.1565 + try {
14.1566 + zmem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, zmem, null, NoSuchMethodException.class);
14.1567 + } catch (IllegalAccessException|NoSuchMethodException ex) {
14.1568 + throw newInternalError(ex);
14.1569 + }
14.1570 + NamedFunction zcon = new NamedFunction(zmem);
14.1571 + Name n = new Name(zcon).newIndex(0);
14.1572 + assert(n.type == ALL_TYPES.charAt(tn));
14.1573 + CONSTANT_ZERO[tn] = n;
14.1574 + assert(n.isConstantZero());
14.1575 + }
14.1576 + }
14.1577 +
14.1578 + // Avoid appealing to ValueConversions at bootstrap time:
14.1579 + private static int zeroI() { return 0; }
14.1580 + private static long zeroJ() { return 0; }
14.1581 + private static float zeroF() { return 0; }
14.1582 + private static double zeroD() { return 0; }
14.1583 + private static Object zeroL() { return null; }
14.1584 +
14.1585 + // Put this last, so that previous static inits can run before.
14.1586 + static {
14.1587 + if (USE_PREDEFINED_INTERPRET_METHODS)
14.1588 + PREPARED_FORMS.putAll(computeInitialPreparedForms());
14.1589 + }
14.1590 +
14.1591 + /**
14.1592 + * Internal marker for byte-compiled LambdaForms.
14.1593 + */
14.1594 + /*non-public*/
14.1595 + @Target(ElementType.METHOD)
14.1596 + @Retention(RetentionPolicy.RUNTIME)
14.1597 + @interface Compiled {
14.1598 + }
14.1599 +
14.1600 + /**
14.1601 + * Internal marker for LambdaForm interpreter frames.
14.1602 + */
14.1603 + /*non-public*/
14.1604 + @Target(ElementType.METHOD)
14.1605 + @Retention(RetentionPolicy.RUNTIME)
14.1606 + @interface Hidden {
14.1607 + }
14.1608 +
14.1609 +
14.1610 +/*
14.1611 + // Smoke-test for the invokers used in this file.
14.1612 + static void testMethodHandleLinkers() throws Throwable {
14.1613 + MemberName.Factory lookup = MemberName.getFactory();
14.1614 + MemberName asList_MN = new MemberName(Arrays.class, "asList",
14.1615 + MethodType.methodType(List.class, Object[].class),
14.1616 + REF_invokeStatic);
14.1617 + //MethodHandleNatives.resolve(asList_MN, null);
14.1618 + asList_MN = lookup.resolveOrFail(asList_MN, REF_invokeStatic, null, NoSuchMethodException.class);
14.1619 + System.out.println("about to call "+asList_MN);
14.1620 + Object[] abc = { "a", "bc" };
14.1621 + List<?> lst = (List<?>) MethodHandle.linkToStatic(abc, asList_MN);
14.1622 + System.out.println("lst="+lst);
14.1623 + MemberName toString_MN = new MemberName(Object.class.getMethod("toString"));
14.1624 + String s1 = (String) MethodHandle.linkToVirtual(lst, toString_MN);
14.1625 + toString_MN = new MemberName(Object.class.getMethod("toString"), true);
14.1626 + String s2 = (String) MethodHandle.linkToSpecial(lst, toString_MN);
14.1627 + System.out.println("[s1,s2,lst]="+Arrays.asList(s1, s2, lst.toString()));
14.1628 + MemberName toArray_MN = new MemberName(List.class.getMethod("toArray"));
14.1629 + Object[] arr = (Object[]) MethodHandle.linkToInterface(lst, toArray_MN);
14.1630 + System.out.println("toArray="+Arrays.toString(arr));
14.1631 + }
14.1632 + static { try { testMethodHandleLinkers(); } catch (Throwable ex) { throw new RuntimeException(ex); } }
14.1633 + // Requires these definitions in MethodHandle:
14.1634 + static final native Object linkToStatic(Object x1, MemberName mn) throws Throwable;
14.1635 + static final native Object linkToVirtual(Object x1, MemberName mn) throws Throwable;
14.1636 + static final native Object linkToSpecial(Object x1, MemberName mn) throws Throwable;
14.1637 + static final native Object linkToInterface(Object x1, MemberName mn) throws Throwable;
14.1638 + */
14.1639 +
14.1640 + static { NamedFunction.initializeInvokers(); }
14.1641 +
14.1642 + // The following hack is necessary in order to suppress TRACE_INTERPRETER
14.1643 + // during execution of the static initializes of this class.
14.1644 + // Turning on TRACE_INTERPRETER too early will cause
14.1645 + // stack overflows and other misbehavior during attempts to trace events
14.1646 + // that occur during LambdaForm.<clinit>.
14.1647 + // Therefore, do not move this line higher in this file, and do not remove.
14.1648 + private static final boolean TRACE_INTERPRETER = MethodHandleStatics.TRACE_INTERPRETER;
14.1649 +}
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
15.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/LambdaMetafactory.java Sat Aug 09 11:12:05 2014 +0200
15.3 @@ -0,0 +1,475 @@
15.4 +/*
15.5 + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
15.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
15.7 + *
15.8 + * This code is free software; you can redistribute it and/or modify it
15.9 + * under the terms of the GNU General Public License version 2 only, as
15.10 + * published by the Free Software Foundation. Oracle designates this
15.11 + * particular file as subject to the "Classpath" exception as provided
15.12 + * by Oracle in the LICENSE file that accompanied this code.
15.13 + *
15.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
15.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15.17 + * version 2 for more details (a copy is included in the LICENSE file that
15.18 + * accompanied this code).
15.19 + *
15.20 + * You should have received a copy of the GNU General Public License version
15.21 + * 2 along with this work; if not, write to the Free Software Foundation,
15.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
15.23 + *
15.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
15.25 + * or visit www.oracle.com if you need additional information or have any
15.26 + * questions.
15.27 + */
15.28 +
15.29 +package java.lang.invoke;
15.30 +
15.31 +import java.io.Serializable;
15.32 +import java.util.Arrays;
15.33 +
15.34 +/**
15.35 + * <p>Methods to facilitate the creation of simple "function objects" that
15.36 + * implement one or more interfaces by delegation to a provided {@link MethodHandle},
15.37 + * possibly after type adaptation and partial evaluation of arguments. These
15.38 + * methods are typically used as <em>bootstrap methods</em> for {@code invokedynamic}
15.39 + * call sites, to support the <em>lambda expression</em> and <em>method
15.40 + * reference expression</em> features of the Java Programming Language.
15.41 + *
15.42 + * <p>Indirect access to the behavior specified by the provided {@code MethodHandle}
15.43 + * proceeds in order through three phases:
15.44 + * <ul>
15.45 + * <li><em>Linkage</em> occurs when the methods in this class are invoked.
15.46 + * They take as arguments an interface to be implemented (typically a
15.47 + * <em>functional interface</em>, one with a single abstract method), a
15.48 + * name and signature of a method from that interface to be implemented, a
15.49 + * method handle describing the desired implementation behavior
15.50 + * for that method, and possibly other additional metadata, and produce a
15.51 + * {@link CallSite} whose target can be used to create suitable function
15.52 + * objects. Linkage may involve dynamically loading a new class that
15.53 + * implements the target interface. The {@code CallSite} can be considered a
15.54 + * "factory" for function objects and so these linkage methods are referred
15.55 + * to as "metafactories".</li>
15.56 + *
15.57 + * <li><em>Capture</em> occurs when the {@code CallSite}'s target is
15.58 + * invoked, typically through an {@code invokedynamic} call site,
15.59 + * producing a function object. This may occur many times for
15.60 + * a single factory {@code CallSite}. Capture may involve allocation of a
15.61 + * new function object, or may return an existing function object. The
15.62 + * behavior {@code MethodHandle} may have additional parameters beyond those
15.63 + * of the specified interface method; these are referred to as <em>captured
15.64 + * parameters</em>, which must be provided as arguments to the
15.65 + * {@code CallSite} target, and which may be early-bound to the behavior
15.66 + * {@code MethodHandle}. The number of captured parameters and their types
15.67 + * are determined during linkage.</li>
15.68 + *
15.69 + * <li><em>Invocation</em> occurs when an implemented interface method
15.70 + * is invoked on a function object. This may occur many times for a single
15.71 + * function object. The method referenced by the behavior {@code MethodHandle}
15.72 + * is invoked with the captured arguments and any additional arguments
15.73 + * provided on invocation, as if by {@link MethodHandle#invoke(Object...)}.</li>
15.74 + * </ul>
15.75 + *
15.76 + * <p>It is sometimes useful to restrict the set of inputs or results permitted
15.77 + * at invocation. For example, when the generic interface {@code Predicate<T>}
15.78 + * is parameterized as {@code Predicate<String>}, the input must be a
15.79 + * {@code String}, even though the method to implement allows any {@code Object}.
15.80 + * At linkage time, an additional {@link MethodType} parameter describes the
15.81 + * "instantiated" method type; on invocation, the arguments and eventual result
15.82 + * are checked against this {@code MethodType}.
15.83 + *
15.84 + * <p>This class provides two forms of linkage methods: a standard version
15.85 + * ({@link #metafactory(MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType)})
15.86 + * using an optimized protocol, and an alternate version
15.87 + * {@link #altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)}).
15.88 + * The alternate version is a generalization of the standard version, providing
15.89 + * additional control over the behavior of the generated function objects via
15.90 + * flags and additional arguments. The alternate version adds the ability to
15.91 + * manage the following attributes of function objects:
15.92 + *
15.93 + * <ul>
15.94 + * <li><em>Bridging.</em> It is sometimes useful to implement multiple
15.95 + * variations of the method signature, involving argument or return type
15.96 + * adaptation. This occurs when multiple distinct VM signatures for a method
15.97 + * are logically considered to be the same method by the language. The
15.98 + * flag {@code FLAG_BRIDGES} indicates that a list of additional
15.99 + * {@code MethodType}s will be provided, each of which will be implemented
15.100 + * by the resulting function object. These methods will share the same
15.101 + * name and instantiated type.</li>
15.102 + *
15.103 + * <li><em>Multiple interfaces.</em> If needed, more than one interface
15.104 + * can be implemented by the function object. (These additional interfaces
15.105 + * are typically marker interfaces with no methods.) The flag {@code FLAG_MARKERS}
15.106 + * indicates that a list of additional interfaces will be provided, each of
15.107 + * which should be implemented by the resulting function object.</li>
15.108 + *
15.109 + * <li><em>Serializability.</em> The generated function objects do not
15.110 + * generally support serialization. If desired, {@code FLAG_SERIALIZABLE}
15.111 + * can be used to indicate that the function objects should be serializable.
15.112 + * Serializable function objects will use, as their serialized form,
15.113 + * instances of the class {@code SerializedLambda}, which requires additional
15.114 + * assistance from the capturing class (the class described by the
15.115 + * {@link MethodHandles.Lookup} parameter {@code caller}); see
15.116 + * {@link SerializedLambda} for details.</li>
15.117 + * </ul>
15.118 + *
15.119 + * <p>Assume the linkage arguments are as follows:
15.120 + * <ul>
15.121 + * <li>{@code invokedType} (describing the {@code CallSite} signature) has
15.122 + * K parameters of types (D1..Dk) and return type Rd;</li>
15.123 + * <li>{@code samMethodType} (describing the implemented method type) has N
15.124 + * parameters, of types (U1..Un) and return type Ru;</li>
15.125 + * <li>{@code implMethod} (the {@code MethodHandle} providing the
15.126 + * implementation has M parameters, of types (A1..Am) and return type Ra
15.127 + * (if the method describes an instance method, the method type of this
15.128 + * method handle already includes an extra first argument corresponding to
15.129 + * the receiver);</li>
15.130 + * <li>{@code instantiatedMethodType} (allowing restrictions on invocation)
15.131 + * has N parameters, of types (T1..Tn) and return type Rt.</li>
15.132 + * </ul>
15.133 + *
15.134 + * <p>Then the following linkage invariants must hold:
15.135 + * <ul>
15.136 + * <li>Rd is an interface</li>
15.137 + * <li>{@code implMethod} is a <em>direct method handle</em></li>
15.138 + * <li>{@code samMethodType} and {@code instantiatedMethodType} have the same
15.139 + * arity N, and for i=1..N, Ti and Ui are the same type, or Ti and Ui are
15.140 + * both reference types and Ti is a subtype of Ui</li>
15.141 + * <li>Either Rt and Ru are the same type, or both are reference types and
15.142 + * Rt is a subtype of Ru</li>
15.143 + * <li>K + N = M</li>
15.144 + * <li>For i=1..K, Di = Ai</li>
15.145 + * <li>For i=1..N, Ti is adaptable to Aj, where j=i+k</li>
15.146 + * <li>The return type Rt is void, or the return type Ra is not void and is
15.147 + * adaptable to Rt</li>
15.148 + * </ul>
15.149 + *
15.150 + * <p>Further, at capture time, if {@code implMethod} corresponds to an instance
15.151 + * method, and there are any capture arguments ({@code K > 0}), then the first
15.152 + * capture argument (corresponding to the receiver) must be non-null.
15.153 + *
15.154 + * <p>A type Q is considered adaptable to S as follows:
15.155 + * <table summary="adaptable types">
15.156 + * <tr><th>Q</th><th>S</th><th>Link-time checks</th><th>Invocation-time checks</th></tr>
15.157 + * <tr>
15.158 + * <td>Primitive</td><td>Primitive</td>
15.159 + * <td>Q can be converted to S via a primitive widening conversion</td>
15.160 + * <td>None</td>
15.161 + * </tr>
15.162 + * <tr>
15.163 + * <td>Primitive</td><td>Reference</td>
15.164 + * <td>S is a supertype of the Wrapper(Q)</td>
15.165 + * <td>Cast from Wrapper(Q) to S</td>
15.166 + * </tr>
15.167 + * <tr>
15.168 + * <td>Reference</td><td>Primitive</td>
15.169 + * <td>for parameter types: Q is a primitive wrapper and Primitive(Q)
15.170 + * can be widened to S
15.171 + * <br>for return types: If Q is a primitive wrapper, check that
15.172 + * Primitive(Q) can be widened to S</td>
15.173 + * <td>If Q is not a primitive wrapper, cast Q to the base Wrapper(S);
15.174 + * for example Number for numeric types</td>
15.175 + * </tr>
15.176 + * <tr>
15.177 + * <td>Reference</td><td>Reference</td>
15.178 + * <td>for parameter types: S is a supertype of Q
15.179 + * <br>for return types: none</td>
15.180 + * <td>Cast from Q to S</td>
15.181 + * </tr>
15.182 + * </table>
15.183 + *
15.184 + * @apiNote These linkage methods are designed to support the evaluation
15.185 + * of <em>lambda expressions</em> and <em>method references</em> in the Java
15.186 + * Language. For every lambda expressions or method reference in the source code,
15.187 + * there is a target type which is a functional interface. Evaluating a lambda
15.188 + * expression produces an object of its target type. The recommended mechanism
15.189 + * for evaluating lambda expressions is to desugar the lambda body to a method,
15.190 + * invoke an invokedynamic call site whose static argument list describes the
15.191 + * sole method of the functional interface and the desugared implementation
15.192 + * method, and returns an object (the lambda object) that implements the target
15.193 + * type. (For method references, the implementation method is simply the
15.194 + * referenced method; no desugaring is needed.)
15.195 + *
15.196 + * <p>The argument list of the implementation method and the argument list of
15.197 + * the interface method(s) may differ in several ways. The implementation
15.198 + * methods may have additional arguments to accommodate arguments captured by
15.199 + * the lambda expression; there may also be differences resulting from permitted
15.200 + * adaptations of arguments, such as casting, boxing, unboxing, and primitive
15.201 + * widening. (Varargs adaptations are not handled by the metafactories; these are
15.202 + * expected to be handled by the caller.)
15.203 + *
15.204 + * <p>Invokedynamic call sites have two argument lists: a static argument list
15.205 + * and a dynamic argument list. The static argument list is stored in the
15.206 + * constant pool; the dynamic argument is pushed on the operand stack at capture
15.207 + * time. The bootstrap method has access to the entire static argument list
15.208 + * (which in this case, includes information describing the implementation method,
15.209 + * the target interface, and the target interface method(s)), as well as a
15.210 + * method signature describing the number and static types (but not the values)
15.211 + * of the dynamic arguments and the static return type of the invokedynamic site.
15.212 + *
15.213 + * @implNote The implementation method is described with a method handle. In
15.214 + * theory, any method handle could be used. Currently supported are direct method
15.215 + * handles representing invocation of virtual, interface, constructor and static
15.216 + * methods.
15.217 + */
15.218 +public class LambdaMetafactory {
15.219 +
15.220 + /** Flag for alternate metafactories indicating the lambda object
15.221 + * must be serializable */
15.222 + public static final int FLAG_SERIALIZABLE = 1 << 0;
15.223 +
15.224 + /**
15.225 + * Flag for alternate metafactories indicating the lambda object implements
15.226 + * other marker interfaces
15.227 + * besides Serializable
15.228 + */
15.229 + public static final int FLAG_MARKERS = 1 << 1;
15.230 +
15.231 + /**
15.232 + * Flag for alternate metafactories indicating the lambda object requires
15.233 + * additional bridge methods
15.234 + */
15.235 + public static final int FLAG_BRIDGES = 1 << 2;
15.236 +
15.237 + private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
15.238 + private static final MethodType[] EMPTY_MT_ARRAY = new MethodType[0];
15.239 +
15.240 + /**
15.241 + * Facilitates the creation of simple "function objects" that implement one
15.242 + * or more interfaces by delegation to a provided {@link MethodHandle},
15.243 + * after appropriate type adaptation and partial evaluation of arguments.
15.244 + * Typically used as a <em>bootstrap method</em> for {@code invokedynamic}
15.245 + * call sites, to support the <em>lambda expression</em> and <em>method
15.246 + * reference expression</em> features of the Java Programming Language.
15.247 + *
15.248 + * <p>This is the standard, streamlined metafactory; additional flexibility
15.249 + * is provided by {@link #altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)}.
15.250 + * A general description of the behavior of this method is provided
15.251 + * {@link LambdaMetafactory above}.
15.252 + *
15.253 + * <p>When the target of the {@code CallSite} returned from this method is
15.254 + * invoked, the resulting function objects are instances of a class which
15.255 + * implements the interface named by the return type of {@code invokedType},
15.256 + * declares a method with the name given by {@code invokedName} and the
15.257 + * signature given by {@code samMethodType}. It may also override additional
15.258 + * methods from {@code Object}.
15.259 + *
15.260 + * @param caller Represents a lookup context with the accessibility
15.261 + * privileges of the caller. When used with {@code invokedynamic},
15.262 + * this is stacked automatically by the VM.
15.263 + * @param invokedName The name of the method to implement. When used with
15.264 + * {@code invokedynamic}, this is provided by the
15.265 + * {@code NameAndType} of the {@code InvokeDynamic}
15.266 + * structure and is stacked automatically by the VM.
15.267 + * @param invokedType The expected signature of the {@code CallSite}. The
15.268 + * parameter types represent the types of capture variables;
15.269 + * the return type is the interface to implement. When
15.270 + * used with {@code invokedynamic}, this is provided by
15.271 + * the {@code NameAndType} of the {@code InvokeDynamic}
15.272 + * structure and is stacked automatically by the VM.
15.273 + * In the event that the implementation method is an
15.274 + * instance method and this signature has any parameters,
15.275 + * the first parameter in the invocation signature must
15.276 + * correspond to the receiver.
15.277 + * @param samMethodType Signature and return type of method to be implemented
15.278 + * by the function object.
15.279 + * @param implMethod A direct method handle describing the implementation
15.280 + * method which should be called (with suitable adaptation
15.281 + * of argument types, return types, and with captured
15.282 + * arguments prepended to the invocation arguments) at
15.283 + * invocation time.
15.284 + * @param instantiatedMethodType The signature and return type that should
15.285 + * be enforced dynamically at invocation time.
15.286 + * This may be the same as {@code samMethodType},
15.287 + * or may be a specialization of it.
15.288 + * @return a CallSite whose target can be used to perform capture, generating
15.289 + * instances of the interface named by {@code invokedType}
15.290 + * @throws LambdaConversionException If any of the linkage invariants
15.291 + * described {@link LambdaMetafactory above}
15.292 + * are violated
15.293 + */
15.294 + public static CallSite metafactory(MethodHandles.Lookup caller,
15.295 + String invokedName,
15.296 + MethodType invokedType,
15.297 + MethodType samMethodType,
15.298 + MethodHandle implMethod,
15.299 + MethodType instantiatedMethodType)
15.300 + throws LambdaConversionException {
15.301 + AbstractValidatingLambdaMetafactory mf;
15.302 + mf = new InnerClassLambdaMetafactory(caller, invokedType,
15.303 + invokedName, samMethodType,
15.304 + implMethod, instantiatedMethodType,
15.305 + false, EMPTY_CLASS_ARRAY, EMPTY_MT_ARRAY);
15.306 + mf.validateMetafactoryArgs();
15.307 + return mf.buildCallSite();
15.308 + }
15.309 +
15.310 + /**
15.311 + * Facilitates the creation of simple "function objects" that implement one
15.312 + * or more interfaces by delegation to a provided {@link MethodHandle},
15.313 + * after appropriate type adaptation and partial evaluation of arguments.
15.314 + * Typically used as a <em>bootstrap method</em> for {@code invokedynamic}
15.315 + * call sites, to support the <em>lambda expression</em> and <em>method
15.316 + * reference expression</em> features of the Java Programming Language.
15.317 + *
15.318 + * <p>This is the general, more flexible metafactory; a streamlined version
15.319 + * is provided by {@link #altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)}.
15.320 + * A general description of the behavior of this method is provided
15.321 + * {@link LambdaMetafactory above}.
15.322 + *
15.323 + * <p>The argument list for this method includes three fixed parameters,
15.324 + * corresponding to the parameters automatically stacked by the VM for the
15.325 + * bootstrap method in an {@code invokedynamic} invocation, and an {@code Object[]}
15.326 + * parameter that contains additional parameters. The declared argument
15.327 + * list for this method is:
15.328 + *
15.329 + * <pre>{@code
15.330 + * CallSite altMetafactory(MethodHandles.Lookup caller,
15.331 + * String invokedName,
15.332 + * MethodType invokedType,
15.333 + * Object... args)
15.334 + * }</pre>
15.335 + *
15.336 + * <p>but it behaves as if the argument list is as follows:
15.337 + *
15.338 + * <pre>{@code
15.339 + * CallSite altMetafactory(MethodHandles.Lookup caller,
15.340 + * String invokedName,
15.341 + * MethodType invokedType,
15.342 + * MethodType samMethodType,
15.343 + * MethodHandle implMethod,
15.344 + * MethodType instantiatedMethodType,
15.345 + * int flags,
15.346 + * int markerInterfaceCount, // IF flags has MARKERS set
15.347 + * Class... markerInterfaces, // IF flags has MARKERS set
15.348 + * int bridgeCount, // IF flags has BRIDGES set
15.349 + * MethodType... bridges // IF flags has BRIDGES set
15.350 + * )
15.351 + * }</pre>
15.352 + *
15.353 + * <p>Arguments that appear in the argument list for
15.354 + * {@link #metafactory(MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType)}
15.355 + * have the same specification as in that method. The additional arguments
15.356 + * are interpreted as follows:
15.357 + * <ul>
15.358 + * <li>{@code flags} indicates additional options; this is a bitwise
15.359 + * OR of desired flags. Defined flags are {@link #FLAG_BRIDGES},
15.360 + * {@link #FLAG_MARKERS}, and {@link #FLAG_SERIALIZABLE}.</li>
15.361 + * <li>{@code markerInterfaceCount} is the number of additional interfaces
15.362 + * the function object should implement, and is present if and only if the
15.363 + * {@code FLAG_MARKERS} flag is set.</li>
15.364 + * <li>{@code markerInterfaces} is a variable-length list of additional
15.365 + * interfaces to implement, whose length equals {@code markerInterfaceCount},
15.366 + * and is present if and only if the {@code FLAG_MARKERS} flag is set.</li>
15.367 + * <li>{@code bridgeCount} is the number of additional method signatures
15.368 + * the function object should implement, and is present if and only if
15.369 + * the {@code FLAG_BRIDGES} flag is set.</li>
15.370 + * <li>{@code bridges} is a variable-length list of additional
15.371 + * methods signatures to implement, whose length equals {@code bridgeCount},
15.372 + * and is present if and only if the {@code FLAG_BRIDGES} flag is set.</li>
15.373 + * </ul>
15.374 + *
15.375 + * <p>Each class named by {@code markerInterfaces} is subject to the same
15.376 + * restrictions as {@code Rd}, the return type of {@code invokedType},
15.377 + * as described {@link LambdaMetafactory above}. Each {@code MethodType}
15.378 + * named by {@code bridges} is subject to the same restrictions as
15.379 + * {@code samMethodType}, as described {@link LambdaMetafactory above}.
15.380 + *
15.381 + * <p>When FLAG_SERIALIZABLE is set in {@code flags}, the function objects
15.382 + * will implement {@code Serializable}, and will have a {@code writeReplace}
15.383 + * method that returns an appropriate {@link SerializedLambda}. The
15.384 + * {@code caller} class must have an appropriate {@code $deserializeLambda$}
15.385 + * method, as described in {@link SerializedLambda}.
15.386 + *
15.387 + * <p>When the target of the {@code CallSite} returned from this method is
15.388 + * invoked, the resulting function objects are instances of a class with
15.389 + * the following properties:
15.390 + * <ul>
15.391 + * <li>The class implements the interface named by the return type
15.392 + * of {@code invokedType} and any interfaces named by {@code markerInterfaces}</li>
15.393 + * <li>The class declares methods with the name given by {@code invokedName},
15.394 + * and the signature given by {@code samMethodType} and additional signatures
15.395 + * given by {@code bridges}</li>
15.396 + * <li>The class may override methods from {@code Object}, and may
15.397 + * implement methods related to serialization.</li>
15.398 + * </ul>
15.399 + *
15.400 + * @param caller Represents a lookup context with the accessibility
15.401 + * privileges of the caller. When used with {@code invokedynamic},
15.402 + * this is stacked automatically by the VM.
15.403 + * @param invokedName The name of the method to implement. When used with
15.404 + * {@code invokedynamic}, this is provided by the
15.405 + * {@code NameAndType} of the {@code InvokeDynamic}
15.406 + * structure and is stacked automatically by the VM.
15.407 + * @param invokedType The expected signature of the {@code CallSite}. The
15.408 + * parameter types represent the types of capture variables;
15.409 + * the return type is the interface to implement. When
15.410 + * used with {@code invokedynamic}, this is provided by
15.411 + * the {@code NameAndType} of the {@code InvokeDynamic}
15.412 + * structure and is stacked automatically by the VM.
15.413 + * In the event that the implementation method is an
15.414 + * instance method and this signature has any parameters,
15.415 + * the first parameter in the invocation signature must
15.416 + * correspond to the receiver.
15.417 + * @param args An {@code Object[]} array containing the required
15.418 + * arguments {@code samMethodType}, {@code implMethod},
15.419 + * {@code instantiatedMethodType}, {@code flags}, and any
15.420 + * optional arguments, as described
15.421 + * {@link #altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)} above}
15.422 + * @return a CallSite whose target can be used to perform capture, generating
15.423 + * instances of the interface named by {@code invokedType}
15.424 + * @throws LambdaConversionException If any of the linkage invariants
15.425 + * described {@link LambdaMetafactory above}
15.426 + * are violated
15.427 + */
15.428 + public static CallSite altMetafactory(MethodHandles.Lookup caller,
15.429 + String invokedName,
15.430 + MethodType invokedType,
15.431 + Object... args)
15.432 + throws LambdaConversionException {
15.433 + MethodType samMethodType = (MethodType)args[0];
15.434 + MethodHandle implMethod = (MethodHandle)args[1];
15.435 + MethodType instantiatedMethodType = (MethodType)args[2];
15.436 + int flags = (Integer) args[3];
15.437 + Class<?>[] markerInterfaces;
15.438 + MethodType[] bridges;
15.439 + int argIndex = 4;
15.440 + if ((flags & FLAG_MARKERS) != 0) {
15.441 + int markerCount = (Integer) args[argIndex++];
15.442 + markerInterfaces = new Class<?>[markerCount];
15.443 + System.arraycopy(args, argIndex, markerInterfaces, 0, markerCount);
15.444 + argIndex += markerCount;
15.445 + }
15.446 + else
15.447 + markerInterfaces = EMPTY_CLASS_ARRAY;
15.448 + if ((flags & FLAG_BRIDGES) != 0) {
15.449 + int bridgeCount = (Integer) args[argIndex++];
15.450 + bridges = new MethodType[bridgeCount];
15.451 + System.arraycopy(args, argIndex, bridges, 0, bridgeCount);
15.452 + argIndex += bridgeCount;
15.453 + }
15.454 + else
15.455 + bridges = EMPTY_MT_ARRAY;
15.456 +
15.457 + boolean isSerializable = ((flags & FLAG_SERIALIZABLE) != 0);
15.458 + if (isSerializable) {
15.459 + boolean foundSerializableSupertype = Serializable.class.isAssignableFrom(invokedType.returnType());
15.460 + for (Class<?> c : markerInterfaces)
15.461 + foundSerializableSupertype |= Serializable.class.isAssignableFrom(c);
15.462 + if (!foundSerializableSupertype) {
15.463 + markerInterfaces = Arrays.copyOf(markerInterfaces, markerInterfaces.length + 1);
15.464 + markerInterfaces[markerInterfaces.length-1] = Serializable.class;
15.465 + }
15.466 + }
15.467 +
15.468 + AbstractValidatingLambdaMetafactory mf
15.469 + = new InnerClassLambdaMetafactory(caller, invokedType,
15.470 + invokedName, samMethodType,
15.471 + implMethod,
15.472 + instantiatedMethodType,
15.473 + isSerializable,
15.474 + markerInterfaces, bridges);
15.475 + mf.validateMetafactoryArgs();
15.476 + return mf.buildCallSite();
15.477 + }
15.478 +}
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
16.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/MemberName.java Sat Aug 09 11:12:05 2014 +0200
16.3 @@ -0,0 +1,1080 @@
16.4 +/*
16.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
16.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
16.7 + *
16.8 + * This code is free software; you can redistribute it and/or modify it
16.9 + * under the terms of the GNU General Public License version 2 only, as
16.10 + * published by the Free Software Foundation. Oracle designates this
16.11 + * particular file as subject to the "Classpath" exception as provided
16.12 + * by Oracle in the LICENSE file that accompanied this code.
16.13 + *
16.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
16.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16.17 + * version 2 for more details (a copy is included in the LICENSE file that
16.18 + * accompanied this code).
16.19 + *
16.20 + * You should have received a copy of the GNU General Public License version
16.21 + * 2 along with this work; if not, write to the Free Software Foundation,
16.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
16.23 + *
16.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
16.25 + * or visit www.oracle.com if you need additional information or have any
16.26 + * questions.
16.27 + */
16.28 +
16.29 +package java.lang.invoke;
16.30 +
16.31 +import sun.invoke.util.BytecodeDescriptor;
16.32 +import sun.invoke.util.VerifyAccess;
16.33 +
16.34 +import java.lang.reflect.Constructor;
16.35 +import java.lang.reflect.Field;
16.36 +import java.lang.reflect.Method;
16.37 +import java.lang.reflect.Member;
16.38 +import java.lang.reflect.Modifier;
16.39 +import java.util.ArrayList;
16.40 +import java.util.Arrays;
16.41 +import java.util.Collections;
16.42 +import java.util.Iterator;
16.43 +import java.util.List;
16.44 +import static java.lang.invoke.MethodHandleNatives.Constants.*;
16.45 +import static java.lang.invoke.MethodHandleStatics.*;
16.46 +import java.util.Objects;
16.47 +
16.48 +/**
16.49 + * A {@code MemberName} is a compact symbolic datum which fully characterizes
16.50 + * a method or field reference.
16.51 + * A member name refers to a field, method, constructor, or member type.
16.52 + * Every member name has a simple name (a string) and a type (either a Class or MethodType).
16.53 + * A member name may also have a non-null declaring class, or it may be simply
16.54 + * a naked name/type pair.
16.55 + * A member name may also have non-zero modifier flags.
16.56 + * Finally, a member name may be either resolved or unresolved.
16.57 + * If it is resolved, the existence of the named
16.58 + * <p>
16.59 + * Whether resolved or not, a member name provides no access rights or
16.60 + * invocation capability to its possessor. It is merely a compact
16.61 + * representation of all symbolic information necessary to link to
16.62 + * and properly use the named member.
16.63 + * <p>
16.64 + * When resolved, a member name's internal implementation may include references to JVM metadata.
16.65 + * This representation is stateless and only decriptive.
16.66 + * It provides no private information and no capability to use the member.
16.67 + * <p>
16.68 + * By contrast, a {@linkplain java.lang.reflect.Method} contains fuller information
16.69 + * about the internals of a method (except its bytecodes) and also
16.70 + * allows invocation. A MemberName is much lighter than a Method,
16.71 + * since it contains about 7 fields to the 16 of Method (plus its sub-arrays),
16.72 + * and those seven fields omit much of the information in Method.
16.73 + * @author jrose
16.74 + */
16.75 +/*non-public*/ final class MemberName implements Member, Cloneable {
16.76 + private Class<?> clazz; // class in which the method is defined
16.77 + private String name; // may be null if not yet materialized
16.78 + private Object type; // may be null if not yet materialized
16.79 + private int flags; // modifier bits; see reflect.Modifier
16.80 + //@Injected JVM_Method* vmtarget;
16.81 + //@Injected int vmindex;
16.82 + private Object resolution; // if null, this guy is resolved
16.83 +
16.84 + /** Return the declaring class of this member.
16.85 + * In the case of a bare name and type, the declaring class will be null.
16.86 + */
16.87 + public Class<?> getDeclaringClass() {
16.88 + return clazz;
16.89 + }
16.90 +
16.91 + /** Utility method producing the class loader of the declaring class. */
16.92 + public ClassLoader getClassLoader() {
16.93 + return clazz.getClassLoader();
16.94 + }
16.95 +
16.96 + /** Return the simple name of this member.
16.97 + * For a type, it is the same as {@link Class#getSimpleName}.
16.98 + * For a method or field, it is the simple name of the member.
16.99 + * For a constructor, it is always {@code "<init>"}.
16.100 + */
16.101 + public String getName() {
16.102 + if (name == null) {
16.103 + expandFromVM();
16.104 + if (name == null) {
16.105 + return null;
16.106 + }
16.107 + }
16.108 + return name;
16.109 + }
16.110 +
16.111 + public MethodType getMethodOrFieldType() {
16.112 + if (isInvocable())
16.113 + return getMethodType();
16.114 + if (isGetter())
16.115 + return MethodType.methodType(getFieldType());
16.116 + if (isSetter())
16.117 + return MethodType.methodType(void.class, getFieldType());
16.118 + throw new InternalError("not a method or field: "+this);
16.119 + }
16.120 +
16.121 + /** Return the declared type of this member, which
16.122 + * must be a method or constructor.
16.123 + */
16.124 + public MethodType getMethodType() {
16.125 + if (type == null) {
16.126 + expandFromVM();
16.127 + if (type == null) {
16.128 + return null;
16.129 + }
16.130 + }
16.131 + if (!isInvocable()) {
16.132 + throw newIllegalArgumentException("not invocable, no method type");
16.133 + }
16.134 +
16.135 + {
16.136 + // Get a snapshot of type which doesn't get changed by racing threads.
16.137 + final Object type = this.type;
16.138 + if (type instanceof MethodType) {
16.139 + return (MethodType) type;
16.140 + }
16.141 + }
16.142 +
16.143 + // type is not a MethodType yet. Convert it thread-safely.
16.144 + synchronized (this) {
16.145 + if (type instanceof String) {
16.146 + String sig = (String) type;
16.147 + MethodType res = MethodType.fromMethodDescriptorString(sig, getClassLoader());
16.148 + type = res;
16.149 + } else if (type instanceof Object[]) {
16.150 + Object[] typeInfo = (Object[]) type;
16.151 + Class<?>[] ptypes = (Class<?>[]) typeInfo[1];
16.152 + Class<?> rtype = (Class<?>) typeInfo[0];
16.153 + MethodType res = MethodType.methodType(rtype, ptypes);
16.154 + type = res;
16.155 + }
16.156 + // Make sure type is a MethodType for racing threads.
16.157 + assert type instanceof MethodType : "bad method type " + type;
16.158 + }
16.159 + return (MethodType) type;
16.160 + }
16.161 +
16.162 + /** Return the actual type under which this method or constructor must be invoked.
16.163 + * For non-static methods or constructors, this is the type with a leading parameter,
16.164 + * a reference to declaring class. For static methods, it is the same as the declared type.
16.165 + */
16.166 + public MethodType getInvocationType() {
16.167 + MethodType itype = getMethodOrFieldType();
16.168 + if (isConstructor() && getReferenceKind() == REF_newInvokeSpecial)
16.169 + return itype.changeReturnType(clazz);
16.170 + if (!isStatic())
16.171 + return itype.insertParameterTypes(0, clazz);
16.172 + return itype;
16.173 + }
16.174 +
16.175 + /** Utility method producing the parameter types of the method type. */
16.176 + public Class<?>[] getParameterTypes() {
16.177 + return getMethodType().parameterArray();
16.178 + }
16.179 +
16.180 + /** Utility method producing the return type of the method type. */
16.181 + public Class<?> getReturnType() {
16.182 + return getMethodType().returnType();
16.183 + }
16.184 +
16.185 + /** Return the declared type of this member, which
16.186 + * must be a field or type.
16.187 + * If it is a type member, that type itself is returned.
16.188 + */
16.189 + public Class<?> getFieldType() {
16.190 + if (type == null) {
16.191 + expandFromVM();
16.192 + if (type == null) {
16.193 + return null;
16.194 + }
16.195 + }
16.196 + if (isInvocable()) {
16.197 + throw newIllegalArgumentException("not a field or nested class, no simple type");
16.198 + }
16.199 +
16.200 + {
16.201 + // Get a snapshot of type which doesn't get changed by racing threads.
16.202 + final Object type = this.type;
16.203 + if (type instanceof Class<?>) {
16.204 + return (Class<?>) type;
16.205 + }
16.206 + }
16.207 +
16.208 + // type is not a Class yet. Convert it thread-safely.
16.209 + synchronized (this) {
16.210 + if (type instanceof String) {
16.211 + String sig = (String) type;
16.212 + MethodType mtype = MethodType.fromMethodDescriptorString("()"+sig, getClassLoader());
16.213 + Class<?> res = mtype.returnType();
16.214 + type = res;
16.215 + }
16.216 + // Make sure type is a Class for racing threads.
16.217 + assert type instanceof Class<?> : "bad field type " + type;
16.218 + }
16.219 + return (Class<?>) type;
16.220 + }
16.221 +
16.222 + /** Utility method to produce either the method type or field type of this member. */
16.223 + public Object getType() {
16.224 + return (isInvocable() ? getMethodType() : getFieldType());
16.225 + }
16.226 +
16.227 + /** Utility method to produce the signature of this member,
16.228 + * used within the class file format to describe its type.
16.229 + */
16.230 + public String getSignature() {
16.231 + if (type == null) {
16.232 + expandFromVM();
16.233 + if (type == null) {
16.234 + return null;
16.235 + }
16.236 + }
16.237 + if (isInvocable())
16.238 + return BytecodeDescriptor.unparse(getMethodType());
16.239 + else
16.240 + return BytecodeDescriptor.unparse(getFieldType());
16.241 + }
16.242 +
16.243 + /** Return the modifier flags of this member.
16.244 + * @see java.lang.reflect.Modifier
16.245 + */
16.246 + public int getModifiers() {
16.247 + return (flags & RECOGNIZED_MODIFIERS);
16.248 + }
16.249 +
16.250 + /** Return the reference kind of this member, or zero if none.
16.251 + */
16.252 + public byte getReferenceKind() {
16.253 + return (byte) ((flags >>> MN_REFERENCE_KIND_SHIFT) & MN_REFERENCE_KIND_MASK);
16.254 + }
16.255 + private boolean referenceKindIsConsistent() {
16.256 + byte refKind = getReferenceKind();
16.257 + if (refKind == REF_NONE) return isType();
16.258 + if (isField()) {
16.259 + assert(staticIsConsistent());
16.260 + assert(MethodHandleNatives.refKindIsField(refKind));
16.261 + } else if (isConstructor()) {
16.262 + assert(refKind == REF_newInvokeSpecial || refKind == REF_invokeSpecial);
16.263 + } else if (isMethod()) {
16.264 + assert(staticIsConsistent());
16.265 + assert(MethodHandleNatives.refKindIsMethod(refKind));
16.266 + if (clazz.isInterface())
16.267 + assert(refKind == REF_invokeInterface ||
16.268 + refKind == REF_invokeStatic ||
16.269 + refKind == REF_invokeSpecial ||
16.270 + refKind == REF_invokeVirtual && isObjectPublicMethod());
16.271 + } else {
16.272 + assert(false);
16.273 + }
16.274 + return true;
16.275 + }
16.276 + private boolean isObjectPublicMethod() {
16.277 + if (clazz == Object.class) return true;
16.278 + MethodType mtype = getMethodType();
16.279 + if (name.equals("toString") && mtype.returnType() == String.class && mtype.parameterCount() == 0)
16.280 + return true;
16.281 + if (name.equals("hashCode") && mtype.returnType() == int.class && mtype.parameterCount() == 0)
16.282 + return true;
16.283 + if (name.equals("equals") && mtype.returnType() == boolean.class && mtype.parameterCount() == 1 && mtype.parameterType(0) == Object.class)
16.284 + return true;
16.285 + return false;
16.286 + }
16.287 + /*non-public*/ boolean referenceKindIsConsistentWith(int originalRefKind) {
16.288 + int refKind = getReferenceKind();
16.289 + if (refKind == originalRefKind) return true;
16.290 + switch (originalRefKind) {
16.291 + case REF_invokeInterface:
16.292 + // Looking up an interface method, can get (e.g.) Object.hashCode
16.293 + assert(refKind == REF_invokeVirtual ||
16.294 + refKind == REF_invokeSpecial) : this;
16.295 + return true;
16.296 + case REF_invokeVirtual:
16.297 + case REF_newInvokeSpecial:
16.298 + // Looked up a virtual, can get (e.g.) final String.hashCode.
16.299 + assert(refKind == REF_invokeSpecial) : this;
16.300 + return true;
16.301 + }
16.302 + assert(false) : this+" != "+MethodHandleNatives.refKindName((byte)originalRefKind);
16.303 + return true;
16.304 + }
16.305 + private boolean staticIsConsistent() {
16.306 + byte refKind = getReferenceKind();
16.307 + return MethodHandleNatives.refKindIsStatic(refKind) == isStatic() || getModifiers() == 0;
16.308 + }
16.309 + private boolean vminfoIsConsistent() {
16.310 + byte refKind = getReferenceKind();
16.311 + assert(isResolved()); // else don't call
16.312 + Object vminfo = MethodHandleNatives.getMemberVMInfo(this);
16.313 + assert(vminfo instanceof Object[]);
16.314 + long vmindex = (Long) ((Object[])vminfo)[0];
16.315 + Object vmtarget = ((Object[])vminfo)[1];
16.316 + if (MethodHandleNatives.refKindIsField(refKind)) {
16.317 + assert(vmindex >= 0) : vmindex + ":" + this;
16.318 + assert(vmtarget instanceof Class);
16.319 + } else {
16.320 + if (MethodHandleNatives.refKindDoesDispatch(refKind))
16.321 + assert(vmindex >= 0) : vmindex + ":" + this;
16.322 + else
16.323 + assert(vmindex < 0) : vmindex;
16.324 + assert(vmtarget instanceof MemberName) : vmtarget + " in " + this;
16.325 + }
16.326 + return true;
16.327 + }
16.328 +
16.329 + private MemberName changeReferenceKind(byte refKind, byte oldKind) {
16.330 + assert(getReferenceKind() == oldKind);
16.331 + assert(MethodHandleNatives.refKindIsValid(refKind));
16.332 + flags += (((int)refKind - oldKind) << MN_REFERENCE_KIND_SHIFT);
16.333 +// if (isConstructor() && refKind != REF_newInvokeSpecial)
16.334 +// flags += (IS_METHOD - IS_CONSTRUCTOR);
16.335 +// else if (refKind == REF_newInvokeSpecial && isMethod())
16.336 +// flags += (IS_CONSTRUCTOR - IS_METHOD);
16.337 + return this;
16.338 + }
16.339 +
16.340 + private boolean testFlags(int mask, int value) {
16.341 + return (flags & mask) == value;
16.342 + }
16.343 + private boolean testAllFlags(int mask) {
16.344 + return testFlags(mask, mask);
16.345 + }
16.346 + private boolean testAnyFlags(int mask) {
16.347 + return !testFlags(mask, 0);
16.348 + }
16.349 +
16.350 + /** Utility method to query if this member is a method handle invocation (invoke or invokeExact). */
16.351 + public boolean isMethodHandleInvoke() {
16.352 + final int bits = MH_INVOKE_MODS;
16.353 + final int negs = Modifier.STATIC;
16.354 + if (testFlags(bits | negs, bits) &&
16.355 + clazz == MethodHandle.class) {
16.356 + return isMethodHandleInvokeName(name);
16.357 + }
16.358 + return false;
16.359 + }
16.360 + public static boolean isMethodHandleInvokeName(String name) {
16.361 + return name.equals("invoke") || name.equals("invokeExact");
16.362 + }
16.363 + private static final int MH_INVOKE_MODS = Modifier.NATIVE | Modifier.FINAL | Modifier.PUBLIC;
16.364 +
16.365 + /** Utility method to query the modifier flags of this member. */
16.366 + public boolean isStatic() {
16.367 + return Modifier.isStatic(flags);
16.368 + }
16.369 + /** Utility method to query the modifier flags of this member. */
16.370 + public boolean isPublic() {
16.371 + return Modifier.isPublic(flags);
16.372 + }
16.373 + /** Utility method to query the modifier flags of this member. */
16.374 + public boolean isPrivate() {
16.375 + return Modifier.isPrivate(flags);
16.376 + }
16.377 + /** Utility method to query the modifier flags of this member. */
16.378 + public boolean isProtected() {
16.379 + return Modifier.isProtected(flags);
16.380 + }
16.381 + /** Utility method to query the modifier flags of this member. */
16.382 + public boolean isFinal() {
16.383 + return Modifier.isFinal(flags);
16.384 + }
16.385 + /** Utility method to query whether this member or its defining class is final. */
16.386 + public boolean canBeStaticallyBound() {
16.387 + return Modifier.isFinal(flags | clazz.getModifiers());
16.388 + }
16.389 + /** Utility method to query the modifier flags of this member. */
16.390 + public boolean isVolatile() {
16.391 + return Modifier.isVolatile(flags);
16.392 + }
16.393 + /** Utility method to query the modifier flags of this member. */
16.394 + public boolean isAbstract() {
16.395 + return Modifier.isAbstract(flags);
16.396 + }
16.397 + /** Utility method to query the modifier flags of this member. */
16.398 + public boolean isNative() {
16.399 + return Modifier.isNative(flags);
16.400 + }
16.401 + // let the rest (native, volatile, transient, etc.) be tested via Modifier.isFoo
16.402 +
16.403 + // unofficial modifier flags, used by HotSpot:
16.404 + static final int BRIDGE = 0x00000040;
16.405 + static final int VARARGS = 0x00000080;
16.406 + static final int SYNTHETIC = 0x00001000;
16.407 + static final int ANNOTATION= 0x00002000;
16.408 + static final int ENUM = 0x00004000;
16.409 + /** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
16.410 + public boolean isBridge() {
16.411 + return testAllFlags(IS_METHOD | BRIDGE);
16.412 + }
16.413 + /** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
16.414 + public boolean isVarargs() {
16.415 + return testAllFlags(VARARGS) && isInvocable();
16.416 + }
16.417 + /** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
16.418 + public boolean isSynthetic() {
16.419 + return testAllFlags(SYNTHETIC);
16.420 + }
16.421 +
16.422 + static final String CONSTRUCTOR_NAME = "<init>"; // the ever-popular
16.423 +
16.424 + // modifiers exported by the JVM:
16.425 + static final int RECOGNIZED_MODIFIERS = 0xFFFF;
16.426 +
16.427 + // private flags, not part of RECOGNIZED_MODIFIERS:
16.428 + static final int
16.429 + IS_METHOD = MN_IS_METHOD, // method (not constructor)
16.430 + IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor
16.431 + IS_FIELD = MN_IS_FIELD, // field
16.432 + IS_TYPE = MN_IS_TYPE, // nested type
16.433 + CALLER_SENSITIVE = MN_CALLER_SENSITIVE; // @CallerSensitive annotation detected
16.434 +
16.435 + static final int ALL_ACCESS = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED;
16.436 + static final int ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE;
16.437 + static final int IS_INVOCABLE = IS_METHOD | IS_CONSTRUCTOR;
16.438 + static final int IS_FIELD_OR_METHOD = IS_METHOD | IS_FIELD;
16.439 + static final int SEARCH_ALL_SUPERS = MN_SEARCH_SUPERCLASSES | MN_SEARCH_INTERFACES;
16.440 +
16.441 + /** Utility method to query whether this member is a method or constructor. */
16.442 + public boolean isInvocable() {
16.443 + return testAnyFlags(IS_INVOCABLE);
16.444 + }
16.445 + /** Utility method to query whether this member is a method, constructor, or field. */
16.446 + public boolean isFieldOrMethod() {
16.447 + return testAnyFlags(IS_FIELD_OR_METHOD);
16.448 + }
16.449 + /** Query whether this member is a method. */
16.450 + public boolean isMethod() {
16.451 + return testAllFlags(IS_METHOD);
16.452 + }
16.453 + /** Query whether this member is a constructor. */
16.454 + public boolean isConstructor() {
16.455 + return testAllFlags(IS_CONSTRUCTOR);
16.456 + }
16.457 + /** Query whether this member is a field. */
16.458 + public boolean isField() {
16.459 + return testAllFlags(IS_FIELD);
16.460 + }
16.461 + /** Query whether this member is a type. */
16.462 + public boolean isType() {
16.463 + return testAllFlags(IS_TYPE);
16.464 + }
16.465 + /** Utility method to query whether this member is neither public, private, nor protected. */
16.466 + public boolean isPackage() {
16.467 + return !testAnyFlags(ALL_ACCESS);
16.468 + }
16.469 + /** Query whether this member has a CallerSensitive annotation. */
16.470 + public boolean isCallerSensitive() {
16.471 + return testAllFlags(CALLER_SENSITIVE);
16.472 + }
16.473 +
16.474 + /** Utility method to query whether this member is accessible from a given lookup class. */
16.475 + public boolean isAccessibleFrom(Class<?> lookupClass) {
16.476 + return VerifyAccess.isMemberAccessible(this.getDeclaringClass(), this.getDeclaringClass(), flags,
16.477 + lookupClass, ALL_ACCESS|MethodHandles.Lookup.PACKAGE);
16.478 + }
16.479 +
16.480 + /** Initialize a query. It is not resolved. */
16.481 + private void init(Class<?> defClass, String name, Object type, int flags) {
16.482 + // defining class is allowed to be null (for a naked name/type pair)
16.483 + //name.toString(); // null check
16.484 + //type.equals(type); // null check
16.485 + // fill in fields:
16.486 + this.clazz = defClass;
16.487 + this.name = name;
16.488 + this.type = type;
16.489 + this.flags = flags;
16.490 + assert(testAnyFlags(ALL_KINDS));
16.491 + assert(this.resolution == null); // nobody should have touched this yet
16.492 + //assert(referenceKindIsConsistent()); // do this after resolution
16.493 + }
16.494 +
16.495 + /**
16.496 + * Calls down to the VM to fill in the fields. This method is
16.497 + * synchronized to avoid racing calls.
16.498 + */
16.499 + private void expandFromVM() {
16.500 + if (type != null) {
16.501 + return;
16.502 + }
16.503 + if (!isResolved()) {
16.504 + return;
16.505 + }
16.506 + MethodHandleNatives.expand(this);
16.507 + }
16.508 +
16.509 + // Capturing information from the Core Reflection API:
16.510 + private static int flagsMods(int flags, int mods, byte refKind) {
16.511 + assert((flags & RECOGNIZED_MODIFIERS) == 0);
16.512 + assert((mods & ~RECOGNIZED_MODIFIERS) == 0);
16.513 + assert((refKind & ~MN_REFERENCE_KIND_MASK) == 0);
16.514 + return flags | mods | (refKind << MN_REFERENCE_KIND_SHIFT);
16.515 + }
16.516 + /** Create a name for the given reflected method. The resulting name will be in a resolved state. */
16.517 + public MemberName(Method m) {
16.518 + this(m, false);
16.519 + }
16.520 + @SuppressWarnings("LeakingThisInConstructor")
16.521 + public MemberName(Method m, boolean wantSpecial) {
16.522 + m.getClass(); // NPE check
16.523 + // fill in vmtarget, vmindex while we have m in hand:
16.524 + MethodHandleNatives.init(this, m);
16.525 + if (clazz == null) { // MHN.init failed
16.526 + if (m.getDeclaringClass() == MethodHandle.class &&
16.527 + isMethodHandleInvokeName(m.getName())) {
16.528 + // The JVM did not reify this signature-polymorphic instance.
16.529 + // Need a special case here.
16.530 + // See comments on MethodHandleNatives.linkMethod.
16.531 + MethodType type = MethodType.methodType(m.getReturnType(), m.getParameterTypes());
16.532 + int flags = flagsMods(IS_METHOD, m.getModifiers(), REF_invokeVirtual);
16.533 + init(MethodHandle.class, m.getName(), type, flags);
16.534 + if (isMethodHandleInvoke())
16.535 + return;
16.536 + }
16.537 + throw new LinkageError(m.toString());
16.538 + }
16.539 + assert(isResolved() && this.clazz != null);
16.540 + this.name = m.getName();
16.541 + if (this.type == null)
16.542 + this.type = new Object[] { m.getReturnType(), m.getParameterTypes() };
16.543 + if (wantSpecial) {
16.544 + if (isAbstract())
16.545 + throw new AbstractMethodError(this.toString());
16.546 + if (getReferenceKind() == REF_invokeVirtual)
16.547 + changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
16.548 + else if (getReferenceKind() == REF_invokeInterface)
16.549 + // invokeSpecial on a default method
16.550 + changeReferenceKind(REF_invokeSpecial, REF_invokeInterface);
16.551 + }
16.552 + }
16.553 + public MemberName asSpecial() {
16.554 + switch (getReferenceKind()) {
16.555 + case REF_invokeSpecial: return this;
16.556 + case REF_invokeVirtual: return clone().changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
16.557 + case REF_invokeInterface: return clone().changeReferenceKind(REF_invokeSpecial, REF_invokeInterface);
16.558 + case REF_newInvokeSpecial: return clone().changeReferenceKind(REF_invokeSpecial, REF_newInvokeSpecial);
16.559 + }
16.560 + throw new IllegalArgumentException(this.toString());
16.561 + }
16.562 + /** If this MN is not REF_newInvokeSpecial, return a clone with that ref. kind.
16.563 + * In that case it must already be REF_invokeSpecial.
16.564 + */
16.565 + public MemberName asConstructor() {
16.566 + switch (getReferenceKind()) {
16.567 + case REF_invokeSpecial: return clone().changeReferenceKind(REF_newInvokeSpecial, REF_invokeSpecial);
16.568 + case REF_newInvokeSpecial: return this;
16.569 + }
16.570 + throw new IllegalArgumentException(this.toString());
16.571 + }
16.572 + /** If this MN is a REF_invokeSpecial, return a clone with the "normal" kind
16.573 + * REF_invokeVirtual; also switch either to REF_invokeInterface if clazz.isInterface.
16.574 + * The end result is to get a fully virtualized version of the MN.
16.575 + * (Note that resolving in the JVM will sometimes devirtualize, changing
16.576 + * REF_invokeVirtual of a final to REF_invokeSpecial, and REF_invokeInterface
16.577 + * in some corner cases to either of the previous two; this transform
16.578 + * undoes that change under the assumption that it occurred.)
16.579 + */
16.580 + public MemberName asNormalOriginal() {
16.581 + byte normalVirtual = clazz.isInterface() ? REF_invokeInterface : REF_invokeVirtual;
16.582 + byte refKind = getReferenceKind();
16.583 + byte newRefKind = refKind;
16.584 + MemberName result = this;
16.585 + switch (refKind) {
16.586 + case REF_invokeInterface:
16.587 + case REF_invokeVirtual:
16.588 + case REF_invokeSpecial:
16.589 + newRefKind = normalVirtual;
16.590 + break;
16.591 + }
16.592 + if (newRefKind == refKind)
16.593 + return this;
16.594 + result = clone().changeReferenceKind(newRefKind, refKind);
16.595 + assert(this.referenceKindIsConsistentWith(result.getReferenceKind()));
16.596 + return result;
16.597 + }
16.598 + /** Create a name for the given reflected constructor. The resulting name will be in a resolved state. */
16.599 + @SuppressWarnings("LeakingThisInConstructor")
16.600 + public MemberName(Constructor<?> ctor) {
16.601 + ctor.getClass(); // NPE check
16.602 + // fill in vmtarget, vmindex while we have ctor in hand:
16.603 + MethodHandleNatives.init(this, ctor);
16.604 + assert(isResolved() && this.clazz != null);
16.605 + this.name = CONSTRUCTOR_NAME;
16.606 + if (this.type == null)
16.607 + this.type = new Object[] { void.class, ctor.getParameterTypes() };
16.608 + }
16.609 + /** Create a name for the given reflected field. The resulting name will be in a resolved state.
16.610 + */
16.611 + public MemberName(Field fld) {
16.612 + this(fld, false);
16.613 + }
16.614 + @SuppressWarnings("LeakingThisInConstructor")
16.615 + public MemberName(Field fld, boolean makeSetter) {
16.616 + fld.getClass(); // NPE check
16.617 + // fill in vmtarget, vmindex while we have fld in hand:
16.618 + MethodHandleNatives.init(this, fld);
16.619 + assert(isResolved() && this.clazz != null);
16.620 + this.name = fld.getName();
16.621 + this.type = fld.getType();
16.622 + assert((REF_putStatic - REF_getStatic) == (REF_putField - REF_getField));
16.623 + byte refKind = this.getReferenceKind();
16.624 + assert(refKind == (isStatic() ? REF_getStatic : REF_getField));
16.625 + if (makeSetter) {
16.626 + changeReferenceKind((byte)(refKind + (REF_putStatic - REF_getStatic)), refKind);
16.627 + }
16.628 + }
16.629 + public boolean isGetter() {
16.630 + return MethodHandleNatives.refKindIsGetter(getReferenceKind());
16.631 + }
16.632 + public boolean isSetter() {
16.633 + return MethodHandleNatives.refKindIsSetter(getReferenceKind());
16.634 + }
16.635 + public MemberName asSetter() {
16.636 + byte refKind = getReferenceKind();
16.637 + assert(MethodHandleNatives.refKindIsGetter(refKind));
16.638 + assert((REF_putStatic - REF_getStatic) == (REF_putField - REF_getField));
16.639 + byte setterRefKind = (byte)(refKind + (REF_putField - REF_getField));
16.640 + return clone().changeReferenceKind(setterRefKind, refKind);
16.641 + }
16.642 + /** Create a name for the given class. The resulting name will be in a resolved state. */
16.643 + public MemberName(Class<?> type) {
16.644 + init(type.getDeclaringClass(), type.getSimpleName(), type,
16.645 + flagsMods(IS_TYPE, type.getModifiers(), REF_NONE));
16.646 + initResolved(true);
16.647 + }
16.648 +
16.649 + /**
16.650 + * Create a name for a signature-polymorphic invoker.
16.651 + * This is a placeholder for a signature-polymorphic instance
16.652 + * (of MH.invokeExact, etc.) that the JVM does not reify.
16.653 + * See comments on {@link MethodHandleNatives#linkMethod}.
16.654 + */
16.655 + static MemberName makeMethodHandleInvoke(String name, MethodType type) {
16.656 + return makeMethodHandleInvoke(name, type, MH_INVOKE_MODS | SYNTHETIC);
16.657 + }
16.658 + static MemberName makeMethodHandleInvoke(String name, MethodType type, int mods) {
16.659 + MemberName mem = new MemberName(MethodHandle.class, name, type, REF_invokeVirtual);
16.660 + mem.flags |= mods; // it's not resolved, but add these modifiers anyway
16.661 + assert(mem.isMethodHandleInvoke()) : mem;
16.662 + return mem;
16.663 + }
16.664 +
16.665 + // bare-bones constructor; the JVM will fill it in
16.666 + MemberName() { }
16.667 +
16.668 + // locally useful cloner
16.669 + @Override protected MemberName clone() {
16.670 + try {
16.671 + return (MemberName) super.clone();
16.672 + } catch (CloneNotSupportedException ex) {
16.673 + throw newInternalError(ex);
16.674 + }
16.675 + }
16.676 +
16.677 + /** Get the definition of this member name.
16.678 + * This may be in a super-class of the declaring class of this member.
16.679 + */
16.680 + public MemberName getDefinition() {
16.681 + if (!isResolved()) throw new IllegalStateException("must be resolved: "+this);
16.682 + if (isType()) return this;
16.683 + MemberName res = this.clone();
16.684 + res.clazz = null;
16.685 + res.type = null;
16.686 + res.name = null;
16.687 + res.resolution = res;
16.688 + res.expandFromVM();
16.689 + assert(res.getName().equals(this.getName()));
16.690 + return res;
16.691 + }
16.692 +
16.693 + @Override
16.694 + public int hashCode() {
16.695 + return Objects.hash(clazz, getReferenceKind(), name, getType());
16.696 + }
16.697 + @Override
16.698 + public boolean equals(Object that) {
16.699 + return (that instanceof MemberName && this.equals((MemberName)that));
16.700 + }
16.701 +
16.702 + /** Decide if two member names have exactly the same symbolic content.
16.703 + * Does not take into account any actual class members, so even if
16.704 + * two member names resolve to the same actual member, they may
16.705 + * be distinct references.
16.706 + */
16.707 + public boolean equals(MemberName that) {
16.708 + if (this == that) return true;
16.709 + if (that == null) return false;
16.710 + return this.clazz == that.clazz
16.711 + && this.getReferenceKind() == that.getReferenceKind()
16.712 + && Objects.equals(this.name, that.name)
16.713 + && Objects.equals(this.getType(), that.getType());
16.714 + }
16.715 +
16.716 + // Construction from symbolic parts, for queries:
16.717 + /** Create a field or type name from the given components:
16.718 + * Declaring class, name, type, reference kind.
16.719 + * The declaring class may be supplied as null if this is to be a bare name and type.
16.720 + * The resulting name will in an unresolved state.
16.721 + */
16.722 + public MemberName(Class<?> defClass, String name, Class<?> type, byte refKind) {
16.723 + init(defClass, name, type, flagsMods(IS_FIELD, 0, refKind));
16.724 + initResolved(false);
16.725 + }
16.726 + /** Create a field or type name from the given components: Declaring class, name, type.
16.727 + * The declaring class may be supplied as null if this is to be a bare name and type.
16.728 + * The modifier flags default to zero.
16.729 + * The resulting name will in an unresolved state.
16.730 + */
16.731 + public MemberName(Class<?> defClass, String name, Class<?> type, Void unused) {
16.732 + this(defClass, name, type, REF_NONE);
16.733 + initResolved(false);
16.734 + }
16.735 + /** Create a method or constructor name from the given components: Declaring class, name, type, modifiers.
16.736 + * It will be a constructor if and only if the name is {@code "<init>"}.
16.737 + * The declaring class may be supplied as null if this is to be a bare name and type.
16.738 + * The last argument is optional, a boolean which requests REF_invokeSpecial.
16.739 + * The resulting name will in an unresolved state.
16.740 + */
16.741 + public MemberName(Class<?> defClass, String name, MethodType type, byte refKind) {
16.742 + int initFlags = (name != null && name.equals(CONSTRUCTOR_NAME) ? IS_CONSTRUCTOR : IS_METHOD);
16.743 + init(defClass, name, type, flagsMods(initFlags, 0, refKind));
16.744 + initResolved(false);
16.745 + }
16.746 + /** Create a method, constructor, or field name from the given components:
16.747 + * Reference kind, declaring class, name, type.
16.748 + */
16.749 + public MemberName(byte refKind, Class<?> defClass, String name, Object type) {
16.750 + int kindFlags;
16.751 + if (MethodHandleNatives.refKindIsField(refKind)) {
16.752 + kindFlags = IS_FIELD;
16.753 + if (!(type instanceof Class))
16.754 + throw newIllegalArgumentException("not a field type");
16.755 + } else if (MethodHandleNatives.refKindIsMethod(refKind)) {
16.756 + kindFlags = IS_METHOD;
16.757 + if (!(type instanceof MethodType))
16.758 + throw newIllegalArgumentException("not a method type");
16.759 + } else if (refKind == REF_newInvokeSpecial) {
16.760 + kindFlags = IS_CONSTRUCTOR;
16.761 + if (!(type instanceof MethodType) ||
16.762 + !CONSTRUCTOR_NAME.equals(name))
16.763 + throw newIllegalArgumentException("not a constructor type or name");
16.764 + } else {
16.765 + throw newIllegalArgumentException("bad reference kind "+refKind);
16.766 + }
16.767 + init(defClass, name, type, flagsMods(kindFlags, 0, refKind));
16.768 + initResolved(false);
16.769 + }
16.770 + /** Query whether this member name is resolved to a non-static, non-final method.
16.771 + */
16.772 + public boolean hasReceiverTypeDispatch() {
16.773 + return MethodHandleNatives.refKindDoesDispatch(getReferenceKind());
16.774 + }
16.775 +
16.776 + /** Query whether this member name is resolved.
16.777 + * A resolved member name is one for which the JVM has found
16.778 + * a method, constructor, field, or type binding corresponding exactly to the name.
16.779 + * (Document?)
16.780 + */
16.781 + public boolean isResolved() {
16.782 + return resolution == null;
16.783 + }
16.784 +
16.785 + private void initResolved(boolean isResolved) {
16.786 + assert(this.resolution == null); // not initialized yet!
16.787 + if (!isResolved)
16.788 + this.resolution = this;
16.789 + assert(isResolved() == isResolved);
16.790 + }
16.791 +
16.792 + void checkForTypeAlias() {
16.793 + if (isInvocable()) {
16.794 + MethodType type;
16.795 + if (this.type instanceof MethodType)
16.796 + type = (MethodType) this.type;
16.797 + else
16.798 + this.type = type = getMethodType();
16.799 + if (type.erase() == type) return;
16.800 + if (VerifyAccess.isTypeVisible(type, clazz)) return;
16.801 + throw new LinkageError("bad method type alias: "+type+" not visible from "+clazz);
16.802 + } else {
16.803 + Class<?> type;
16.804 + if (this.type instanceof Class<?>)
16.805 + type = (Class<?>) this.type;
16.806 + else
16.807 + this.type = type = getFieldType();
16.808 + if (VerifyAccess.isTypeVisible(type, clazz)) return;
16.809 + throw new LinkageError("bad field type alias: "+type+" not visible from "+clazz);
16.810 + }
16.811 + }
16.812 +
16.813 +
16.814 + /** Produce a string form of this member name.
16.815 + * For types, it is simply the type's own string (as reported by {@code toString}).
16.816 + * For fields, it is {@code "DeclaringClass.name/type"}.
16.817 + * For methods and constructors, it is {@code "DeclaringClass.name(ptype...)rtype"}.
16.818 + * If the declaring class is null, the prefix {@code "DeclaringClass."} is omitted.
16.819 + * If the member is unresolved, a prefix {@code "*."} is prepended.
16.820 + */
16.821 + @SuppressWarnings("LocalVariableHidesMemberVariable")
16.822 + @Override
16.823 + public String toString() {
16.824 + if (isType())
16.825 + return type.toString(); // class java.lang.String
16.826 + // else it is a field, method, or constructor
16.827 + StringBuilder buf = new StringBuilder();
16.828 + if (getDeclaringClass() != null) {
16.829 + buf.append(getName(clazz));
16.830 + buf.append('.');
16.831 + }
16.832 + String name = getName();
16.833 + buf.append(name == null ? "*" : name);
16.834 + Object type = getType();
16.835 + if (!isInvocable()) {
16.836 + buf.append('/');
16.837 + buf.append(type == null ? "*" : getName(type));
16.838 + } else {
16.839 + buf.append(type == null ? "(*)*" : getName(type));
16.840 + }
16.841 + byte refKind = getReferenceKind();
16.842 + if (refKind != REF_NONE) {
16.843 + buf.append('/');
16.844 + buf.append(MethodHandleNatives.refKindName(refKind));
16.845 + }
16.846 + //buf.append("#").append(System.identityHashCode(this));
16.847 + return buf.toString();
16.848 + }
16.849 + private static String getName(Object obj) {
16.850 + if (obj instanceof Class<?>)
16.851 + return ((Class<?>)obj).getName();
16.852 + return String.valueOf(obj);
16.853 + }
16.854 +
16.855 + public IllegalAccessException makeAccessException(String message, Object from) {
16.856 + message = message + ": "+ toString();
16.857 + if (from != null) message += ", from " + from;
16.858 + return new IllegalAccessException(message);
16.859 + }
16.860 + private String message() {
16.861 + if (isResolved())
16.862 + return "no access";
16.863 + else if (isConstructor())
16.864 + return "no such constructor";
16.865 + else if (isMethod())
16.866 + return "no such method";
16.867 + else
16.868 + return "no such field";
16.869 + }
16.870 + public ReflectiveOperationException makeAccessException() {
16.871 + String message = message() + ": "+ toString();
16.872 + ReflectiveOperationException ex;
16.873 + if (isResolved() || !(resolution instanceof NoSuchMethodError ||
16.874 + resolution instanceof NoSuchFieldError))
16.875 + ex = new IllegalAccessException(message);
16.876 + else if (isConstructor())
16.877 + ex = new NoSuchMethodException(message);
16.878 + else if (isMethod())
16.879 + ex = new NoSuchMethodException(message);
16.880 + else
16.881 + ex = new NoSuchFieldException(message);
16.882 + if (resolution instanceof Throwable)
16.883 + ex.initCause((Throwable) resolution);
16.884 + return ex;
16.885 + }
16.886 +
16.887 + /** Actually making a query requires an access check. */
16.888 + /*non-public*/ static Factory getFactory() {
16.889 + return Factory.INSTANCE;
16.890 + }
16.891 + /** A factory type for resolving member names with the help of the VM.
16.892 + * TBD: Define access-safe public constructors for this factory.
16.893 + */
16.894 + /*non-public*/ static class Factory {
16.895 + private Factory() { } // singleton pattern
16.896 + static Factory INSTANCE = new Factory();
16.897 +
16.898 + private static int ALLOWED_FLAGS = ALL_KINDS;
16.899 +
16.900 + /// Queries
16.901 + List<MemberName> getMembers(Class<?> defc,
16.902 + String matchName, Object matchType,
16.903 + int matchFlags, Class<?> lookupClass) {
16.904 + matchFlags &= ALLOWED_FLAGS;
16.905 + String matchSig = null;
16.906 + if (matchType != null) {
16.907 + matchSig = BytecodeDescriptor.unparse(matchType);
16.908 + if (matchSig.startsWith("("))
16.909 + matchFlags &= ~(ALL_KINDS & ~IS_INVOCABLE);
16.910 + else
16.911 + matchFlags &= ~(ALL_KINDS & ~IS_FIELD);
16.912 + }
16.913 + final int BUF_MAX = 0x2000;
16.914 + int len1 = matchName == null ? 10 : matchType == null ? 4 : 1;
16.915 + MemberName[] buf = newMemberBuffer(len1);
16.916 + int totalCount = 0;
16.917 + ArrayList<MemberName[]> bufs = null;
16.918 + int bufCount = 0;
16.919 + for (;;) {
16.920 + bufCount = MethodHandleNatives.getMembers(defc,
16.921 + matchName, matchSig, matchFlags,
16.922 + lookupClass,
16.923 + totalCount, buf);
16.924 + if (bufCount <= buf.length) {
16.925 + if (bufCount < 0) bufCount = 0;
16.926 + totalCount += bufCount;
16.927 + break;
16.928 + }
16.929 + // JVM returned to us with an intentional overflow!
16.930 + totalCount += buf.length;
16.931 + int excess = bufCount - buf.length;
16.932 + if (bufs == null) bufs = new ArrayList<>(1);
16.933 + bufs.add(buf);
16.934 + int len2 = buf.length;
16.935 + len2 = Math.max(len2, excess);
16.936 + len2 = Math.max(len2, totalCount / 4);
16.937 + buf = newMemberBuffer(Math.min(BUF_MAX, len2));
16.938 + }
16.939 + ArrayList<MemberName> result = new ArrayList<>(totalCount);
16.940 + if (bufs != null) {
16.941 + for (MemberName[] buf0 : bufs) {
16.942 + Collections.addAll(result, buf0);
16.943 + }
16.944 + }
16.945 + result.addAll(Arrays.asList(buf).subList(0, bufCount));
16.946 + // Signature matching is not the same as type matching, since
16.947 + // one signature might correspond to several types.
16.948 + // So if matchType is a Class or MethodType, refilter the results.
16.949 + if (matchType != null && matchType != matchSig) {
16.950 + for (Iterator<MemberName> it = result.iterator(); it.hasNext();) {
16.951 + MemberName m = it.next();
16.952 + if (!matchType.equals(m.getType()))
16.953 + it.remove();
16.954 + }
16.955 + }
16.956 + return result;
16.957 + }
16.958 + /** Produce a resolved version of the given member.
16.959 + * Super types are searched (for inherited members) if {@code searchSupers} is true.
16.960 + * Access checking is performed on behalf of the given {@code lookupClass}.
16.961 + * If lookup fails or access is not permitted, null is returned.
16.962 + * Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
16.963 + */
16.964 + private MemberName resolve(byte refKind, MemberName ref, Class<?> lookupClass) {
16.965 + MemberName m = ref.clone(); // JVM will side-effect the ref
16.966 + assert(refKind == m.getReferenceKind());
16.967 + try {
16.968 + m = MethodHandleNatives.resolve(m, lookupClass);
16.969 + m.checkForTypeAlias();
16.970 + m.resolution = null;
16.971 + } catch (LinkageError ex) {
16.972 + // JVM reports that the "bytecode behavior" would get an error
16.973 + assert(!m.isResolved());
16.974 + m.resolution = ex;
16.975 + return m;
16.976 + }
16.977 + assert(m.referenceKindIsConsistent());
16.978 + m.initResolved(true);
16.979 + assert(m.vminfoIsConsistent());
16.980 + return m;
16.981 + }
16.982 + /** Produce a resolved version of the given member.
16.983 + * Super types are searched (for inherited members) if {@code searchSupers} is true.
16.984 + * Access checking is performed on behalf of the given {@code lookupClass}.
16.985 + * If lookup fails or access is not permitted, a {@linkplain ReflectiveOperationException} is thrown.
16.986 + * Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
16.987 + */
16.988 + public
16.989 + <NoSuchMemberException extends ReflectiveOperationException>
16.990 + MemberName resolveOrFail(byte refKind, MemberName m, Class<?> lookupClass,
16.991 + Class<NoSuchMemberException> nsmClass)
16.992 + throws IllegalAccessException, NoSuchMemberException {
16.993 + MemberName result = resolve(refKind, m, lookupClass);
16.994 + if (result.isResolved())
16.995 + return result;
16.996 + ReflectiveOperationException ex = result.makeAccessException();
16.997 + if (ex instanceof IllegalAccessException) throw (IllegalAccessException) ex;
16.998 + throw nsmClass.cast(ex);
16.999 + }
16.1000 + /** Produce a resolved version of the given member.
16.1001 + * Super types are searched (for inherited members) if {@code searchSupers} is true.
16.1002 + * Access checking is performed on behalf of the given {@code lookupClass}.
16.1003 + * If lookup fails or access is not permitted, return null.
16.1004 + * Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
16.1005 + */
16.1006 + public
16.1007 + MemberName resolveOrNull(byte refKind, MemberName m, Class<?> lookupClass) {
16.1008 + MemberName result = resolve(refKind, m, lookupClass);
16.1009 + if (result.isResolved())
16.1010 + return result;
16.1011 + return null;
16.1012 + }
16.1013 + /** Return a list of all methods defined by the given class.
16.1014 + * Super types are searched (for inherited members) if {@code searchSupers} is true.
16.1015 + * Access checking is performed on behalf of the given {@code lookupClass}.
16.1016 + * Inaccessible members are not added to the last.
16.1017 + */
16.1018 + public List<MemberName> getMethods(Class<?> defc, boolean searchSupers,
16.1019 + Class<?> lookupClass) {
16.1020 + return getMethods(defc, searchSupers, null, null, lookupClass);
16.1021 + }
16.1022 + /** Return a list of matching methods defined by the given class.
16.1023 + * Super types are searched (for inherited members) if {@code searchSupers} is true.
16.1024 + * Returned methods will match the name (if not null) and the type (if not null).
16.1025 + * Access checking is performed on behalf of the given {@code lookupClass}.
16.1026 + * Inaccessible members are not added to the last.
16.1027 + */
16.1028 + public List<MemberName> getMethods(Class<?> defc, boolean searchSupers,
16.1029 + String name, MethodType type, Class<?> lookupClass) {
16.1030 + int matchFlags = IS_METHOD | (searchSupers ? SEARCH_ALL_SUPERS : 0);
16.1031 + return getMembers(defc, name, type, matchFlags, lookupClass);
16.1032 + }
16.1033 + /** Return a list of all constructors defined by the given class.
16.1034 + * Access checking is performed on behalf of the given {@code lookupClass}.
16.1035 + * Inaccessible members are not added to the last.
16.1036 + */
16.1037 + public List<MemberName> getConstructors(Class<?> defc, Class<?> lookupClass) {
16.1038 + return getMembers(defc, null, null, IS_CONSTRUCTOR, lookupClass);
16.1039 + }
16.1040 + /** Return a list of all fields defined by the given class.
16.1041 + * Super types are searched (for inherited members) if {@code searchSupers} is true.
16.1042 + * Access checking is performed on behalf of the given {@code lookupClass}.
16.1043 + * Inaccessible members are not added to the last.
16.1044 + */
16.1045 + public List<MemberName> getFields(Class<?> defc, boolean searchSupers,
16.1046 + Class<?> lookupClass) {
16.1047 + return getFields(defc, searchSupers, null, null, lookupClass);
16.1048 + }
16.1049 + /** Return a list of all fields defined by the given class.
16.1050 + * Super types are searched (for inherited members) if {@code searchSupers} is true.
16.1051 + * Returned fields will match the name (if not null) and the type (if not null).
16.1052 + * Access checking is performed on behalf of the given {@code lookupClass}.
16.1053 + * Inaccessible members are not added to the last.
16.1054 + */
16.1055 + public List<MemberName> getFields(Class<?> defc, boolean searchSupers,
16.1056 + String name, Class<?> type, Class<?> lookupClass) {
16.1057 + int matchFlags = IS_FIELD | (searchSupers ? SEARCH_ALL_SUPERS : 0);
16.1058 + return getMembers(defc, name, type, matchFlags, lookupClass);
16.1059 + }
16.1060 + /** Return a list of all nested types defined by the given class.
16.1061 + * Super types are searched (for inherited members) if {@code searchSupers} is true.
16.1062 + * Access checking is performed on behalf of the given {@code lookupClass}.
16.1063 + * Inaccessible members are not added to the last.
16.1064 + */
16.1065 + public List<MemberName> getNestedTypes(Class<?> defc, boolean searchSupers,
16.1066 + Class<?> lookupClass) {
16.1067 + int matchFlags = IS_TYPE | (searchSupers ? SEARCH_ALL_SUPERS : 0);
16.1068 + return getMembers(defc, null, null, matchFlags, lookupClass);
16.1069 + }
16.1070 + private static MemberName[] newMemberBuffer(int length) {
16.1071 + MemberName[] buf = new MemberName[length];
16.1072 + // fill the buffer with dummy structs for the JVM to fill in
16.1073 + for (int i = 0; i < length; i++)
16.1074 + buf[i] = new MemberName();
16.1075 + return buf;
16.1076 + }
16.1077 + }
16.1078 +
16.1079 +// static {
16.1080 +// System.out.println("Hello world! My methods are:");
16.1081 +// System.out.println(Factory.INSTANCE.getMethods(MemberName.class, true, null));
16.1082 +// }
16.1083 +}
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
17.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/MethodHandle.java Sat Aug 09 11:12:05 2014 +0200
17.3 @@ -0,0 +1,1505 @@
17.4 +/*
17.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
17.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
17.7 + *
17.8 + * This code is free software; you can redistribute it and/or modify it
17.9 + * under the terms of the GNU General Public License version 2 only, as
17.10 + * published by the Free Software Foundation. Oracle designates this
17.11 + * particular file as subject to the "Classpath" exception as provided
17.12 + * by Oracle in the LICENSE file that accompanied this code.
17.13 + *
17.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
17.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17.17 + * version 2 for more details (a copy is included in the LICENSE file that
17.18 + * accompanied this code).
17.19 + *
17.20 + * You should have received a copy of the GNU General Public License version
17.21 + * 2 along with this work; if not, write to the Free Software Foundation,
17.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17.23 + *
17.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
17.25 + * or visit www.oracle.com if you need additional information or have any
17.26 + * questions.
17.27 + */
17.28 +
17.29 +package java.lang.invoke;
17.30 +
17.31 +
17.32 +import java.util.*;
17.33 +import sun.invoke.util.*;
17.34 +import sun.misc.Unsafe;
17.35 +
17.36 +import static java.lang.invoke.MethodHandleStatics.*;
17.37 +import java.util.logging.Level;
17.38 +import java.util.logging.Logger;
17.39 +
17.40 +/**
17.41 + * A method handle is a typed, directly executable reference to an underlying method,
17.42 + * constructor, field, or similar low-level operation, with optional
17.43 + * transformations of arguments or return values.
17.44 + * These transformations are quite general, and include such patterns as
17.45 + * {@linkplain #asType conversion},
17.46 + * {@linkplain #bindTo insertion},
17.47 + * {@linkplain java.lang.invoke.MethodHandles#dropArguments deletion},
17.48 + * and {@linkplain java.lang.invoke.MethodHandles#filterArguments substitution}.
17.49 + *
17.50 + * <h1>Method handle contents</h1>
17.51 + * Method handles are dynamically and strongly typed according to their parameter and return types.
17.52 + * They are not distinguished by the name or the defining class of their underlying methods.
17.53 + * A method handle must be invoked using a symbolic type descriptor which matches
17.54 + * the method handle's own {@linkplain #type type descriptor}.
17.55 + * <p>
17.56 + * Every method handle reports its type descriptor via the {@link #type type} accessor.
17.57 + * This type descriptor is a {@link java.lang.invoke.MethodType MethodType} object,
17.58 + * whose structure is a series of classes, one of which is
17.59 + * the return type of the method (or {@code void.class} if none).
17.60 + * <p>
17.61 + * A method handle's type controls the types of invocations it accepts,
17.62 + * and the kinds of transformations that apply to it.
17.63 + * <p>
17.64 + * A method handle contains a pair of special invoker methods
17.65 + * called {@link #invokeExact invokeExact} and {@link #invoke invoke}.
17.66 + * Both invoker methods provide direct access to the method handle's
17.67 + * underlying method, constructor, field, or other operation,
17.68 + * as modified by transformations of arguments and return values.
17.69 + * Both invokers accept calls which exactly match the method handle's own type.
17.70 + * The plain, inexact invoker also accepts a range of other call types.
17.71 + * <p>
17.72 + * Method handles are immutable and have no visible state.
17.73 + * Of course, they can be bound to underlying methods or data which exhibit state.
17.74 + * With respect to the Java Memory Model, any method handle will behave
17.75 + * as if all of its (internal) fields are final variables. This means that any method
17.76 + * handle made visible to the application will always be fully formed.
17.77 + * This is true even if the method handle is published through a shared
17.78 + * variable in a data race.
17.79 + * <p>
17.80 + * Method handles cannot be subclassed by the user.
17.81 + * Implementations may (or may not) create internal subclasses of {@code MethodHandle}
17.82 + * which may be visible via the {@link java.lang.Object#getClass Object.getClass}
17.83 + * operation. The programmer should not draw conclusions about a method handle
17.84 + * from its specific class, as the method handle class hierarchy (if any)
17.85 + * may change from time to time or across implementations from different vendors.
17.86 + *
17.87 + * <h1>Method handle compilation</h1>
17.88 + * A Java method call expression naming {@code invokeExact} or {@code invoke}
17.89 + * can invoke a method handle from Java source code.
17.90 + * From the viewpoint of source code, these methods can take any arguments
17.91 + * and their result can be cast to any return type.
17.92 + * Formally this is accomplished by giving the invoker methods
17.93 + * {@code Object} return types and variable arity {@code Object} arguments,
17.94 + * but they have an additional quality called <em>signature polymorphism</em>
17.95 + * which connects this freedom of invocation directly to the JVM execution stack.
17.96 + * <p>
17.97 + * As is usual with virtual methods, source-level calls to {@code invokeExact}
17.98 + * and {@code invoke} compile to an {@code invokevirtual} instruction.
17.99 + * More unusually, the compiler must record the actual argument types,
17.100 + * and may not perform method invocation conversions on the arguments.
17.101 + * Instead, it must push them on the stack according to their own unconverted types.
17.102 + * The method handle object itself is pushed on the stack before the arguments.
17.103 + * The compiler then calls the method handle with a symbolic type descriptor which
17.104 + * describes the argument and return types.
17.105 + * <p>
17.106 + * To issue a complete symbolic type descriptor, the compiler must also determine
17.107 + * the return type. This is based on a cast on the method invocation expression,
17.108 + * if there is one, or else {@code Object} if the invocation is an expression
17.109 + * or else {@code void} if the invocation is a statement.
17.110 + * The cast may be to a primitive type (but not {@code void}).
17.111 + * <p>
17.112 + * As a corner case, an uncasted {@code null} argument is given
17.113 + * a symbolic type descriptor of {@code java.lang.Void}.
17.114 + * The ambiguity with the type {@code Void} is harmless, since there are no references of type
17.115 + * {@code Void} except the null reference.
17.116 + *
17.117 + * <h1>Method handle invocation</h1>
17.118 + * The first time a {@code invokevirtual} instruction is executed
17.119 + * it is linked, by symbolically resolving the names in the instruction
17.120 + * and verifying that the method call is statically legal.
17.121 + * This is true of calls to {@code invokeExact} and {@code invoke}.
17.122 + * In this case, the symbolic type descriptor emitted by the compiler is checked for
17.123 + * correct syntax and names it contains are resolved.
17.124 + * Thus, an {@code invokevirtual} instruction which invokes
17.125 + * a method handle will always link, as long
17.126 + * as the symbolic type descriptor is syntactically well-formed
17.127 + * and the types exist.
17.128 + * <p>
17.129 + * When the {@code invokevirtual} is executed after linking,
17.130 + * the receiving method handle's type is first checked by the JVM
17.131 + * to ensure that it matches the symbolic type descriptor.
17.132 + * If the type match fails, it means that the method which the
17.133 + * caller is invoking is not present on the individual
17.134 + * method handle being invoked.
17.135 + * <p>
17.136 + * In the case of {@code invokeExact}, the type descriptor of the invocation
17.137 + * (after resolving symbolic type names) must exactly match the method type
17.138 + * of the receiving method handle.
17.139 + * In the case of plain, inexact {@code invoke}, the resolved type descriptor
17.140 + * must be a valid argument to the receiver's {@link #asType asType} method.
17.141 + * Thus, plain {@code invoke} is more permissive than {@code invokeExact}.
17.142 + * <p>
17.143 + * After type matching, a call to {@code invokeExact} directly
17.144 + * and immediately invoke the method handle's underlying method
17.145 + * (or other behavior, as the case may be).
17.146 + * <p>
17.147 + * A call to plain {@code invoke} works the same as a call to
17.148 + * {@code invokeExact}, if the symbolic type descriptor specified by the caller
17.149 + * exactly matches the method handle's own type.
17.150 + * If there is a type mismatch, {@code invoke} attempts
17.151 + * to adjust the type of the receiving method handle,
17.152 + * as if by a call to {@link #asType asType},
17.153 + * to obtain an exactly invokable method handle {@code M2}.
17.154 + * This allows a more powerful negotiation of method type
17.155 + * between caller and callee.
17.156 + * <p>
17.157 + * (<em>Note:</em> The adjusted method handle {@code M2} is not directly observable,
17.158 + * and implementations are therefore not required to materialize it.)
17.159 + *
17.160 + * <h1>Invocation checking</h1>
17.161 + * In typical programs, method handle type matching will usually succeed.
17.162 + * But if a match fails, the JVM will throw a {@link WrongMethodTypeException},
17.163 + * either directly (in the case of {@code invokeExact}) or indirectly as if
17.164 + * by a failed call to {@code asType} (in the case of {@code invoke}).
17.165 + * <p>
17.166 + * Thus, a method type mismatch which might show up as a linkage error
17.167 + * in a statically typed program can show up as
17.168 + * a dynamic {@code WrongMethodTypeException}
17.169 + * in a program which uses method handles.
17.170 + * <p>
17.171 + * Because method types contain "live" {@code Class} objects,
17.172 + * method type matching takes into account both types names and class loaders.
17.173 + * Thus, even if a method handle {@code M} is created in one
17.174 + * class loader {@code L1} and used in another {@code L2},
17.175 + * method handle calls are type-safe, because the caller's symbolic type
17.176 + * descriptor, as resolved in {@code L2},
17.177 + * is matched against the original callee method's symbolic type descriptor,
17.178 + * as resolved in {@code L1}.
17.179 + * The resolution in {@code L1} happens when {@code M} is created
17.180 + * and its type is assigned, while the resolution in {@code L2} happens
17.181 + * when the {@code invokevirtual} instruction is linked.
17.182 + * <p>
17.183 + * Apart from the checking of type descriptors,
17.184 + * a method handle's capability to call its underlying method is unrestricted.
17.185 + * If a method handle is formed on a non-public method by a class
17.186 + * that has access to that method, the resulting handle can be used
17.187 + * in any place by any caller who receives a reference to it.
17.188 + * <p>
17.189 + * Unlike with the Core Reflection API, where access is checked every time
17.190 + * a reflective method is invoked,
17.191 + * method handle access checking is performed
17.192 + * <a href="MethodHandles.Lookup.html#access">when the method handle is created</a>.
17.193 + * In the case of {@code ldc} (see below), access checking is performed as part of linking
17.194 + * the constant pool entry underlying the constant method handle.
17.195 + * <p>
17.196 + * Thus, handles to non-public methods, or to methods in non-public classes,
17.197 + * should generally be kept secret.
17.198 + * They should not be passed to untrusted code unless their use from
17.199 + * the untrusted code would be harmless.
17.200 + *
17.201 + * <h1>Method handle creation</h1>
17.202 + * Java code can create a method handle that directly accesses
17.203 + * any method, constructor, or field that is accessible to that code.
17.204 + * This is done via a reflective, capability-based API called
17.205 + * {@link java.lang.invoke.MethodHandles.Lookup MethodHandles.Lookup}
17.206 + * For example, a static method handle can be obtained
17.207 + * from {@link java.lang.invoke.MethodHandles.Lookup#findStatic Lookup.findStatic}.
17.208 + * There are also conversion methods from Core Reflection API objects,
17.209 + * such as {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect}.
17.210 + * <p>
17.211 + * Like classes and strings, method handles that correspond to accessible
17.212 + * fields, methods, and constructors can also be represented directly
17.213 + * in a class file's constant pool as constants to be loaded by {@code ldc} bytecodes.
17.214 + * A new type of constant pool entry, {@code CONSTANT_MethodHandle},
17.215 + * refers directly to an associated {@code CONSTANT_Methodref},
17.216 + * {@code CONSTANT_InterfaceMethodref}, or {@code CONSTANT_Fieldref}
17.217 + * constant pool entry.
17.218 + * (For full details on method handle constants,
17.219 + * see sections 4.4.8 and 5.4.3.5 of the Java Virtual Machine Specification.)
17.220 + * <p>
17.221 + * Method handles produced by lookups or constant loads from methods or
17.222 + * constructors with the variable arity modifier bit ({@code 0x0080})
17.223 + * have a corresponding variable arity, as if they were defined with
17.224 + * the help of {@link #asVarargsCollector asVarargsCollector}.
17.225 + * <p>
17.226 + * A method reference may refer either to a static or non-static method.
17.227 + * In the non-static case, the method handle type includes an explicit
17.228 + * receiver argument, prepended before any other arguments.
17.229 + * In the method handle's type, the initial receiver argument is typed
17.230 + * according to the class under which the method was initially requested.
17.231 + * (E.g., if a non-static method handle is obtained via {@code ldc},
17.232 + * the type of the receiver is the class named in the constant pool entry.)
17.233 + * <p>
17.234 + * Method handle constants are subject to the same link-time access checks
17.235 + * their corresponding bytecode instructions, and the {@code ldc} instruction
17.236 + * will throw corresponding linkage errors if the bytecode behaviors would
17.237 + * throw such errors.
17.238 + * <p>
17.239 + * As a corollary of this, access to protected members is restricted
17.240 + * to receivers only of the accessing class, or one of its subclasses,
17.241 + * and the accessing class must in turn be a subclass (or package sibling)
17.242 + * of the protected member's defining class.
17.243 + * If a method reference refers to a protected non-static method or field
17.244 + * of a class outside the current package, the receiver argument will
17.245 + * be narrowed to the type of the accessing class.
17.246 + * <p>
17.247 + * When a method handle to a virtual method is invoked, the method is
17.248 + * always looked up in the receiver (that is, the first argument).
17.249 + * <p>
17.250 + * A non-virtual method handle to a specific virtual method implementation
17.251 + * can also be created. These do not perform virtual lookup based on
17.252 + * receiver type. Such a method handle simulates the effect of
17.253 + * an {@code invokespecial} instruction to the same method.
17.254 + *
17.255 + * <h1>Usage examples</h1>
17.256 + * Here are some examples of usage:
17.257 + * <blockquote><pre>{@code
17.258 +Object x, y; String s; int i;
17.259 +MethodType mt; MethodHandle mh;
17.260 +MethodHandles.Lookup lookup = MethodHandles.lookup();
17.261 +// mt is (char,char)String
17.262 +mt = MethodType.methodType(String.class, char.class, char.class);
17.263 +mh = lookup.findVirtual(String.class, "replace", mt);
17.264 +s = (String) mh.invokeExact("daddy",'d','n');
17.265 +// invokeExact(Ljava/lang/String;CC)Ljava/lang/String;
17.266 +assertEquals(s, "nanny");
17.267 +// weakly typed invocation (using MHs.invoke)
17.268 +s = (String) mh.invokeWithArguments("sappy", 'p', 'v');
17.269 +assertEquals(s, "savvy");
17.270 +// mt is (Object[])List
17.271 +mt = MethodType.methodType(java.util.List.class, Object[].class);
17.272 +mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
17.273 +assert(mh.isVarargsCollector());
17.274 +x = mh.invoke("one", "two");
17.275 +// invoke(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
17.276 +assertEquals(x, java.util.Arrays.asList("one","two"));
17.277 +// mt is (Object,Object,Object)Object
17.278 +mt = MethodType.genericMethodType(3);
17.279 +mh = mh.asType(mt);
17.280 +x = mh.invokeExact((Object)1, (Object)2, (Object)3);
17.281 +// invokeExact(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
17.282 +assertEquals(x, java.util.Arrays.asList(1,2,3));
17.283 +// mt is ()int
17.284 +mt = MethodType.methodType(int.class);
17.285 +mh = lookup.findVirtual(java.util.List.class, "size", mt);
17.286 +i = (int) mh.invokeExact(java.util.Arrays.asList(1,2,3));
17.287 +// invokeExact(Ljava/util/List;)I
17.288 +assert(i == 3);
17.289 +mt = MethodType.methodType(void.class, String.class);
17.290 +mh = lookup.findVirtual(java.io.PrintStream.class, "println", mt);
17.291 +mh.invokeExact(System.out, "Hello, world.");
17.292 +// invokeExact(Ljava/io/PrintStream;Ljava/lang/String;)V
17.293 + * }</pre></blockquote>
17.294 + * Each of the above calls to {@code invokeExact} or plain {@code invoke}
17.295 + * generates a single invokevirtual instruction with
17.296 + * the symbolic type descriptor indicated in the following comment.
17.297 + * In these examples, the helper method {@code assertEquals} is assumed to
17.298 + * be a method which calls {@link java.util.Objects#equals(Object,Object) Objects.equals}
17.299 + * on its arguments, and asserts that the result is true.
17.300 + *
17.301 + * <h1>Exceptions</h1>
17.302 + * The methods {@code invokeExact} and {@code invoke} are declared
17.303 + * to throw {@link java.lang.Throwable Throwable},
17.304 + * which is to say that there is no static restriction on what a method handle
17.305 + * can throw. Since the JVM does not distinguish between checked
17.306 + * and unchecked exceptions (other than by their class, of course),
17.307 + * there is no particular effect on bytecode shape from ascribing
17.308 + * checked exceptions to method handle invocations. But in Java source
17.309 + * code, methods which perform method handle calls must either explicitly
17.310 + * throw {@code Throwable}, or else must catch all
17.311 + * throwables locally, rethrowing only those which are legal in the context,
17.312 + * and wrapping ones which are illegal.
17.313 + *
17.314 + * <h1><a name="sigpoly"></a>Signature polymorphism</h1>
17.315 + * The unusual compilation and linkage behavior of
17.316 + * {@code invokeExact} and plain {@code invoke}
17.317 + * is referenced by the term <em>signature polymorphism</em>.
17.318 + * As defined in the Java Language Specification,
17.319 + * a signature polymorphic method is one which can operate with
17.320 + * any of a wide range of call signatures and return types.
17.321 + * <p>
17.322 + * In source code, a call to a signature polymorphic method will
17.323 + * compile, regardless of the requested symbolic type descriptor.
17.324 + * As usual, the Java compiler emits an {@code invokevirtual}
17.325 + * instruction with the given symbolic type descriptor against the named method.
17.326 + * The unusual part is that the symbolic type descriptor is derived from
17.327 + * the actual argument and return types, not from the method declaration.
17.328 + * <p>
17.329 + * When the JVM processes bytecode containing signature polymorphic calls,
17.330 + * it will successfully link any such call, regardless of its symbolic type descriptor.
17.331 + * (In order to retain type safety, the JVM will guard such calls with suitable
17.332 + * dynamic type checks, as described elsewhere.)
17.333 + * <p>
17.334 + * Bytecode generators, including the compiler back end, are required to emit
17.335 + * untransformed symbolic type descriptors for these methods.
17.336 + * Tools which determine symbolic linkage are required to accept such
17.337 + * untransformed descriptors, without reporting linkage errors.
17.338 + *
17.339 + * <h1>Interoperation between method handles and the Core Reflection API</h1>
17.340 + * Using factory methods in the {@link java.lang.invoke.MethodHandles.Lookup Lookup} API,
17.341 + * any class member represented by a Core Reflection API object
17.342 + * can be converted to a behaviorally equivalent method handle.
17.343 + * For example, a reflective {@link java.lang.reflect.Method Method} can
17.344 + * be converted to a method handle using
17.345 + * {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect}.
17.346 + * The resulting method handles generally provide more direct and efficient
17.347 + * access to the underlying class members.
17.348 + * <p>
17.349 + * As a special case,
17.350 + * when the Core Reflection API is used to view the signature polymorphic
17.351 + * methods {@code invokeExact} or plain {@code invoke} in this class,
17.352 + * they appear as ordinary non-polymorphic methods.
17.353 + * Their reflective appearance, as viewed by
17.354 + * {@link java.lang.Class#getDeclaredMethod Class.getDeclaredMethod},
17.355 + * is unaffected by their special status in this API.
17.356 + * For example, {@link java.lang.reflect.Method#getModifiers Method.getModifiers}
17.357 + * will report exactly those modifier bits required for any similarly
17.358 + * declared method, including in this case {@code native} and {@code varargs} bits.
17.359 + * <p>
17.360 + * As with any reflected method, these methods (when reflected) may be
17.361 + * invoked via {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}.
17.362 + * However, such reflective calls do not result in method handle invocations.
17.363 + * Such a call, if passed the required argument
17.364 + * (a single one, of type {@code Object[]}), will ignore the argument and
17.365 + * will throw an {@code UnsupportedOperationException}.
17.366 + * <p>
17.367 + * Since {@code invokevirtual} instructions can natively
17.368 + * invoke method handles under any symbolic type descriptor, this reflective view conflicts
17.369 + * with the normal presentation of these methods via bytecodes.
17.370 + * Thus, these two native methods, when reflectively viewed by
17.371 + * {@code Class.getDeclaredMethod}, may be regarded as placeholders only.
17.372 + * <p>
17.373 + * In order to obtain an invoker method for a particular type descriptor,
17.374 + * use {@link java.lang.invoke.MethodHandles#exactInvoker MethodHandles.exactInvoker},
17.375 + * or {@link java.lang.invoke.MethodHandles#invoker MethodHandles.invoker}.
17.376 + * The {@link java.lang.invoke.MethodHandles.Lookup#findVirtual Lookup.findVirtual}
17.377 + * API is also able to return a method handle
17.378 + * to call {@code invokeExact} or plain {@code invoke},
17.379 + * for any specified type descriptor .
17.380 + *
17.381 + * <h1>Interoperation between method handles and Java generics</h1>
17.382 + * A method handle can be obtained on a method, constructor, or field
17.383 + * which is declared with Java generic types.
17.384 + * As with the Core Reflection API, the type of the method handle
17.385 + * will constructed from the erasure of the source-level type.
17.386 + * When a method handle is invoked, the types of its arguments
17.387 + * or the return value cast type may be generic types or type instances.
17.388 + * If this occurs, the compiler will replace those
17.389 + * types by their erasures when it constructs the symbolic type descriptor
17.390 + * for the {@code invokevirtual} instruction.
17.391 + * <p>
17.392 + * Method handles do not represent
17.393 + * their function-like types in terms of Java parameterized (generic) types,
17.394 + * because there are three mismatches between function-like types and parameterized
17.395 + * Java types.
17.396 + * <ul>
17.397 + * <li>Method types range over all possible arities,
17.398 + * from no arguments to up to the <a href="MethodHandle.html#maxarity">maximum number</a> of allowed arguments.
17.399 + * Generics are not variadic, and so cannot represent this.</li>
17.400 + * <li>Method types can specify arguments of primitive types,
17.401 + * which Java generic types cannot range over.</li>
17.402 + * <li>Higher order functions over method handles (combinators) are
17.403 + * often generic across a wide range of function types, including
17.404 + * those of multiple arities. It is impossible to represent such
17.405 + * genericity with a Java type parameter.</li>
17.406 + * </ul>
17.407 + *
17.408 + * <h1><a name="maxarity"></a>Arity limits</h1>
17.409 + * The JVM imposes on all methods and constructors of any kind an absolute
17.410 + * limit of 255 stacked arguments. This limit can appear more restrictive
17.411 + * in certain cases:
17.412 + * <ul>
17.413 + * <li>A {@code long} or {@code double} argument counts (for purposes of arity limits) as two argument slots.
17.414 + * <li>A non-static method consumes an extra argument for the object on which the method is called.
17.415 + * <li>A constructor consumes an extra argument for the object which is being constructed.
17.416 + * <li>Since a method handle’s {@code invoke} method (or other signature-polymorphic method) is non-virtual,
17.417 + * it consumes an extra argument for the method handle itself, in addition to any non-virtual receiver object.
17.418 + * </ul>
17.419 + * These limits imply that certain method handles cannot be created, solely because of the JVM limit on stacked arguments.
17.420 + * For example, if a static JVM method accepts exactly 255 arguments, a method handle cannot be created for it.
17.421 + * Attempts to create method handles with impossible method types lead to an {@link IllegalArgumentException}.
17.422 + * In particular, a method handle’s type must not have an arity of the exact maximum 255.
17.423 + *
17.424 + * @see MethodType
17.425 + * @see MethodHandles
17.426 + * @author John Rose, JSR 292 EG
17.427 + */
17.428 +public abstract class MethodHandle {
17.429 + static { MethodHandleImpl.initStatics(); }
17.430 +
17.431 + /**
17.432 + * Internal marker interface which distinguishes (to the Java compiler)
17.433 + * those methods which are <a href="MethodHandle.html#sigpoly">signature polymorphic</a>.
17.434 + */
17.435 + @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD})
17.436 + @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
17.437 + @interface PolymorphicSignature { }
17.438 +
17.439 + private final MethodType type;
17.440 + /*private*/ final LambdaForm form;
17.441 + // form is not private so that invokers can easily fetch it
17.442 + /*private*/ MethodHandle asTypeCache;
17.443 + // asTypeCache is not private so that invokers can easily fetch it
17.444 +
17.445 + /**
17.446 + * Reports the type of this method handle.
17.447 + * Every invocation of this method handle via {@code invokeExact} must exactly match this type.
17.448 + * @return the method handle type
17.449 + */
17.450 + public MethodType type() {
17.451 + return type;
17.452 + }
17.453 +
17.454 + /**
17.455 + * Package-private constructor for the method handle implementation hierarchy.
17.456 + * Method handle inheritance will be contained completely within
17.457 + * the {@code java.lang.invoke} package.
17.458 + */
17.459 + // @param type type (permanently assigned) of the new method handle
17.460 + /*non-public*/ MethodHandle(MethodType type, LambdaForm form) {
17.461 + type.getClass(); // explicit NPE
17.462 + form.getClass(); // explicit NPE
17.463 + this.type = type;
17.464 + this.form = form;
17.465 +
17.466 + form.prepare(); // TO DO: Try to delay this step until just before invocation.
17.467 + }
17.468 +
17.469 + /**
17.470 + * Invokes the method handle, allowing any caller type descriptor, but requiring an exact type match.
17.471 + * The symbolic type descriptor at the call site of {@code invokeExact} must
17.472 + * exactly match this method handle's {@link #type type}.
17.473 + * No conversions are allowed on arguments or return values.
17.474 + * <p>
17.475 + * When this method is observed via the Core Reflection API,
17.476 + * it will appear as a single native method, taking an object array and returning an object.
17.477 + * If this native method is invoked directly via
17.478 + * {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}, via JNI,
17.479 + * or indirectly via {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect},
17.480 + * it will throw an {@code UnsupportedOperationException}.
17.481 + * @param args the signature-polymorphic parameter list, statically represented using varargs
17.482 + * @return the signature-polymorphic result, statically represented using {@code Object}
17.483 + * @throws WrongMethodTypeException if the target's type is not identical with the caller's symbolic type descriptor
17.484 + * @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call
17.485 + */
17.486 + public final native @PolymorphicSignature Object invokeExact(Object... args) throws Throwable;
17.487 +
17.488 + /**
17.489 + * Invokes the method handle, allowing any caller type descriptor,
17.490 + * and optionally performing conversions on arguments and return values.
17.491 + * <p>
17.492 + * If the call site's symbolic type descriptor exactly matches this method handle's {@link #type type},
17.493 + * the call proceeds as if by {@link #invokeExact invokeExact}.
17.494 + * <p>
17.495 + * Otherwise, the call proceeds as if this method handle were first
17.496 + * adjusted by calling {@link #asType asType} to adjust this method handle
17.497 + * to the required type, and then the call proceeds as if by
17.498 + * {@link #invokeExact invokeExact} on the adjusted method handle.
17.499 + * <p>
17.500 + * There is no guarantee that the {@code asType} call is actually made.
17.501 + * If the JVM can predict the results of making the call, it may perform
17.502 + * adaptations directly on the caller's arguments,
17.503 + * and call the target method handle according to its own exact type.
17.504 + * <p>
17.505 + * The resolved type descriptor at the call site of {@code invoke} must
17.506 + * be a valid argument to the receivers {@code asType} method.
17.507 + * In particular, the caller must specify the same argument arity
17.508 + * as the callee's type,
17.509 + * if the callee is not a {@linkplain #asVarargsCollector variable arity collector}.
17.510 + * <p>
17.511 + * When this method is observed via the Core Reflection API,
17.512 + * it will appear as a single native method, taking an object array and returning an object.
17.513 + * If this native method is invoked directly via
17.514 + * {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}, via JNI,
17.515 + * or indirectly via {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect},
17.516 + * it will throw an {@code UnsupportedOperationException}.
17.517 + * @param args the signature-polymorphic parameter list, statically represented using varargs
17.518 + * @return the signature-polymorphic result, statically represented using {@code Object}
17.519 + * @throws WrongMethodTypeException if the target's type cannot be adjusted to the caller's symbolic type descriptor
17.520 + * @throws ClassCastException if the target's type can be adjusted to the caller, but a reference cast fails
17.521 + * @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call
17.522 + */
17.523 + public final native @PolymorphicSignature Object invoke(Object... args) throws Throwable;
17.524 +
17.525 + /**
17.526 + * Private method for trusted invocation of a method handle respecting simplified signatures.
17.527 + * Type mismatches will not throw {@code WrongMethodTypeException}, but could crash the JVM.
17.528 + * <p>
17.529 + * The caller signature is restricted to the following basic types:
17.530 + * Object, int, long, float, double, and void return.
17.531 + * <p>
17.532 + * The caller is responsible for maintaining type correctness by ensuring
17.533 + * that the each outgoing argument value is a member of the range of the corresponding
17.534 + * callee argument type.
17.535 + * (The caller should therefore issue appropriate casts and integer narrowing
17.536 + * operations on outgoing argument values.)
17.537 + * The caller can assume that the incoming result value is part of the range
17.538 + * of the callee's return type.
17.539 + * @param args the signature-polymorphic parameter list, statically represented using varargs
17.540 + * @return the signature-polymorphic result, statically represented using {@code Object}
17.541 + */
17.542 + /*non-public*/ final native @PolymorphicSignature Object invokeBasic(Object... args) throws Throwable;
17.543 +
17.544 + /**
17.545 + * Private method for trusted invocation of a MemberName of kind {@code REF_invokeVirtual}.
17.546 + * The caller signature is restricted to basic types as with {@code invokeBasic}.
17.547 + * The trailing (not leading) argument must be a MemberName.
17.548 + * @param args the signature-polymorphic parameter list, statically represented using varargs
17.549 + * @return the signature-polymorphic result, statically represented using {@code Object}
17.550 + */
17.551 + /*non-public*/ static native @PolymorphicSignature Object linkToVirtual(Object... args) throws Throwable;
17.552 +
17.553 + /**
17.554 + * Private method for trusted invocation of a MemberName of kind {@code REF_invokeStatic}.
17.555 + * The caller signature is restricted to basic types as with {@code invokeBasic}.
17.556 + * The trailing (not leading) argument must be a MemberName.
17.557 + * @param args the signature-polymorphic parameter list, statically represented using varargs
17.558 + * @return the signature-polymorphic result, statically represented using {@code Object}
17.559 + */
17.560 + /*non-public*/ static native @PolymorphicSignature Object linkToStatic(Object... args) throws Throwable;
17.561 +
17.562 + /**
17.563 + * Private method for trusted invocation of a MemberName of kind {@code REF_invokeSpecial}.
17.564 + * The caller signature is restricted to basic types as with {@code invokeBasic}.
17.565 + * The trailing (not leading) argument must be a MemberName.
17.566 + * @param args the signature-polymorphic parameter list, statically represented using varargs
17.567 + * @return the signature-polymorphic result, statically represented using {@code Object}
17.568 + */
17.569 + /*non-public*/ static native @PolymorphicSignature Object linkToSpecial(Object... args) throws Throwable;
17.570 +
17.571 + /**
17.572 + * Private method for trusted invocation of a MemberName of kind {@code REF_invokeInterface}.
17.573 + * The caller signature is restricted to basic types as with {@code invokeBasic}.
17.574 + * The trailing (not leading) argument must be a MemberName.
17.575 + * @param args the signature-polymorphic parameter list, statically represented using varargs
17.576 + * @return the signature-polymorphic result, statically represented using {@code Object}
17.577 + */
17.578 + /*non-public*/ static native @PolymorphicSignature Object linkToInterface(Object... args) throws Throwable;
17.579 +
17.580 + /**
17.581 + * Performs a variable arity invocation, passing the arguments in the given list
17.582 + * to the method handle, as if via an inexact {@link #invoke invoke} from a call site
17.583 + * which mentions only the type {@code Object}, and whose arity is the length
17.584 + * of the argument list.
17.585 + * <p>
17.586 + * Specifically, execution proceeds as if by the following steps,
17.587 + * although the methods are not guaranteed to be called if the JVM
17.588 + * can predict their effects.
17.589 + * <ul>
17.590 + * <li>Determine the length of the argument array as {@code N}.
17.591 + * For a null reference, {@code N=0}. </li>
17.592 + * <li>Determine the general type {@code TN} of {@code N} arguments as
17.593 + * as {@code TN=MethodType.genericMethodType(N)}.</li>
17.594 + * <li>Force the original target method handle {@code MH0} to the
17.595 + * required type, as {@code MH1 = MH0.asType(TN)}. </li>
17.596 + * <li>Spread the array into {@code N} separate arguments {@code A0, ...}. </li>
17.597 + * <li>Invoke the type-adjusted method handle on the unpacked arguments:
17.598 + * MH1.invokeExact(A0, ...). </li>
17.599 + * <li>Take the return value as an {@code Object} reference. </li>
17.600 + * </ul>
17.601 + * <p>
17.602 + * Because of the action of the {@code asType} step, the following argument
17.603 + * conversions are applied as necessary:
17.604 + * <ul>
17.605 + * <li>reference casting
17.606 + * <li>unboxing
17.607 + * <li>widening primitive conversions
17.608 + * </ul>
17.609 + * <p>
17.610 + * The result returned by the call is boxed if it is a primitive,
17.611 + * or forced to null if the return type is void.
17.612 + * <p>
17.613 + * This call is equivalent to the following code:
17.614 + * <blockquote><pre>{@code
17.615 + * MethodHandle invoker = MethodHandles.spreadInvoker(this.type(), 0);
17.616 + * Object result = invoker.invokeExact(this, arguments);
17.617 + * }</pre></blockquote>
17.618 + * <p>
17.619 + * Unlike the signature polymorphic methods {@code invokeExact} and {@code invoke},
17.620 + * {@code invokeWithArguments} can be accessed normally via the Core Reflection API and JNI.
17.621 + * It can therefore be used as a bridge between native or reflective code and method handles.
17.622 + *
17.623 + * @param arguments the arguments to pass to the target
17.624 + * @return the result returned by the target
17.625 + * @throws ClassCastException if an argument cannot be converted by reference casting
17.626 + * @throws WrongMethodTypeException if the target's type cannot be adjusted to take the given number of {@code Object} arguments
17.627 + * @throws Throwable anything thrown by the target method invocation
17.628 + * @see MethodHandles#spreadInvoker
17.629 + */
17.630 + public Object invokeWithArguments(Object... arguments) throws Throwable {
17.631 + int argc = arguments == null ? 0 : arguments.length;
17.632 + @SuppressWarnings("LocalVariableHidesMemberVariable")
17.633 + MethodType type = type();
17.634 + if (type.parameterCount() != argc || isVarargsCollector()) {
17.635 + // simulate invoke
17.636 + return asType(MethodType.genericMethodType(argc)).invokeWithArguments(arguments);
17.637 + }
17.638 + MethodHandle invoker = type.invokers().varargsInvoker();
17.639 + return invoker.invokeExact(this, arguments);
17.640 + }
17.641 +
17.642 + /**
17.643 + * Performs a variable arity invocation, passing the arguments in the given array
17.644 + * to the method handle, as if via an inexact {@link #invoke invoke} from a call site
17.645 + * which mentions only the type {@code Object}, and whose arity is the length
17.646 + * of the argument array.
17.647 + * <p>
17.648 + * This method is also equivalent to the following code:
17.649 + * <blockquote><pre>{@code
17.650 + * invokeWithArguments(arguments.toArray()
17.651 + * }</pre></blockquote>
17.652 + *
17.653 + * @param arguments the arguments to pass to the target
17.654 + * @return the result returned by the target
17.655 + * @throws NullPointerException if {@code arguments} is a null reference
17.656 + * @throws ClassCastException if an argument cannot be converted by reference casting
17.657 + * @throws WrongMethodTypeException if the target's type cannot be adjusted to take the given number of {@code Object} arguments
17.658 + * @throws Throwable anything thrown by the target method invocation
17.659 + */
17.660 + public Object invokeWithArguments(java.util.List<?> arguments) throws Throwable {
17.661 + return invokeWithArguments(arguments.toArray());
17.662 + }
17.663 +
17.664 + /**
17.665 + * Produces an adapter method handle which adapts the type of the
17.666 + * current method handle to a new type.
17.667 + * The resulting method handle is guaranteed to report a type
17.668 + * which is equal to the desired new type.
17.669 + * <p>
17.670 + * If the original type and new type are equal, returns {@code this}.
17.671 + * <p>
17.672 + * The new method handle, when invoked, will perform the following
17.673 + * steps:
17.674 + * <ul>
17.675 + * <li>Convert the incoming argument list to match the original
17.676 + * method handle's argument list.
17.677 + * <li>Invoke the original method handle on the converted argument list.
17.678 + * <li>Convert any result returned by the original method handle
17.679 + * to the return type of new method handle.
17.680 + * </ul>
17.681 + * <p>
17.682 + * This method provides the crucial behavioral difference between
17.683 + * {@link #invokeExact invokeExact} and plain, inexact {@link #invoke invoke}.
17.684 + * The two methods
17.685 + * perform the same steps when the caller's type descriptor exactly m atches
17.686 + * the callee's, but when the types differ, plain {@link #invoke invoke}
17.687 + * also calls {@code asType} (or some internal equivalent) in order
17.688 + * to match up the caller's and callee's types.
17.689 + * <p>
17.690 + * If the current method is a variable arity method handle
17.691 + * argument list conversion may involve the conversion and collection
17.692 + * of several arguments into an array, as
17.693 + * {@linkplain #asVarargsCollector described elsewhere}.
17.694 + * In every other case, all conversions are applied <em>pairwise</em>,
17.695 + * which means that each argument or return value is converted to
17.696 + * exactly one argument or return value (or no return value).
17.697 + * The applied conversions are defined by consulting the
17.698 + * the corresponding component types of the old and new
17.699 + * method handle types.
17.700 + * <p>
17.701 + * Let <em>T0</em> and <em>T1</em> be corresponding new and old parameter types,
17.702 + * or old and new return types. Specifically, for some valid index {@code i}, let
17.703 + * <em>T0</em>{@code =newType.parameterType(i)} and <em>T1</em>{@code =this.type().parameterType(i)}.
17.704 + * Or else, going the other way for return values, let
17.705 + * <em>T0</em>{@code =this.type().returnType()} and <em>T1</em>{@code =newType.returnType()}.
17.706 + * If the types are the same, the new method handle makes no change
17.707 + * to the corresponding argument or return value (if any).
17.708 + * Otherwise, one of the following conversions is applied
17.709 + * if possible:
17.710 + * <ul>
17.711 + * <li>If <em>T0</em> and <em>T1</em> are references, then a cast to <em>T1</em> is applied.
17.712 + * (The types do not need to be related in any particular way.
17.713 + * This is because a dynamic value of null can convert to any reference type.)
17.714 + * <li>If <em>T0</em> and <em>T1</em> are primitives, then a Java method invocation
17.715 + * conversion (JLS 5.3) is applied, if one exists.
17.716 + * (Specifically, <em>T0</em> must convert to <em>T1</em> by a widening primitive conversion.)
17.717 + * <li>If <em>T0</em> is a primitive and <em>T1</em> a reference,
17.718 + * a Java casting conversion (JLS 5.5) is applied if one exists.
17.719 + * (Specifically, the value is boxed from <em>T0</em> to its wrapper class,
17.720 + * which is then widened as needed to <em>T1</em>.)
17.721 + * <li>If <em>T0</em> is a reference and <em>T1</em> a primitive, an unboxing
17.722 + * conversion will be applied at runtime, possibly followed
17.723 + * by a Java method invocation conversion (JLS 5.3)
17.724 + * on the primitive value. (These are the primitive widening conversions.)
17.725 + * <em>T0</em> must be a wrapper class or a supertype of one.
17.726 + * (In the case where <em>T0</em> is Object, these are the conversions
17.727 + * allowed by {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}.)
17.728 + * The unboxing conversion must have a possibility of success, which means that
17.729 + * if <em>T0</em> is not itself a wrapper class, there must exist at least one
17.730 + * wrapper class <em>TW</em> which is a subtype of <em>T0</em> and whose unboxed
17.731 + * primitive value can be widened to <em>T1</em>.
17.732 + * <li>If the return type <em>T1</em> is marked as void, any returned value is discarded
17.733 + * <li>If the return type <em>T0</em> is void and <em>T1</em> a reference, a null value is introduced.
17.734 + * <li>If the return type <em>T0</em> is void and <em>T1</em> a primitive,
17.735 + * a zero value is introduced.
17.736 + * </ul>
17.737 + * (<em>Note:</em> Both <em>T0</em> and <em>T1</em> may be regarded as static types,
17.738 + * because neither corresponds specifically to the <em>dynamic type</em> of any
17.739 + * actual argument or return value.)
17.740 + * <p>
17.741 + * The method handle conversion cannot be made if any one of the required
17.742 + * pairwise conversions cannot be made.
17.743 + * <p>
17.744 + * At runtime, the conversions applied to reference arguments
17.745 + * or return values may require additional runtime checks which can fail.
17.746 + * An unboxing operation may fail because the original reference is null,
17.747 + * causing a {@link java.lang.NullPointerException NullPointerException}.
17.748 + * An unboxing operation or a reference cast may also fail on a reference
17.749 + * to an object of the wrong type,
17.750 + * causing a {@link java.lang.ClassCastException ClassCastException}.
17.751 + * Although an unboxing operation may accept several kinds of wrappers,
17.752 + * if none are available, a {@code ClassCastException} will be thrown.
17.753 + *
17.754 + * @param newType the expected type of the new method handle
17.755 + * @return a method handle which delegates to {@code this} after performing
17.756 + * any necessary argument conversions, and arranges for any
17.757 + * necessary return value conversions
17.758 + * @throws NullPointerException if {@code newType} is a null reference
17.759 + * @throws WrongMethodTypeException if the conversion cannot be made
17.760 + * @see MethodHandles#explicitCastArguments
17.761 + */
17.762 + public MethodHandle asType(MethodType newType) {
17.763 + // Fast path alternative to a heavyweight {@code asType} call.
17.764 + // Return 'this' if the conversion will be a no-op.
17.765 + if (newType == type) {
17.766 + return this;
17.767 + }
17.768 + // Return 'this.asTypeCache' if the conversion is already memoized.
17.769 + MethodHandle atc = asTypeCache;
17.770 + if (atc != null && newType == atc.type) {
17.771 + return atc;
17.772 + }
17.773 + return asTypeUncached(newType);
17.774 + }
17.775 +
17.776 + /** Override this to change asType behavior. */
17.777 + /*non-public*/ MethodHandle asTypeUncached(MethodType newType) {
17.778 + if (!type.isConvertibleTo(newType))
17.779 + throw new WrongMethodTypeException("cannot convert "+this+" to "+newType);
17.780 + return asTypeCache = convertArguments(newType);
17.781 + }
17.782 +
17.783 + /**
17.784 + * Makes an <em>array-spreading</em> method handle, which accepts a trailing array argument
17.785 + * and spreads its elements as positional arguments.
17.786 + * The new method handle adapts, as its <i>target</i>,
17.787 + * the current method handle. The type of the adapter will be
17.788 + * the same as the type of the target, except that the final
17.789 + * {@code arrayLength} parameters of the target's type are replaced
17.790 + * by a single array parameter of type {@code arrayType}.
17.791 + * <p>
17.792 + * If the array element type differs from any of the corresponding
17.793 + * argument types on the original target,
17.794 + * the original target is adapted to take the array elements directly,
17.795 + * as if by a call to {@link #asType asType}.
17.796 + * <p>
17.797 + * When called, the adapter replaces a trailing array argument
17.798 + * by the array's elements, each as its own argument to the target.
17.799 + * (The order of the arguments is preserved.)
17.800 + * They are converted pairwise by casting and/or unboxing
17.801 + * to the types of the trailing parameters of the target.
17.802 + * Finally the target is called.
17.803 + * What the target eventually returns is returned unchanged by the adapter.
17.804 + * <p>
17.805 + * Before calling the target, the adapter verifies that the array
17.806 + * contains exactly enough elements to provide a correct argument count
17.807 + * to the target method handle.
17.808 + * (The array may also be null when zero elements are required.)
17.809 + * <p>
17.810 + * If, when the adapter is called, the supplied array argument does
17.811 + * not have the correct number of elements, the adapter will throw
17.812 + * an {@link IllegalArgumentException} instead of invoking the target.
17.813 + * <p>
17.814 + * Here are some simple examples of array-spreading method handles:
17.815 + * <blockquote><pre>{@code
17.816 +MethodHandle equals = publicLookup()
17.817 + .findVirtual(String.class, "equals", methodType(boolean.class, Object.class));
17.818 +assert( (boolean) equals.invokeExact("me", (Object)"me"));
17.819 +assert(!(boolean) equals.invokeExact("me", (Object)"thee"));
17.820 +// spread both arguments from a 2-array:
17.821 +MethodHandle eq2 = equals.asSpreader(Object[].class, 2);
17.822 +assert( (boolean) eq2.invokeExact(new Object[]{ "me", "me" }));
17.823 +assert(!(boolean) eq2.invokeExact(new Object[]{ "me", "thee" }));
17.824 +// try to spread from anything but a 2-array:
17.825 +for (int n = 0; n <= 10; n++) {
17.826 + Object[] badArityArgs = (n == 2 ? null : new Object[n]);
17.827 + try { assert((boolean) eq2.invokeExact(badArityArgs) && false); }
17.828 + catch (IllegalArgumentException ex) { } // OK
17.829 +}
17.830 +// spread both arguments from a String array:
17.831 +MethodHandle eq2s = equals.asSpreader(String[].class, 2);
17.832 +assert( (boolean) eq2s.invokeExact(new String[]{ "me", "me" }));
17.833 +assert(!(boolean) eq2s.invokeExact(new String[]{ "me", "thee" }));
17.834 +// spread second arguments from a 1-array:
17.835 +MethodHandle eq1 = equals.asSpreader(Object[].class, 1);
17.836 +assert( (boolean) eq1.invokeExact("me", new Object[]{ "me" }));
17.837 +assert(!(boolean) eq1.invokeExact("me", new Object[]{ "thee" }));
17.838 +// spread no arguments from a 0-array or null:
17.839 +MethodHandle eq0 = equals.asSpreader(Object[].class, 0);
17.840 +assert( (boolean) eq0.invokeExact("me", (Object)"me", new Object[0]));
17.841 +assert(!(boolean) eq0.invokeExact("me", (Object)"thee", (Object[])null));
17.842 +// asSpreader and asCollector are approximate inverses:
17.843 +for (int n = 0; n <= 2; n++) {
17.844 + for (Class<?> a : new Class<?>[]{Object[].class, String[].class, CharSequence[].class}) {
17.845 + MethodHandle equals2 = equals.asSpreader(a, n).asCollector(a, n);
17.846 + assert( (boolean) equals2.invokeWithArguments("me", "me"));
17.847 + assert(!(boolean) equals2.invokeWithArguments("me", "thee"));
17.848 + }
17.849 +}
17.850 +MethodHandle caToString = publicLookup()
17.851 + .findStatic(Arrays.class, "toString", methodType(String.class, char[].class));
17.852 +assertEquals("[A, B, C]", (String) caToString.invokeExact("ABC".toCharArray()));
17.853 +MethodHandle caString3 = caToString.asCollector(char[].class, 3);
17.854 +assertEquals("[A, B, C]", (String) caString3.invokeExact('A', 'B', 'C'));
17.855 +MethodHandle caToString2 = caString3.asSpreader(char[].class, 2);
17.856 +assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray()));
17.857 + * }</pre></blockquote>
17.858 + * @param arrayType usually {@code Object[]}, the type of the array argument from which to extract the spread arguments
17.859 + * @param arrayLength the number of arguments to spread from an incoming array argument
17.860 + * @return a new method handle which spreads its final array argument,
17.861 + * before calling the original method handle
17.862 + * @throws NullPointerException if {@code arrayType} is a null reference
17.863 + * @throws IllegalArgumentException if {@code arrayType} is not an array type,
17.864 + * or if target does not have at least
17.865 + * {@code arrayLength} parameter types,
17.866 + * or if {@code arrayLength} is negative,
17.867 + * or if the resulting method handle's type would have
17.868 + * <a href="MethodHandle.html#maxarity">too many parameters</a>
17.869 + * @throws WrongMethodTypeException if the implied {@code asType} call fails
17.870 + * @see #asCollector
17.871 + */
17.872 + public MethodHandle asSpreader(Class<?> arrayType, int arrayLength) {
17.873 + asSpreaderChecks(arrayType, arrayLength);
17.874 + int spreadArgPos = type.parameterCount() - arrayLength;
17.875 + return MethodHandleImpl.makeSpreadArguments(this, arrayType, spreadArgPos, arrayLength);
17.876 + }
17.877 +
17.878 + private void asSpreaderChecks(Class<?> arrayType, int arrayLength) {
17.879 + spreadArrayChecks(arrayType, arrayLength);
17.880 + int nargs = type().parameterCount();
17.881 + if (nargs < arrayLength || arrayLength < 0)
17.882 + throw newIllegalArgumentException("bad spread array length");
17.883 + if (arrayType != Object[].class && arrayLength != 0) {
17.884 + boolean sawProblem = false;
17.885 + Class<?> arrayElement = arrayType.getComponentType();
17.886 + for (int i = nargs - arrayLength; i < nargs; i++) {
17.887 + if (!MethodType.canConvert(arrayElement, type().parameterType(i))) {
17.888 + sawProblem = true;
17.889 + break;
17.890 + }
17.891 + }
17.892 + if (sawProblem) {
17.893 + ArrayList<Class<?>> ptypes = new ArrayList<>(type().parameterList());
17.894 + for (int i = nargs - arrayLength; i < nargs; i++) {
17.895 + ptypes.set(i, arrayElement);
17.896 + }
17.897 + // elicit an error:
17.898 + this.asType(MethodType.methodType(type().returnType(), ptypes));
17.899 + }
17.900 + }
17.901 + }
17.902 +
17.903 + private void spreadArrayChecks(Class<?> arrayType, int arrayLength) {
17.904 + Class<?> arrayElement = arrayType.getComponentType();
17.905 + if (arrayElement == null)
17.906 + throw newIllegalArgumentException("not an array type", arrayType);
17.907 + if ((arrayLength & 0x7F) != arrayLength) {
17.908 + if ((arrayLength & 0xFF) != arrayLength)
17.909 + throw newIllegalArgumentException("array length is not legal", arrayLength);
17.910 + assert(arrayLength >= 128);
17.911 + if (arrayElement == long.class ||
17.912 + arrayElement == double.class)
17.913 + throw newIllegalArgumentException("array length is not legal for long[] or double[]", arrayLength);
17.914 + }
17.915 + }
17.916 +
17.917 + /**
17.918 + * Makes an <em>array-collecting</em> method handle, which accepts a given number of trailing
17.919 + * positional arguments and collects them into an array argument.
17.920 + * The new method handle adapts, as its <i>target</i>,
17.921 + * the current method handle. The type of the adapter will be
17.922 + * the same as the type of the target, except that a single trailing
17.923 + * parameter (usually of type {@code arrayType}) is replaced by
17.924 + * {@code arrayLength} parameters whose type is element type of {@code arrayType}.
17.925 + * <p>
17.926 + * If the array type differs from the final argument type on the original target,
17.927 + * the original target is adapted to take the array type directly,
17.928 + * as if by a call to {@link #asType asType}.
17.929 + * <p>
17.930 + * When called, the adapter replaces its trailing {@code arrayLength}
17.931 + * arguments by a single new array of type {@code arrayType}, whose elements
17.932 + * comprise (in order) the replaced arguments.
17.933 + * Finally the target is called.
17.934 + * What the target eventually returns is returned unchanged by the adapter.
17.935 + * <p>
17.936 + * (The array may also be a shared constant when {@code arrayLength} is zero.)
17.937 + * <p>
17.938 + * (<em>Note:</em> The {@code arrayType} is often identical to the last
17.939 + * parameter type of the original target.
17.940 + * It is an explicit argument for symmetry with {@code asSpreader}, and also
17.941 + * to allow the target to use a simple {@code Object} as its last parameter type.)
17.942 + * <p>
17.943 + * In order to create a collecting adapter which is not restricted to a particular
17.944 + * number of collected arguments, use {@link #asVarargsCollector asVarargsCollector} instead.
17.945 + * <p>
17.946 + * Here are some examples of array-collecting method handles:
17.947 + * <blockquote><pre>{@code
17.948 +MethodHandle deepToString = publicLookup()
17.949 + .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
17.950 +assertEquals("[won]", (String) deepToString.invokeExact(new Object[]{"won"}));
17.951 +MethodHandle ts1 = deepToString.asCollector(Object[].class, 1);
17.952 +assertEquals(methodType(String.class, Object.class), ts1.type());
17.953 +//assertEquals("[won]", (String) ts1.invokeExact( new Object[]{"won"})); //FAIL
17.954 +assertEquals("[[won]]", (String) ts1.invokeExact((Object) new Object[]{"won"}));
17.955 +// arrayType can be a subtype of Object[]
17.956 +MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
17.957 +assertEquals(methodType(String.class, String.class, String.class), ts2.type());
17.958 +assertEquals("[two, too]", (String) ts2.invokeExact("two", "too"));
17.959 +MethodHandle ts0 = deepToString.asCollector(Object[].class, 0);
17.960 +assertEquals("[]", (String) ts0.invokeExact());
17.961 +// collectors can be nested, Lisp-style
17.962 +MethodHandle ts22 = deepToString.asCollector(Object[].class, 3).asCollector(String[].class, 2);
17.963 +assertEquals("[A, B, [C, D]]", ((String) ts22.invokeExact((Object)'A', (Object)"B", "C", "D")));
17.964 +// arrayType can be any primitive array type
17.965 +MethodHandle bytesToString = publicLookup()
17.966 + .findStatic(Arrays.class, "toString", methodType(String.class, byte[].class))
17.967 + .asCollector(byte[].class, 3);
17.968 +assertEquals("[1, 2, 3]", (String) bytesToString.invokeExact((byte)1, (byte)2, (byte)3));
17.969 +MethodHandle longsToString = publicLookup()
17.970 + .findStatic(Arrays.class, "toString", methodType(String.class, long[].class))
17.971 + .asCollector(long[].class, 1);
17.972 +assertEquals("[123]", (String) longsToString.invokeExact((long)123));
17.973 + * }</pre></blockquote>
17.974 + * @param arrayType often {@code Object[]}, the type of the array argument which will collect the arguments
17.975 + * @param arrayLength the number of arguments to collect into a new array argument
17.976 + * @return a new method handle which collects some trailing argument
17.977 + * into an array, before calling the original method handle
17.978 + * @throws NullPointerException if {@code arrayType} is a null reference
17.979 + * @throws IllegalArgumentException if {@code arrayType} is not an array type
17.980 + * or {@code arrayType} is not assignable to this method handle's trailing parameter type,
17.981 + * or {@code arrayLength} is not a legal array size,
17.982 + * or the resulting method handle's type would have
17.983 + * <a href="MethodHandle.html#maxarity">too many parameters</a>
17.984 + * @throws WrongMethodTypeException if the implied {@code asType} call fails
17.985 + * @see #asSpreader
17.986 + * @see #asVarargsCollector
17.987 + */
17.988 + public MethodHandle asCollector(Class<?> arrayType, int arrayLength) {
17.989 + asCollectorChecks(arrayType, arrayLength);
17.990 + int collectArgPos = type().parameterCount()-1;
17.991 + MethodHandle target = this;
17.992 + if (arrayType != type().parameterType(collectArgPos))
17.993 + target = convertArguments(type().changeParameterType(collectArgPos, arrayType));
17.994 + MethodHandle collector = ValueConversions.varargsArray(arrayType, arrayLength);
17.995 + return MethodHandles.collectArguments(target, collectArgPos, collector);
17.996 + }
17.997 +
17.998 + // private API: return true if last param exactly matches arrayType
17.999 + private boolean asCollectorChecks(Class<?> arrayType, int arrayLength) {
17.1000 + spreadArrayChecks(arrayType, arrayLength);
17.1001 + int nargs = type().parameterCount();
17.1002 + if (nargs != 0) {
17.1003 + Class<?> lastParam = type().parameterType(nargs-1);
17.1004 + if (lastParam == arrayType) return true;
17.1005 + if (lastParam.isAssignableFrom(arrayType)) return false;
17.1006 + }
17.1007 + throw newIllegalArgumentException("array type not assignable to trailing argument", this, arrayType);
17.1008 + }
17.1009 +
17.1010 + /**
17.1011 + * Makes a <em>variable arity</em> adapter which is able to accept
17.1012 + * any number of trailing positional arguments and collect them
17.1013 + * into an array argument.
17.1014 + * <p>
17.1015 + * The type and behavior of the adapter will be the same as
17.1016 + * the type and behavior of the target, except that certain
17.1017 + * {@code invoke} and {@code asType} requests can lead to
17.1018 + * trailing positional arguments being collected into target's
17.1019 + * trailing parameter.
17.1020 + * Also, the last parameter type of the adapter will be
17.1021 + * {@code arrayType}, even if the target has a different
17.1022 + * last parameter type.
17.1023 + * <p>
17.1024 + * This transformation may return {@code this} if the method handle is
17.1025 + * already of variable arity and its trailing parameter type
17.1026 + * is identical to {@code arrayType}.
17.1027 + * <p>
17.1028 + * When called with {@link #invokeExact invokeExact}, the adapter invokes
17.1029 + * the target with no argument changes.
17.1030 + * (<em>Note:</em> This behavior is different from a
17.1031 + * {@linkplain #asCollector fixed arity collector},
17.1032 + * since it accepts a whole array of indeterminate length,
17.1033 + * rather than a fixed number of arguments.)
17.1034 + * <p>
17.1035 + * When called with plain, inexact {@link #invoke invoke}, if the caller
17.1036 + * type is the same as the adapter, the adapter invokes the target as with
17.1037 + * {@code invokeExact}.
17.1038 + * (This is the normal behavior for {@code invoke} when types match.)
17.1039 + * <p>
17.1040 + * Otherwise, if the caller and adapter arity are the same, and the
17.1041 + * trailing parameter type of the caller is a reference type identical to
17.1042 + * or assignable to the trailing parameter type of the adapter,
17.1043 + * the arguments and return values are converted pairwise,
17.1044 + * as if by {@link #asType asType} on a fixed arity
17.1045 + * method handle.
17.1046 + * <p>
17.1047 + * Otherwise, the arities differ, or the adapter's trailing parameter
17.1048 + * type is not assignable from the corresponding caller type.
17.1049 + * In this case, the adapter replaces all trailing arguments from
17.1050 + * the original trailing argument position onward, by
17.1051 + * a new array of type {@code arrayType}, whose elements
17.1052 + * comprise (in order) the replaced arguments.
17.1053 + * <p>
17.1054 + * The caller type must provides as least enough arguments,
17.1055 + * and of the correct type, to satisfy the target's requirement for
17.1056 + * positional arguments before the trailing array argument.
17.1057 + * Thus, the caller must supply, at a minimum, {@code N-1} arguments,
17.1058 + * where {@code N} is the arity of the target.
17.1059 + * Also, there must exist conversions from the incoming arguments
17.1060 + * to the target's arguments.
17.1061 + * As with other uses of plain {@code invoke}, if these basic
17.1062 + * requirements are not fulfilled, a {@code WrongMethodTypeException}
17.1063 + * may be thrown.
17.1064 + * <p>
17.1065 + * In all cases, what the target eventually returns is returned unchanged by the adapter.
17.1066 + * <p>
17.1067 + * In the final case, it is exactly as if the target method handle were
17.1068 + * temporarily adapted with a {@linkplain #asCollector fixed arity collector}
17.1069 + * to the arity required by the caller type.
17.1070 + * (As with {@code asCollector}, if the array length is zero,
17.1071 + * a shared constant may be used instead of a new array.
17.1072 + * If the implied call to {@code asCollector} would throw
17.1073 + * an {@code IllegalArgumentException} or {@code WrongMethodTypeException},
17.1074 + * the call to the variable arity adapter must throw
17.1075 + * {@code WrongMethodTypeException}.)
17.1076 + * <p>
17.1077 + * The behavior of {@link #asType asType} is also specialized for
17.1078 + * variable arity adapters, to maintain the invariant that
17.1079 + * plain, inexact {@code invoke} is always equivalent to an {@code asType}
17.1080 + * call to adjust the target type, followed by {@code invokeExact}.
17.1081 + * Therefore, a variable arity adapter responds
17.1082 + * to an {@code asType} request by building a fixed arity collector,
17.1083 + * if and only if the adapter and requested type differ either
17.1084 + * in arity or trailing argument type.
17.1085 + * The resulting fixed arity collector has its type further adjusted
17.1086 + * (if necessary) to the requested type by pairwise conversion,
17.1087 + * as if by another application of {@code asType}.
17.1088 + * <p>
17.1089 + * When a method handle is obtained by executing an {@code ldc} instruction
17.1090 + * of a {@code CONSTANT_MethodHandle} constant, and the target method is marked
17.1091 + * as a variable arity method (with the modifier bit {@code 0x0080}),
17.1092 + * the method handle will accept multiple arities, as if the method handle
17.1093 + * constant were created by means of a call to {@code asVarargsCollector}.
17.1094 + * <p>
17.1095 + * In order to create a collecting adapter which collects a predetermined
17.1096 + * number of arguments, and whose type reflects this predetermined number,
17.1097 + * use {@link #asCollector asCollector} instead.
17.1098 + * <p>
17.1099 + * No method handle transformations produce new method handles with
17.1100 + * variable arity, unless they are documented as doing so.
17.1101 + * Therefore, besides {@code asVarargsCollector},
17.1102 + * all methods in {@code MethodHandle} and {@code MethodHandles}
17.1103 + * will return a method handle with fixed arity,
17.1104 + * except in the cases where they are specified to return their original
17.1105 + * operand (e.g., {@code asType} of the method handle's own type).
17.1106 + * <p>
17.1107 + * Calling {@code asVarargsCollector} on a method handle which is already
17.1108 + * of variable arity will produce a method handle with the same type and behavior.
17.1109 + * It may (or may not) return the original variable arity method handle.
17.1110 + * <p>
17.1111 + * Here is an example, of a list-making variable arity method handle:
17.1112 + * <blockquote><pre>{@code
17.1113 +MethodHandle deepToString = publicLookup()
17.1114 + .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
17.1115 +MethodHandle ts1 = deepToString.asVarargsCollector(Object[].class);
17.1116 +assertEquals("[won]", (String) ts1.invokeExact( new Object[]{"won"}));
17.1117 +assertEquals("[won]", (String) ts1.invoke( new Object[]{"won"}));
17.1118 +assertEquals("[won]", (String) ts1.invoke( "won" ));
17.1119 +assertEquals("[[won]]", (String) ts1.invoke((Object) new Object[]{"won"}));
17.1120 +// findStatic of Arrays.asList(...) produces a variable arity method handle:
17.1121 +MethodHandle asList = publicLookup()
17.1122 + .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class));
17.1123 +assertEquals(methodType(List.class, Object[].class), asList.type());
17.1124 +assert(asList.isVarargsCollector());
17.1125 +assertEquals("[]", asList.invoke().toString());
17.1126 +assertEquals("[1]", asList.invoke(1).toString());
17.1127 +assertEquals("[two, too]", asList.invoke("two", "too").toString());
17.1128 +String[] argv = { "three", "thee", "tee" };
17.1129 +assertEquals("[three, thee, tee]", asList.invoke(argv).toString());
17.1130 +assertEquals("[three, thee, tee]", asList.invoke((Object[])argv).toString());
17.1131 +List ls = (List) asList.invoke((Object)argv);
17.1132 +assertEquals(1, ls.size());
17.1133 +assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0)));
17.1134 + * }</pre></blockquote>
17.1135 + * <p style="font-size:smaller;">
17.1136 + * <em>Discussion:</em>
17.1137 + * These rules are designed as a dynamically-typed variation
17.1138 + * of the Java rules for variable arity methods.
17.1139 + * In both cases, callers to a variable arity method or method handle
17.1140 + * can either pass zero or more positional arguments, or else pass
17.1141 + * pre-collected arrays of any length. Users should be aware of the
17.1142 + * special role of the final argument, and of the effect of a
17.1143 + * type match on that final argument, which determines whether
17.1144 + * or not a single trailing argument is interpreted as a whole
17.1145 + * array or a single element of an array to be collected.
17.1146 + * Note that the dynamic type of the trailing argument has no
17.1147 + * effect on this decision, only a comparison between the symbolic
17.1148 + * type descriptor of the call site and the type descriptor of the method handle.)
17.1149 + *
17.1150 + * @param arrayType often {@code Object[]}, the type of the array argument which will collect the arguments
17.1151 + * @return a new method handle which can collect any number of trailing arguments
17.1152 + * into an array, before calling the original method handle
17.1153 + * @throws NullPointerException if {@code arrayType} is a null reference
17.1154 + * @throws IllegalArgumentException if {@code arrayType} is not an array type
17.1155 + * or {@code arrayType} is not assignable to this method handle's trailing parameter type
17.1156 + * @see #asCollector
17.1157 + * @see #isVarargsCollector
17.1158 + * @see #asFixedArity
17.1159 + */
17.1160 + public MethodHandle asVarargsCollector(Class<?> arrayType) {
17.1161 + Class<?> arrayElement = arrayType.getComponentType();
17.1162 + boolean lastMatch = asCollectorChecks(arrayType, 0);
17.1163 + if (isVarargsCollector() && lastMatch)
17.1164 + return this;
17.1165 + return MethodHandleImpl.makeVarargsCollector(this, arrayType);
17.1166 + }
17.1167 +
17.1168 + /**
17.1169 + * Determines if this method handle
17.1170 + * supports {@linkplain #asVarargsCollector variable arity} calls.
17.1171 + * Such method handles arise from the following sources:
17.1172 + * <ul>
17.1173 + * <li>a call to {@linkplain #asVarargsCollector asVarargsCollector}
17.1174 + * <li>a call to a {@linkplain java.lang.invoke.MethodHandles.Lookup lookup method}
17.1175 + * which resolves to a variable arity Java method or constructor
17.1176 + * <li>an {@code ldc} instruction of a {@code CONSTANT_MethodHandle}
17.1177 + * which resolves to a variable arity Java method or constructor
17.1178 + * </ul>
17.1179 + * @return true if this method handle accepts more than one arity of plain, inexact {@code invoke} calls
17.1180 + * @see #asVarargsCollector
17.1181 + * @see #asFixedArity
17.1182 + */
17.1183 + public boolean isVarargsCollector() {
17.1184 + return false;
17.1185 + }
17.1186 +
17.1187 + /**
17.1188 + * Makes a <em>fixed arity</em> method handle which is otherwise
17.1189 + * equivalent to the current method handle.
17.1190 + * <p>
17.1191 + * If the current method handle is not of
17.1192 + * {@linkplain #asVarargsCollector variable arity},
17.1193 + * the current method handle is returned.
17.1194 + * This is true even if the current method handle
17.1195 + * could not be a valid input to {@code asVarargsCollector}.
17.1196 + * <p>
17.1197 + * Otherwise, the resulting fixed-arity method handle has the same
17.1198 + * type and behavior of the current method handle,
17.1199 + * except that {@link #isVarargsCollector isVarargsCollector}
17.1200 + * will be false.
17.1201 + * The fixed-arity method handle may (or may not) be the
17.1202 + * a previous argument to {@code asVarargsCollector}.
17.1203 + * <p>
17.1204 + * Here is an example, of a list-making variable arity method handle:
17.1205 + * <blockquote><pre>{@code
17.1206 +MethodHandle asListVar = publicLookup()
17.1207 + .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class))
17.1208 + .asVarargsCollector(Object[].class);
17.1209 +MethodHandle asListFix = asListVar.asFixedArity();
17.1210 +assertEquals("[1]", asListVar.invoke(1).toString());
17.1211 +Exception caught = null;
17.1212 +try { asListFix.invoke((Object)1); }
17.1213 +catch (Exception ex) { caught = ex; }
17.1214 +assert(caught instanceof ClassCastException);
17.1215 +assertEquals("[two, too]", asListVar.invoke("two", "too").toString());
17.1216 +try { asListFix.invoke("two", "too"); }
17.1217 +catch (Exception ex) { caught = ex; }
17.1218 +assert(caught instanceof WrongMethodTypeException);
17.1219 +Object[] argv = { "three", "thee", "tee" };
17.1220 +assertEquals("[three, thee, tee]", asListVar.invoke(argv).toString());
17.1221 +assertEquals("[three, thee, tee]", asListFix.invoke(argv).toString());
17.1222 +assertEquals(1, ((List) asListVar.invoke((Object)argv)).size());
17.1223 +assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
17.1224 + * }</pre></blockquote>
17.1225 + *
17.1226 + * @return a new method handle which accepts only a fixed number of arguments
17.1227 + * @see #asVarargsCollector
17.1228 + * @see #isVarargsCollector
17.1229 + */
17.1230 + public MethodHandle asFixedArity() {
17.1231 + assert(!isVarargsCollector());
17.1232 + return this;
17.1233 + }
17.1234 +
17.1235 + /**
17.1236 + * Binds a value {@code x} to the first argument of a method handle, without invoking it.
17.1237 + * The new method handle adapts, as its <i>target</i>,
17.1238 + * the current method handle by binding it to the given argument.
17.1239 + * The type of the bound handle will be
17.1240 + * the same as the type of the target, except that a single leading
17.1241 + * reference parameter will be omitted.
17.1242 + * <p>
17.1243 + * When called, the bound handle inserts the given value {@code x}
17.1244 + * as a new leading argument to the target. The other arguments are
17.1245 + * also passed unchanged.
17.1246 + * What the target eventually returns is returned unchanged by the bound handle.
17.1247 + * <p>
17.1248 + * The reference {@code x} must be convertible to the first parameter
17.1249 + * type of the target.
17.1250 + * <p>
17.1251 + * (<em>Note:</em> Because method handles are immutable, the target method handle
17.1252 + * retains its original type and behavior.)
17.1253 + * @param x the value to bind to the first argument of the target
17.1254 + * @return a new method handle which prepends the given value to the incoming
17.1255 + * argument list, before calling the original method handle
17.1256 + * @throws IllegalArgumentException if the target does not have a
17.1257 + * leading parameter type that is a reference type
17.1258 + * @throws ClassCastException if {@code x} cannot be converted
17.1259 + * to the leading parameter type of the target
17.1260 + * @see MethodHandles#insertArguments
17.1261 + */
17.1262 + public MethodHandle bindTo(Object x) {
17.1263 + Class<?> ptype;
17.1264 + @SuppressWarnings("LocalVariableHidesMemberVariable")
17.1265 + MethodType type = type();
17.1266 + if (type.parameterCount() == 0 ||
17.1267 + (ptype = type.parameterType(0)).isPrimitive())
17.1268 + throw newIllegalArgumentException("no leading reference parameter", x);
17.1269 + x = ptype.cast(x); // throw CCE if needed
17.1270 + return bindReceiver(x);
17.1271 + }
17.1272 +
17.1273 + /**
17.1274 + * Returns a string representation of the method handle,
17.1275 + * starting with the string {@code "MethodHandle"} and
17.1276 + * ending with the string representation of the method handle's type.
17.1277 + * In other words, this method returns a string equal to the value of:
17.1278 + * <blockquote><pre>{@code
17.1279 + * "MethodHandle" + type().toString()
17.1280 + * }</pre></blockquote>
17.1281 + * <p>
17.1282 + * (<em>Note:</em> Future releases of this API may add further information
17.1283 + * to the string representation.
17.1284 + * Therefore, the present syntax should not be parsed by applications.)
17.1285 + *
17.1286 + * @return a string representation of the method handle
17.1287 + */
17.1288 + @Override
17.1289 + public String toString() {
17.1290 + if (DEBUG_METHOD_HANDLE_NAMES) return debugString();
17.1291 + return standardString();
17.1292 + }
17.1293 + String standardString() {
17.1294 + return "MethodHandle"+type;
17.1295 + }
17.1296 + String debugString() {
17.1297 + return standardString()+"/LF="+internalForm()+internalProperties();
17.1298 + }
17.1299 +
17.1300 + //// Implementation methods.
17.1301 + //// Sub-classes can override these default implementations.
17.1302 + //// All these methods assume arguments are already validated.
17.1303 +
17.1304 + // Other transforms to do: convert, explicitCast, permute, drop, filter, fold, GWT, catch
17.1305 +
17.1306 + /*non-public*/
17.1307 + MethodHandle setVarargs(MemberName member) throws IllegalAccessException {
17.1308 + if (!member.isVarargs()) return this;
17.1309 + int argc = type().parameterCount();
17.1310 + if (argc != 0) {
17.1311 + Class<?> arrayType = type().parameterType(argc-1);
17.1312 + if (arrayType.isArray()) {
17.1313 + return MethodHandleImpl.makeVarargsCollector(this, arrayType);
17.1314 + }
17.1315 + }
17.1316 + throw member.makeAccessException("cannot make variable arity", null);
17.1317 + }
17.1318 + /*non-public*/
17.1319 + MethodHandle viewAsType(MethodType newType) {
17.1320 + // No actual conversions, just a new view of the same method.
17.1321 + return MethodHandleImpl.makePairwiseConvert(this, newType, 0);
17.1322 + }
17.1323 +
17.1324 + // Decoding
17.1325 +
17.1326 + /*non-public*/
17.1327 + LambdaForm internalForm() {
17.1328 + return form;
17.1329 + }
17.1330 +
17.1331 + /*non-public*/
17.1332 + MemberName internalMemberName() {
17.1333 + return null; // DMH returns DMH.member
17.1334 + }
17.1335 +
17.1336 + /*non-public*/
17.1337 + Class<?> internalCallerClass() {
17.1338 + return null; // caller-bound MH for @CallerSensitive method returns caller
17.1339 + }
17.1340 +
17.1341 + /*non-public*/
17.1342 + MethodHandle withInternalMemberName(MemberName member) {
17.1343 + if (member != null) {
17.1344 + return MethodHandleImpl.makeWrappedMember(this, member);
17.1345 + } else if (internalMemberName() == null) {
17.1346 + // The required internaMemberName is null, and this MH (like most) doesn't have one.
17.1347 + return this;
17.1348 + } else {
17.1349 + // The following case is rare. Mask the internalMemberName by wrapping the MH in a BMH.
17.1350 + MethodHandle result = rebind();
17.1351 + assert (result.internalMemberName() == null);
17.1352 + return result;
17.1353 + }
17.1354 + }
17.1355 +
17.1356 + /*non-public*/
17.1357 + boolean isInvokeSpecial() {
17.1358 + return false; // DMH.Special returns true
17.1359 + }
17.1360 +
17.1361 + /*non-public*/
17.1362 + Object internalValues() {
17.1363 + return null;
17.1364 + }
17.1365 +
17.1366 + /*non-public*/
17.1367 + Object internalProperties() {
17.1368 + // Override to something like "/FOO=bar"
17.1369 + return "";
17.1370 + }
17.1371 +
17.1372 + //// Method handle implementation methods.
17.1373 + //// Sub-classes can override these default implementations.
17.1374 + //// All these methods assume arguments are already validated.
17.1375 +
17.1376 + /*non-public*/ MethodHandle convertArguments(MethodType newType) {
17.1377 + // Override this if it can be improved.
17.1378 + return MethodHandleImpl.makePairwiseConvert(this, newType, 1);
17.1379 + }
17.1380 +
17.1381 + /*non-public*/
17.1382 + MethodHandle bindArgument(int pos, char basicType, Object value) {
17.1383 + // Override this if it can be improved.
17.1384 + return rebind().bindArgument(pos, basicType, value);
17.1385 + }
17.1386 +
17.1387 + /*non-public*/
17.1388 + MethodHandle bindReceiver(Object receiver) {
17.1389 + // Override this if it can be improved.
17.1390 + return bindArgument(0, 'L', receiver);
17.1391 + }
17.1392 +
17.1393 + /*non-public*/
17.1394 + MethodHandle bindImmediate(int pos, char basicType, Object value) {
17.1395 + // Bind an immediate value to a position in the arguments.
17.1396 + // This means, elide the respective argument,
17.1397 + // and replace all references to it in NamedFunction args with the specified value.
17.1398 +
17.1399 + // CURRENT RESTRICTIONS
17.1400 + // * only for pos 0 and UNSAFE (position is adjusted in MHImpl to make API usable for others)
17.1401 + assert pos == 0 && basicType == 'L' && value instanceof Unsafe;
17.1402 + MethodType type2 = type.dropParameterTypes(pos, pos + 1); // adjustment: ignore receiver!
17.1403 + LambdaForm form2 = form.bindImmediate(pos + 1, basicType, value); // adjust pos to form-relative pos
17.1404 + return copyWith(type2, form2);
17.1405 + }
17.1406 +
17.1407 + /*non-public*/
17.1408 + MethodHandle copyWith(MethodType mt, LambdaForm lf) {
17.1409 + throw new InternalError("copyWith: " + this.getClass());
17.1410 + }
17.1411 +
17.1412 + /*non-public*/
17.1413 + MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
17.1414 + // Override this if it can be improved.
17.1415 + return rebind().dropArguments(srcType, pos, drops);
17.1416 + }
17.1417 +
17.1418 + /*non-public*/
17.1419 + MethodHandle permuteArguments(MethodType newType, int[] reorder) {
17.1420 + // Override this if it can be improved.
17.1421 + return rebind().permuteArguments(newType, reorder);
17.1422 + }
17.1423 +
17.1424 + /*non-public*/
17.1425 + MethodHandle rebind() {
17.1426 + // Bind 'this' into a new invoker, of the known class BMH.
17.1427 + MethodType type2 = type();
17.1428 + LambdaForm form2 = reinvokerForm(this);
17.1429 + // form2 = lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) }
17.1430 + return BoundMethodHandle.bindSingle(type2, form2, this);
17.1431 + }
17.1432 +
17.1433 + /*non-public*/
17.1434 + MethodHandle reinvokerTarget() {
17.1435 + throw new InternalError("not a reinvoker MH: "+this.getClass().getName()+": "+this);
17.1436 + }
17.1437 +
17.1438 + /** Create a LF which simply reinvokes a target of the given basic type.
17.1439 + * The target MH must override {@link #reinvokerTarget} to provide the target.
17.1440 + */
17.1441 + static LambdaForm reinvokerForm(MethodHandle target) {
17.1442 + MethodType mtype = target.type().basicType();
17.1443 + LambdaForm reinvoker = mtype.form().cachedLambdaForm(MethodTypeForm.LF_REINVOKE);
17.1444 + if (reinvoker != null) return reinvoker;
17.1445 + if (mtype.parameterSlotCount() >= MethodType.MAX_MH_ARITY)
17.1446 + return makeReinvokerForm(target.type(), target); // cannot cache this
17.1447 + reinvoker = makeReinvokerForm(mtype, null);
17.1448 + return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_REINVOKE, reinvoker);
17.1449 + }
17.1450 + private static LambdaForm makeReinvokerForm(MethodType mtype, MethodHandle customTargetOrNull) {
17.1451 + boolean customized = (customTargetOrNull != null);
17.1452 + MethodHandle MH_invokeBasic = customized ? null : MethodHandles.basicInvoker(mtype);
17.1453 + final int THIS_BMH = 0;
17.1454 + final int ARG_BASE = 1;
17.1455 + final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
17.1456 + int nameCursor = ARG_LIMIT;
17.1457 + final int NEXT_MH = customized ? -1 : nameCursor++;
17.1458 + final int REINVOKE = nameCursor++;
17.1459 + LambdaForm.Name[] names = LambdaForm.arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
17.1460 + Object[] targetArgs;
17.1461 + MethodHandle targetMH;
17.1462 + if (customized) {
17.1463 + targetArgs = Arrays.copyOfRange(names, ARG_BASE, ARG_LIMIT, Object[].class);
17.1464 + targetMH = customTargetOrNull;
17.1465 + } else {
17.1466 + names[NEXT_MH] = new LambdaForm.Name(NF_reinvokerTarget, names[THIS_BMH]);
17.1467 + targetArgs = Arrays.copyOfRange(names, THIS_BMH, ARG_LIMIT, Object[].class);
17.1468 + targetArgs[0] = names[NEXT_MH]; // overwrite this MH with next MH
17.1469 + targetMH = MethodHandles.basicInvoker(mtype);
17.1470 + }
17.1471 + names[REINVOKE] = new LambdaForm.Name(targetMH, targetArgs);
17.1472 + return new LambdaForm("BMH.reinvoke", ARG_LIMIT, names);
17.1473 + }
17.1474 +
17.1475 + private static final LambdaForm.NamedFunction NF_reinvokerTarget;
17.1476 + static {
17.1477 + try {
17.1478 + NF_reinvokerTarget = new LambdaForm.NamedFunction(MethodHandle.class
17.1479 + .getDeclaredMethod("reinvokerTarget"));
17.1480 + } catch (ReflectiveOperationException ex) {
17.1481 + throw newInternalError(ex);
17.1482 + }
17.1483 + }
17.1484 +
17.1485 + /**
17.1486 + * Replace the old lambda form of this method handle with a new one.
17.1487 + * The new one must be functionally equivalent to the old one.
17.1488 + * Threads may continue running the old form indefinitely,
17.1489 + * but it is likely that the new one will be preferred for new executions.
17.1490 + * Use with discretion.
17.1491 + */
17.1492 + /*non-public*/
17.1493 + void updateForm(LambdaForm newForm) {
17.1494 + if (form == newForm) return;
17.1495 + // ISSUE: Should we have a memory fence here?
17.1496 + UNSAFE.putObject(this, FORM_OFFSET, newForm);
17.1497 + this.form.prepare(); // as in MethodHandle.<init>
17.1498 + }
17.1499 +
17.1500 + private static final long FORM_OFFSET;
17.1501 + static {
17.1502 + try {
17.1503 + FORM_OFFSET = UNSAFE.objectFieldOffset(MethodHandle.class.getDeclaredField("form"));
17.1504 + } catch (ReflectiveOperationException ex) {
17.1505 + throw newInternalError(ex);
17.1506 + }
17.1507 + }
17.1508 +}
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
18.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/MethodHandleImpl.java Sat Aug 09 11:12:05 2014 +0200
18.3 @@ -0,0 +1,1013 @@
18.4 +/*
18.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
18.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
18.7 + *
18.8 + * This code is free software; you can redistribute it and/or modify it
18.9 + * under the terms of the GNU General Public License version 2 only, as
18.10 + * published by the Free Software Foundation. Oracle designates this
18.11 + * particular file as subject to the "Classpath" exception as provided
18.12 + * by Oracle in the LICENSE file that accompanied this code.
18.13 + *
18.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
18.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18.17 + * version 2 for more details (a copy is included in the LICENSE file that
18.18 + * accompanied this code).
18.19 + *
18.20 + * You should have received a copy of the GNU General Public License version
18.21 + * 2 along with this work; if not, write to the Free Software Foundation,
18.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18.23 + *
18.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
18.25 + * or visit www.oracle.com if you need additional information or have any
18.26 + * questions.
18.27 + */
18.28 +
18.29 +package java.lang.invoke;
18.30 +
18.31 +import java.security.AccessController;
18.32 +import java.security.PrivilegedAction;
18.33 +import java.util.ArrayList;
18.34 +import java.util.Arrays;
18.35 +import java.util.HashMap;
18.36 +import sun.invoke.empty.Empty;
18.37 +import sun.invoke.util.ValueConversions;
18.38 +import sun.invoke.util.VerifyType;
18.39 +import sun.invoke.util.Wrapper;
18.40 +import sun.reflect.CallerSensitive;
18.41 +import sun.reflect.Reflection;
18.42 +import static java.lang.invoke.LambdaForm.*;
18.43 +import static java.lang.invoke.MethodHandleStatics.*;
18.44 +import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
18.45 +
18.46 +/**
18.47 + * Trusted implementation code for MethodHandle.
18.48 + * @author jrose
18.49 + */
18.50 +/*non-public*/ abstract class MethodHandleImpl {
18.51 + /// Factory methods to create method handles:
18.52 +
18.53 + static void initStatics() {
18.54 + // Trigger selected static initializations.
18.55 + MemberName.Factory.INSTANCE.getClass();
18.56 + }
18.57 +
18.58 + static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, boolean isSetter) {
18.59 + if (!arrayClass.isArray())
18.60 + throw newIllegalArgumentException("not an array: "+arrayClass);
18.61 + MethodHandle accessor = ArrayAccessor.getAccessor(arrayClass, isSetter);
18.62 + MethodType srcType = accessor.type().erase();
18.63 + MethodType lambdaType = srcType.invokerType();
18.64 + Name[] names = arguments(1, lambdaType);
18.65 + Name[] args = Arrays.copyOfRange(names, 1, 1 + srcType.parameterCount());
18.66 + names[names.length - 1] = new Name(accessor.asType(srcType), (Object[]) args);
18.67 + LambdaForm form = new LambdaForm("getElement", lambdaType.parameterCount(), names);
18.68 + MethodHandle mh = SimpleMethodHandle.make(srcType, form);
18.69 + if (ArrayAccessor.needCast(arrayClass)) {
18.70 + mh = mh.bindTo(arrayClass);
18.71 + }
18.72 + mh = mh.asType(ArrayAccessor.correctType(arrayClass, isSetter));
18.73 + return mh;
18.74 + }
18.75 +
18.76 + static final class ArrayAccessor {
18.77 + /// Support for array element access
18.78 + static final HashMap<Class<?>, MethodHandle> GETTER_CACHE = new HashMap<>(); // TODO use it
18.79 + static final HashMap<Class<?>, MethodHandle> SETTER_CACHE = new HashMap<>(); // TODO use it
18.80 +
18.81 + static int getElementI(int[] a, int i) { return a[i]; }
18.82 + static long getElementJ(long[] a, int i) { return a[i]; }
18.83 + static float getElementF(float[] a, int i) { return a[i]; }
18.84 + static double getElementD(double[] a, int i) { return a[i]; }
18.85 + static boolean getElementZ(boolean[] a, int i) { return a[i]; }
18.86 + static byte getElementB(byte[] a, int i) { return a[i]; }
18.87 + static short getElementS(short[] a, int i) { return a[i]; }
18.88 + static char getElementC(char[] a, int i) { return a[i]; }
18.89 + static Object getElementL(Object[] a, int i) { return a[i]; }
18.90 +
18.91 + static void setElementI(int[] a, int i, int x) { a[i] = x; }
18.92 + static void setElementJ(long[] a, int i, long x) { a[i] = x; }
18.93 + static void setElementF(float[] a, int i, float x) { a[i] = x; }
18.94 + static void setElementD(double[] a, int i, double x) { a[i] = x; }
18.95 + static void setElementZ(boolean[] a, int i, boolean x) { a[i] = x; }
18.96 + static void setElementB(byte[] a, int i, byte x) { a[i] = x; }
18.97 + static void setElementS(short[] a, int i, short x) { a[i] = x; }
18.98 + static void setElementC(char[] a, int i, char x) { a[i] = x; }
18.99 + static void setElementL(Object[] a, int i, Object x) { a[i] = x; }
18.100 +
18.101 + static Object getElementL(Class<?> arrayClass, Object[] a, int i) { arrayClass.cast(a); return a[i]; }
18.102 + static void setElementL(Class<?> arrayClass, Object[] a, int i, Object x) { arrayClass.cast(a); a[i] = x; }
18.103 +
18.104 + // Weakly typed wrappers of Object[] accessors:
18.105 + static Object getElementL(Object a, int i) { return getElementL((Object[])a, i); }
18.106 + static void setElementL(Object a, int i, Object x) { setElementL((Object[]) a, i, x); }
18.107 + static Object getElementL(Object arrayClass, Object a, int i) { return getElementL((Class<?>) arrayClass, (Object[])a, i); }
18.108 + static void setElementL(Object arrayClass, Object a, int i, Object x) { setElementL((Class<?>) arrayClass, (Object[])a, i, x); }
18.109 +
18.110 + static boolean needCast(Class<?> arrayClass) {
18.111 + Class<?> elemClass = arrayClass.getComponentType();
18.112 + return !elemClass.isPrimitive() && elemClass != Object.class;
18.113 + }
18.114 + static String name(Class<?> arrayClass, boolean isSetter) {
18.115 + Class<?> elemClass = arrayClass.getComponentType();
18.116 + if (elemClass == null) throw new IllegalArgumentException();
18.117 + return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(elemClass);
18.118 + }
18.119 + static final boolean USE_WEAKLY_TYPED_ARRAY_ACCESSORS = false; // FIXME: decide
18.120 + static MethodType type(Class<?> arrayClass, boolean isSetter) {
18.121 + Class<?> elemClass = arrayClass.getComponentType();
18.122 + Class<?> arrayArgClass = arrayClass;
18.123 + if (!elemClass.isPrimitive()) {
18.124 + arrayArgClass = Object[].class;
18.125 + if (USE_WEAKLY_TYPED_ARRAY_ACCESSORS)
18.126 + arrayArgClass = Object.class;
18.127 + }
18.128 + if (!needCast(arrayClass)) {
18.129 + return !isSetter ?
18.130 + MethodType.methodType(elemClass, arrayArgClass, int.class) :
18.131 + MethodType.methodType(void.class, arrayArgClass, int.class, elemClass);
18.132 + } else {
18.133 + Class<?> classArgClass = Class.class;
18.134 + if (USE_WEAKLY_TYPED_ARRAY_ACCESSORS)
18.135 + classArgClass = Object.class;
18.136 + return !isSetter ?
18.137 + MethodType.methodType(Object.class, classArgClass, arrayArgClass, int.class) :
18.138 + MethodType.methodType(void.class, classArgClass, arrayArgClass, int.class, Object.class);
18.139 + }
18.140 + }
18.141 + static MethodType correctType(Class<?> arrayClass, boolean isSetter) {
18.142 + Class<?> elemClass = arrayClass.getComponentType();
18.143 + return !isSetter ?
18.144 + MethodType.methodType(elemClass, arrayClass, int.class) :
18.145 + MethodType.methodType(void.class, arrayClass, int.class, elemClass);
18.146 + }
18.147 + static MethodHandle getAccessor(Class<?> arrayClass, boolean isSetter) {
18.148 + String name = name(arrayClass, isSetter);
18.149 + MethodType type = type(arrayClass, isSetter);
18.150 + try {
18.151 + return IMPL_LOOKUP.findStatic(ArrayAccessor.class, name, type);
18.152 + } catch (ReflectiveOperationException ex) {
18.153 + throw uncaughtException(ex);
18.154 + }
18.155 + }
18.156 + }
18.157 +
18.158 + /**
18.159 + * Create a JVM-level adapter method handle to conform the given method
18.160 + * handle to the similar newType, using only pairwise argument conversions.
18.161 + * For each argument, convert incoming argument to the exact type needed.
18.162 + * The argument conversions allowed are casting, boxing and unboxing,
18.163 + * integral widening or narrowing, and floating point widening or narrowing.
18.164 + * @param srcType required call type
18.165 + * @param target original method handle
18.166 + * @param level which strength of conversion is allowed
18.167 + * @return an adapter to the original handle with the desired new type,
18.168 + * or the original target if the types are already identical
18.169 + * or null if the adaptation cannot be made
18.170 + */
18.171 + static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, int level) {
18.172 + assert(level >= 0 && level <= 2);
18.173 + MethodType dstType = target.type();
18.174 + assert(dstType.parameterCount() == target.type().parameterCount());
18.175 + if (srcType == dstType)
18.176 + return target;
18.177 +
18.178 + // Calculate extra arguments (temporaries) required in the names array.
18.179 + // FIXME: Use an ArrayList<Name>. Some arguments require more than one conversion step.
18.180 + final int INARG_COUNT = srcType.parameterCount();
18.181 + int conversions = 0;
18.182 + boolean[] needConv = new boolean[1+INARG_COUNT];
18.183 + for (int i = 0; i <= INARG_COUNT; i++) {
18.184 + Class<?> src = (i == INARG_COUNT) ? dstType.returnType() : srcType.parameterType(i);
18.185 + Class<?> dst = (i == INARG_COUNT) ? srcType.returnType() : dstType.parameterType(i);
18.186 + if (!VerifyType.isNullConversion(src, dst) ||
18.187 + level <= 1 && dst.isInterface() && !dst.isAssignableFrom(src)) {
18.188 + needConv[i] = true;
18.189 + conversions++;
18.190 + }
18.191 + }
18.192 + boolean retConv = needConv[INARG_COUNT];
18.193 +
18.194 + final int IN_MH = 0;
18.195 + final int INARG_BASE = 1;
18.196 + final int INARG_LIMIT = INARG_BASE + INARG_COUNT;
18.197 + final int NAME_LIMIT = INARG_LIMIT + conversions + 1;
18.198 + final int RETURN_CONV = (!retConv ? -1 : NAME_LIMIT - 1);
18.199 + final int OUT_CALL = (!retConv ? NAME_LIMIT : RETURN_CONV) - 1;
18.200 +
18.201 + // Now build a LambdaForm.
18.202 + MethodType lambdaType = srcType.basicType().invokerType();
18.203 + Name[] names = arguments(NAME_LIMIT - INARG_LIMIT, lambdaType);
18.204 +
18.205 + // Collect the arguments to the outgoing call, maybe with conversions:
18.206 + final int OUTARG_BASE = 0; // target MH is Name.function, name Name.arguments[0]
18.207 + Object[] outArgs = new Object[OUTARG_BASE + INARG_COUNT];
18.208 +
18.209 + int nameCursor = INARG_LIMIT;
18.210 + for (int i = 0; i < INARG_COUNT; i++) {
18.211 + Class<?> src = srcType.parameterType(i);
18.212 + Class<?> dst = dstType.parameterType(i);
18.213 +
18.214 + if (!needConv[i]) {
18.215 + // do nothing: difference is trivial
18.216 + outArgs[OUTARG_BASE + i] = names[INARG_BASE + i];
18.217 + continue;
18.218 + }
18.219 +
18.220 + // Tricky case analysis follows.
18.221 + MethodHandle fn = null;
18.222 + if (src.isPrimitive()) {
18.223 + if (dst.isPrimitive()) {
18.224 + fn = ValueConversions.convertPrimitive(src, dst);
18.225 + } else {
18.226 + Wrapper w = Wrapper.forPrimitiveType(src);
18.227 + MethodHandle boxMethod = ValueConversions.box(w);
18.228 + if (dst == w.wrapperType())
18.229 + fn = boxMethod;
18.230 + else
18.231 + fn = boxMethod.asType(MethodType.methodType(dst, src));
18.232 + }
18.233 + } else {
18.234 + if (dst.isPrimitive()) {
18.235 + // Caller has boxed a primitive. Unbox it for the target.
18.236 + Wrapper w = Wrapper.forPrimitiveType(dst);
18.237 + if (level == 0 || VerifyType.isNullConversion(src, w.wrapperType())) {
18.238 + fn = ValueConversions.unbox(dst);
18.239 + } else if (src == Object.class || !Wrapper.isWrapperType(src)) {
18.240 + // Examples: Object->int, Number->int, Comparable->int; Byte->int, Character->int
18.241 + // must include additional conversions
18.242 + // src must be examined at runtime, to detect Byte, Character, etc.
18.243 + MethodHandle unboxMethod = (level == 1
18.244 + ? ValueConversions.unbox(dst)
18.245 + : ValueConversions.unboxCast(dst));
18.246 + fn = unboxMethod;
18.247 + } else {
18.248 + // Example: Byte->int
18.249 + // Do this by reformulating the problem to Byte->byte.
18.250 + Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType();
18.251 + MethodHandle unbox = ValueConversions.unbox(srcPrim);
18.252 + // Compose the two conversions. FIXME: should make two Names for this job
18.253 + fn = unbox.asType(MethodType.methodType(dst, src));
18.254 + }
18.255 + } else {
18.256 + // Simple reference conversion.
18.257 + // Note: Do not check for a class hierarchy relation
18.258 + // between src and dst. In all cases a 'null' argument
18.259 + // will pass the cast conversion.
18.260 + fn = ValueConversions.cast(dst);
18.261 + }
18.262 + }
18.263 + Name conv = new Name(fn, names[INARG_BASE + i]);
18.264 + assert(names[nameCursor] == null);
18.265 + names[nameCursor++] = conv;
18.266 + assert(outArgs[OUTARG_BASE + i] == null);
18.267 + outArgs[OUTARG_BASE + i] = conv;
18.268 + }
18.269 +
18.270 + // Build argument array for the call.
18.271 + assert(nameCursor == OUT_CALL);
18.272 + names[OUT_CALL] = new Name(target, outArgs);
18.273 +
18.274 + if (RETURN_CONV < 0) {
18.275 + assert(OUT_CALL == names.length-1);
18.276 + } else {
18.277 + Class<?> needReturn = srcType.returnType();
18.278 + Class<?> haveReturn = dstType.returnType();
18.279 + MethodHandle fn;
18.280 + Object[] arg = { names[OUT_CALL] };
18.281 + if (haveReturn == void.class) {
18.282 + // synthesize a zero value for the given void
18.283 + Object zero = Wrapper.forBasicType(needReturn).zero();
18.284 + fn = MethodHandles.constant(needReturn, zero);
18.285 + arg = new Object[0]; // don't pass names[OUT_CALL] to conversion
18.286 + } else {
18.287 + MethodHandle identity = MethodHandles.identity(needReturn);
18.288 + MethodType needConversion = identity.type().changeParameterType(0, haveReturn);
18.289 + fn = makePairwiseConvert(identity, needConversion, level);
18.290 + }
18.291 + assert(names[RETURN_CONV] == null);
18.292 + names[RETURN_CONV] = new Name(fn, arg);
18.293 + assert(RETURN_CONV == names.length-1);
18.294 + }
18.295 +
18.296 + LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names);
18.297 + return SimpleMethodHandle.make(srcType, form);
18.298 + }
18.299 +
18.300 + static MethodHandle makeReferenceIdentity(Class<?> refType) {
18.301 + MethodType lambdaType = MethodType.genericMethodType(1).invokerType();
18.302 + Name[] names = arguments(1, lambdaType);
18.303 + names[names.length - 1] = new Name(ValueConversions.identity(), names[1]);
18.304 + LambdaForm form = new LambdaForm("identity", lambdaType.parameterCount(), names);
18.305 + return SimpleMethodHandle.make(MethodType.methodType(refType, refType), form);
18.306 + }
18.307 +
18.308 + static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
18.309 + MethodType type = target.type();
18.310 + int last = type.parameterCount() - 1;
18.311 + if (type.parameterType(last) != arrayType)
18.312 + target = target.asType(type.changeParameterType(last, arrayType));
18.313 + target = target.asFixedArity(); // make sure this attribute is turned off
18.314 + return new AsVarargsCollector(target, target.type(), arrayType);
18.315 + }
18.316 +
18.317 + static class AsVarargsCollector extends MethodHandle {
18.318 + private final MethodHandle target;
18.319 + private final Class<?> arrayType;
18.320 + private /*@Stable*/ MethodHandle asCollectorCache;
18.321 +
18.322 + AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) {
18.323 + super(type, reinvokerForm(target));
18.324 + this.target = target;
18.325 + this.arrayType = arrayType;
18.326 + this.asCollectorCache = target.asCollector(arrayType, 0);
18.327 + }
18.328 +
18.329 + @Override MethodHandle reinvokerTarget() { return target; }
18.330 +
18.331 + @Override
18.332 + public boolean isVarargsCollector() {
18.333 + return true;
18.334 + }
18.335 +
18.336 + @Override
18.337 + public MethodHandle asFixedArity() {
18.338 + return target;
18.339 + }
18.340 +
18.341 + @Override
18.342 + public MethodHandle asTypeUncached(MethodType newType) {
18.343 + MethodType type = this.type();
18.344 + int collectArg = type.parameterCount() - 1;
18.345 + int newArity = newType.parameterCount();
18.346 + if (newArity == collectArg+1 &&
18.347 + type.parameterType(collectArg).isAssignableFrom(newType.parameterType(collectArg))) {
18.348 + // if arity and trailing parameter are compatible, do normal thing
18.349 + return asTypeCache = asFixedArity().asType(newType);
18.350 + }
18.351 + // check cache
18.352 + MethodHandle acc = asCollectorCache;
18.353 + if (acc != null && acc.type().parameterCount() == newArity)
18.354 + return asTypeCache = acc.asType(newType);
18.355 + // build and cache a collector
18.356 + int arrayLength = newArity - collectArg;
18.357 + MethodHandle collector;
18.358 + try {
18.359 + collector = asFixedArity().asCollector(arrayType, arrayLength);
18.360 + assert(collector.type().parameterCount() == newArity) : "newArity="+newArity+" but collector="+collector;
18.361 + } catch (IllegalArgumentException ex) {
18.362 + throw new WrongMethodTypeException("cannot build collector", ex);
18.363 + }
18.364 + asCollectorCache = collector;
18.365 + return asTypeCache = collector.asType(newType);
18.366 + }
18.367 +
18.368 + @Override
18.369 + MethodHandle setVarargs(MemberName member) {
18.370 + if (member.isVarargs()) return this;
18.371 + return asFixedArity();
18.372 + }
18.373 +
18.374 + @Override
18.375 + MethodHandle viewAsType(MethodType newType) {
18.376 + if (newType.lastParameterType() != type().lastParameterType())
18.377 + throw new InternalError();
18.378 + MethodHandle newTarget = asFixedArity().viewAsType(newType);
18.379 + // put back the varargs bit:
18.380 + return new AsVarargsCollector(newTarget, newType, arrayType);
18.381 + }
18.382 +
18.383 + @Override
18.384 + MemberName internalMemberName() {
18.385 + return asFixedArity().internalMemberName();
18.386 + }
18.387 + @Override
18.388 + Class<?> internalCallerClass() {
18.389 + return asFixedArity().internalCallerClass();
18.390 + }
18.391 +
18.392 + /*non-public*/
18.393 + @Override
18.394 + boolean isInvokeSpecial() {
18.395 + return asFixedArity().isInvokeSpecial();
18.396 + }
18.397 +
18.398 +
18.399 + @Override
18.400 + MethodHandle bindArgument(int pos, char basicType, Object value) {
18.401 + return asFixedArity().bindArgument(pos, basicType, value);
18.402 + }
18.403 +
18.404 + @Override
18.405 + MethodHandle bindReceiver(Object receiver) {
18.406 + return asFixedArity().bindReceiver(receiver);
18.407 + }
18.408 +
18.409 + @Override
18.410 + MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
18.411 + return asFixedArity().dropArguments(srcType, pos, drops);
18.412 + }
18.413 +
18.414 + @Override
18.415 + MethodHandle permuteArguments(MethodType newType, int[] reorder) {
18.416 + return asFixedArity().permuteArguments(newType, reorder);
18.417 + }
18.418 + }
18.419 +
18.420 + /** Factory method: Spread selected argument. */
18.421 + static MethodHandle makeSpreadArguments(MethodHandle target,
18.422 + Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
18.423 + MethodType targetType = target.type();
18.424 +
18.425 + for (int i = 0; i < spreadArgCount; i++) {
18.426 + Class<?> arg = VerifyType.spreadArgElementType(spreadArgType, i);
18.427 + if (arg == null) arg = Object.class;
18.428 + targetType = targetType.changeParameterType(spreadArgPos + i, arg);
18.429 + }
18.430 + target = target.asType(targetType);
18.431 +
18.432 + MethodType srcType = targetType
18.433 + .replaceParameterTypes(spreadArgPos, spreadArgPos + spreadArgCount, spreadArgType);
18.434 + // Now build a LambdaForm.
18.435 + MethodType lambdaType = srcType.invokerType();
18.436 + Name[] names = arguments(spreadArgCount + 2, lambdaType);
18.437 + int nameCursor = lambdaType.parameterCount();
18.438 + int[] indexes = new int[targetType.parameterCount()];
18.439 +
18.440 + for (int i = 0, argIndex = 1; i < targetType.parameterCount() + 1; i++, argIndex++) {
18.441 + Class<?> src = lambdaType.parameterType(i);
18.442 + if (i == spreadArgPos) {
18.443 + // Spread the array.
18.444 + MethodHandle aload = MethodHandles.arrayElementGetter(spreadArgType);
18.445 + Name array = names[argIndex];
18.446 + names[nameCursor++] = new Name(Lazy.NF_checkSpreadArgument, array, spreadArgCount);
18.447 + for (int j = 0; j < spreadArgCount; i++, j++) {
18.448 + indexes[i] = nameCursor;
18.449 + names[nameCursor++] = new Name(aload, array, j);
18.450 + }
18.451 + } else if (i < indexes.length) {
18.452 + indexes[i] = argIndex;
18.453 + }
18.454 + }
18.455 + assert(nameCursor == names.length-1); // leave room for the final call
18.456 +
18.457 + // Build argument array for the call.
18.458 + Name[] targetArgs = new Name[targetType.parameterCount()];
18.459 + for (int i = 0; i < targetType.parameterCount(); i++) {
18.460 + int idx = indexes[i];
18.461 + targetArgs[i] = names[idx];
18.462 + }
18.463 + names[names.length - 1] = new Name(target, (Object[]) targetArgs);
18.464 +
18.465 + LambdaForm form = new LambdaForm("spread", lambdaType.parameterCount(), names);
18.466 + return SimpleMethodHandle.make(srcType, form);
18.467 + }
18.468 +
18.469 + static void checkSpreadArgument(Object av, int n) {
18.470 + if (av == null) {
18.471 + if (n == 0) return;
18.472 + } else if (av instanceof Object[]) {
18.473 + int len = ((Object[])av).length;
18.474 + if (len == n) return;
18.475 + } else {
18.476 + int len = java.lang.reflect.Array.getLength(av);
18.477 + if (len == n) return;
18.478 + }
18.479 + // fall through to error:
18.480 + throw newIllegalArgumentException("array is not of length "+n);
18.481 + }
18.482 +
18.483 + /**
18.484 + * Pre-initialized NamedFunctions for bootstrapping purposes.
18.485 + * Factored in an inner class to delay initialization until first usage.
18.486 + */
18.487 + private static class Lazy {
18.488 + static final NamedFunction NF_checkSpreadArgument;
18.489 + static {
18.490 + try {
18.491 + NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class
18.492 + .getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
18.493 + NF_checkSpreadArgument.resolve();
18.494 + } catch (ReflectiveOperationException ex) {
18.495 + throw newInternalError(ex);
18.496 + }
18.497 + }
18.498 + }
18.499 +
18.500 + /** Factory method: Collect or filter selected argument(s). */
18.501 + static MethodHandle makeCollectArguments(MethodHandle target,
18.502 + MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) {
18.503 + MethodType targetType = target.type(); // (a..., c, [b...])=>r
18.504 + MethodType collectorType = collector.type(); // (b...)=>c
18.505 + int collectArgCount = collectorType.parameterCount();
18.506 + Class<?> collectValType = collectorType.returnType();
18.507 + int collectValCount = (collectValType == void.class ? 0 : 1);
18.508 + MethodType srcType = targetType // (a..., [b...])=>r
18.509 + .dropParameterTypes(collectArgPos, collectArgPos+collectValCount);
18.510 + if (!retainOriginalArgs) { // (a..., b...)=>r
18.511 + srcType = srcType.insertParameterTypes(collectArgPos, collectorType.parameterList());
18.512 + }
18.513 + // in arglist: [0: ...keep1 | cpos: collect... | cpos+cacount: keep2... ]
18.514 + // out arglist: [0: ...keep1 | cpos: collectVal? | cpos+cvcount: keep2... ]
18.515 + // out(retain): [0: ...keep1 | cpos: cV? coll... | cpos+cvc+cac: keep2... ]
18.516 +
18.517 + // Now build a LambdaForm.
18.518 + MethodType lambdaType = srcType.invokerType();
18.519 + Name[] names = arguments(2, lambdaType);
18.520 + final int collectNamePos = names.length - 2;
18.521 + final int targetNamePos = names.length - 1;
18.522 +
18.523 + Name[] collectorArgs = Arrays.copyOfRange(names, 1 + collectArgPos, 1 + collectArgPos + collectArgCount);
18.524 + names[collectNamePos] = new Name(collector, (Object[]) collectorArgs);
18.525 +
18.526 + // Build argument array for the target.
18.527 + // Incoming LF args to copy are: [ (mh) headArgs collectArgs tailArgs ].
18.528 + // Output argument array is [ headArgs (collectVal)? (collectArgs)? tailArgs ].
18.529 + Name[] targetArgs = new Name[targetType.parameterCount()];
18.530 + int inputArgPos = 1; // incoming LF args to copy to target
18.531 + int targetArgPos = 0; // fill pointer for targetArgs
18.532 + int chunk = collectArgPos; // |headArgs|
18.533 + System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk);
18.534 + inputArgPos += chunk;
18.535 + targetArgPos += chunk;
18.536 + if (collectValType != void.class) {
18.537 + targetArgs[targetArgPos++] = names[collectNamePos];
18.538 + }
18.539 + chunk = collectArgCount;
18.540 + if (retainOriginalArgs) {
18.541 + System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk);
18.542 + targetArgPos += chunk; // optionally pass on the collected chunk
18.543 + }
18.544 + inputArgPos += chunk;
18.545 + chunk = targetArgs.length - targetArgPos; // all the rest
18.546 + System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk);
18.547 + assert(inputArgPos + chunk == collectNamePos); // use of rest of input args also
18.548 + names[targetNamePos] = new Name(target, (Object[]) targetArgs);
18.549 +
18.550 + LambdaForm form = new LambdaForm("collect", lambdaType.parameterCount(), names);
18.551 + return SimpleMethodHandle.make(srcType, form);
18.552 + }
18.553 +
18.554 + static
18.555 + MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) {
18.556 + return testResult ? target : fallback;
18.557 + }
18.558 +
18.559 + static MethodHandle SELECT_ALTERNATIVE;
18.560 + static MethodHandle selectAlternative() {
18.561 + if (SELECT_ALTERNATIVE != null) return SELECT_ALTERNATIVE;
18.562 + try {
18.563 + SELECT_ALTERNATIVE
18.564 + = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "selectAlternative",
18.565 + MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class));
18.566 + } catch (ReflectiveOperationException ex) {
18.567 + throw new RuntimeException(ex);
18.568 + }
18.569 + return SELECT_ALTERNATIVE;
18.570 + }
18.571 +
18.572 + static
18.573 + MethodHandle makeGuardWithTest(MethodHandle test,
18.574 + MethodHandle target,
18.575 + MethodHandle fallback) {
18.576 + MethodType basicType = target.type().basicType();
18.577 + MethodHandle invokeBasic = MethodHandles.basicInvoker(basicType);
18.578 + int arity = basicType.parameterCount();
18.579 + int extraNames = 3;
18.580 + MethodType lambdaType = basicType.invokerType();
18.581 + Name[] names = arguments(extraNames, lambdaType);
18.582 +
18.583 + Object[] testArgs = Arrays.copyOfRange(names, 1, 1 + arity, Object[].class);
18.584 + Object[] targetArgs = Arrays.copyOfRange(names, 0, 1 + arity, Object[].class);
18.585 +
18.586 + // call test
18.587 + names[arity + 1] = new Name(test, testArgs);
18.588 +
18.589 + // call selectAlternative
18.590 + Object[] selectArgs = { names[arity + 1], target, fallback };
18.591 + names[arity + 2] = new Name(MethodHandleImpl.selectAlternative(), selectArgs);
18.592 + targetArgs[0] = names[arity + 2];
18.593 +
18.594 + // call target or fallback
18.595 + names[arity + 3] = new Name(new NamedFunction(invokeBasic), targetArgs);
18.596 +
18.597 + LambdaForm form = new LambdaForm("guard", lambdaType.parameterCount(), names);
18.598 + return SimpleMethodHandle.make(target.type(), form);
18.599 + }
18.600 +
18.601 + private static class GuardWithCatch {
18.602 + private final MethodHandle target;
18.603 + private final Class<? extends Throwable> exType;
18.604 + private final MethodHandle catcher;
18.605 + // FIXME: Build the control flow out of foldArguments.
18.606 + GuardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
18.607 + this.target = target;
18.608 + this.exType = exType;
18.609 + this.catcher = catcher;
18.610 + }
18.611 + @LambdaForm.Hidden
18.612 + private Object invoke_V(Object... av) throws Throwable {
18.613 + try {
18.614 + return target.invokeExact(av);
18.615 + } catch (Throwable t) {
18.616 + if (!exType.isInstance(t)) throw t;
18.617 + return catcher.invokeExact(t, av);
18.618 + }
18.619 + }
18.620 + @LambdaForm.Hidden
18.621 + private Object invoke_L0() throws Throwable {
18.622 + try {
18.623 + return target.invokeExact();
18.624 + } catch (Throwable t) {
18.625 + if (!exType.isInstance(t)) throw t;
18.626 + return catcher.invokeExact(t);
18.627 + }
18.628 + }
18.629 + @LambdaForm.Hidden
18.630 + private Object invoke_L1(Object a0) throws Throwable {
18.631 + try {
18.632 + return target.invokeExact(a0);
18.633 + } catch (Throwable t) {
18.634 + if (!exType.isInstance(t)) throw t;
18.635 + return catcher.invokeExact(t, a0);
18.636 + }
18.637 + }
18.638 + @LambdaForm.Hidden
18.639 + private Object invoke_L2(Object a0, Object a1) throws Throwable {
18.640 + try {
18.641 + return target.invokeExact(a0, a1);
18.642 + } catch (Throwable t) {
18.643 + if (!exType.isInstance(t)) throw t;
18.644 + return catcher.invokeExact(t, a0, a1);
18.645 + }
18.646 + }
18.647 + @LambdaForm.Hidden
18.648 + private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
18.649 + try {
18.650 + return target.invokeExact(a0, a1, a2);
18.651 + } catch (Throwable t) {
18.652 + if (!exType.isInstance(t)) throw t;
18.653 + return catcher.invokeExact(t, a0, a1, a2);
18.654 + }
18.655 + }
18.656 + @LambdaForm.Hidden
18.657 + private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
18.658 + try {
18.659 + return target.invokeExact(a0, a1, a2, a3);
18.660 + } catch (Throwable t) {
18.661 + if (!exType.isInstance(t)) throw t;
18.662 + return catcher.invokeExact(t, a0, a1, a2, a3);
18.663 + }
18.664 + }
18.665 + @LambdaForm.Hidden
18.666 + private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
18.667 + try {
18.668 + return target.invokeExact(a0, a1, a2, a3, a4);
18.669 + } catch (Throwable t) {
18.670 + if (!exType.isInstance(t)) throw t;
18.671 + return catcher.invokeExact(t, a0, a1, a2, a3, a4);
18.672 + }
18.673 + }
18.674 + @LambdaForm.Hidden
18.675 + private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
18.676 + try {
18.677 + return target.invokeExact(a0, a1, a2, a3, a4, a5);
18.678 + } catch (Throwable t) {
18.679 + if (!exType.isInstance(t)) throw t;
18.680 + return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5);
18.681 + }
18.682 + }
18.683 + @LambdaForm.Hidden
18.684 + private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
18.685 + try {
18.686 + return target.invokeExact(a0, a1, a2, a3, a4, a5, a6);
18.687 + } catch (Throwable t) {
18.688 + if (!exType.isInstance(t)) throw t;
18.689 + return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6);
18.690 + }
18.691 + }
18.692 + @LambdaForm.Hidden
18.693 + private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
18.694 + try {
18.695 + return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
18.696 + } catch (Throwable t) {
18.697 + if (!exType.isInstance(t)) throw t;
18.698 + return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6, a7);
18.699 + }
18.700 + }
18.701 + static MethodHandle[] makeInvokes() {
18.702 + ArrayList<MethodHandle> invokes = new ArrayList<>();
18.703 + MethodHandles.Lookup lookup = IMPL_LOOKUP;
18.704 + for (;;) {
18.705 + int nargs = invokes.size();
18.706 + String name = "invoke_L"+nargs;
18.707 + MethodHandle invoke = null;
18.708 + try {
18.709 + invoke = lookup.findVirtual(GuardWithCatch.class, name, MethodType.genericMethodType(nargs));
18.710 + } catch (ReflectiveOperationException ex) {
18.711 + }
18.712 + if (invoke == null) break;
18.713 + invokes.add(invoke);
18.714 + }
18.715 + assert(invokes.size() == 9); // current number of methods
18.716 + return invokes.toArray(new MethodHandle[0]);
18.717 + };
18.718 + static final MethodHandle[] INVOKES = makeInvokes();
18.719 + // For testing use this:
18.720 + //static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2);
18.721 + static final MethodHandle VARARGS_INVOKE;
18.722 + static {
18.723 + try {
18.724 + VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(GuardWithCatch.class, "invoke_V", MethodType.genericMethodType(0, true));
18.725 + } catch (ReflectiveOperationException ex) {
18.726 + throw uncaughtException(ex);
18.727 + }
18.728 + }
18.729 + }
18.730 +
18.731 +
18.732 + static
18.733 + MethodHandle makeGuardWithCatch(MethodHandle target,
18.734 + Class<? extends Throwable> exType,
18.735 + MethodHandle catcher) {
18.736 + MethodType type = target.type();
18.737 + MethodType ctype = catcher.type();
18.738 + int nargs = type.parameterCount();
18.739 + if (nargs < GuardWithCatch.INVOKES.length) {
18.740 + MethodType gtype = type.generic();
18.741 + MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
18.742 + // Note: convertArguments(...2) avoids interface casts present in convertArguments(...0)
18.743 + MethodHandle gtarget = makePairwiseConvert(target, gtype, 2);
18.744 + MethodHandle gcatcher = makePairwiseConvert(catcher, gcatchType, 2);
18.745 + GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher);
18.746 + if (gtarget == null || gcatcher == null) throw new InternalError();
18.747 + MethodHandle ginvoker = GuardWithCatch.INVOKES[nargs].bindReceiver(gguard);
18.748 + return makePairwiseConvert(ginvoker, type, 2);
18.749 + } else {
18.750 + target = target.asType(type.changeReturnType(Object.class));
18.751 + MethodHandle gtarget = makeSpreadArguments(target, Object[].class, 0, nargs);
18.752 + MethodType catcherType = ctype.changeParameterType(0, Throwable.class)
18.753 + .changeReturnType(Object.class);
18.754 + catcher = catcher.asType(catcherType);
18.755 + MethodHandle gcatcher = makeSpreadArguments(catcher, Object[].class, 1, nargs);
18.756 + GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher);
18.757 + if (gtarget == null || gcatcher == null) throw new InternalError();
18.758 + MethodHandle ginvoker = GuardWithCatch.VARARGS_INVOKE.bindReceiver(gguard);
18.759 + MethodHandle gcollect = makeCollectArguments(ginvoker, ValueConversions.varargsArray(nargs), 0, false);
18.760 + return makePairwiseConvert(gcollect, type, 2);
18.761 + }
18.762 + }
18.763 +
18.764 + static
18.765 + MethodHandle throwException(MethodType type) {
18.766 + assert(Throwable.class.isAssignableFrom(type.parameterType(0)));
18.767 + int arity = type.parameterCount();
18.768 + if (arity > 1) {
18.769 + return throwException(type.dropParameterTypes(1, arity)).dropArguments(type, 1, arity-1);
18.770 + }
18.771 + return makePairwiseConvert(throwException(), type, 2);
18.772 + }
18.773 +
18.774 + static MethodHandle THROW_EXCEPTION;
18.775 + static MethodHandle throwException() {
18.776 + MethodHandle mh = THROW_EXCEPTION;
18.777 + if (mh != null) return mh;
18.778 + try {
18.779 + mh
18.780 + = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException",
18.781 + MethodType.methodType(Empty.class, Throwable.class));
18.782 + } catch (ReflectiveOperationException ex) {
18.783 + throw new RuntimeException(ex);
18.784 + }
18.785 + THROW_EXCEPTION = mh;
18.786 + return mh;
18.787 + }
18.788 + static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
18.789 +
18.790 + static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2];
18.791 + static MethodHandle fakeMethodHandleInvoke(MemberName method) {
18.792 + int idx;
18.793 + assert(method.isMethodHandleInvoke());
18.794 + switch (method.getName()) {
18.795 + case "invoke": idx = 0; break;
18.796 + case "invokeExact": idx = 1; break;
18.797 + default: throw new InternalError(method.getName());
18.798 + }
18.799 + MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE[idx];
18.800 + if (mh != null) return mh;
18.801 + MethodType type = MethodType.methodType(Object.class, UnsupportedOperationException.class,
18.802 + MethodHandle.class, Object[].class);
18.803 + mh = throwException(type);
18.804 + mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle"));
18.805 + if (!method.getInvocationType().equals(mh.type()))
18.806 + throw new InternalError(method.toString());
18.807 + mh = mh.withInternalMemberName(method);
18.808 + mh = mh.asVarargsCollector(Object[].class);
18.809 + assert(method.isVarargs());
18.810 + FAKE_METHOD_HANDLE_INVOKE[idx] = mh;
18.811 + return mh;
18.812 + }
18.813 +
18.814 + /**
18.815 + * Create an alias for the method handle which, when called,
18.816 + * appears to be called from the same class loader and protection domain
18.817 + * as hostClass.
18.818 + * This is an expensive no-op unless the method which is called
18.819 + * is sensitive to its caller. A small number of system methods
18.820 + * are in this category, including Class.forName and Method.invoke.
18.821 + */
18.822 + static
18.823 + MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) {
18.824 + return BindCaller.bindCaller(mh, hostClass);
18.825 + }
18.826 +
18.827 + // Put the whole mess into its own nested class.
18.828 + // That way we can lazily load the code and set up the constants.
18.829 + private static class BindCaller {
18.830 + static
18.831 + MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) {
18.832 + // Do not use this function to inject calls into system classes.
18.833 + if (hostClass == null
18.834 + || (hostClass.isArray() ||
18.835 + hostClass.isPrimitive() ||
18.836 + hostClass.getName().startsWith("java.") ||
18.837 + hostClass.getName().startsWith("sun."))) {
18.838 + throw new InternalError(); // does not happen, and should not anyway
18.839 + }
18.840 + // For simplicity, convert mh to a varargs-like method.
18.841 + MethodHandle vamh = prepareForInvoker(mh);
18.842 + // Cache the result of makeInjectedInvoker once per argument class.
18.843 + MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass);
18.844 + return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName(), hostClass);
18.845 + }
18.846 +
18.847 + private static MethodHandle makeInjectedInvoker(Class<?> hostClass) {
18.848 + Class<?> bcc = UNSAFE.defineAnonymousClass(hostClass, T_BYTES, null);
18.849 + if (hostClass.getClassLoader() != bcc.getClassLoader())
18.850 + throw new InternalError(hostClass.getName()+" (CL)");
18.851 + try {
18.852 + if (hostClass.getProtectionDomain() != bcc.getProtectionDomain())
18.853 + throw new InternalError(hostClass.getName()+" (PD)");
18.854 + } catch (SecurityException ex) {
18.855 + // Self-check was blocked by security manager. This is OK.
18.856 + // In fact the whole try body could be turned into an assertion.
18.857 + }
18.858 + try {
18.859 + MethodHandle init = IMPL_LOOKUP.findStatic(bcc, "init", MethodType.methodType(void.class));
18.860 + init.invokeExact(); // force initialization of the class
18.861 + } catch (Throwable ex) {
18.862 + throw uncaughtException(ex);
18.863 + }
18.864 + MethodHandle bccInvoker;
18.865 + try {
18.866 + MethodType invokerMT = MethodType.methodType(Object.class, MethodHandle.class, Object[].class);
18.867 + bccInvoker = IMPL_LOOKUP.findStatic(bcc, "invoke_V", invokerMT);
18.868 + } catch (ReflectiveOperationException ex) {
18.869 + throw uncaughtException(ex);
18.870 + }
18.871 + // Test the invoker, to ensure that it really injects into the right place.
18.872 + try {
18.873 + MethodHandle vamh = prepareForInvoker(MH_checkCallerClass);
18.874 + Object ok = bccInvoker.invokeExact(vamh, new Object[]{hostClass, bcc});
18.875 + } catch (Throwable ex) {
18.876 + throw new InternalError(ex);
18.877 + }
18.878 + return bccInvoker;
18.879 + }
18.880 + private static ClassValue<MethodHandle> CV_makeInjectedInvoker = new ClassValue<MethodHandle>() {
18.881 + @Override protected MethodHandle computeValue(Class<?> hostClass) {
18.882 + return makeInjectedInvoker(hostClass);
18.883 + }
18.884 + };
18.885 +
18.886 + // Adapt mh so that it can be called directly from an injected invoker:
18.887 + private static MethodHandle prepareForInvoker(MethodHandle mh) {
18.888 + mh = mh.asFixedArity();
18.889 + MethodType mt = mh.type();
18.890 + int arity = mt.parameterCount();
18.891 + MethodHandle vamh = mh.asType(mt.generic());
18.892 + vamh.internalForm().compileToBytecode(); // eliminate LFI stack frames
18.893 + vamh = vamh.asSpreader(Object[].class, arity);
18.894 + vamh.internalForm().compileToBytecode(); // eliminate LFI stack frames
18.895 + return vamh;
18.896 + }
18.897 +
18.898 + // Undo the adapter effect of prepareForInvoker:
18.899 + private static MethodHandle restoreToType(MethodHandle vamh, MethodType type,
18.900 + MemberName member,
18.901 + Class<?> hostClass) {
18.902 + MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount());
18.903 + mh = mh.asType(type);
18.904 + mh = new WrappedMember(mh, type, member, hostClass);
18.905 + return mh;
18.906 + }
18.907 +
18.908 + private static final MethodHandle MH_checkCallerClass;
18.909 + static {
18.910 + final Class<?> THIS_CLASS = BindCaller.class;
18.911 + assert(checkCallerClass(THIS_CLASS, THIS_CLASS));
18.912 + try {
18.913 + MH_checkCallerClass = IMPL_LOOKUP
18.914 + .findStatic(THIS_CLASS, "checkCallerClass",
18.915 + MethodType.methodType(boolean.class, Class.class, Class.class));
18.916 + assert((boolean) MH_checkCallerClass.invokeExact(THIS_CLASS, THIS_CLASS));
18.917 + } catch (Throwable ex) {
18.918 + throw new InternalError(ex);
18.919 + }
18.920 + }
18.921 +
18.922 + @CallerSensitive
18.923 + private static boolean checkCallerClass(Class<?> expected, Class<?> expected2) {
18.924 + // This method is called via MH_checkCallerClass and so it's
18.925 + // correct to ask for the immediate caller here.
18.926 + Class<?> actual = Reflection.getCallerClass();
18.927 + if (actual != expected && actual != expected2)
18.928 + throw new InternalError("found "+actual.getName()+", expected "+expected.getName()
18.929 + +(expected == expected2 ? "" : ", or else "+expected2.getName()));
18.930 + return true;
18.931 + }
18.932 +
18.933 + private static final byte[] T_BYTES;
18.934 + static {
18.935 + final Object[] values = {null};
18.936 + AccessController.doPrivileged(new PrivilegedAction<Void>() {
18.937 + public Void run() {
18.938 + try {
18.939 + Class<T> tClass = T.class;
18.940 + String tName = tClass.getName();
18.941 + String tResource = tName.substring(tName.lastIndexOf('.')+1)+".class";
18.942 + java.net.URLConnection uconn = tClass.getResource(tResource).openConnection();
18.943 + int len = uconn.getContentLength();
18.944 + byte[] bytes = new byte[len];
18.945 + try (java.io.InputStream str = uconn.getInputStream()) {
18.946 + int nr = str.read(bytes);
18.947 + if (nr != len) throw new java.io.IOException(tResource);
18.948 + }
18.949 + values[0] = bytes;
18.950 + } catch (java.io.IOException ex) {
18.951 + throw new InternalError(ex);
18.952 + }
18.953 + return null;
18.954 + }
18.955 + });
18.956 + T_BYTES = (byte[]) values[0];
18.957 + }
18.958 +
18.959 + // The following class is used as a template for Unsafe.defineAnonymousClass:
18.960 + private static class T {
18.961 + static void init() { } // side effect: initializes this class
18.962 + static Object invoke_V(MethodHandle vamh, Object[] args) throws Throwable {
18.963 + return vamh.invokeExact(args);
18.964 + }
18.965 + }
18.966 + }
18.967 +
18.968 +
18.969 + /** This subclass allows a wrapped method handle to be re-associated with an arbitrary member name. */
18.970 + static class WrappedMember extends MethodHandle {
18.971 + private final MethodHandle target;
18.972 + private final MemberName member;
18.973 + private final Class<?> callerClass;
18.974 +
18.975 + private WrappedMember(MethodHandle target, MethodType type, MemberName member, Class<?> callerClass) {
18.976 + super(type, reinvokerForm(target));
18.977 + this.target = target;
18.978 + this.member = member;
18.979 + this.callerClass = callerClass;
18.980 + }
18.981 +
18.982 + @Override
18.983 + MethodHandle reinvokerTarget() {
18.984 + return target;
18.985 + }
18.986 + @Override
18.987 + public MethodHandle asTypeUncached(MethodType newType) {
18.988 + // This MH is an alias for target, except for the MemberName
18.989 + // Drop the MemberName if there is any conversion.
18.990 + return asTypeCache = target.asType(newType);
18.991 + }
18.992 + @Override
18.993 + MemberName internalMemberName() {
18.994 + return member;
18.995 + }
18.996 + @Override
18.997 + Class<?> internalCallerClass() {
18.998 + return callerClass;
18.999 + }
18.1000 + @Override
18.1001 + boolean isInvokeSpecial() {
18.1002 + return target.isInvokeSpecial();
18.1003 + }
18.1004 + @Override
18.1005 + MethodHandle viewAsType(MethodType newType) {
18.1006 + return new WrappedMember(target, newType, member, callerClass);
18.1007 + }
18.1008 + }
18.1009 +
18.1010 + static MethodHandle makeWrappedMember(MethodHandle target, MemberName member) {
18.1011 + if (member.equals(target.internalMemberName()))
18.1012 + return target;
18.1013 + return new WrappedMember(target, target.type(), member, null);
18.1014 + }
18.1015 +
18.1016 +}
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
19.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/MethodHandleInfo.java Sat Aug 09 11:12:05 2014 +0200
19.3 @@ -0,0 +1,284 @@
19.4 +/*
19.5 + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
19.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
19.7 + *
19.8 + * This code is free software; you can redistribute it and/or modify it
19.9 + * under the terms of the GNU General Public License version 2 only, as
19.10 + * published by the Free Software Foundation. Oracle designates this
19.11 + * particular file as subject to the "Classpath" exception as provided
19.12 + * by Oracle in the LICENSE file that accompanied this code.
19.13 + *
19.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
19.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19.17 + * version 2 for more details (a copy is included in the LICENSE file that
19.18 + * accompanied this code).
19.19 + *
19.20 + * You should have received a copy of the GNU General Public License version
19.21 + * 2 along with this work; if not, write to the Free Software Foundation,
19.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19.23 + *
19.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
19.25 + * or visit www.oracle.com if you need additional information or have any
19.26 + * questions.
19.27 + */
19.28 +
19.29 +package java.lang.invoke;
19.30 +
19.31 +import java.lang.reflect.*;
19.32 +import java.util.*;
19.33 +import java.lang.invoke.MethodHandleNatives.Constants;
19.34 +import java.lang.invoke.MethodHandles.Lookup;
19.35 +import static java.lang.invoke.MethodHandleStatics.*;
19.36 +
19.37 +/**
19.38 + * A symbolic reference obtained by cracking a direct method handle
19.39 + * into its consitutent symbolic parts.
19.40 + * To crack a direct method handle, call {@link Lookup#revealDirect Lookup.revealDirect}.
19.41 + * <h1><a name="directmh"></a>Direct Method Handles</h1>
19.42 + * A <em>direct method handle</em> represents a method, constructor, or field without
19.43 + * any intervening argument bindings or other transformations.
19.44 + * The method, constructor, or field referred to by a direct method handle is called
19.45 + * its <em>underlying member</em>.
19.46 + * Direct method handles may be obtained in any of these ways:
19.47 + * <ul>
19.48 + * <li>By executing an {@code ldc} instruction on a {@code CONSTANT_MethodHandle} constant.
19.49 + * (See the Java Virtual Machine Specification, sections 4.4.8 and 5.4.3.)
19.50 + * <li>By calling one of the <a href="MethodHandles.Lookup.html#lookups">Lookup Factory Methods</a>,
19.51 + * such as {@link Lookup#findVirtual Lookup.findVirtual},
19.52 + * to resolve a symbolic reference into a method handle.
19.53 + * A symbolic reference consists of a class, name string, and type.
19.54 + * <li>By calling the factory method {@link Lookup#unreflect Lookup.unreflect}
19.55 + * or {@link Lookup#unreflectSpecial Lookup.unreflectSpecial}
19.56 + * to convert a {@link Method} into a method handle.
19.57 + * <li>By calling the factory method {@link Lookup#unreflectConstructor Lookup.unreflectConstructor}
19.58 + * to convert a {@link Constructor} into a method handle.
19.59 + * <li>By calling the factory method {@link Lookup#unreflectGetter Lookup.unreflectGetter}
19.60 + * or {@link Lookup#unreflectSetter Lookup.unreflectSetter}
19.61 + * to convert a {@link Field} into a method handle.
19.62 + * </ul>
19.63 + *
19.64 + * <h1>Restrictions on Cracking</h1>
19.65 + * Given a suitable {@code Lookup} object, it is possible to crack any direct method handle
19.66 + * to recover a symbolic reference for the underlying method, constructor, or field.
19.67 + * Cracking must be done via a {@code Lookup} object equivalent to that which created
19.68 + * the target method handle, or which has enough access permissions to recreate
19.69 + * an equivalent method handle.
19.70 + * <p>
19.71 + * If the underlying method is <a href="MethodHandles.Lookup.html#callsens">caller sensitive</a>,
19.72 + * the direct method handle will have been "bound" to a particular caller class, the
19.73 + * {@linkplain java.lang.invoke.MethodHandles.Lookup#lookupClass() lookup class}
19.74 + * of the lookup object used to create it.
19.75 + * Cracking this method handle with a different lookup class will fail
19.76 + * even if the underlying method is public (like {@code Class.forName}).
19.77 + * <p>
19.78 + * The requirement of lookup object matching provides a "fast fail" behavior
19.79 + * for programs which may otherwise trust erroneous revelation of a method
19.80 + * handle with symbolic information (or caller binding) from an unexpected scope.
19.81 + * Use {@link java.lang.invoke.MethodHandles#reflectAs} to override this limitation.
19.82 + *
19.83 + * <h1><a name="refkinds"></a>Reference kinds</h1>
19.84 + * The <a href="MethodHandles.Lookup.html#lookups">Lookup Factory Methods</a>
19.85 + * correspond to all major use cases for methods, constructors, and fields.
19.86 + * These use cases may be distinguished using small integers as follows:
19.87 + * <table border=1 cellpadding=5 summary="reference kinds">
19.88 + * <tr><th>reference kind</th><th>descriptive name</th><th>scope</th><th>member</th><th>behavior</th></tr>
19.89 + * <tr>
19.90 + * <td>{@code 1}</td><td>{@code REF_getField}</td><td>{@code class}</td>
19.91 + * <td>{@code FT f;}</td><td>{@code (T) this.f;}</td>
19.92 + * </tr>
19.93 + * <tr>
19.94 + * <td>{@code 2}</td><td>{@code REF_getStatic}</td><td>{@code class} or {@code interface}</td>
19.95 + * <td>{@code static}<br>{@code FT f;}</td><td>{@code (T) C.f;}</td>
19.96 + * </tr>
19.97 + * <tr>
19.98 + * <td>{@code 3}</td><td>{@code REF_putField}</td><td>{@code class}</td>
19.99 + * <td>{@code FT f;}</td><td>{@code this.f = x;}</td>
19.100 + * </tr>
19.101 + * <tr>
19.102 + * <td>{@code 4}</td><td>{@code REF_putStatic}</td><td>{@code class}</td>
19.103 + * <td>{@code static}<br>{@code FT f;}</td><td>{@code C.f = arg;}</td>
19.104 + * </tr>
19.105 + * <tr>
19.106 + * <td>{@code 5}</td><td>{@code REF_invokeVirtual}</td><td>{@code class}</td>
19.107 + * <td>{@code T m(A*);}</td><td>{@code (T) this.m(arg*);}</td>
19.108 + * </tr>
19.109 + * <tr>
19.110 + * <td>{@code 6}</td><td>{@code REF_invokeStatic}</td><td>{@code class} or {@code interface}</td>
19.111 + * <td>{@code static}<br>{@code T m(A*);}</td><td>{@code (T) C.m(arg*);}</td>
19.112 + * </tr>
19.113 + * <tr>
19.114 + * <td>{@code 7}</td><td>{@code REF_invokeSpecial}</td><td>{@code class} or {@code interface}</td>
19.115 + * <td>{@code T m(A*);}</td><td>{@code (T) super.m(arg*);}</td>
19.116 + * </tr>
19.117 + * <tr>
19.118 + * <td>{@code 8}</td><td>{@code REF_newInvokeSpecial}</td><td>{@code class}</td>
19.119 + * <td>{@code C(A*);}</td><td>{@code new C(arg*);}</td>
19.120 + * </tr>
19.121 + * <tr>
19.122 + * <td>{@code 9}</td><td>{@code REF_invokeInterface}</td><td>{@code interface}</td>
19.123 + * <td>{@code T m(A*);}</td><td>{@code (T) this.m(arg*);}</td>
19.124 + * </tr>
19.125 + * </table>
19.126 + * @since 1.8
19.127 + */
19.128 +public
19.129 +interface MethodHandleInfo {
19.130 + /**
19.131 + * A direct method handle reference kind,
19.132 + * as defined in the <a href="MethodHandleInfo.html#refkinds">table above</a>.
19.133 + */
19.134 + public static final int
19.135 + REF_getField = Constants.REF_getField,
19.136 + REF_getStatic = Constants.REF_getStatic,
19.137 + REF_putField = Constants.REF_putField,
19.138 + REF_putStatic = Constants.REF_putStatic,
19.139 + REF_invokeVirtual = Constants.REF_invokeVirtual,
19.140 + REF_invokeStatic = Constants.REF_invokeStatic,
19.141 + REF_invokeSpecial = Constants.REF_invokeSpecial,
19.142 + REF_newInvokeSpecial = Constants.REF_newInvokeSpecial,
19.143 + REF_invokeInterface = Constants.REF_invokeInterface;
19.144 +
19.145 + /**
19.146 + * Returns the reference kind of the cracked method handle, which in turn
19.147 + * determines whether the method handle's underlying member was a constructor, method, or field.
19.148 + * See the <a href="MethodHandleInfo.html#refkinds">table above</a> for definitions.
19.149 + * @return the integer code for the kind of reference used to access the underlying member
19.150 + */
19.151 + public int getReferenceKind();
19.152 +
19.153 + /**
19.154 + * Returns the class in which the cracked method handle's underlying member was defined.
19.155 + * @return the declaring class of the underlying member
19.156 + */
19.157 + public Class<?> getDeclaringClass();
19.158 +
19.159 + /**
19.160 + * Returns the name of the cracked method handle's underlying member.
19.161 + * This is {@code "<init>"} if the underlying member was a constructor,
19.162 + * else it is a simple method name or field name.
19.163 + * @return the simple name of the underlying member
19.164 + */
19.165 + public String getName();
19.166 +
19.167 + /**
19.168 + * Returns the nominal type of the cracked symbolic reference, expressed as a method type.
19.169 + * If the reference is to a constructor, the return type will be {@code void}.
19.170 + * If it is to a non-static method, the method type will not mention the {@code this} parameter.
19.171 + * If it is to a field and the requested access is to read the field,
19.172 + * the method type will have no parameters and return the field type.
19.173 + * If it is to a field and the requested access is to write the field,
19.174 + * the method type will have one parameter of the field type and return {@code void}.
19.175 + * <p>
19.176 + * Note that original direct method handle may include a leading {@code this} parameter,
19.177 + * or (in the case of a constructor) will replace the {@code void} return type
19.178 + * with the constructed class.
19.179 + * The nominal type does not include any {@code this} parameter,
19.180 + * and (in the case of a constructor) will return {@code void}.
19.181 + * @return the type of the underlying member, expressed as a method type
19.182 + */
19.183 + public MethodType getMethodType();
19.184 +
19.185 + // Utility methods.
19.186 + // NOTE: class/name/type and reference kind constitute a symbolic reference
19.187 + // member and modifiers are an add-on, derived from Core Reflection (or the equivalent)
19.188 +
19.189 + /**
19.190 + * Reflects the underlying member as a method, constructor, or field object.
19.191 + * If the underlying member is public, it is reflected as if by
19.192 + * {@code getMethod}, {@code getConstructor}, or {@code getField}.
19.193 + * Otherwise, it is reflected as if by
19.194 + * {@code getDeclaredMethod}, {@code getDeclaredConstructor}, or {@code getDeclaredField}.
19.195 + * The underlying member must be accessible to the given lookup object.
19.196 + * @param <T> the desired type of the result, either {@link Member} or a subtype
19.197 + * @param expected a class object representing the desired result type {@code T}
19.198 + * @param lookup the lookup object that created this MethodHandleInfo, or one with equivalent access privileges
19.199 + * @return a reference to the method, constructor, or field object
19.200 + * @exception ClassCastException if the member is not of the expected type
19.201 + * @exception NullPointerException if either argument is {@code null}
19.202 + * @exception IllegalArgumentException if the underlying member is not accessible to the given lookup object
19.203 + */
19.204 + public <T extends Member> T reflectAs(Class<T> expected, Lookup lookup);
19.205 +
19.206 + /**
19.207 + * Returns the access modifiers of the underlying member.
19.208 + * @return the Java language modifiers for underlying member,
19.209 + * or -1 if the member cannot be accessed
19.210 + * @see Modifier
19.211 + * @see #reflectAs
19.212 + */
19.213 + public int getModifiers();
19.214 +
19.215 + /**
19.216 + * Determines if the underlying member was a variable arity method or constructor.
19.217 + * Such members are represented by method handles that are varargs collectors.
19.218 + * @implSpec
19.219 + * This produces a result equivalent to:
19.220 + * <pre>{@code
19.221 + * getReferenceKind() >= REF_invokeVirtual && Modifier.isTransient(getModifiers())
19.222 + * }</pre>
19.223 + *
19.224 + *
19.225 + * @return {@code true} if and only if the underlying member was declared with variable arity.
19.226 + */
19.227 + // spelling derived from java.lang.reflect.Executable, not MethodHandle.isVarargsCollector
19.228 + public default boolean isVarArgs() {
19.229 + // fields are never varargs:
19.230 + if (MethodHandleNatives.refKindIsField((byte) getReferenceKind()))
19.231 + return false;
19.232 + // not in the public API: Modifier.VARARGS
19.233 + final int ACC_VARARGS = 0x00000080; // from JVMS 4.6 (Table 4.20)
19.234 + assert(ACC_VARARGS == Modifier.TRANSIENT);
19.235 + return Modifier.isTransient(getModifiers());
19.236 + }
19.237 +
19.238 + /**
19.239 + * Returns the descriptive name of the given reference kind,
19.240 + * as defined in the <a href="MethodHandleInfo.html#refkinds">table above</a>.
19.241 + * The conventional prefix "REF_" is omitted.
19.242 + * @param referenceKind an integer code for a kind of reference used to access a class member
19.243 + * @return a mixed-case string such as {@code "getField"}
19.244 + * @exception IllegalArgumentException if the argument is not a valid
19.245 + * <a href="MethodHandleInfo.html#refkinds">reference kind number</a>
19.246 + */
19.247 + public static String referenceKindToString(int referenceKind) {
19.248 + if (!MethodHandleNatives.refKindIsValid(referenceKind))
19.249 + throw newIllegalArgumentException("invalid reference kind", referenceKind);
19.250 + return MethodHandleNatives.refKindName((byte)referenceKind);
19.251 + }
19.252 +
19.253 + /**
19.254 + * Returns a string representation for a {@code MethodHandleInfo},
19.255 + * given the four parts of its symbolic reference.
19.256 + * This is defined to be of the form {@code "RK C.N:MT"}, where {@code RK} is the
19.257 + * {@linkplain #referenceKindToString reference kind string} for {@code kind},
19.258 + * {@code C} is the {@linkplain java.lang.Class#getName name} of {@code defc}
19.259 + * {@code N} is the {@code name}, and
19.260 + * {@code MT} is the {@code type}.
19.261 + * These four values may be obtained from the
19.262 + * {@linkplain #getReferenceKind reference kind},
19.263 + * {@linkplain #getDeclaringClass declaring class},
19.264 + * {@linkplain #getName member name},
19.265 + * and {@linkplain #getMethodType method type}
19.266 + * of a {@code MethodHandleInfo} object.
19.267 + *
19.268 + * @implSpec
19.269 + * This produces a result equivalent to:
19.270 + * <pre>{@code
19.271 + * String.format("%s %s.%s:%s", referenceKindToString(kind), defc.getName(), name, type)
19.272 + * }</pre>
19.273 + *
19.274 + * @param kind the {@linkplain #getReferenceKind reference kind} part of the symbolic reference
19.275 + * @param defc the {@linkplain #getDeclaringClass declaring class} part of the symbolic reference
19.276 + * @param name the {@linkplain #getName member name} part of the symbolic reference
19.277 + * @param type the {@linkplain #getMethodType method type} part of the symbolic reference
19.278 + * @return a string of the form {@code "RK C.N:MT"}
19.279 + * @exception IllegalArgumentException if the first argument is not a valid
19.280 + * <a href="MethodHandleInfo.html#refkinds">reference kind number</a>
19.281 + * @exception NullPointerException if any reference argument is {@code null}
19.282 + */
19.283 + public static String toString(int kind, Class<?> defc, String name, MethodType type) {
19.284 + Objects.requireNonNull(name); Objects.requireNonNull(type);
19.285 + return String.format("%s %s.%s:%s", referenceKindToString(kind), defc.getName(), name, type);
19.286 + }
19.287 +}
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
20.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/MethodHandleNatives.java Sat Aug 09 11:12:05 2014 +0200
20.3 @@ -0,0 +1,505 @@
20.4 +/*
20.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
20.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
20.7 + *
20.8 + * This code is free software; you can redistribute it and/or modify it
20.9 + * under the terms of the GNU General Public License version 2 only, as
20.10 + * published by the Free Software Foundation. Oracle designates this
20.11 + * particular file as subject to the "Classpath" exception as provided
20.12 + * by Oracle in the LICENSE file that accompanied this code.
20.13 + *
20.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
20.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20.17 + * version 2 for more details (a copy is included in the LICENSE file that
20.18 + * accompanied this code).
20.19 + *
20.20 + * You should have received a copy of the GNU General Public License version
20.21 + * 2 along with this work; if not, write to the Free Software Foundation,
20.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20.23 + *
20.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20.25 + * or visit www.oracle.com if you need additional information or have any
20.26 + * questions.
20.27 + */
20.28 +
20.29 +package java.lang.invoke;
20.30 +
20.31 +import java.lang.invoke.MethodHandles.Lookup;
20.32 +import java.lang.reflect.Field;
20.33 +import static java.lang.invoke.MethodHandleNatives.Constants.*;
20.34 +import static java.lang.invoke.MethodHandleStatics.*;
20.35 +import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
20.36 +
20.37 +/**
20.38 + * The JVM interface for the method handles package is all here.
20.39 + * This is an interface internal and private to an implementation of JSR 292.
20.40 + * <em>This class is not part of the JSR 292 standard.</em>
20.41 + * @author jrose
20.42 + */
20.43 +class MethodHandleNatives {
20.44 +
20.45 + private MethodHandleNatives() { } // static only
20.46 +
20.47 + /// MemberName support
20.48 +
20.49 + static native void init(MemberName self, Object ref);
20.50 + static native void expand(MemberName self);
20.51 + static native MemberName resolve(MemberName self, Class<?> caller) throws LinkageError;
20.52 + static native int getMembers(Class<?> defc, String matchName, String matchSig,
20.53 + int matchFlags, Class<?> caller, int skip, MemberName[] results);
20.54 +
20.55 + /// Field layout queries parallel to sun.misc.Unsafe:
20.56 + static native long objectFieldOffset(MemberName self); // e.g., returns vmindex
20.57 + static native long staticFieldOffset(MemberName self); // e.g., returns vmindex
20.58 + static native Object staticFieldBase(MemberName self); // e.g., returns clazz
20.59 + static native Object getMemberVMInfo(MemberName self); // returns {vmindex,vmtarget}
20.60 +
20.61 + /// MethodHandle support
20.62 +
20.63 + /** Fetch MH-related JVM parameter.
20.64 + * which=0 retrieves MethodHandlePushLimit
20.65 + * which=1 retrieves stack slot push size (in address units)
20.66 + */
20.67 + static native int getConstant(int which);
20.68 +
20.69 + static final boolean COUNT_GWT;
20.70 +
20.71 + /// CallSite support
20.72 +
20.73 + /** Tell the JVM that we need to change the target of a CallSite. */
20.74 + static native void setCallSiteTargetNormal(CallSite site, MethodHandle target);
20.75 + static native void setCallSiteTargetVolatile(CallSite site, MethodHandle target);
20.76 +
20.77 + private static native void registerNatives();
20.78 + static {
20.79 + registerNatives();
20.80 + COUNT_GWT = getConstant(Constants.GC_COUNT_GWT) != 0;
20.81 +
20.82 + // The JVM calls MethodHandleNatives.<clinit>. Cascade the <clinit> calls as needed:
20.83 + MethodHandleImpl.initStatics();
20.84 +}
20.85 +
20.86 + // All compile-time constants go here.
20.87 + // There is an opportunity to check them against the JVM's idea of them.
20.88 + static class Constants {
20.89 + Constants() { } // static only
20.90 + // MethodHandleImpl
20.91 + static final int // for getConstant
20.92 + GC_COUNT_GWT = 4,
20.93 + GC_LAMBDA_SUPPORT = 5;
20.94 +
20.95 + // MemberName
20.96 + // The JVM uses values of -2 and above for vtable indexes.
20.97 + // Field values are simple positive offsets.
20.98 + // Ref: src/share/vm/oops/methodOop.hpp
20.99 + // This value is negative enough to avoid such numbers,
20.100 + // but not too negative.
20.101 + static final int
20.102 + MN_IS_METHOD = 0x00010000, // method (not constructor)
20.103 + MN_IS_CONSTRUCTOR = 0x00020000, // constructor
20.104 + MN_IS_FIELD = 0x00040000, // field
20.105 + MN_IS_TYPE = 0x00080000, // nested type
20.106 + MN_CALLER_SENSITIVE = 0x00100000, // @CallerSensitive annotation detected
20.107 + MN_REFERENCE_KIND_SHIFT = 24, // refKind
20.108 + MN_REFERENCE_KIND_MASK = 0x0F000000 >> MN_REFERENCE_KIND_SHIFT,
20.109 + // The SEARCH_* bits are not for MN.flags but for the matchFlags argument of MHN.getMembers:
20.110 + MN_SEARCH_SUPERCLASSES = 0x00100000,
20.111 + MN_SEARCH_INTERFACES = 0x00200000;
20.112 +
20.113 + /**
20.114 + * Basic types as encoded in the JVM. These code values are not
20.115 + * intended for use outside this class. They are used as part of
20.116 + * a private interface between the JVM and this class.
20.117 + */
20.118 + static final int
20.119 + T_BOOLEAN = 4,
20.120 + T_CHAR = 5,
20.121 + T_FLOAT = 6,
20.122 + T_DOUBLE = 7,
20.123 + T_BYTE = 8,
20.124 + T_SHORT = 9,
20.125 + T_INT = 10,
20.126 + T_LONG = 11,
20.127 + T_OBJECT = 12,
20.128 + //T_ARRAY = 13
20.129 + T_VOID = 14,
20.130 + //T_ADDRESS = 15
20.131 + T_ILLEGAL = 99;
20.132 +
20.133 + /**
20.134 + * Constant pool entry types.
20.135 + */
20.136 + static final byte
20.137 + CONSTANT_Utf8 = 1,
20.138 + CONSTANT_Integer = 3,
20.139 + CONSTANT_Float = 4,
20.140 + CONSTANT_Long = 5,
20.141 + CONSTANT_Double = 6,
20.142 + CONSTANT_Class = 7,
20.143 + CONSTANT_String = 8,
20.144 + CONSTANT_Fieldref = 9,
20.145 + CONSTANT_Methodref = 10,
20.146 + CONSTANT_InterfaceMethodref = 11,
20.147 + CONSTANT_NameAndType = 12,
20.148 + CONSTANT_MethodHandle = 15, // JSR 292
20.149 + CONSTANT_MethodType = 16, // JSR 292
20.150 + CONSTANT_InvokeDynamic = 18,
20.151 + CONSTANT_LIMIT = 19; // Limit to tags found in classfiles
20.152 +
20.153 + /**
20.154 + * Access modifier flags.
20.155 + */
20.156 + static final char
20.157 + ACC_PUBLIC = 0x0001,
20.158 + ACC_PRIVATE = 0x0002,
20.159 + ACC_PROTECTED = 0x0004,
20.160 + ACC_STATIC = 0x0008,
20.161 + ACC_FINAL = 0x0010,
20.162 + ACC_SYNCHRONIZED = 0x0020,
20.163 + ACC_VOLATILE = 0x0040,
20.164 + ACC_TRANSIENT = 0x0080,
20.165 + ACC_NATIVE = 0x0100,
20.166 + ACC_INTERFACE = 0x0200,
20.167 + ACC_ABSTRACT = 0x0400,
20.168 + ACC_STRICT = 0x0800,
20.169 + ACC_SYNTHETIC = 0x1000,
20.170 + ACC_ANNOTATION = 0x2000,
20.171 + ACC_ENUM = 0x4000,
20.172 + // aliases:
20.173 + ACC_SUPER = ACC_SYNCHRONIZED,
20.174 + ACC_BRIDGE = ACC_VOLATILE,
20.175 + ACC_VARARGS = ACC_TRANSIENT;
20.176 +
20.177 + /**
20.178 + * Constant pool reference-kind codes, as used by CONSTANT_MethodHandle CP entries.
20.179 + */
20.180 + static final byte
20.181 + REF_NONE = 0, // null value
20.182 + REF_getField = 1,
20.183 + REF_getStatic = 2,
20.184 + REF_putField = 3,
20.185 + REF_putStatic = 4,
20.186 + REF_invokeVirtual = 5,
20.187 + REF_invokeStatic = 6,
20.188 + REF_invokeSpecial = 7,
20.189 + REF_newInvokeSpecial = 8,
20.190 + REF_invokeInterface = 9,
20.191 + REF_LIMIT = 10;
20.192 + }
20.193 +
20.194 + static boolean refKindIsValid(int refKind) {
20.195 + return (refKind > REF_NONE && refKind < REF_LIMIT);
20.196 + }
20.197 + static boolean refKindIsField(byte refKind) {
20.198 + assert(refKindIsValid(refKind));
20.199 + return (refKind <= REF_putStatic);
20.200 + }
20.201 + static boolean refKindIsGetter(byte refKind) {
20.202 + assert(refKindIsValid(refKind));
20.203 + return (refKind <= REF_getStatic);
20.204 + }
20.205 + static boolean refKindIsSetter(byte refKind) {
20.206 + return refKindIsField(refKind) && !refKindIsGetter(refKind);
20.207 + }
20.208 + static boolean refKindIsMethod(byte refKind) {
20.209 + return !refKindIsField(refKind) && (refKind != REF_newInvokeSpecial);
20.210 + }
20.211 + static boolean refKindIsConstructor(byte refKind) {
20.212 + return (refKind == REF_newInvokeSpecial);
20.213 + }
20.214 + static boolean refKindHasReceiver(byte refKind) {
20.215 + assert(refKindIsValid(refKind));
20.216 + return (refKind & 1) != 0;
20.217 + }
20.218 + static boolean refKindIsStatic(byte refKind) {
20.219 + return !refKindHasReceiver(refKind) && (refKind != REF_newInvokeSpecial);
20.220 + }
20.221 + static boolean refKindDoesDispatch(byte refKind) {
20.222 + assert(refKindIsValid(refKind));
20.223 + return (refKind == REF_invokeVirtual ||
20.224 + refKind == REF_invokeInterface);
20.225 + }
20.226 + static {
20.227 + final int HR_MASK = ((1 << REF_getField) |
20.228 + (1 << REF_putField) |
20.229 + (1 << REF_invokeVirtual) |
20.230 + (1 << REF_invokeSpecial) |
20.231 + (1 << REF_invokeInterface)
20.232 + );
20.233 + for (byte refKind = REF_NONE+1; refKind < REF_LIMIT; refKind++) {
20.234 + assert(refKindHasReceiver(refKind) == (((1<<refKind) & HR_MASK) != 0)) : refKind;
20.235 + }
20.236 + }
20.237 + static String refKindName(byte refKind) {
20.238 + assert(refKindIsValid(refKind));
20.239 + switch (refKind) {
20.240 + case REF_getField: return "getField";
20.241 + case REF_getStatic: return "getStatic";
20.242 + case REF_putField: return "putField";
20.243 + case REF_putStatic: return "putStatic";
20.244 + case REF_invokeVirtual: return "invokeVirtual";
20.245 + case REF_invokeStatic: return "invokeStatic";
20.246 + case REF_invokeSpecial: return "invokeSpecial";
20.247 + case REF_newInvokeSpecial: return "newInvokeSpecial";
20.248 + case REF_invokeInterface: return "invokeInterface";
20.249 + default: return "REF_???";
20.250 + }
20.251 + }
20.252 +
20.253 + private static native int getNamedCon(int which, Object[] name);
20.254 + static boolean verifyConstants() {
20.255 + Object[] box = { null };
20.256 + for (int i = 0; ; i++) {
20.257 + box[0] = null;
20.258 + int vmval = getNamedCon(i, box);
20.259 + if (box[0] == null) break;
20.260 + String name = (String) box[0];
20.261 + try {
20.262 + Field con = Constants.class.getDeclaredField(name);
20.263 + int jval = con.getInt(null);
20.264 + if (jval == vmval) continue;
20.265 + String err = (name+": JVM has "+vmval+" while Java has "+jval);
20.266 + if (name.equals("CONV_OP_LIMIT")) {
20.267 + System.err.println("warning: "+err);
20.268 + continue;
20.269 + }
20.270 + throw new InternalError(err);
20.271 + } catch (NoSuchFieldException | IllegalAccessException ex) {
20.272 + String err = (name+": JVM has "+vmval+" which Java does not define");
20.273 + // ignore exotic ops the JVM cares about; we just wont issue them
20.274 + //System.err.println("warning: "+err);
20.275 + continue;
20.276 + }
20.277 + }
20.278 + return true;
20.279 + }
20.280 + static {
20.281 + assert(verifyConstants());
20.282 + }
20.283 +
20.284 + // Up-calls from the JVM.
20.285 + // These must NOT be public.
20.286 +
20.287 + /**
20.288 + * The JVM is linking an invokedynamic instruction. Create a reified call site for it.
20.289 + */
20.290 + static MemberName linkCallSite(Object callerObj,
20.291 + Object bootstrapMethodObj,
20.292 + Object nameObj, Object typeObj,
20.293 + Object staticArguments,
20.294 + Object[] appendixResult) {
20.295 + MethodHandle bootstrapMethod = (MethodHandle)bootstrapMethodObj;
20.296 + Class<?> caller = (Class<?>)callerObj;
20.297 + String name = nameObj.toString().intern();
20.298 + MethodType type = (MethodType)typeObj;
20.299 + CallSite callSite = CallSite.makeSite(bootstrapMethod,
20.300 + name,
20.301 + type,
20.302 + staticArguments,
20.303 + caller);
20.304 + if (callSite instanceof ConstantCallSite) {
20.305 + appendixResult[0] = callSite.dynamicInvoker();
20.306 + return Invokers.linkToTargetMethod(type);
20.307 + } else {
20.308 + appendixResult[0] = callSite;
20.309 + return Invokers.linkToCallSiteMethod(type);
20.310 + }
20.311 + }
20.312 +
20.313 + /**
20.314 + * The JVM wants a pointer to a MethodType. Oblige it by finding or creating one.
20.315 + */
20.316 + static MethodType findMethodHandleType(Class<?> rtype, Class<?>[] ptypes) {
20.317 + return MethodType.makeImpl(rtype, ptypes, true);
20.318 + }
20.319 +
20.320 + /**
20.321 + * The JVM wants to link a call site that requires a dynamic type check.
20.322 + * Name is a type-checking invoker, invokeExact or invoke.
20.323 + * Return a JVM method (MemberName) to handle the invoking.
20.324 + * The method assumes the following arguments on the stack:
20.325 + * 0: the method handle being invoked
20.326 + * 1-N: the arguments to the method handle invocation
20.327 + * N+1: an optional, implicitly added argument (typically the given MethodType)
20.328 + * <p>
20.329 + * The nominal method at such a call site is an instance of
20.330 + * a signature-polymorphic method (see @PolymorphicSignature).
20.331 + * Such method instances are user-visible entities which are
20.332 + * "split" from the generic placeholder method in {@code MethodHandle}.
20.333 + * (Note that the placeholder method is not identical with any of
20.334 + * its instances. If invoked reflectively, is guaranteed to throw an
20.335 + * {@code UnsupportedOperationException}.)
20.336 + * If the signature-polymorphic method instance is ever reified,
20.337 + * it appears as a "copy" of the original placeholder
20.338 + * (a native final member of {@code MethodHandle}) except
20.339 + * that its type descriptor has shape required by the instance,
20.340 + * and the method instance is <em>not</em> varargs.
20.341 + * The method instance is also marked synthetic, since the
20.342 + * method (by definition) does not appear in Java source code.
20.343 + * <p>
20.344 + * The JVM is allowed to reify this method as instance metadata.
20.345 + * For example, {@code invokeBasic} is always reified.
20.346 + * But the JVM may instead call {@code linkMethod}.
20.347 + * If the result is an * ordered pair of a {@code (method, appendix)},
20.348 + * the method gets all the arguments (0..N inclusive)
20.349 + * plus the appendix (N+1), and uses the appendix to complete the call.
20.350 + * In this way, one reusable method (called a "linker method")
20.351 + * can perform the function of any number of polymorphic instance
20.352 + * methods.
20.353 + * <p>
20.354 + * Linker methods are allowed to be weakly typed, with any or
20.355 + * all references rewritten to {@code Object} and any primitives
20.356 + * (except {@code long}/{@code float}/{@code double})
20.357 + * rewritten to {@code int}.
20.358 + * A linker method is trusted to return a strongly typed result,
20.359 + * according to the specific method type descriptor of the
20.360 + * signature-polymorphic instance it is emulating.
20.361 + * This can involve (as necessary) a dynamic check using
20.362 + * data extracted from the appendix argument.
20.363 + * <p>
20.364 + * The JVM does not inspect the appendix, other than to pass
20.365 + * it verbatim to the linker method at every call.
20.366 + * This means that the JDK runtime has wide latitude
20.367 + * for choosing the shape of each linker method and its
20.368 + * corresponding appendix.
20.369 + * Linker methods should be generated from {@code LambdaForm}s
20.370 + * so that they do not become visible on stack traces.
20.371 + * <p>
20.372 + * The {@code linkMethod} call is free to omit the appendix
20.373 + * (returning null) and instead emulate the required function
20.374 + * completely in the linker method.
20.375 + * As a corner case, if N==255, no appendix is possible.
20.376 + * In this case, the method returned must be custom-generated to
20.377 + * to perform any needed type checking.
20.378 + * <p>
20.379 + * If the JVM does not reify a method at a call site, but instead
20.380 + * calls {@code linkMethod}, the corresponding call represented
20.381 + * in the bytecodes may mention a valid method which is not
20.382 + * representable with a {@code MemberName}.
20.383 + * Therefore, use cases for {@code linkMethod} tend to correspond to
20.384 + * special cases in reflective code such as {@code findVirtual}
20.385 + * or {@code revealDirect}.
20.386 + */
20.387 + static MemberName linkMethod(Class<?> callerClass, int refKind,
20.388 + Class<?> defc, String name, Object type,
20.389 + Object[] appendixResult) {
20.390 + if (!TRACE_METHOD_LINKAGE)
20.391 + return linkMethodImpl(callerClass, refKind, defc, name, type, appendixResult);
20.392 + return linkMethodTracing(callerClass, refKind, defc, name, type, appendixResult);
20.393 + }
20.394 + static MemberName linkMethodImpl(Class<?> callerClass, int refKind,
20.395 + Class<?> defc, String name, Object type,
20.396 + Object[] appendixResult) {
20.397 + try {
20.398 + if (defc == MethodHandle.class && refKind == REF_invokeVirtual) {
20.399 + return Invokers.methodHandleInvokeLinkerMethod(name, fixMethodType(callerClass, type), appendixResult);
20.400 + }
20.401 + } catch (Throwable ex) {
20.402 + if (ex instanceof LinkageError)
20.403 + throw (LinkageError) ex;
20.404 + else
20.405 + throw new LinkageError(ex.getMessage(), ex);
20.406 + }
20.407 + throw new LinkageError("no such method "+defc.getName()+"."+name+type);
20.408 + }
20.409 + private static MethodType fixMethodType(Class<?> callerClass, Object type) {
20.410 + if (type instanceof MethodType)
20.411 + return (MethodType) type;
20.412 + else
20.413 + return MethodType.fromMethodDescriptorString((String)type, callerClass.getClassLoader());
20.414 + }
20.415 + // Tracing logic:
20.416 + static MemberName linkMethodTracing(Class<?> callerClass, int refKind,
20.417 + Class<?> defc, String name, Object type,
20.418 + Object[] appendixResult) {
20.419 + System.out.println("linkMethod "+defc.getName()+"."+
20.420 + name+type+"/"+Integer.toHexString(refKind));
20.421 + try {
20.422 + MemberName res = linkMethodImpl(callerClass, refKind, defc, name, type, appendixResult);
20.423 + System.out.println("linkMethod => "+res+" + "+appendixResult[0]);
20.424 + return res;
20.425 + } catch (Throwable ex) {
20.426 + System.out.println("linkMethod => throw "+ex);
20.427 + throw ex;
20.428 + }
20.429 + }
20.430 +
20.431 +
20.432 + /**
20.433 + * The JVM is resolving a CONSTANT_MethodHandle CP entry. And it wants our help.
20.434 + * It will make an up-call to this method. (Do not change the name or signature.)
20.435 + * The type argument is a Class for field requests and a MethodType for non-fields.
20.436 + * <p>
20.437 + * Recent versions of the JVM may also pass a resolved MemberName for the type.
20.438 + * In that case, the name is ignored and may be null.
20.439 + */
20.440 + static MethodHandle linkMethodHandleConstant(Class<?> callerClass, int refKind,
20.441 + Class<?> defc, String name, Object type) {
20.442 + try {
20.443 + Lookup lookup = IMPL_LOOKUP.in(callerClass);
20.444 + assert(refKindIsValid(refKind));
20.445 + return lookup.linkMethodHandleConstant((byte) refKind, defc, name, type);
20.446 + } catch (IllegalAccessException ex) {
20.447 + Throwable cause = ex.getCause();
20.448 + if (cause instanceof AbstractMethodError) {
20.449 + throw (AbstractMethodError) cause;
20.450 + } else {
20.451 + Error err = new IllegalAccessError(ex.getMessage());
20.452 + throw initCauseFrom(err, ex);
20.453 + }
20.454 + } catch (NoSuchMethodException ex) {
20.455 + Error err = new NoSuchMethodError(ex.getMessage());
20.456 + throw initCauseFrom(err, ex);
20.457 + } catch (NoSuchFieldException ex) {
20.458 + Error err = new NoSuchFieldError(ex.getMessage());
20.459 + throw initCauseFrom(err, ex);
20.460 + } catch (ReflectiveOperationException ex) {
20.461 + Error err = new IncompatibleClassChangeError();
20.462 + throw initCauseFrom(err, ex);
20.463 + }
20.464 + }
20.465 +
20.466 + /**
20.467 + * Use best possible cause for err.initCause(), substituting the
20.468 + * cause for err itself if the cause has the same (or better) type.
20.469 + */
20.470 + static private Error initCauseFrom(Error err, Exception ex) {
20.471 + Throwable th = ex.getCause();
20.472 + if (err.getClass().isInstance(th))
20.473 + return (Error) th;
20.474 + err.initCause(th == null ? ex : th);
20.475 + return err;
20.476 + }
20.477 +
20.478 + /**
20.479 + * Is this method a caller-sensitive method?
20.480 + * I.e., does it call Reflection.getCallerClass or a similer method
20.481 + * to ask about the identity of its caller?
20.482 + */
20.483 + static boolean isCallerSensitive(MemberName mem) {
20.484 + if (!mem.isInvocable()) return false; // fields are not caller sensitive
20.485 +
20.486 + return mem.isCallerSensitive() || canBeCalledVirtual(mem);
20.487 + }
20.488 +
20.489 + static boolean canBeCalledVirtual(MemberName mem) {
20.490 + assert(mem.isInvocable());
20.491 + Class<?> defc = mem.getDeclaringClass();
20.492 + switch (mem.getName()) {
20.493 + case "checkMemberAccess":
20.494 + return canBeCalledVirtual(mem, java.lang.SecurityManager.class);
20.495 + case "getContextClassLoader":
20.496 + return canBeCalledVirtual(mem, java.lang.Thread.class);
20.497 + }
20.498 + return false;
20.499 + }
20.500 +
20.501 + static boolean canBeCalledVirtual(MemberName symbolicRef, Class<?> definingClass) {
20.502 + Class<?> symbolicRefClass = symbolicRef.getDeclaringClass();
20.503 + if (symbolicRefClass == definingClass) return true;
20.504 + if (symbolicRef.isStatic() || symbolicRef.isPrivate()) return false;
20.505 + return (definingClass.isAssignableFrom(symbolicRefClass) || // Msym overrides Mdef
20.506 + symbolicRefClass.isInterface()); // Mdef implements Msym
20.507 + }
20.508 +}
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
21.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/MethodHandleProxies.java Sat Aug 09 11:12:05 2014 +0200
21.3 @@ -0,0 +1,321 @@
21.4 +/*
21.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
21.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
21.7 + *
21.8 + * This code is free software; you can redistribute it and/or modify it
21.9 + * under the terms of the GNU General Public License version 2 only, as
21.10 + * published by the Free Software Foundation. Oracle designates this
21.11 + * particular file as subject to the "Classpath" exception as provided
21.12 + * by Oracle in the LICENSE file that accompanied this code.
21.13 + *
21.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
21.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21.17 + * version 2 for more details (a copy is included in the LICENSE file that
21.18 + * accompanied this code).
21.19 + *
21.20 + * You should have received a copy of the GNU General Public License version
21.21 + * 2 along with this work; if not, write to the Free Software Foundation,
21.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21.23 + *
21.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21.25 + * or visit www.oracle.com if you need additional information or have any
21.26 + * questions.
21.27 + */
21.28 +
21.29 +package java.lang.invoke;
21.30 +
21.31 +import java.lang.reflect.*;
21.32 +import java.security.AccessController;
21.33 +import java.security.PrivilegedAction;
21.34 +import sun.invoke.WrapperInstance;
21.35 +import java.util.ArrayList;
21.36 +import sun.reflect.CallerSensitive;
21.37 +import sun.reflect.Reflection;
21.38 +import sun.reflect.misc.ReflectUtil;
21.39 +
21.40 +/**
21.41 + * This class consists exclusively of static methods that help adapt
21.42 + * method handles to other JVM types, such as interfaces.
21.43 + */
21.44 +public class MethodHandleProxies {
21.45 +
21.46 + private MethodHandleProxies() { } // do not instantiate
21.47 +
21.48 + /**
21.49 + * Produces an instance of the given single-method interface which redirects
21.50 + * its calls to the given method handle.
21.51 + * <p>
21.52 + * A single-method interface is an interface which declares a uniquely named method.
21.53 + * When determining the uniquely named method of a single-method interface,
21.54 + * the public {@code Object} methods ({@code toString}, {@code equals}, {@code hashCode})
21.55 + * are disregarded. For example, {@link java.util.Comparator} is a single-method interface,
21.56 + * even though it re-declares the {@code Object.equals} method.
21.57 + * <p>
21.58 + * The interface must be public. No additional access checks are performed.
21.59 + * <p>
21.60 + * The resulting instance of the required type will respond to
21.61 + * invocation of the type's uniquely named method by calling
21.62 + * the given target on the incoming arguments,
21.63 + * and returning or throwing whatever the target
21.64 + * returns or throws. The invocation will be as if by
21.65 + * {@code target.invoke}.
21.66 + * The target's type will be checked before the
21.67 + * instance is created, as if by a call to {@code asType},
21.68 + * which may result in a {@code WrongMethodTypeException}.
21.69 + * <p>
21.70 + * The uniquely named method is allowed to be multiply declared,
21.71 + * with distinct type descriptors. (E.g., it can be overloaded,
21.72 + * or can possess bridge methods.) All such declarations are
21.73 + * connected directly to the target method handle.
21.74 + * Argument and return types are adjusted by {@code asType}
21.75 + * for each individual declaration.
21.76 + * <p>
21.77 + * The wrapper instance will implement the requested interface
21.78 + * and its super-types, but no other single-method interfaces.
21.79 + * This means that the instance will not unexpectedly
21.80 + * pass an {@code instanceof} test for any unrequested type.
21.81 + * <p style="font-size:smaller;">
21.82 + * <em>Implementation Note:</em>
21.83 + * Therefore, each instance must implement a unique single-method interface.
21.84 + * Implementations may not bundle together
21.85 + * multiple single-method interfaces onto single implementation classes
21.86 + * in the style of {@link java.awt.AWTEventMulticaster}.
21.87 + * <p>
21.88 + * The method handle may throw an <em>undeclared exception</em>,
21.89 + * which means any checked exception (or other checked throwable)
21.90 + * not declared by the requested type's single abstract method.
21.91 + * If this happens, the throwable will be wrapped in an instance of
21.92 + * {@link java.lang.reflect.UndeclaredThrowableException UndeclaredThrowableException}
21.93 + * and thrown in that wrapped form.
21.94 + * <p>
21.95 + * Like {@link java.lang.Integer#valueOf Integer.valueOf},
21.96 + * {@code asInterfaceInstance} is a factory method whose results are defined
21.97 + * by their behavior.
21.98 + * It is not guaranteed to return a new instance for every call.
21.99 + * <p>
21.100 + * Because of the possibility of {@linkplain java.lang.reflect.Method#isBridge bridge methods}
21.101 + * and other corner cases, the interface may also have several abstract methods
21.102 + * with the same name but having distinct descriptors (types of returns and parameters).
21.103 + * In this case, all the methods are bound in common to the one given target.
21.104 + * The type check and effective {@code asType} conversion is applied to each
21.105 + * method type descriptor, and all abstract methods are bound to the target in common.
21.106 + * Beyond this type check, no further checks are made to determine that the
21.107 + * abstract methods are related in any way.
21.108 + * <p>
21.109 + * Future versions of this API may accept additional types,
21.110 + * such as abstract classes with single abstract methods.
21.111 + * Future versions of this API may also equip wrapper instances
21.112 + * with one or more additional public "marker" interfaces.
21.113 + * <p>
21.114 + * If a security manager is installed, this method is caller sensitive.
21.115 + * During any invocation of the target method handle via the returned wrapper,
21.116 + * the original creator of the wrapper (the caller) will be visible
21.117 + * to context checks requested by the security manager.
21.118 + *
21.119 + * @param <T> the desired type of the wrapper, a single-method interface
21.120 + * @param intfc a class object representing {@code T}
21.121 + * @param target the method handle to invoke from the wrapper
21.122 + * @return a correctly-typed wrapper for the given target
21.123 + * @throws NullPointerException if either argument is null
21.124 + * @throws IllegalArgumentException if the {@code intfc} is not a
21.125 + * valid argument to this method
21.126 + * @throws WrongMethodTypeException if the target cannot
21.127 + * be converted to the type required by the requested interface
21.128 + */
21.129 + // Other notes to implementors:
21.130 + // <p>
21.131 + // No stable mapping is promised between the single-method interface and
21.132 + // the implementation class C. Over time, several implementation
21.133 + // classes might be used for the same type.
21.134 + // <p>
21.135 + // If the implementation is able
21.136 + // to prove that a wrapper of the required type
21.137 + // has already been created for a given
21.138 + // method handle, or for another method handle with the
21.139 + // same behavior, the implementation may return that wrapper in place of
21.140 + // a new wrapper.
21.141 + // <p>
21.142 + // This method is designed to apply to common use cases
21.143 + // where a single method handle must interoperate with
21.144 + // an interface that implements a function-like
21.145 + // API. Additional variations, such as single-abstract-method classes with
21.146 + // private constructors, or interfaces with multiple but related
21.147 + // entry points, must be covered by hand-written or automatically
21.148 + // generated adapter classes.
21.149 + //
21.150 + @CallerSensitive
21.151 + public static
21.152 + <T> T asInterfaceInstance(final Class<T> intfc, final MethodHandle target) {
21.153 + if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers()))
21.154 + throw new IllegalArgumentException("not a public interface: "+intfc.getName());
21.155 + final MethodHandle mh;
21.156 + if (System.getSecurityManager() != null) {
21.157 + final Class<?> caller = Reflection.getCallerClass();
21.158 + final ClassLoader ccl = caller != null ? caller.getClassLoader() : null;
21.159 + ReflectUtil.checkProxyPackageAccess(ccl, intfc);
21.160 + mh = ccl != null ? bindCaller(target, caller) : target;
21.161 + } else {
21.162 + mh = target;
21.163 + }
21.164 + ClassLoader proxyLoader = intfc.getClassLoader();
21.165 + if (proxyLoader == null) {
21.166 + ClassLoader cl = Thread.currentThread().getContextClassLoader(); // avoid use of BCP
21.167 + proxyLoader = cl != null ? cl : ClassLoader.getSystemClassLoader();
21.168 + }
21.169 + final Method[] methods = getSingleNameMethods(intfc);
21.170 + if (methods == null)
21.171 + throw new IllegalArgumentException("not a single-method interface: "+intfc.getName());
21.172 + final MethodHandle[] vaTargets = new MethodHandle[methods.length];
21.173 + for (int i = 0; i < methods.length; i++) {
21.174 + Method sm = methods[i];
21.175 + MethodType smMT = MethodType.methodType(sm.getReturnType(), sm.getParameterTypes());
21.176 + MethodHandle checkTarget = mh.asType(smMT); // make throw WMT
21.177 + checkTarget = checkTarget.asType(checkTarget.type().changeReturnType(Object.class));
21.178 + vaTargets[i] = checkTarget.asSpreader(Object[].class, smMT.parameterCount());
21.179 + }
21.180 + final InvocationHandler ih = new InvocationHandler() {
21.181 + private Object getArg(String name) {
21.182 + if ((Object)name == "getWrapperInstanceTarget") return target;
21.183 + if ((Object)name == "getWrapperInstanceType") return intfc;
21.184 + throw new AssertionError();
21.185 + }
21.186 + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
21.187 + for (int i = 0; i < methods.length; i++) {
21.188 + if (method.equals(methods[i]))
21.189 + return vaTargets[i].invokeExact(args);
21.190 + }
21.191 + if (method.getDeclaringClass() == WrapperInstance.class)
21.192 + return getArg(method.getName());
21.193 + if (isObjectMethod(method))
21.194 + return callObjectMethod(proxy, method, args);
21.195 + throw new InternalError("bad proxy method: "+method);
21.196 + }
21.197 + };
21.198 +
21.199 + final Object proxy;
21.200 + if (System.getSecurityManager() != null) {
21.201 + // sun.invoke.WrapperInstance is a restricted interface not accessible
21.202 + // by any non-null class loader.
21.203 + final ClassLoader loader = proxyLoader;
21.204 + proxy = AccessController.doPrivileged(new PrivilegedAction<Object>() {
21.205 + public Object run() {
21.206 + return Proxy.newProxyInstance(
21.207 + loader,
21.208 + new Class<?>[]{ intfc, WrapperInstance.class },
21.209 + ih);
21.210 + }
21.211 + });
21.212 + } else {
21.213 + proxy = Proxy.newProxyInstance(proxyLoader,
21.214 + new Class<?>[]{ intfc, WrapperInstance.class },
21.215 + ih);
21.216 + }
21.217 + return intfc.cast(proxy);
21.218 + }
21.219 +
21.220 + private static MethodHandle bindCaller(MethodHandle target, Class<?> hostClass) {
21.221 + MethodHandle cbmh = MethodHandleImpl.bindCaller(target, hostClass);
21.222 + if (target.isVarargsCollector()) {
21.223 + MethodType type = cbmh.type();
21.224 + int arity = type.parameterCount();
21.225 + return cbmh.asVarargsCollector(type.parameterType(arity-1));
21.226 + }
21.227 + return cbmh;
21.228 + }
21.229 +
21.230 + /**
21.231 + * Determines if the given object was produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
21.232 + * @param x any reference
21.233 + * @return true if the reference is not null and points to an object produced by {@code asInterfaceInstance}
21.234 + */
21.235 + public static
21.236 + boolean isWrapperInstance(Object x) {
21.237 + return x instanceof WrapperInstance;
21.238 + }
21.239 +
21.240 + private static WrapperInstance asWrapperInstance(Object x) {
21.241 + try {
21.242 + if (x != null)
21.243 + return (WrapperInstance) x;
21.244 + } catch (ClassCastException ex) {
21.245 + }
21.246 + throw new IllegalArgumentException("not a wrapper instance");
21.247 + }
21.248 +
21.249 + /**
21.250 + * Produces or recovers a target method handle which is behaviorally
21.251 + * equivalent to the unique method of this wrapper instance.
21.252 + * The object {@code x} must have been produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
21.253 + * This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}.
21.254 + * @param x any reference
21.255 + * @return a method handle implementing the unique method
21.256 + * @throws IllegalArgumentException if the reference x is not to a wrapper instance
21.257 + */
21.258 + public static
21.259 + MethodHandle wrapperInstanceTarget(Object x) {
21.260 + return asWrapperInstance(x).getWrapperInstanceTarget();
21.261 + }
21.262 +
21.263 + /**
21.264 + * Recovers the unique single-method interface type for which this wrapper instance was created.
21.265 + * The object {@code x} must have been produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
21.266 + * This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}.
21.267 + * @param x any reference
21.268 + * @return the single-method interface type for which the wrapper was created
21.269 + * @throws IllegalArgumentException if the reference x is not to a wrapper instance
21.270 + */
21.271 + public static
21.272 + Class<?> wrapperInstanceType(Object x) {
21.273 + return asWrapperInstance(x).getWrapperInstanceType();
21.274 + }
21.275 +
21.276 + private static
21.277 + boolean isObjectMethod(Method m) {
21.278 + switch (m.getName()) {
21.279 + case "toString":
21.280 + return (m.getReturnType() == String.class
21.281 + && m.getParameterTypes().length == 0);
21.282 + case "hashCode":
21.283 + return (m.getReturnType() == int.class
21.284 + && m.getParameterTypes().length == 0);
21.285 + case "equals":
21.286 + return (m.getReturnType() == boolean.class
21.287 + && m.getParameterTypes().length == 1
21.288 + && m.getParameterTypes()[0] == Object.class);
21.289 + }
21.290 + return false;
21.291 + }
21.292 +
21.293 + private static
21.294 + Object callObjectMethod(Object self, Method m, Object[] args) {
21.295 + assert(isObjectMethod(m)) : m;
21.296 + switch (m.getName()) {
21.297 + case "toString":
21.298 + return self.getClass().getName() + "@" + Integer.toHexString(self.hashCode());
21.299 + case "hashCode":
21.300 + return System.identityHashCode(self);
21.301 + case "equals":
21.302 + return (self == args[0]);
21.303 + }
21.304 + return null;
21.305 + }
21.306 +
21.307 + private static
21.308 + Method[] getSingleNameMethods(Class<?> intfc) {
21.309 + ArrayList<Method> methods = new ArrayList<Method>();
21.310 + String uniqueName = null;
21.311 + for (Method m : intfc.getMethods()) {
21.312 + if (isObjectMethod(m)) continue;
21.313 + if (!Modifier.isAbstract(m.getModifiers())) continue;
21.314 + String mname = m.getName();
21.315 + if (uniqueName == null)
21.316 + uniqueName = mname;
21.317 + else if (!uniqueName.equals(mname))
21.318 + return null; // too many abstract methods
21.319 + methods.add(m);
21.320 + }
21.321 + if (uniqueName == null) return null;
21.322 + return methods.toArray(new Method[methods.size()]);
21.323 + }
21.324 +}
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
22.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/MethodHandleStatics.java Sat Aug 09 11:12:05 2014 +0200
22.3 @@ -0,0 +1,131 @@
22.4 +/*
22.5 + * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
22.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
22.7 + *
22.8 + * This code is free software; you can redistribute it and/or modify it
22.9 + * under the terms of the GNU General Public License version 2 only, as
22.10 + * published by the Free Software Foundation. Oracle designates this
22.11 + * particular file as subject to the "Classpath" exception as provided
22.12 + * by Oracle in the LICENSE file that accompanied this code.
22.13 + *
22.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
22.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
22.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22.17 + * version 2 for more details (a copy is included in the LICENSE file that
22.18 + * accompanied this code).
22.19 + *
22.20 + * You should have received a copy of the GNU General Public License version
22.21 + * 2 along with this work; if not, write to the Free Software Foundation,
22.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22.23 + *
22.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22.25 + * or visit www.oracle.com if you need additional information or have any
22.26 + * questions.
22.27 + */
22.28 +
22.29 +package java.lang.invoke;
22.30 +
22.31 +import java.security.AccessController;
22.32 +import java.security.PrivilegedAction;
22.33 +import sun.misc.Unsafe;
22.34 +
22.35 +/**
22.36 + * This class consists exclusively of static names internal to the
22.37 + * method handle implementation.
22.38 + * Usage: {@code import static java.lang.invoke.MethodHandleStatics.*}
22.39 + * @author John Rose, JSR 292 EG
22.40 + */
22.41 +/*non-public*/ class MethodHandleStatics {
22.42 +
22.43 + private MethodHandleStatics() { } // do not instantiate
22.44 +
22.45 + static final Unsafe UNSAFE = Unsafe.getUnsafe();
22.46 +
22.47 + static final boolean DEBUG_METHOD_HANDLE_NAMES;
22.48 + static final boolean DUMP_CLASS_FILES;
22.49 + static final boolean TRACE_INTERPRETER;
22.50 + static final boolean TRACE_METHOD_LINKAGE;
22.51 + static final Integer COMPILE_THRESHOLD;
22.52 + static {
22.53 + final Object[] values = { false, false, false, false, null };
22.54 + AccessController.doPrivileged(new PrivilegedAction<Void>() {
22.55 + public Void run() {
22.56 + values[0] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
22.57 + values[1] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES");
22.58 + values[2] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_INTERPRETER");
22.59 + values[3] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE");
22.60 + values[4] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD");
22.61 + return null;
22.62 + }
22.63 + });
22.64 + DEBUG_METHOD_HANDLE_NAMES = (Boolean) values[0];
22.65 + DUMP_CLASS_FILES = (Boolean) values[1];
22.66 + TRACE_INTERPRETER = (Boolean) values[2];
22.67 + TRACE_METHOD_LINKAGE = (Boolean) values[3];
22.68 + COMPILE_THRESHOLD = (Integer) values[4];
22.69 + }
22.70 +
22.71 + /*non-public*/ static String getNameString(MethodHandle target, MethodType type) {
22.72 + if (type == null)
22.73 + type = target.type();
22.74 + MemberName name = null;
22.75 + if (target != null)
22.76 + name = target.internalMemberName();
22.77 + if (name == null)
22.78 + return "invoke" + type;
22.79 + return name.getName() + type;
22.80 + }
22.81 +
22.82 + /*non-public*/ static String getNameString(MethodHandle target, MethodHandle typeHolder) {
22.83 + return getNameString(target, typeHolder == null ? (MethodType) null : typeHolder.type());
22.84 + }
22.85 +
22.86 + /*non-public*/ static String getNameString(MethodHandle target) {
22.87 + return getNameString(target, (MethodType) null);
22.88 + }
22.89 +
22.90 + /*non-public*/ static String addTypeString(Object obj, MethodHandle target) {
22.91 + String str = String.valueOf(obj);
22.92 + if (target == null) return str;
22.93 + int paren = str.indexOf('(');
22.94 + if (paren >= 0) str = str.substring(0, paren);
22.95 + return str + target.type();
22.96 + }
22.97 +
22.98 + // handy shared exception makers (they simplify the common case code)
22.99 + /*non-public*/ static InternalError newInternalError(String message, Throwable cause) {
22.100 + return new InternalError(message, cause);
22.101 + }
22.102 + /*non-public*/ static InternalError newInternalError(Throwable cause) {
22.103 + return new InternalError(cause);
22.104 + }
22.105 + /*non-public*/ static RuntimeException newIllegalStateException(String message) {
22.106 + return new IllegalStateException(message);
22.107 + }
22.108 + /*non-public*/ static RuntimeException newIllegalStateException(String message, Object obj) {
22.109 + return new IllegalStateException(message(message, obj));
22.110 + }
22.111 + /*non-public*/ static RuntimeException newIllegalArgumentException(String message) {
22.112 + return new IllegalArgumentException(message);
22.113 + }
22.114 + /*non-public*/ static RuntimeException newIllegalArgumentException(String message, Object obj) {
22.115 + return new IllegalArgumentException(message(message, obj));
22.116 + }
22.117 + /*non-public*/ static RuntimeException newIllegalArgumentException(String message, Object obj, Object obj2) {
22.118 + return new IllegalArgumentException(message(message, obj, obj2));
22.119 + }
22.120 + /*non-public*/ static Error uncaughtException(Throwable ex) {
22.121 + throw newInternalError("uncaught exception", ex);
22.122 + }
22.123 + static Error NYI() {
22.124 + throw new AssertionError("NYI");
22.125 + }
22.126 + private static String message(String message, Object obj) {
22.127 + if (obj != null) message = message + ": " + obj;
22.128 + return message;
22.129 + }
22.130 + private static String message(String message, Object obj, Object obj2) {
22.131 + if (obj != null || obj2 != null) message = message + ": " + obj + ", " + obj2;
22.132 + return message;
22.133 + }
22.134 +}
23.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
23.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/MethodHandles.java Sat Aug 09 11:12:05 2014 +0200
23.3 @@ -0,0 +1,2848 @@
23.4 +/*
23.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
23.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
23.7 + *
23.8 + * This code is free software; you can redistribute it and/or modify it
23.9 + * under the terms of the GNU General Public License version 2 only, as
23.10 + * published by the Free Software Foundation. Oracle designates this
23.11 + * particular file as subject to the "Classpath" exception as provided
23.12 + * by Oracle in the LICENSE file that accompanied this code.
23.13 + *
23.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
23.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
23.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23.17 + * version 2 for more details (a copy is included in the LICENSE file that
23.18 + * accompanied this code).
23.19 + *
23.20 + * You should have received a copy of the GNU General Public License version
23.21 + * 2 along with this work; if not, write to the Free Software Foundation,
23.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
23.23 + *
23.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23.25 + * or visit www.oracle.com if you need additional information or have any
23.26 + * questions.
23.27 + */
23.28 +
23.29 +package java.lang.invoke;
23.30 +
23.31 +import java.lang.reflect.*;
23.32 +import java.util.List;
23.33 +import java.util.ArrayList;
23.34 +import java.util.Arrays;
23.35 +
23.36 +import sun.invoke.util.ValueConversions;
23.37 +import sun.invoke.util.VerifyAccess;
23.38 +import sun.invoke.util.Wrapper;
23.39 +import sun.reflect.CallerSensitive;
23.40 +import sun.reflect.Reflection;
23.41 +import sun.reflect.misc.ReflectUtil;
23.42 +import sun.security.util.SecurityConstants;
23.43 +import static java.lang.invoke.MethodHandleStatics.*;
23.44 +import static java.lang.invoke.MethodHandleNatives.Constants.*;
23.45 +import java.util.concurrent.ConcurrentHashMap;
23.46 +import sun.security.util.SecurityConstants;
23.47 +
23.48 +/**
23.49 + * This class consists exclusively of static methods that operate on or return
23.50 + * method handles. They fall into several categories:
23.51 + * <ul>
23.52 + * <li>Lookup methods which help create method handles for methods and fields.
23.53 + * <li>Combinator methods, which combine or transform pre-existing method handles into new ones.
23.54 + * <li>Other factory methods to create method handles that emulate other common JVM operations or control flow patterns.
23.55 + * </ul>
23.56 + * <p>
23.57 + * @author John Rose, JSR 292 EG
23.58 + * @since 1.7
23.59 + */
23.60 +public class MethodHandles {
23.61 +
23.62 + private MethodHandles() { } // do not instantiate
23.63 +
23.64 + private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
23.65 + static { MethodHandleImpl.initStatics(); }
23.66 + // See IMPL_LOOKUP below.
23.67 +
23.68 + //// Method handle creation from ordinary methods.
23.69 +
23.70 + /**
23.71 + * Returns a {@link Lookup lookup object} with
23.72 + * full capabilities to emulate all supported bytecode behaviors of the caller.
23.73 + * These capabilities include <a href="MethodHandles.Lookup.html#privacc">private access</a> to the caller.
23.74 + * Factory methods on the lookup object can create
23.75 + * <a href="MethodHandleInfo.html#directmh">direct method handles</a>
23.76 + * for any member that the caller has access to via bytecodes,
23.77 + * including protected and private fields and methods.
23.78 + * This lookup object is a <em>capability</em> which may be delegated to trusted agents.
23.79 + * Do not store it in place where untrusted code can access it.
23.80 + * <p>
23.81 + * This method is caller sensitive, which means that it may return different
23.82 + * values to different callers.
23.83 + * <p>
23.84 + * For any given caller class {@code C}, the lookup object returned by this call
23.85 + * has equivalent capabilities to any lookup object
23.86 + * supplied by the JVM to the bootstrap method of an
23.87 + * <a href="package-summary.html#indyinsn">invokedynamic instruction</a>
23.88 + * executing in the same caller class {@code C}.
23.89 + * @return a lookup object for the caller of this method, with private access
23.90 + */
23.91 + @CallerSensitive
23.92 + public static Lookup lookup() {
23.93 + return new Lookup(Reflection.getCallerClass());
23.94 + }
23.95 +
23.96 + /**
23.97 + * Returns a {@link Lookup lookup object} which is trusted minimally.
23.98 + * It can only be used to create method handles to
23.99 + * publicly accessible fields and methods.
23.100 + * <p>
23.101 + * As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class}
23.102 + * of this lookup object will be {@link java.lang.Object}.
23.103 + *
23.104 + * <p style="font-size:smaller;">
23.105 + * <em>Discussion:</em>
23.106 + * The lookup class can be changed to any other class {@code C} using an expression of the form
23.107 + * {@link Lookup#in publicLookup().in(C.class)}.
23.108 + * Since all classes have equal access to public names,
23.109 + * such a change would confer no new access rights.
23.110 + * A public lookup object is always subject to
23.111 + * <a href="MethodHandles.Lookup.html#secmgr">security manager checks</a>.
23.112 + * Also, it cannot access
23.113 + * <a href="MethodHandles.Lookup.html#callsens">caller sensitive methods</a>.
23.114 + * @return a lookup object which is trusted minimally
23.115 + */
23.116 + public static Lookup publicLookup() {
23.117 + return Lookup.PUBLIC_LOOKUP;
23.118 + }
23.119 +
23.120 + /**
23.121 + * Performs an unchecked "crack" of a
23.122 + * <a href="MethodHandleInfo.html#directmh">direct method handle</a>.
23.123 + * The result is as if the user had obtained a lookup object capable enough
23.124 + * to crack the target method handle, called
23.125 + * {@link java.lang.invoke.MethodHandles.Lookup#revealDirect Lookup.revealDirect}
23.126 + * on the target to obtain its symbolic reference, and then called
23.127 + * {@link java.lang.invoke.MethodHandleInfo#reflectAs MethodHandleInfo.reflectAs}
23.128 + * to resolve the symbolic reference to a member.
23.129 + * <p>
23.130 + * If there is a security manager, its {@code checkPermission} method
23.131 + * is called with a {@code ReflectPermission("suppressAccessChecks")} permission.
23.132 + * @param <T> the desired type of the result, either {@link Member} or a subtype
23.133 + * @param target a direct method handle to crack into symbolic reference components
23.134 + * @param expected a class object representing the desired result type {@code T}
23.135 + * @return a reference to the method, constructor, or field object
23.136 + * @exception SecurityException if the caller is not privileged to call {@code setAccessible}
23.137 + * @exception NullPointerException if either argument is {@code null}
23.138 + * @exception IllegalArgumentException if the target is not a direct method handle
23.139 + * @exception ClassCastException if the member is not of the expected type
23.140 + * @since 1.8
23.141 + */
23.142 + public static <T extends Member> T
23.143 + reflectAs(Class<T> expected, MethodHandle target) {
23.144 + SecurityManager smgr = System.getSecurityManager();
23.145 + if (smgr != null) smgr.checkPermission(ACCESS_PERMISSION);
23.146 + Lookup lookup = Lookup.IMPL_LOOKUP; // use maximally privileged lookup
23.147 + return lookup.revealDirect(target).reflectAs(expected, lookup);
23.148 + }
23.149 + // Copied from AccessibleObject, as used by Method.setAccessible, etc.:
23.150 + static final private java.security.Permission ACCESS_PERMISSION =
23.151 + new ReflectPermission("suppressAccessChecks");
23.152 +
23.153 + /**
23.154 + * A <em>lookup object</em> is a factory for creating method handles,
23.155 + * when the creation requires access checking.
23.156 + * Method handles do not perform
23.157 + * access checks when they are called, but rather when they are created.
23.158 + * Therefore, method handle access
23.159 + * restrictions must be enforced when a method handle is created.
23.160 + * The caller class against which those restrictions are enforced
23.161 + * is known as the {@linkplain #lookupClass lookup class}.
23.162 + * <p>
23.163 + * A lookup class which needs to create method handles will call
23.164 + * {@link MethodHandles#lookup MethodHandles.lookup} to create a factory for itself.
23.165 + * When the {@code Lookup} factory object is created, the identity of the lookup class is
23.166 + * determined, and securely stored in the {@code Lookup} object.
23.167 + * The lookup class (or its delegates) may then use factory methods
23.168 + * on the {@code Lookup} object to create method handles for access-checked members.
23.169 + * This includes all methods, constructors, and fields which are allowed to the lookup class,
23.170 + * even private ones.
23.171 + *
23.172 + * <h1><a name="lookups"></a>Lookup Factory Methods</h1>
23.173 + * The factory methods on a {@code Lookup} object correspond to all major
23.174 + * use cases for methods, constructors, and fields.
23.175 + * Each method handle created by a factory method is the functional
23.176 + * equivalent of a particular <em>bytecode behavior</em>.
23.177 + * (Bytecode behaviors are described in section 5.4.3.5 of the Java Virtual Machine Specification.)
23.178 + * Here is a summary of the correspondence between these factory methods and
23.179 + * the behavior the resulting method handles:
23.180 + * <table border=1 cellpadding=5 summary="lookup method behaviors">
23.181 + * <tr>
23.182 + * <th><a name="equiv"></a>lookup expression</th>
23.183 + * <th>member</th>
23.184 + * <th>bytecode behavior</th>
23.185 + * </tr>
23.186 + * <tr>
23.187 + * <td>{@link java.lang.invoke.MethodHandles.Lookup#findGetter lookup.findGetter(C.class,"f",FT.class)}</td>
23.188 + * <td>{@code FT f;}</td><td>{@code (T) this.f;}</td>
23.189 + * </tr>
23.190 + * <tr>
23.191 + * <td>{@link java.lang.invoke.MethodHandles.Lookup#findStaticGetter lookup.findStaticGetter(C.class,"f",FT.class)}</td>
23.192 + * <td>{@code static}<br>{@code FT f;}</td><td>{@code (T) C.f;}</td>
23.193 + * </tr>
23.194 + * <tr>
23.195 + * <td>{@link java.lang.invoke.MethodHandles.Lookup#findSetter lookup.findSetter(C.class,"f",FT.class)}</td>
23.196 + * <td>{@code FT f;}</td><td>{@code this.f = x;}</td>
23.197 + * </tr>
23.198 + * <tr>
23.199 + * <td>{@link java.lang.invoke.MethodHandles.Lookup#findStaticSetter lookup.findStaticSetter(C.class,"f",FT.class)}</td>
23.200 + * <td>{@code static}<br>{@code FT f;}</td><td>{@code C.f = arg;}</td>
23.201 + * </tr>
23.202 + * <tr>
23.203 + * <td>{@link java.lang.invoke.MethodHandles.Lookup#findVirtual lookup.findVirtual(C.class,"m",MT)}</td>
23.204 + * <td>{@code T m(A*);}</td><td>{@code (T) this.m(arg*);}</td>
23.205 + * </tr>
23.206 + * <tr>
23.207 + * <td>{@link java.lang.invoke.MethodHandles.Lookup#findStatic lookup.findStatic(C.class,"m",MT)}</td>
23.208 + * <td>{@code static}<br>{@code T m(A*);}</td><td>{@code (T) C.m(arg*);}</td>
23.209 + * </tr>
23.210 + * <tr>
23.211 + * <td>{@link java.lang.invoke.MethodHandles.Lookup#findSpecial lookup.findSpecial(C.class,"m",MT,this.class)}</td>
23.212 + * <td>{@code T m(A*);}</td><td>{@code (T) super.m(arg*);}</td>
23.213 + * </tr>
23.214 + * <tr>
23.215 + * <td>{@link java.lang.invoke.MethodHandles.Lookup#findConstructor lookup.findConstructor(C.class,MT)}</td>
23.216 + * <td>{@code C(A*);}</td><td>{@code new C(arg*);}</td>
23.217 + * </tr>
23.218 + * <tr>
23.219 + * <td>{@link java.lang.invoke.MethodHandles.Lookup#unreflectGetter lookup.unreflectGetter(aField)}</td>
23.220 + * <td>({@code static})?<br>{@code FT f;}</td><td>{@code (FT) aField.get(thisOrNull);}</td>
23.221 + * </tr>
23.222 + * <tr>
23.223 + * <td>{@link java.lang.invoke.MethodHandles.Lookup#unreflectSetter lookup.unreflectSetter(aField)}</td>
23.224 + * <td>({@code static})?<br>{@code FT f;}</td><td>{@code aField.set(thisOrNull, arg);}</td>
23.225 + * </tr>
23.226 + * <tr>
23.227 + * <td>{@link java.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)}</td>
23.228 + * <td>({@code static})?<br>{@code T m(A*);}</td><td>{@code (T) aMethod.invoke(thisOrNull, arg*);}</td>
23.229 + * </tr>
23.230 + * <tr>
23.231 + * <td>{@link java.lang.invoke.MethodHandles.Lookup#unreflectConstructor lookup.unreflectConstructor(aConstructor)}</td>
23.232 + * <td>{@code C(A*);}</td><td>{@code (C) aConstructor.newInstance(arg*);}</td>
23.233 + * </tr>
23.234 + * <tr>
23.235 + * <td>{@link java.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)}</td>
23.236 + * <td>({@code static})?<br>{@code T m(A*);}</td><td>{@code (T) aMethod.invoke(thisOrNull, arg*);}</td>
23.237 + * </tr>
23.238 + * </table>
23.239 + *
23.240 + * Here, the type {@code C} is the class or interface being searched for a member,
23.241 + * documented as a parameter named {@code refc} in the lookup methods.
23.242 + * The method type {@code MT} is composed from the return type {@code T}
23.243 + * and the sequence of argument types {@code A*}.
23.244 + * The constructor also has a sequence of argument types {@code A*} and
23.245 + * is deemed to return the newly-created object of type {@code C}.
23.246 + * Both {@code MT} and the field type {@code FT} are documented as a parameter named {@code type}.
23.247 + * The formal parameter {@code this} stands for the self-reference of type {@code C};
23.248 + * if it is present, it is always the leading argument to the method handle invocation.
23.249 + * (In the case of some {@code protected} members, {@code this} may be
23.250 + * restricted in type to the lookup class; see below.)
23.251 + * The name {@code arg} stands for all the other method handle arguments.
23.252 + * In the code examples for the Core Reflection API, the name {@code thisOrNull}
23.253 + * stands for a null reference if the accessed method or field is static,
23.254 + * and {@code this} otherwise.
23.255 + * The names {@code aMethod}, {@code aField}, and {@code aConstructor} stand
23.256 + * for reflective objects corresponding to the given members.
23.257 + * <p>
23.258 + * In cases where the given member is of variable arity (i.e., a method or constructor)
23.259 + * the returned method handle will also be of {@linkplain MethodHandle#asVarargsCollector variable arity}.
23.260 + * In all other cases, the returned method handle will be of fixed arity.
23.261 + * <p style="font-size:smaller;">
23.262 + * <em>Discussion:</em>
23.263 + * The equivalence between looked-up method handles and underlying
23.264 + * class members and bytecode behaviors
23.265 + * can break down in a few ways:
23.266 + * <ul style="font-size:smaller;">
23.267 + * <li>If {@code C} is not symbolically accessible from the lookup class's loader,
23.268 + * the lookup can still succeed, even when there is no equivalent
23.269 + * Java expression or bytecoded constant.
23.270 + * <li>Likewise, if {@code T} or {@code MT}
23.271 + * is not symbolically accessible from the lookup class's loader,
23.272 + * the lookup can still succeed.
23.273 + * For example, lookups for {@code MethodHandle.invokeExact} and
23.274 + * {@code MethodHandle.invoke} will always succeed, regardless of requested type.
23.275 + * <li>If there is a security manager installed, it can forbid the lookup
23.276 + * on various grounds (<a href="MethodHandles.Lookup.html#secmgr">see below</a>).
23.277 + * By contrast, the {@code ldc} instruction on a {@code CONSTANT_MethodHandle}
23.278 + * constant is not subject to security manager checks.
23.279 + * <li>If the looked-up method has a
23.280 + * <a href="MethodHandle.html#maxarity">very large arity</a>,
23.281 + * the method handle creation may fail, due to the method handle
23.282 + * type having too many parameters.
23.283 + * </ul>
23.284 + *
23.285 + * <h1><a name="access"></a>Access checking</h1>
23.286 + * Access checks are applied in the factory methods of {@code Lookup},
23.287 + * when a method handle is created.
23.288 + * This is a key difference from the Core Reflection API, since
23.289 + * {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}
23.290 + * performs access checking against every caller, on every call.
23.291 + * <p>
23.292 + * All access checks start from a {@code Lookup} object, which
23.293 + * compares its recorded lookup class against all requests to
23.294 + * create method handles.
23.295 + * A single {@code Lookup} object can be used to create any number
23.296 + * of access-checked method handles, all checked against a single
23.297 + * lookup class.
23.298 + * <p>
23.299 + * A {@code Lookup} object can be shared with other trusted code,
23.300 + * such as a metaobject protocol.
23.301 + * A shared {@code Lookup} object delegates the capability
23.302 + * to create method handles on private members of the lookup class.
23.303 + * Even if privileged code uses the {@code Lookup} object,
23.304 + * the access checking is confined to the privileges of the
23.305 + * original lookup class.
23.306 + * <p>
23.307 + * A lookup can fail, because
23.308 + * the containing class is not accessible to the lookup class, or
23.309 + * because the desired class member is missing, or because the
23.310 + * desired class member is not accessible to the lookup class, or
23.311 + * because the lookup object is not trusted enough to access the member.
23.312 + * In any of these cases, a {@code ReflectiveOperationException} will be
23.313 + * thrown from the attempted lookup. The exact class will be one of
23.314 + * the following:
23.315 + * <ul>
23.316 + * <li>NoSuchMethodException — if a method is requested but does not exist
23.317 + * <li>NoSuchFieldException — if a field is requested but does not exist
23.318 + * <li>IllegalAccessException — if the member exists but an access check fails
23.319 + * </ul>
23.320 + * <p>
23.321 + * In general, the conditions under which a method handle may be
23.322 + * looked up for a method {@code M} are no more restrictive than the conditions
23.323 + * under which the lookup class could have compiled, verified, and resolved a call to {@code M}.
23.324 + * Where the JVM would raise exceptions like {@code NoSuchMethodError},
23.325 + * a method handle lookup will generally raise a corresponding
23.326 + * checked exception, such as {@code NoSuchMethodException}.
23.327 + * And the effect of invoking the method handle resulting from the lookup
23.328 + * is <a href="MethodHandles.Lookup.html#equiv">exactly equivalent</a>
23.329 + * to executing the compiled, verified, and resolved call to {@code M}.
23.330 + * The same point is true of fields and constructors.
23.331 + * <p style="font-size:smaller;">
23.332 + * <em>Discussion:</em>
23.333 + * Access checks only apply to named and reflected methods,
23.334 + * constructors, and fields.
23.335 + * Other method handle creation methods, such as
23.336 + * {@link MethodHandle#asType MethodHandle.asType},
23.337 + * do not require any access checks, and are used
23.338 + * independently of any {@code Lookup} object.
23.339 + * <p>
23.340 + * If the desired member is {@code protected}, the usual JVM rules apply,
23.341 + * including the requirement that the lookup class must be either be in the
23.342 + * same package as the desired member, or must inherit that member.
23.343 + * (See the Java Virtual Machine Specification, sections 4.9.2, 5.4.3.5, and 6.4.)
23.344 + * In addition, if the desired member is a non-static field or method
23.345 + * in a different package, the resulting method handle may only be applied
23.346 + * to objects of the lookup class or one of its subclasses.
23.347 + * This requirement is enforced by narrowing the type of the leading
23.348 + * {@code this} parameter from {@code C}
23.349 + * (which will necessarily be a superclass of the lookup class)
23.350 + * to the lookup class itself.
23.351 + * <p>
23.352 + * The JVM imposes a similar requirement on {@code invokespecial} instruction,
23.353 + * that the receiver argument must match both the resolved method <em>and</em>
23.354 + * the current class. Again, this requirement is enforced by narrowing the
23.355 + * type of the leading parameter to the resulting method handle.
23.356 + * (See the Java Virtual Machine Specification, section 4.10.1.9.)
23.357 + * <p>
23.358 + * The JVM represents constructors and static initializer blocks as internal methods
23.359 + * with special names ({@code "<init>"} and {@code "<clinit>"}).
23.360 + * The internal syntax of invocation instructions allows them to refer to such internal
23.361 + * methods as if they were normal methods, but the JVM bytecode verifier rejects them.
23.362 + * A lookup of such an internal method will produce a {@code NoSuchMethodException}.
23.363 + * <p>
23.364 + * In some cases, access between nested classes is obtained by the Java compiler by creating
23.365 + * an wrapper method to access a private method of another class
23.366 + * in the same top-level declaration.
23.367 + * For example, a nested class {@code C.D}
23.368 + * can access private members within other related classes such as
23.369 + * {@code C}, {@code C.D.E}, or {@code C.B},
23.370 + * but the Java compiler may need to generate wrapper methods in
23.371 + * those related classes. In such cases, a {@code Lookup} object on
23.372 + * {@code C.E} would be unable to those private members.
23.373 + * A workaround for this limitation is the {@link Lookup#in Lookup.in} method,
23.374 + * which can transform a lookup on {@code C.E} into one on any of those other
23.375 + * classes, without special elevation of privilege.
23.376 + * <p>
23.377 + * The accesses permitted to a given lookup object may be limited,
23.378 + * according to its set of {@link #lookupModes lookupModes},
23.379 + * to a subset of members normally accessible to the lookup class.
23.380 + * For example, the {@link MethodHandles#publicLookup publicLookup}
23.381 + * method produces a lookup object which is only allowed to access
23.382 + * public members in public classes.
23.383 + * The caller sensitive method {@link MethodHandles#lookup lookup}
23.384 + * produces a lookup object with full capabilities relative to
23.385 + * its caller class, to emulate all supported bytecode behaviors.
23.386 + * Also, the {@link Lookup#in Lookup.in} method may produce a lookup object
23.387 + * with fewer access modes than the original lookup object.
23.388 + *
23.389 + * <p style="font-size:smaller;">
23.390 + * <a name="privacc"></a>
23.391 + * <em>Discussion of private access:</em>
23.392 + * We say that a lookup has <em>private access</em>
23.393 + * if its {@linkplain #lookupModes lookup modes}
23.394 + * include the possibility of accessing {@code private} members.
23.395 + * As documented in the relevant methods elsewhere,
23.396 + * only lookups with private access possess the following capabilities:
23.397 + * <ul style="font-size:smaller;">
23.398 + * <li>access private fields, methods, and constructors of the lookup class
23.399 + * <li>create method handles which invoke <a href="MethodHandles.Lookup.html#callsens">caller sensitive</a> methods,
23.400 + * such as {@code Class.forName}
23.401 + * <li>create method handles which {@link Lookup#findSpecial emulate invokespecial} instructions
23.402 + * <li>avoid <a href="MethodHandles.Lookup.html#secmgr">package access checks</a>
23.403 + * for classes accessible to the lookup class
23.404 + * <li>create {@link Lookup#in delegated lookup objects} which have private access to other classes
23.405 + * within the same package member
23.406 + * </ul>
23.407 + * <p style="font-size:smaller;">
23.408 + * Each of these permissions is a consequence of the fact that a lookup object
23.409 + * with private access can be securely traced back to an originating class,
23.410 + * whose <a href="MethodHandles.Lookup.html#equiv">bytecode behaviors</a> and Java language access permissions
23.411 + * can be reliably determined and emulated by method handles.
23.412 + *
23.413 + * <h1><a name="secmgr"></a>Security manager interactions</h1>
23.414 + * Although bytecode instructions can only refer to classes in
23.415 + * a related class loader, this API can search for methods in any
23.416 + * class, as long as a reference to its {@code Class} object is
23.417 + * available. Such cross-loader references are also possible with the
23.418 + * Core Reflection API, and are impossible to bytecode instructions
23.419 + * such as {@code invokestatic} or {@code getfield}.
23.420 + * There is a {@linkplain java.lang.SecurityManager security manager API}
23.421 + * to allow applications to check such cross-loader references.
23.422 + * These checks apply to both the {@code MethodHandles.Lookup} API
23.423 + * and the Core Reflection API
23.424 + * (as found on {@link java.lang.Class Class}).
23.425 + * <p>
23.426 + * If a security manager is present, member lookups are subject to
23.427 + * additional checks.
23.428 + * From one to three calls are made to the security manager.
23.429 + * Any of these calls can refuse access by throwing a
23.430 + * {@link java.lang.SecurityException SecurityException}.
23.431 + * Define {@code smgr} as the security manager,
23.432 + * {@code lookc} as the lookup class of the current lookup object,
23.433 + * {@code refc} as the containing class in which the member
23.434 + * is being sought, and {@code defc} as the class in which the
23.435 + * member is actually defined.
23.436 + * The value {@code lookc} is defined as <em>not present</em>
23.437 + * if the current lookup object does not have
23.438 + * <a href="MethodHandles.Lookup.html#privacc">private access</a>.
23.439 + * The calls are made according to the following rules:
23.440 + * <ul>
23.441 + * <li><b>Step 1:</b>
23.442 + * If {@code lookc} is not present, or if its class loader is not
23.443 + * the same as or an ancestor of the class loader of {@code refc},
23.444 + * then {@link SecurityManager#checkPackageAccess
23.445 + * smgr.checkPackageAccess(refcPkg)} is called,
23.446 + * where {@code refcPkg} is the package of {@code refc}.
23.447 + * <li><b>Step 2:</b>
23.448 + * If the retrieved member is not public and
23.449 + * {@code lookc} is not present, then
23.450 + * {@link SecurityManager#checkPermission smgr.checkPermission}
23.451 + * with {@code RuntimePermission("accessDeclaredMembers")} is called.
23.452 + * <li><b>Step 3:</b>
23.453 + * If the retrieved member is not public,
23.454 + * and if {@code lookc} is not present,
23.455 + * and if {@code defc} and {@code refc} are different,
23.456 + * then {@link SecurityManager#checkPackageAccess
23.457 + * smgr.checkPackageAccess(defcPkg)} is called,
23.458 + * where {@code defcPkg} is the package of {@code defc}.
23.459 + * </ul>
23.460 + * Security checks are performed after other access checks have passed.
23.461 + * Therefore, the above rules presuppose a member that is public,
23.462 + * or else that is being accessed from a lookup class that has
23.463 + * rights to access the member.
23.464 + *
23.465 + * <h1><a name="callsens"></a>Caller sensitive methods</h1>
23.466 + * A small number of Java methods have a special property called caller sensitivity.
23.467 + * A <em>caller-sensitive</em> method can behave differently depending on the
23.468 + * identity of its immediate caller.
23.469 + * <p>
23.470 + * If a method handle for a caller-sensitive method is requested,
23.471 + * the general rules for <a href="MethodHandles.Lookup.html#equiv">bytecode behaviors</a> apply,
23.472 + * but they take account of the lookup class in a special way.
23.473 + * The resulting method handle behaves as if it were called
23.474 + * from an instruction contained in the lookup class,
23.475 + * so that the caller-sensitive method detects the lookup class.
23.476 + * (By contrast, the invoker of the method handle is disregarded.)
23.477 + * Thus, in the case of caller-sensitive methods,
23.478 + * different lookup classes may give rise to
23.479 + * differently behaving method handles.
23.480 + * <p>
23.481 + * In cases where the lookup object is
23.482 + * {@link MethodHandles#publicLookup() publicLookup()},
23.483 + * or some other lookup object without
23.484 + * <a href="MethodHandles.Lookup.html#privacc">private access</a>,
23.485 + * the lookup class is disregarded.
23.486 + * In such cases, no caller-sensitive method handle can be created,
23.487 + * access is forbidden, and the lookup fails with an
23.488 + * {@code IllegalAccessException}.
23.489 + * <p style="font-size:smaller;">
23.490 + * <em>Discussion:</em>
23.491 + * For example, the caller-sensitive method
23.492 + * {@link java.lang.Class#forName(String) Class.forName(x)}
23.493 + * can return varying classes or throw varying exceptions,
23.494 + * depending on the class loader of the class that calls it.
23.495 + * A public lookup of {@code Class.forName} will fail, because
23.496 + * there is no reasonable way to determine its bytecode behavior.
23.497 + * <p style="font-size:smaller;">
23.498 + * If an application caches method handles for broad sharing,
23.499 + * it should use {@code publicLookup()} to create them.
23.500 + * If there is a lookup of {@code Class.forName}, it will fail,
23.501 + * and the application must take appropriate action in that case.
23.502 + * It may be that a later lookup, perhaps during the invocation of a
23.503 + * bootstrap method, can incorporate the specific identity
23.504 + * of the caller, making the method accessible.
23.505 + * <p style="font-size:smaller;">
23.506 + * The function {@code MethodHandles.lookup} is caller sensitive
23.507 + * so that there can be a secure foundation for lookups.
23.508 + * Nearly all other methods in the JSR 292 API rely on lookup
23.509 + * objects to check access requests.
23.510 + */
23.511 + public static final
23.512 + class Lookup {
23.513 + /** The class on behalf of whom the lookup is being performed. */
23.514 + private final Class<?> lookupClass;
23.515 +
23.516 + /** The allowed sorts of members which may be looked up (PUBLIC, etc.). */
23.517 + private final int allowedModes;
23.518 +
23.519 + /** A single-bit mask representing {@code public} access,
23.520 + * which may contribute to the result of {@link #lookupModes lookupModes}.
23.521 + * The value, {@code 0x01}, happens to be the same as the value of the
23.522 + * {@code public} {@linkplain java.lang.reflect.Modifier#PUBLIC modifier bit}.
23.523 + */
23.524 + public static final int PUBLIC = Modifier.PUBLIC;
23.525 +
23.526 + /** A single-bit mask representing {@code private} access,
23.527 + * which may contribute to the result of {@link #lookupModes lookupModes}.
23.528 + * The value, {@code 0x02}, happens to be the same as the value of the
23.529 + * {@code private} {@linkplain java.lang.reflect.Modifier#PRIVATE modifier bit}.
23.530 + */
23.531 + public static final int PRIVATE = Modifier.PRIVATE;
23.532 +
23.533 + /** A single-bit mask representing {@code protected} access,
23.534 + * which may contribute to the result of {@link #lookupModes lookupModes}.
23.535 + * The value, {@code 0x04}, happens to be the same as the value of the
23.536 + * {@code protected} {@linkplain java.lang.reflect.Modifier#PROTECTED modifier bit}.
23.537 + */
23.538 + public static final int PROTECTED = Modifier.PROTECTED;
23.539 +
23.540 + /** A single-bit mask representing {@code package} access (default access),
23.541 + * which may contribute to the result of {@link #lookupModes lookupModes}.
23.542 + * The value is {@code 0x08}, which does not correspond meaningfully to
23.543 + * any particular {@linkplain java.lang.reflect.Modifier modifier bit}.
23.544 + */
23.545 + public static final int PACKAGE = Modifier.STATIC;
23.546 +
23.547 + private static final int ALL_MODES = (PUBLIC | PRIVATE | PROTECTED | PACKAGE);
23.548 + private static final int TRUSTED = -1;
23.549 +
23.550 + private static int fixmods(int mods) {
23.551 + mods &= (ALL_MODES - PACKAGE);
23.552 + return (mods != 0) ? mods : PACKAGE;
23.553 + }
23.554 +
23.555 + /** Tells which class is performing the lookup. It is this class against
23.556 + * which checks are performed for visibility and access permissions.
23.557 + * <p>
23.558 + * The class implies a maximum level of access permission,
23.559 + * but the permissions may be additionally limited by the bitmask
23.560 + * {@link #lookupModes lookupModes}, which controls whether non-public members
23.561 + * can be accessed.
23.562 + * @return the lookup class, on behalf of which this lookup object finds members
23.563 + */
23.564 + public Class<?> lookupClass() {
23.565 + return lookupClass;
23.566 + }
23.567 +
23.568 + // This is just for calling out to MethodHandleImpl.
23.569 + private Class<?> lookupClassOrNull() {
23.570 + return (allowedModes == TRUSTED) ? null : lookupClass;
23.571 + }
23.572 +
23.573 + /** Tells which access-protection classes of members this lookup object can produce.
23.574 + * The result is a bit-mask of the bits
23.575 + * {@linkplain #PUBLIC PUBLIC (0x01)},
23.576 + * {@linkplain #PRIVATE PRIVATE (0x02)},
23.577 + * {@linkplain #PROTECTED PROTECTED (0x04)},
23.578 + * and {@linkplain #PACKAGE PACKAGE (0x08)}.
23.579 + * <p>
23.580 + * A freshly-created lookup object
23.581 + * on the {@linkplain java.lang.invoke.MethodHandles#lookup() caller's class}
23.582 + * has all possible bits set, since the caller class can access all its own members.
23.583 + * A lookup object on a new lookup class
23.584 + * {@linkplain java.lang.invoke.MethodHandles.Lookup#in created from a previous lookup object}
23.585 + * may have some mode bits set to zero.
23.586 + * The purpose of this is to restrict access via the new lookup object,
23.587 + * so that it can access only names which can be reached by the original
23.588 + * lookup object, and also by the new lookup class.
23.589 + * @return the lookup modes, which limit the kinds of access performed by this lookup object
23.590 + */
23.591 + public int lookupModes() {
23.592 + return allowedModes & ALL_MODES;
23.593 + }
23.594 +
23.595 + /** Embody the current class (the lookupClass) as a lookup class
23.596 + * for method handle creation.
23.597 + * Must be called by from a method in this package,
23.598 + * which in turn is called by a method not in this package.
23.599 + */
23.600 + Lookup(Class<?> lookupClass) {
23.601 + this(lookupClass, ALL_MODES);
23.602 + // make sure we haven't accidentally picked up a privileged class:
23.603 + checkUnprivilegedlookupClass(lookupClass, ALL_MODES);
23.604 + }
23.605 +
23.606 + private Lookup(Class<?> lookupClass, int allowedModes) {
23.607 + this.lookupClass = lookupClass;
23.608 + this.allowedModes = allowedModes;
23.609 + }
23.610 +
23.611 + /**
23.612 + * Creates a lookup on the specified new lookup class.
23.613 + * The resulting object will report the specified
23.614 + * class as its own {@link #lookupClass lookupClass}.
23.615 + * <p>
23.616 + * However, the resulting {@code Lookup} object is guaranteed
23.617 + * to have no more access capabilities than the original.
23.618 + * In particular, access capabilities can be lost as follows:<ul>
23.619 + * <li>If the new lookup class differs from the old one,
23.620 + * protected members will not be accessible by virtue of inheritance.
23.621 + * (Protected members may continue to be accessible because of package sharing.)
23.622 + * <li>If the new lookup class is in a different package
23.623 + * than the old one, protected and default (package) members will not be accessible.
23.624 + * <li>If the new lookup class is not within the same package member
23.625 + * as the old one, private members will not be accessible.
23.626 + * <li>If the new lookup class is not accessible to the old lookup class,
23.627 + * then no members, not even public members, will be accessible.
23.628 + * (In all other cases, public members will continue to be accessible.)
23.629 + * </ul>
23.630 + *
23.631 + * @param requestedLookupClass the desired lookup class for the new lookup object
23.632 + * @return a lookup object which reports the desired lookup class
23.633 + * @throws NullPointerException if the argument is null
23.634 + */
23.635 + public Lookup in(Class<?> requestedLookupClass) {
23.636 + requestedLookupClass.getClass(); // null check
23.637 + if (allowedModes == TRUSTED) // IMPL_LOOKUP can make any lookup at all
23.638 + return new Lookup(requestedLookupClass, ALL_MODES);
23.639 + if (requestedLookupClass == this.lookupClass)
23.640 + return this; // keep same capabilities
23.641 + int newModes = (allowedModes & (ALL_MODES & ~PROTECTED));
23.642 + if ((newModes & PACKAGE) != 0
23.643 + && !VerifyAccess.isSamePackage(this.lookupClass, requestedLookupClass)) {
23.644 + newModes &= ~(PACKAGE|PRIVATE);
23.645 + }
23.646 + // Allow nestmate lookups to be created without special privilege:
23.647 + if ((newModes & PRIVATE) != 0
23.648 + && !VerifyAccess.isSamePackageMember(this.lookupClass, requestedLookupClass)) {
23.649 + newModes &= ~PRIVATE;
23.650 + }
23.651 + if ((newModes & PUBLIC) != 0
23.652 + && !VerifyAccess.isClassAccessible(requestedLookupClass, this.lookupClass, allowedModes)) {
23.653 + // The requested class it not accessible from the lookup class.
23.654 + // No permissions.
23.655 + newModes = 0;
23.656 + }
23.657 + checkUnprivilegedlookupClass(requestedLookupClass, newModes);
23.658 + return new Lookup(requestedLookupClass, newModes);
23.659 + }
23.660 +
23.661 + // Make sure outer class is initialized first.
23.662 + static { IMPL_NAMES.getClass(); }
23.663 +
23.664 + /** Version of lookup which is trusted minimally.
23.665 + * It can only be used to create method handles to
23.666 + * publicly accessible members.
23.667 + */
23.668 + static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, PUBLIC);
23.669 +
23.670 + /** Package-private version of lookup which is trusted. */
23.671 + static final Lookup IMPL_LOOKUP = new Lookup(Object.class, TRUSTED);
23.672 +
23.673 + private static void checkUnprivilegedlookupClass(Class<?> lookupClass, int allowedModes) {
23.674 + String name = lookupClass.getName();
23.675 + if (name.startsWith("java.lang.invoke."))
23.676 + throw newIllegalArgumentException("illegal lookupClass: "+lookupClass);
23.677 +
23.678 + // For caller-sensitive MethodHandles.lookup()
23.679 + // disallow lookup more restricted packages
23.680 + if (allowedModes == ALL_MODES && lookupClass.getClassLoader() == null) {
23.681 + if (name.startsWith("java.") ||
23.682 + (name.startsWith("sun.") && !name.startsWith("sun.invoke."))) {
23.683 + throw newIllegalArgumentException("illegal lookupClass: " + lookupClass);
23.684 + }
23.685 + }
23.686 + }
23.687 +
23.688 + /**
23.689 + * Displays the name of the class from which lookups are to be made.
23.690 + * (The name is the one reported by {@link java.lang.Class#getName() Class.getName}.)
23.691 + * If there are restrictions on the access permitted to this lookup,
23.692 + * this is indicated by adding a suffix to the class name, consisting
23.693 + * of a slash and a keyword. The keyword represents the strongest
23.694 + * allowed access, and is chosen as follows:
23.695 + * <ul>
23.696 + * <li>If no access is allowed, the suffix is "/noaccess".
23.697 + * <li>If only public access is allowed, the suffix is "/public".
23.698 + * <li>If only public and package access are allowed, the suffix is "/package".
23.699 + * <li>If only public, package, and private access are allowed, the suffix is "/private".
23.700 + * </ul>
23.701 + * If none of the above cases apply, it is the case that full
23.702 + * access (public, package, private, and protected) is allowed.
23.703 + * In this case, no suffix is added.
23.704 + * This is true only of an object obtained originally from
23.705 + * {@link java.lang.invoke.MethodHandles#lookup MethodHandles.lookup}.
23.706 + * Objects created by {@link java.lang.invoke.MethodHandles.Lookup#in Lookup.in}
23.707 + * always have restricted access, and will display a suffix.
23.708 + * <p>
23.709 + * (It may seem strange that protected access should be
23.710 + * stronger than private access. Viewed independently from
23.711 + * package access, protected access is the first to be lost,
23.712 + * because it requires a direct subclass relationship between
23.713 + * caller and callee.)
23.714 + * @see #in
23.715 + */
23.716 + @Override
23.717 + public String toString() {
23.718 + String cname = lookupClass.getName();
23.719 + switch (allowedModes) {
23.720 + case 0: // no privileges
23.721 + return cname + "/noaccess";
23.722 + case PUBLIC:
23.723 + return cname + "/public";
23.724 + case PUBLIC|PACKAGE:
23.725 + return cname + "/package";
23.726 + case ALL_MODES & ~PROTECTED:
23.727 + return cname + "/private";
23.728 + case ALL_MODES:
23.729 + return cname;
23.730 + case TRUSTED:
23.731 + return "/trusted"; // internal only; not exported
23.732 + default: // Should not happen, but it's a bitfield...
23.733 + cname = cname + "/" + Integer.toHexString(allowedModes);
23.734 + assert(false) : cname;
23.735 + return cname;
23.736 + }
23.737 + }
23.738 +
23.739 + /**
23.740 + * Produces a method handle for a static method.
23.741 + * The type of the method handle will be that of the method.
23.742 + * (Since static methods do not take receivers, there is no
23.743 + * additional receiver argument inserted into the method handle type,
23.744 + * as there would be with {@link #findVirtual findVirtual} or {@link #findSpecial findSpecial}.)
23.745 + * The method and all its argument types must be accessible to the lookup object.
23.746 + * <p>
23.747 + * The returned method handle will have
23.748 + * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
23.749 + * the method's variable arity modifier bit ({@code 0x0080}) is set.
23.750 + * <p>
23.751 + * If the returned method handle is invoked, the method's class will
23.752 + * be initialized, if it has not already been initialized.
23.753 + * <p><b>Example:</b>
23.754 + * <blockquote><pre>{@code
23.755 +import static java.lang.invoke.MethodHandles.*;
23.756 +import static java.lang.invoke.MethodType.*;
23.757 +...
23.758 +MethodHandle MH_asList = publicLookup().findStatic(Arrays.class,
23.759 + "asList", methodType(List.class, Object[].class));
23.760 +assertEquals("[x, y]", MH_asList.invoke("x", "y").toString());
23.761 + * }</pre></blockquote>
23.762 + * @param refc the class from which the method is accessed
23.763 + * @param name the name of the method
23.764 + * @param type the type of the method
23.765 + * @return the desired method handle
23.766 + * @throws NoSuchMethodException if the method does not exist
23.767 + * @throws IllegalAccessException if access checking fails,
23.768 + * or if the method is not {@code static},
23.769 + * or if the method's variable arity modifier bit
23.770 + * is set and {@code asVarargsCollector} fails
23.771 + * @exception SecurityException if a security manager is present and it
23.772 + * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
23.773 + * @throws NullPointerException if any argument is null
23.774 + */
23.775 + public
23.776 + MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
23.777 + MemberName method = resolveOrFail(REF_invokeStatic, refc, name, type);
23.778 + return getDirectMethod(REF_invokeStatic, refc, method, findBoundCallerClass(method));
23.779 + }
23.780 +
23.781 + /**
23.782 + * Produces a method handle for a virtual method.
23.783 + * The type of the method handle will be that of the method,
23.784 + * with the receiver type (usually {@code refc}) prepended.
23.785 + * The method and all its argument types must be accessible to the lookup object.
23.786 + * <p>
23.787 + * When called, the handle will treat the first argument as a receiver
23.788 + * and dispatch on the receiver's type to determine which method
23.789 + * implementation to enter.
23.790 + * (The dispatching action is identical with that performed by an
23.791 + * {@code invokevirtual} or {@code invokeinterface} instruction.)
23.792 + * <p>
23.793 + * The first argument will be of type {@code refc} if the lookup
23.794 + * class has full privileges to access the member. Otherwise
23.795 + * the member must be {@code protected} and the first argument
23.796 + * will be restricted in type to the lookup class.
23.797 + * <p>
23.798 + * The returned method handle will have
23.799 + * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
23.800 + * the method's variable arity modifier bit ({@code 0x0080}) is set.
23.801 + * <p>
23.802 + * Because of the general <a href="MethodHandles.Lookup.html#equiv">equivalence</a> between {@code invokevirtual}
23.803 + * instructions and method handles produced by {@code findVirtual},
23.804 + * if the class is {@code MethodHandle} and the name string is
23.805 + * {@code invokeExact} or {@code invoke}, the resulting
23.806 + * method handle is equivalent to one produced by
23.807 + * {@link java.lang.invoke.MethodHandles#exactInvoker MethodHandles.exactInvoker} or
23.808 + * {@link java.lang.invoke.MethodHandles#invoker MethodHandles.invoker}
23.809 + * with the same {@code type} argument.
23.810 + *
23.811 + * <b>Example:</b>
23.812 + * <blockquote><pre>{@code
23.813 +import static java.lang.invoke.MethodHandles.*;
23.814 +import static java.lang.invoke.MethodType.*;
23.815 +...
23.816 +MethodHandle MH_concat = publicLookup().findVirtual(String.class,
23.817 + "concat", methodType(String.class, String.class));
23.818 +MethodHandle MH_hashCode = publicLookup().findVirtual(Object.class,
23.819 + "hashCode", methodType(int.class));
23.820 +MethodHandle MH_hashCode_String = publicLookup().findVirtual(String.class,
23.821 + "hashCode", methodType(int.class));
23.822 +assertEquals("xy", (String) MH_concat.invokeExact("x", "y"));
23.823 +assertEquals("xy".hashCode(), (int) MH_hashCode.invokeExact((Object)"xy"));
23.824 +assertEquals("xy".hashCode(), (int) MH_hashCode_String.invokeExact("xy"));
23.825 +// interface method:
23.826 +MethodHandle MH_subSequence = publicLookup().findVirtual(CharSequence.class,
23.827 + "subSequence", methodType(CharSequence.class, int.class, int.class));
23.828 +assertEquals("def", MH_subSequence.invoke("abcdefghi", 3, 6).toString());
23.829 +// constructor "internal method" must be accessed differently:
23.830 +MethodType MT_newString = methodType(void.class); //()V for new String()
23.831 +try { assertEquals("impossible", lookup()
23.832 + .findVirtual(String.class, "<init>", MT_newString));
23.833 + } catch (NoSuchMethodException ex) { } // OK
23.834 +MethodHandle MH_newString = publicLookup()
23.835 + .findConstructor(String.class, MT_newString);
23.836 +assertEquals("", (String) MH_newString.invokeExact());
23.837 + * }</pre></blockquote>
23.838 + *
23.839 + * @param refc the class or interface from which the method is accessed
23.840 + * @param name the name of the method
23.841 + * @param type the type of the method, with the receiver argument omitted
23.842 + * @return the desired method handle
23.843 + * @throws NoSuchMethodException if the method does not exist
23.844 + * @throws IllegalAccessException if access checking fails,
23.845 + * or if the method is {@code static}
23.846 + * or if the method's variable arity modifier bit
23.847 + * is set and {@code asVarargsCollector} fails
23.848 + * @exception SecurityException if a security manager is present and it
23.849 + * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
23.850 + * @throws NullPointerException if any argument is null
23.851 + */
23.852 + public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
23.853 + if (refc == MethodHandle.class) {
23.854 + MethodHandle mh = findVirtualForMH(name, type);
23.855 + if (mh != null) return mh;
23.856 + }
23.857 + byte refKind = (refc.isInterface() ? REF_invokeInterface : REF_invokeVirtual);
23.858 + MemberName method = resolveOrFail(refKind, refc, name, type);
23.859 + return getDirectMethod(refKind, refc, method, findBoundCallerClass(method));
23.860 + }
23.861 + private MethodHandle findVirtualForMH(String name, MethodType type) {
23.862 + // these names require special lookups because of the implicit MethodType argument
23.863 + if ("invoke".equals(name))
23.864 + return invoker(type);
23.865 + if ("invokeExact".equals(name))
23.866 + return exactInvoker(type);
23.867 + assert(!MemberName.isMethodHandleInvokeName(name));
23.868 + return null;
23.869 + }
23.870 +
23.871 + /**
23.872 + * Produces a method handle which creates an object and initializes it, using
23.873 + * the constructor of the specified type.
23.874 + * The parameter types of the method handle will be those of the constructor,
23.875 + * while the return type will be a reference to the constructor's class.
23.876 + * The constructor and all its argument types must be accessible to the lookup object.
23.877 + * <p>
23.878 + * The requested type must have a return type of {@code void}.
23.879 + * (This is consistent with the JVM's treatment of constructor type descriptors.)
23.880 + * <p>
23.881 + * The returned method handle will have
23.882 + * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
23.883 + * the constructor's variable arity modifier bit ({@code 0x0080}) is set.
23.884 + * <p>
23.885 + * If the returned method handle is invoked, the constructor's class will
23.886 + * be initialized, if it has not already been initialized.
23.887 + * <p><b>Example:</b>
23.888 + * <blockquote><pre>{@code
23.889 +import static java.lang.invoke.MethodHandles.*;
23.890 +import static java.lang.invoke.MethodType.*;
23.891 +...
23.892 +MethodHandle MH_newArrayList = publicLookup().findConstructor(
23.893 + ArrayList.class, methodType(void.class, Collection.class));
23.894 +Collection orig = Arrays.asList("x", "y");
23.895 +Collection copy = (ArrayList) MH_newArrayList.invokeExact(orig);
23.896 +assert(orig != copy);
23.897 +assertEquals(orig, copy);
23.898 +// a variable-arity constructor:
23.899 +MethodHandle MH_newProcessBuilder = publicLookup().findConstructor(
23.900 + ProcessBuilder.class, methodType(void.class, String[].class));
23.901 +ProcessBuilder pb = (ProcessBuilder)
23.902 + MH_newProcessBuilder.invoke("x", "y", "z");
23.903 +assertEquals("[x, y, z]", pb.command().toString());
23.904 + * }</pre></blockquote>
23.905 + * @param refc the class or interface from which the method is accessed
23.906 + * @param type the type of the method, with the receiver argument omitted, and a void return type
23.907 + * @return the desired method handle
23.908 + * @throws NoSuchMethodException if the constructor does not exist
23.909 + * @throws IllegalAccessException if access checking fails
23.910 + * or if the method's variable arity modifier bit
23.911 + * is set and {@code asVarargsCollector} fails
23.912 + * @exception SecurityException if a security manager is present and it
23.913 + * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
23.914 + * @throws NullPointerException if any argument is null
23.915 + */
23.916 + public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
23.917 + String name = "<init>";
23.918 + MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type);
23.919 + return getDirectConstructor(refc, ctor);
23.920 + }
23.921 +
23.922 + /**
23.923 + * Produces an early-bound method handle for a virtual method.
23.924 + * It will bypass checks for overriding methods on the receiver,
23.925 + * <a href="MethodHandles.Lookup.html#equiv">as if called</a> from an {@code invokespecial}
23.926 + * instruction from within the explicitly specified {@code specialCaller}.
23.927 + * The type of the method handle will be that of the method,
23.928 + * with a suitably restricted receiver type prepended.
23.929 + * (The receiver type will be {@code specialCaller} or a subtype.)
23.930 + * The method and all its argument types must be accessible
23.931 + * to the lookup object.
23.932 + * <p>
23.933 + * Before method resolution,
23.934 + * if the explicitly specified caller class is not identical with the
23.935 + * lookup class, or if this lookup object does not have
23.936 + * <a href="MethodHandles.Lookup.html#privacc">private access</a>
23.937 + * privileges, the access fails.
23.938 + * <p>
23.939 + * The returned method handle will have
23.940 + * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
23.941 + * the method's variable arity modifier bit ({@code 0x0080}) is set.
23.942 + * <p style="font-size:smaller;">
23.943 + * <em>(Note: JVM internal methods named {@code "<init>"} are not visible to this API,
23.944 + * even though the {@code invokespecial} instruction can refer to them
23.945 + * in special circumstances. Use {@link #findConstructor findConstructor}
23.946 + * to access instance initialization methods in a safe manner.)</em>
23.947 + * <p><b>Example:</b>
23.948 + * <blockquote><pre>{@code
23.949 +import static java.lang.invoke.MethodHandles.*;
23.950 +import static java.lang.invoke.MethodType.*;
23.951 +...
23.952 +static class Listie extends ArrayList {
23.953 + public String toString() { return "[wee Listie]"; }
23.954 + static Lookup lookup() { return MethodHandles.lookup(); }
23.955 +}
23.956 +...
23.957 +// no access to constructor via invokeSpecial:
23.958 +MethodHandle MH_newListie = Listie.lookup()
23.959 + .findConstructor(Listie.class, methodType(void.class));
23.960 +Listie l = (Listie) MH_newListie.invokeExact();
23.961 +try { assertEquals("impossible", Listie.lookup().findSpecial(
23.962 + Listie.class, "<init>", methodType(void.class), Listie.class));
23.963 + } catch (NoSuchMethodException ex) { } // OK
23.964 +// access to super and self methods via invokeSpecial:
23.965 +MethodHandle MH_super = Listie.lookup().findSpecial(
23.966 + ArrayList.class, "toString" , methodType(String.class), Listie.class);
23.967 +MethodHandle MH_this = Listie.lookup().findSpecial(
23.968 + Listie.class, "toString" , methodType(String.class), Listie.class);
23.969 +MethodHandle MH_duper = Listie.lookup().findSpecial(
23.970 + Object.class, "toString" , methodType(String.class), Listie.class);
23.971 +assertEquals("[]", (String) MH_super.invokeExact(l));
23.972 +assertEquals(""+l, (String) MH_this.invokeExact(l));
23.973 +assertEquals("[]", (String) MH_duper.invokeExact(l)); // ArrayList method
23.974 +try { assertEquals("inaccessible", Listie.lookup().findSpecial(
23.975 + String.class, "toString", methodType(String.class), Listie.class));
23.976 + } catch (IllegalAccessException ex) { } // OK
23.977 +Listie subl = new Listie() { public String toString() { return "[subclass]"; } };
23.978 +assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
23.979 + * }</pre></blockquote>
23.980 + *
23.981 + * @param refc the class or interface from which the method is accessed
23.982 + * @param name the name of the method (which must not be "<init>")
23.983 + * @param type the type of the method, with the receiver argument omitted
23.984 + * @param specialCaller the proposed calling class to perform the {@code invokespecial}
23.985 + * @return the desired method handle
23.986 + * @throws NoSuchMethodException if the method does not exist
23.987 + * @throws IllegalAccessException if access checking fails
23.988 + * or if the method's variable arity modifier bit
23.989 + * is set and {@code asVarargsCollector} fails
23.990 + * @exception SecurityException if a security manager is present and it
23.991 + * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
23.992 + * @throws NullPointerException if any argument is null
23.993 + */
23.994 + public MethodHandle findSpecial(Class<?> refc, String name, MethodType type,
23.995 + Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException {
23.996 + checkSpecialCaller(specialCaller);
23.997 + Lookup specialLookup = this.in(specialCaller);
23.998 + MemberName method = specialLookup.resolveOrFail(REF_invokeSpecial, refc, name, type);
23.999 + return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method, findBoundCallerClass(method));
23.1000 + }
23.1001 +
23.1002 + /**
23.1003 + * Produces a method handle giving read access to a non-static field.
23.1004 + * The type of the method handle will have a return type of the field's
23.1005 + * value type.
23.1006 + * The method handle's single argument will be the instance containing
23.1007 + * the field.
23.1008 + * Access checking is performed immediately on behalf of the lookup class.
23.1009 + * @param refc the class or interface from which the method is accessed
23.1010 + * @param name the field's name
23.1011 + * @param type the field's type
23.1012 + * @return a method handle which can load values from the field
23.1013 + * @throws NoSuchFieldException if the field does not exist
23.1014 + * @throws IllegalAccessException if access checking fails, or if the field is {@code static}
23.1015 + * @exception SecurityException if a security manager is present and it
23.1016 + * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
23.1017 + * @throws NullPointerException if any argument is null
23.1018 + */
23.1019 + public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
23.1020 + MemberName field = resolveOrFail(REF_getField, refc, name, type);
23.1021 + return getDirectField(REF_getField, refc, field);
23.1022 + }
23.1023 +
23.1024 + /**
23.1025 + * Produces a method handle giving write access to a non-static field.
23.1026 + * The type of the method handle will have a void return type.
23.1027 + * The method handle will take two arguments, the instance containing
23.1028 + * the field, and the value to be stored.
23.1029 + * The second argument will be of the field's value type.
23.1030 + * Access checking is performed immediately on behalf of the lookup class.
23.1031 + * @param refc the class or interface from which the method is accessed
23.1032 + * @param name the field's name
23.1033 + * @param type the field's type
23.1034 + * @return a method handle which can store values into the field
23.1035 + * @throws NoSuchFieldException if the field does not exist
23.1036 + * @throws IllegalAccessException if access checking fails, or if the field is {@code static}
23.1037 + * @exception SecurityException if a security manager is present and it
23.1038 + * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
23.1039 + * @throws NullPointerException if any argument is null
23.1040 + */
23.1041 + public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
23.1042 + MemberName field = resolveOrFail(REF_putField, refc, name, type);
23.1043 + return getDirectField(REF_putField, refc, field);
23.1044 + }
23.1045 +
23.1046 + /**
23.1047 + * Produces a method handle giving read access to a static field.
23.1048 + * The type of the method handle will have a return type of the field's
23.1049 + * value type.
23.1050 + * The method handle will take no arguments.
23.1051 + * Access checking is performed immediately on behalf of the lookup class.
23.1052 + * <p>
23.1053 + * If the returned method handle is invoked, the field's class will
23.1054 + * be initialized, if it has not already been initialized.
23.1055 + * @param refc the class or interface from which the method is accessed
23.1056 + * @param name the field's name
23.1057 + * @param type the field's type
23.1058 + * @return a method handle which can load values from the field
23.1059 + * @throws NoSuchFieldException if the field does not exist
23.1060 + * @throws IllegalAccessException if access checking fails, or if the field is not {@code static}
23.1061 + * @exception SecurityException if a security manager is present and it
23.1062 + * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
23.1063 + * @throws NullPointerException if any argument is null
23.1064 + */
23.1065 + public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
23.1066 + MemberName field = resolveOrFail(REF_getStatic, refc, name, type);
23.1067 + return getDirectField(REF_getStatic, refc, field);
23.1068 + }
23.1069 +
23.1070 + /**
23.1071 + * Produces a method handle giving write access to a static field.
23.1072 + * The type of the method handle will have a void return type.
23.1073 + * The method handle will take a single
23.1074 + * argument, of the field's value type, the value to be stored.
23.1075 + * Access checking is performed immediately on behalf of the lookup class.
23.1076 + * <p>
23.1077 + * If the returned method handle is invoked, the field's class will
23.1078 + * be initialized, if it has not already been initialized.
23.1079 + * @param refc the class or interface from which the method is accessed
23.1080 + * @param name the field's name
23.1081 + * @param type the field's type
23.1082 + * @return a method handle which can store values into the field
23.1083 + * @throws NoSuchFieldException if the field does not exist
23.1084 + * @throws IllegalAccessException if access checking fails, or if the field is not {@code static}
23.1085 + * @exception SecurityException if a security manager is present and it
23.1086 + * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
23.1087 + * @throws NullPointerException if any argument is null
23.1088 + */
23.1089 + public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
23.1090 + MemberName field = resolveOrFail(REF_putStatic, refc, name, type);
23.1091 + return getDirectField(REF_putStatic, refc, field);
23.1092 + }
23.1093 +
23.1094 + /**
23.1095 + * Produces an early-bound method handle for a non-static method.
23.1096 + * The receiver must have a supertype {@code defc} in which a method
23.1097 + * of the given name and type is accessible to the lookup class.
23.1098 + * The method and all its argument types must be accessible to the lookup object.
23.1099 + * The type of the method handle will be that of the method,
23.1100 + * without any insertion of an additional receiver parameter.
23.1101 + * The given receiver will be bound into the method handle,
23.1102 + * so that every call to the method handle will invoke the
23.1103 + * requested method on the given receiver.
23.1104 + * <p>
23.1105 + * The returned method handle will have
23.1106 + * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
23.1107 + * the method's variable arity modifier bit ({@code 0x0080}) is set
23.1108 + * <em>and</em> the trailing array argument is not the only argument.
23.1109 + * (If the trailing array argument is the only argument,
23.1110 + * the given receiver value will be bound to it.)
23.1111 + * <p>
23.1112 + * This is equivalent to the following code:
23.1113 + * <blockquote><pre>{@code
23.1114 +import static java.lang.invoke.MethodHandles.*;
23.1115 +import static java.lang.invoke.MethodType.*;
23.1116 +...
23.1117 +MethodHandle mh0 = lookup().findVirtual(defc, name, type);
23.1118 +MethodHandle mh1 = mh0.bindTo(receiver);
23.1119 +MethodType mt1 = mh1.type();
23.1120 +if (mh0.isVarargsCollector())
23.1121 + mh1 = mh1.asVarargsCollector(mt1.parameterType(mt1.parameterCount()-1));
23.1122 +return mh1;
23.1123 + * }</pre></blockquote>
23.1124 + * where {@code defc} is either {@code receiver.getClass()} or a super
23.1125 + * type of that class, in which the requested method is accessible
23.1126 + * to the lookup class.
23.1127 + * (Note that {@code bindTo} does not preserve variable arity.)
23.1128 + * @param receiver the object from which the method is accessed
23.1129 + * @param name the name of the method
23.1130 + * @param type the type of the method, with the receiver argument omitted
23.1131 + * @return the desired method handle
23.1132 + * @throws NoSuchMethodException if the method does not exist
23.1133 + * @throws IllegalAccessException if access checking fails
23.1134 + * or if the method's variable arity modifier bit
23.1135 + * is set and {@code asVarargsCollector} fails
23.1136 + * @exception SecurityException if a security manager is present and it
23.1137 + * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
23.1138 + * @throws NullPointerException if any argument is null
23.1139 + * @see MethodHandle#bindTo
23.1140 + * @see #findVirtual
23.1141 + */
23.1142 + public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
23.1143 + Class<? extends Object> refc = receiver.getClass(); // may get NPE
23.1144 + MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type);
23.1145 + MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, findBoundCallerClass(method));
23.1146 + return mh.bindReceiver(receiver).setVarargs(method);
23.1147 + }
23.1148 +
23.1149 + /**
23.1150 + * Makes a <a href="MethodHandleInfo.html#directmh">direct method handle</a>
23.1151 + * to <i>m</i>, if the lookup class has permission.
23.1152 + * If <i>m</i> is non-static, the receiver argument is treated as an initial argument.
23.1153 + * If <i>m</i> is virtual, overriding is respected on every call.
23.1154 + * Unlike the Core Reflection API, exceptions are <em>not</em> wrapped.
23.1155 + * The type of the method handle will be that of the method,
23.1156 + * with the receiver type prepended (but only if it is non-static).
23.1157 + * If the method's {@code accessible} flag is not set,
23.1158 + * access checking is performed immediately on behalf of the lookup class.
23.1159 + * If <i>m</i> is not public, do not share the resulting handle with untrusted parties.
23.1160 + * <p>
23.1161 + * The returned method handle will have
23.1162 + * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
23.1163 + * the method's variable arity modifier bit ({@code 0x0080}) is set.
23.1164 + * <p>
23.1165 + * If <i>m</i> is static, and
23.1166 + * if the returned method handle is invoked, the method's class will
23.1167 + * be initialized, if it has not already been initialized.
23.1168 + * @param m the reflected method
23.1169 + * @return a method handle which can invoke the reflected method
23.1170 + * @throws IllegalAccessException if access checking fails
23.1171 + * or if the method's variable arity modifier bit
23.1172 + * is set and {@code asVarargsCollector} fails
23.1173 + * @throws NullPointerException if the argument is null
23.1174 + */
23.1175 + public MethodHandle unreflect(Method m) throws IllegalAccessException {
23.1176 + if (m.getDeclaringClass() == MethodHandle.class) {
23.1177 + MethodHandle mh = unreflectForMH(m);
23.1178 + if (mh != null) return mh;
23.1179 + }
23.1180 + MemberName method = new MemberName(m);
23.1181 + byte refKind = method.getReferenceKind();
23.1182 + if (refKind == REF_invokeSpecial)
23.1183 + refKind = REF_invokeVirtual;
23.1184 + assert(method.isMethod());
23.1185 + Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
23.1186 + return lookup.getDirectMethodNoSecurityManager(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method));
23.1187 + }
23.1188 + private MethodHandle unreflectForMH(Method m) {
23.1189 + // these names require special lookups because they throw UnsupportedOperationException
23.1190 + if (MemberName.isMethodHandleInvokeName(m.getName()))
23.1191 + return MethodHandleImpl.fakeMethodHandleInvoke(new MemberName(m));
23.1192 + return null;
23.1193 + }
23.1194 +
23.1195 + /**
23.1196 + * Produces a method handle for a reflected method.
23.1197 + * It will bypass checks for overriding methods on the receiver,
23.1198 + * <a href="MethodHandles.Lookup.html#equiv">as if called</a> from an {@code invokespecial}
23.1199 + * instruction from within the explicitly specified {@code specialCaller}.
23.1200 + * The type of the method handle will be that of the method,
23.1201 + * with a suitably restricted receiver type prepended.
23.1202 + * (The receiver type will be {@code specialCaller} or a subtype.)
23.1203 + * If the method's {@code accessible} flag is not set,
23.1204 + * access checking is performed immediately on behalf of the lookup class,
23.1205 + * as if {@code invokespecial} instruction were being linked.
23.1206 + * <p>
23.1207 + * Before method resolution,
23.1208 + * if the explicitly specified caller class is not identical with the
23.1209 + * lookup class, or if this lookup object does not have
23.1210 + * <a href="MethodHandles.Lookup.html#privacc">private access</a>
23.1211 + * privileges, the access fails.
23.1212 + * <p>
23.1213 + * The returned method handle will have
23.1214 + * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
23.1215 + * the method's variable arity modifier bit ({@code 0x0080}) is set.
23.1216 + * @param m the reflected method
23.1217 + * @param specialCaller the class nominally calling the method
23.1218 + * @return a method handle which can invoke the reflected method
23.1219 + * @throws IllegalAccessException if access checking fails
23.1220 + * or if the method's variable arity modifier bit
23.1221 + * is set and {@code asVarargsCollector} fails
23.1222 + * @throws NullPointerException if any argument is null
23.1223 + */
23.1224 + public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException {
23.1225 + checkSpecialCaller(specialCaller);
23.1226 + Lookup specialLookup = this.in(specialCaller);
23.1227 + MemberName method = new MemberName(m, true);
23.1228 + assert(method.isMethod());
23.1229 + // ignore m.isAccessible: this is a new kind of access
23.1230 + return specialLookup.getDirectMethodNoSecurityManager(REF_invokeSpecial, method.getDeclaringClass(), method, findBoundCallerClass(method));
23.1231 + }
23.1232 +
23.1233 + /**
23.1234 + * Produces a method handle for a reflected constructor.
23.1235 + * The type of the method handle will be that of the constructor,
23.1236 + * with the return type changed to the declaring class.
23.1237 + * The method handle will perform a {@code newInstance} operation,
23.1238 + * creating a new instance of the constructor's class on the
23.1239 + * arguments passed to the method handle.
23.1240 + * <p>
23.1241 + * If the constructor's {@code accessible} flag is not set,
23.1242 + * access checking is performed immediately on behalf of the lookup class.
23.1243 + * <p>
23.1244 + * The returned method handle will have
23.1245 + * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
23.1246 + * the constructor's variable arity modifier bit ({@code 0x0080}) is set.
23.1247 + * <p>
23.1248 + * If the returned method handle is invoked, the constructor's class will
23.1249 + * be initialized, if it has not already been initialized.
23.1250 + * @param c the reflected constructor
23.1251 + * @return a method handle which can invoke the reflected constructor
23.1252 + * @throws IllegalAccessException if access checking fails
23.1253 + * or if the method's variable arity modifier bit
23.1254 + * is set and {@code asVarargsCollector} fails
23.1255 + * @throws NullPointerException if the argument is null
23.1256 + */
23.1257 + public MethodHandle unreflectConstructor(Constructor<?> c) throws IllegalAccessException {
23.1258 + MemberName ctor = new MemberName(c);
23.1259 + assert(ctor.isConstructor());
23.1260 + Lookup lookup = c.isAccessible() ? IMPL_LOOKUP : this;
23.1261 + return lookup.getDirectConstructorNoSecurityManager(ctor.getDeclaringClass(), ctor);
23.1262 + }
23.1263 +
23.1264 + /**
23.1265 + * Produces a method handle giving read access to a reflected field.
23.1266 + * The type of the method handle will have a return type of the field's
23.1267 + * value type.
23.1268 + * If the field is static, the method handle will take no arguments.
23.1269 + * Otherwise, its single argument will be the instance containing
23.1270 + * the field.
23.1271 + * If the field's {@code accessible} flag is not set,
23.1272 + * access checking is performed immediately on behalf of the lookup class.
23.1273 + * <p>
23.1274 + * If the field is static, and
23.1275 + * if the returned method handle is invoked, the field's class will
23.1276 + * be initialized, if it has not already been initialized.
23.1277 + * @param f the reflected field
23.1278 + * @return a method handle which can load values from the reflected field
23.1279 + * @throws IllegalAccessException if access checking fails
23.1280 + * @throws NullPointerException if the argument is null
23.1281 + */
23.1282 + public MethodHandle unreflectGetter(Field f) throws IllegalAccessException {
23.1283 + return unreflectField(f, false);
23.1284 + }
23.1285 + private MethodHandle unreflectField(Field f, boolean isSetter) throws IllegalAccessException {
23.1286 + MemberName field = new MemberName(f, isSetter);
23.1287 + assert(isSetter
23.1288 + ? MethodHandleNatives.refKindIsSetter(field.getReferenceKind())
23.1289 + : MethodHandleNatives.refKindIsGetter(field.getReferenceKind()));
23.1290 + Lookup lookup = f.isAccessible() ? IMPL_LOOKUP : this;
23.1291 + return lookup.getDirectFieldNoSecurityManager(field.getReferenceKind(), f.getDeclaringClass(), field);
23.1292 + }
23.1293 +
23.1294 + /**
23.1295 + * Produces a method handle giving write access to a reflected field.
23.1296 + * The type of the method handle will have a void return type.
23.1297 + * If the field is static, the method handle will take a single
23.1298 + * argument, of the field's value type, the value to be stored.
23.1299 + * Otherwise, the two arguments will be the instance containing
23.1300 + * the field, and the value to be stored.
23.1301 + * If the field's {@code accessible} flag is not set,
23.1302 + * access checking is performed immediately on behalf of the lookup class.
23.1303 + * <p>
23.1304 + * If the field is static, and
23.1305 + * if the returned method handle is invoked, the field's class will
23.1306 + * be initialized, if it has not already been initialized.
23.1307 + * @param f the reflected field
23.1308 + * @return a method handle which can store values into the reflected field
23.1309 + * @throws IllegalAccessException if access checking fails
23.1310 + * @throws NullPointerException if the argument is null
23.1311 + */
23.1312 + public MethodHandle unreflectSetter(Field f) throws IllegalAccessException {
23.1313 + return unreflectField(f, true);
23.1314 + }
23.1315 +
23.1316 + /**
23.1317 + * Cracks a <a href="MethodHandleInfo.html#directmh">direct method handle</a>
23.1318 + * created by this lookup object or a similar one.
23.1319 + * Security and access checks are performed to ensure that this lookup object
23.1320 + * is capable of reproducing the target method handle.
23.1321 + * This means that the cracking may fail if target is a direct method handle
23.1322 + * but was created by an unrelated lookup object.
23.1323 + * This can happen if the method handle is <a href="MethodHandles.Lookup.html#callsens">caller sensitive</a>
23.1324 + * and was created by a lookup object for a different class.
23.1325 + * @param target a direct method handle to crack into symbolic reference components
23.1326 + * @return a symbolic reference which can be used to reconstruct this method handle from this lookup object
23.1327 + * @exception SecurityException if a security manager is present and it
23.1328 + * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
23.1329 + * @throws IllegalArgumentException if the target is not a direct method handle or if access checking fails
23.1330 + * @exception NullPointerException if the target is {@code null}
23.1331 + * @see MethodHandleInfo
23.1332 + * @since 1.8
23.1333 + */
23.1334 + public MethodHandleInfo revealDirect(MethodHandle target) {
23.1335 + MemberName member = target.internalMemberName();
23.1336 + if (member == null || (!member.isResolved() && !member.isMethodHandleInvoke()))
23.1337 + throw newIllegalArgumentException("not a direct method handle");
23.1338 + Class<?> defc = member.getDeclaringClass();
23.1339 + byte refKind = member.getReferenceKind();
23.1340 + assert(MethodHandleNatives.refKindIsValid(refKind));
23.1341 + if (refKind == REF_invokeSpecial && !target.isInvokeSpecial())
23.1342 + // Devirtualized method invocation is usually formally virtual.
23.1343 + // To avoid creating extra MemberName objects for this common case,
23.1344 + // we encode this extra degree of freedom using MH.isInvokeSpecial.
23.1345 + refKind = REF_invokeVirtual;
23.1346 + if (refKind == REF_invokeVirtual && defc.isInterface())
23.1347 + // Symbolic reference is through interface but resolves to Object method (toString, etc.)
23.1348 + refKind = REF_invokeInterface;
23.1349 + // Check SM permissions and member access before cracking.
23.1350 + try {
23.1351 + checkAccess(refKind, defc, member);
23.1352 + checkSecurityManager(defc, member);
23.1353 + } catch (IllegalAccessException ex) {
23.1354 + throw new IllegalArgumentException(ex);
23.1355 + }
23.1356 + if (allowedModes != TRUSTED && member.isCallerSensitive()) {
23.1357 + Class<?> callerClass = target.internalCallerClass();
23.1358 + if (!hasPrivateAccess() || callerClass != lookupClass())
23.1359 + throw new IllegalArgumentException("method handle is caller sensitive: "+callerClass);
23.1360 + }
23.1361 + // Produce the handle to the results.
23.1362 + return new InfoFromMemberName(this, member, refKind);
23.1363 + }
23.1364 +
23.1365 + /// Helper methods, all package-private.
23.1366 +
23.1367 + MemberName resolveOrFail(byte refKind, Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
23.1368 + checkSymbolicClass(refc); // do this before attempting to resolve
23.1369 + name.getClass(); // NPE
23.1370 + type.getClass(); // NPE
23.1371 + return IMPL_NAMES.resolveOrFail(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(),
23.1372 + NoSuchFieldException.class);
23.1373 + }
23.1374 +
23.1375 + MemberName resolveOrFail(byte refKind, Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
23.1376 + checkSymbolicClass(refc); // do this before attempting to resolve
23.1377 + name.getClass(); // NPE
23.1378 + type.getClass(); // NPE
23.1379 + checkMethodName(refKind, name); // NPE check on name
23.1380 + return IMPL_NAMES.resolveOrFail(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(),
23.1381 + NoSuchMethodException.class);
23.1382 + }
23.1383 +
23.1384 + MemberName resolveOrFail(byte refKind, MemberName member) throws ReflectiveOperationException {
23.1385 + checkSymbolicClass(member.getDeclaringClass()); // do this before attempting to resolve
23.1386 + member.getName().getClass(); // NPE
23.1387 + member.getType().getClass(); // NPE
23.1388 + return IMPL_NAMES.resolveOrFail(refKind, member, lookupClassOrNull(),
23.1389 + ReflectiveOperationException.class);
23.1390 + }
23.1391 +
23.1392 + void checkSymbolicClass(Class<?> refc) throws IllegalAccessException {
23.1393 + refc.getClass(); // NPE
23.1394 + Class<?> caller = lookupClassOrNull();
23.1395 + if (caller != null && !VerifyAccess.isClassAccessible(refc, caller, allowedModes))
23.1396 + throw new MemberName(refc).makeAccessException("symbolic reference class is not public", this);
23.1397 + }
23.1398 +
23.1399 + /** Check name for an illegal leading "<" character. */
23.1400 + void checkMethodName(byte refKind, String name) throws NoSuchMethodException {
23.1401 + if (name.startsWith("<") && refKind != REF_newInvokeSpecial)
23.1402 + throw new NoSuchMethodException("illegal method name: "+name);
23.1403 + }
23.1404 +
23.1405 +
23.1406 + /**
23.1407 + * Find my trustable caller class if m is a caller sensitive method.
23.1408 + * If this lookup object has private access, then the caller class is the lookupClass.
23.1409 + * Otherwise, if m is caller-sensitive, throw IllegalAccessException.
23.1410 + */
23.1411 + Class<?> findBoundCallerClass(MemberName m) throws IllegalAccessException {
23.1412 + Class<?> callerClass = null;
23.1413 + if (MethodHandleNatives.isCallerSensitive(m)) {
23.1414 + // Only lookups with private access are allowed to resolve caller-sensitive methods
23.1415 + if (hasPrivateAccess()) {
23.1416 + callerClass = lookupClass;
23.1417 + } else {
23.1418 + throw new IllegalAccessException("Attempt to lookup caller-sensitive method using restricted lookup object");
23.1419 + }
23.1420 + }
23.1421 + return callerClass;
23.1422 + }
23.1423 +
23.1424 + private boolean hasPrivateAccess() {
23.1425 + return (allowedModes & PRIVATE) != 0;
23.1426 + }
23.1427 +
23.1428 + /**
23.1429 + * Perform necessary <a href="MethodHandles.Lookup.html#secmgr">access checks</a>.
23.1430 + * Determines a trustable caller class to compare with refc, the symbolic reference class.
23.1431 + * If this lookup object has private access, then the caller class is the lookupClass.
23.1432 + */
23.1433 + void checkSecurityManager(Class<?> refc, MemberName m) {
23.1434 + SecurityManager smgr = System.getSecurityManager();
23.1435 + if (smgr == null) return;
23.1436 + if (allowedModes == TRUSTED) return;
23.1437 +
23.1438 + // Step 1:
23.1439 + boolean fullPowerLookup = hasPrivateAccess();
23.1440 + if (!fullPowerLookup ||
23.1441 + !VerifyAccess.classLoaderIsAncestor(lookupClass, refc)) {
23.1442 + ReflectUtil.checkPackageAccess(refc);
23.1443 + }
23.1444 +
23.1445 + // Step 2:
23.1446 + if (m.isPublic()) return;
23.1447 + if (!fullPowerLookup) {
23.1448 + smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
23.1449 + }
23.1450 +
23.1451 + // Step 3:
23.1452 + Class<?> defc = m.getDeclaringClass();
23.1453 + if (!fullPowerLookup && defc != refc) {
23.1454 + ReflectUtil.checkPackageAccess(defc);
23.1455 + }
23.1456 + }
23.1457 +
23.1458 + void checkMethod(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException {
23.1459 + boolean wantStatic = (refKind == REF_invokeStatic);
23.1460 + String message;
23.1461 + if (m.isConstructor())
23.1462 + message = "expected a method, not a constructor";
23.1463 + else if (!m.isMethod())
23.1464 + message = "expected a method";
23.1465 + else if (wantStatic != m.isStatic())
23.1466 + message = wantStatic ? "expected a static method" : "expected a non-static method";
23.1467 + else
23.1468 + { checkAccess(refKind, refc, m); return; }
23.1469 + throw m.makeAccessException(message, this);
23.1470 + }
23.1471 +
23.1472 + void checkField(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException {
23.1473 + boolean wantStatic = !MethodHandleNatives.refKindHasReceiver(refKind);
23.1474 + String message;
23.1475 + if (wantStatic != m.isStatic())
23.1476 + message = wantStatic ? "expected a static field" : "expected a non-static field";
23.1477 + else
23.1478 + { checkAccess(refKind, refc, m); return; }
23.1479 + throw m.makeAccessException(message, this);
23.1480 + }
23.1481 +
23.1482 + /** Check public/protected/private bits on the symbolic reference class and its member. */
23.1483 + void checkAccess(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException {
23.1484 + assert(m.referenceKindIsConsistentWith(refKind) &&
23.1485 + MethodHandleNatives.refKindIsValid(refKind) &&
23.1486 + (MethodHandleNatives.refKindIsField(refKind) == m.isField()));
23.1487 + int allowedModes = this.allowedModes;
23.1488 + if (allowedModes == TRUSTED) return;
23.1489 + int mods = m.getModifiers();
23.1490 + if (Modifier.isProtected(mods) &&
23.1491 + refKind == REF_invokeVirtual &&
23.1492 + m.getDeclaringClass() == Object.class &&
23.1493 + m.getName().equals("clone") &&
23.1494 + refc.isArray()) {
23.1495 + // The JVM does this hack also.
23.1496 + // (See ClassVerifier::verify_invoke_instructions
23.1497 + // and LinkResolver::check_method_accessability.)
23.1498 + // Because the JVM does not allow separate methods on array types,
23.1499 + // there is no separate method for int[].clone.
23.1500 + // All arrays simply inherit Object.clone.
23.1501 + // But for access checking logic, we make Object.clone
23.1502 + // (normally protected) appear to be public.
23.1503 + // Later on, when the DirectMethodHandle is created,
23.1504 + // its leading argument will be restricted to the
23.1505 + // requested array type.
23.1506 + // N.B. The return type is not adjusted, because
23.1507 + // that is *not* the bytecode behavior.
23.1508 + mods ^= Modifier.PROTECTED | Modifier.PUBLIC;
23.1509 + }
23.1510 + if (Modifier.isFinal(mods) &&
23.1511 + MethodHandleNatives.refKindIsSetter(refKind))
23.1512 + throw m.makeAccessException("unexpected set of a final field", this);
23.1513 + if (Modifier.isPublic(mods) && Modifier.isPublic(refc.getModifiers()) && allowedModes != 0)
23.1514 + return; // common case
23.1515 + int requestedModes = fixmods(mods); // adjust 0 => PACKAGE
23.1516 + if ((requestedModes & allowedModes) != 0) {
23.1517 + if (VerifyAccess.isMemberAccessible(refc, m.getDeclaringClass(),
23.1518 + mods, lookupClass(), allowedModes))
23.1519 + return;
23.1520 + } else {
23.1521 + // Protected members can also be checked as if they were package-private.
23.1522 + if ((requestedModes & PROTECTED) != 0 && (allowedModes & PACKAGE) != 0
23.1523 + && VerifyAccess.isSamePackage(m.getDeclaringClass(), lookupClass()))
23.1524 + return;
23.1525 + }
23.1526 + throw m.makeAccessException(accessFailedMessage(refc, m), this);
23.1527 + }
23.1528 +
23.1529 + String accessFailedMessage(Class<?> refc, MemberName m) {
23.1530 + Class<?> defc = m.getDeclaringClass();
23.1531 + int mods = m.getModifiers();
23.1532 + // check the class first:
23.1533 + boolean classOK = (Modifier.isPublic(defc.getModifiers()) &&
23.1534 + (defc == refc ||
23.1535 + Modifier.isPublic(refc.getModifiers())));
23.1536 + if (!classOK && (allowedModes & PACKAGE) != 0) {
23.1537 + classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), ALL_MODES) &&
23.1538 + (defc == refc ||
23.1539 + VerifyAccess.isClassAccessible(refc, lookupClass(), ALL_MODES)));
23.1540 + }
23.1541 + if (!classOK)
23.1542 + return "class is not public";
23.1543 + if (Modifier.isPublic(mods))
23.1544 + return "access to public member failed"; // (how?)
23.1545 + if (Modifier.isPrivate(mods))
23.1546 + return "member is private";
23.1547 + if (Modifier.isProtected(mods))
23.1548 + return "member is protected";
23.1549 + return "member is private to package";
23.1550 + }
23.1551 +
23.1552 + private static final boolean ALLOW_NESTMATE_ACCESS = false;
23.1553 +
23.1554 + private void checkSpecialCaller(Class<?> specialCaller) throws IllegalAccessException {
23.1555 + int allowedModes = this.allowedModes;
23.1556 + if (allowedModes == TRUSTED) return;
23.1557 + if (!hasPrivateAccess()
23.1558 + || (specialCaller != lookupClass()
23.1559 + && !(ALLOW_NESTMATE_ACCESS &&
23.1560 + VerifyAccess.isSamePackageMember(specialCaller, lookupClass()))))
23.1561 + throw new MemberName(specialCaller).
23.1562 + makeAccessException("no private access for invokespecial", this);
23.1563 + }
23.1564 +
23.1565 + private boolean restrictProtectedReceiver(MemberName method) {
23.1566 + // The accessing class only has the right to use a protected member
23.1567 + // on itself or a subclass. Enforce that restriction, from JVMS 5.4.4, etc.
23.1568 + if (!method.isProtected() || method.isStatic()
23.1569 + || allowedModes == TRUSTED
23.1570 + || method.getDeclaringClass() == lookupClass()
23.1571 + || VerifyAccess.isSamePackage(method.getDeclaringClass(), lookupClass())
23.1572 + || (ALLOW_NESTMATE_ACCESS &&
23.1573 + VerifyAccess.isSamePackageMember(method.getDeclaringClass(), lookupClass())))
23.1574 + return false;
23.1575 + return true;
23.1576 + }
23.1577 + private MethodHandle restrictReceiver(MemberName method, MethodHandle mh, Class<?> caller) throws IllegalAccessException {
23.1578 + assert(!method.isStatic());
23.1579 + // receiver type of mh is too wide; narrow to caller
23.1580 + if (!method.getDeclaringClass().isAssignableFrom(caller)) {
23.1581 + throw method.makeAccessException("caller class must be a subclass below the method", caller);
23.1582 + }
23.1583 + MethodType rawType = mh.type();
23.1584 + if (rawType.parameterType(0) == caller) return mh;
23.1585 + MethodType narrowType = rawType.changeParameterType(0, caller);
23.1586 + return mh.viewAsType(narrowType);
23.1587 + }
23.1588 +
23.1589 + /** Check access and get the requested method. */
23.1590 + private MethodHandle getDirectMethod(byte refKind, Class<?> refc, MemberName method, Class<?> callerClass) throws IllegalAccessException {
23.1591 + final boolean doRestrict = true;
23.1592 + final boolean checkSecurity = true;
23.1593 + return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerClass);
23.1594 + }
23.1595 + /** Check access and get the requested method, eliding receiver narrowing rules. */
23.1596 + private MethodHandle getDirectMethodNoRestrict(byte refKind, Class<?> refc, MemberName method, Class<?> callerClass) throws IllegalAccessException {
23.1597 + final boolean doRestrict = false;
23.1598 + final boolean checkSecurity = true;
23.1599 + return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerClass);
23.1600 + }
23.1601 + /** Check access and get the requested method, eliding security manager checks. */
23.1602 + private MethodHandle getDirectMethodNoSecurityManager(byte refKind, Class<?> refc, MemberName method, Class<?> callerClass) throws IllegalAccessException {
23.1603 + final boolean doRestrict = true;
23.1604 + final boolean checkSecurity = false; // not needed for reflection or for linking CONSTANT_MH constants
23.1605 + return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerClass);
23.1606 + }
23.1607 + /** Common code for all methods; do not call directly except from immediately above. */
23.1608 + private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method,
23.1609 + boolean checkSecurity,
23.1610 + boolean doRestrict, Class<?> callerClass) throws IllegalAccessException {
23.1611 + checkMethod(refKind, refc, method);
23.1612 + // Optionally check with the security manager; this isn't needed for unreflect* calls.
23.1613 + if (checkSecurity)
23.1614 + checkSecurityManager(refc, method);
23.1615 + assert(!method.isMethodHandleInvoke());
23.1616 +
23.1617 + Class<?> refcAsSuper;
23.1618 + if (refKind == REF_invokeSpecial &&
23.1619 + refc != lookupClass() &&
23.1620 + !refc.isInterface() &&
23.1621 + refc != (refcAsSuper = lookupClass().getSuperclass()) &&
23.1622 + refc.isAssignableFrom(lookupClass())) {
23.1623 + assert(!method.getName().equals("<init>")); // not this code path
23.1624 + // Per JVMS 6.5, desc. of invokespecial instruction:
23.1625 + // If the method is in a superclass of the LC,
23.1626 + // and if our original search was above LC.super,
23.1627 + // repeat the search (symbolic lookup) from LC.super.
23.1628 + // FIXME: MemberName.resolve should handle this instead.
23.1629 + MemberName m2 = new MemberName(refcAsSuper,
23.1630 + method.getName(),
23.1631 + method.getMethodType(),
23.1632 + REF_invokeSpecial);
23.1633 + m2 = IMPL_NAMES.resolveOrNull(refKind, m2, lookupClassOrNull());
23.1634 + if (m2 == null) throw new InternalError(method.toString());
23.1635 + method = m2;
23.1636 + refc = refcAsSuper;
23.1637 + // redo basic checks
23.1638 + checkMethod(refKind, refc, method);
23.1639 + }
23.1640 +
23.1641 + MethodHandle mh = DirectMethodHandle.make(refKind, refc, method);
23.1642 + mh = maybeBindCaller(method, mh, callerClass);
23.1643 + mh = mh.setVarargs(method);
23.1644 + // Optionally narrow the receiver argument to refc using restrictReceiver.
23.1645 + if (doRestrict &&
23.1646 + (refKind == REF_invokeSpecial ||
23.1647 + (MethodHandleNatives.refKindHasReceiver(refKind) &&
23.1648 + restrictProtectedReceiver(method))))
23.1649 + mh = restrictReceiver(method, mh, lookupClass());
23.1650 + return mh;
23.1651 + }
23.1652 + private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh,
23.1653 + Class<?> callerClass)
23.1654 + throws IllegalAccessException {
23.1655 + if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method))
23.1656 + return mh;
23.1657 + Class<?> hostClass = lookupClass;
23.1658 + if (!hasPrivateAccess()) // caller must have private access
23.1659 + hostClass = callerClass; // callerClass came from a security manager style stack walk
23.1660 + MethodHandle cbmh = MethodHandleImpl.bindCaller(mh, hostClass);
23.1661 + // Note: caller will apply varargs after this step happens.
23.1662 + return cbmh;
23.1663 + }
23.1664 + /** Check access and get the requested field. */
23.1665 + private MethodHandle getDirectField(byte refKind, Class<?> refc, MemberName field) throws IllegalAccessException {
23.1666 + final boolean checkSecurity = true;
23.1667 + return getDirectFieldCommon(refKind, refc, field, checkSecurity);
23.1668 + }
23.1669 + /** Check access and get the requested field, eliding security manager checks. */
23.1670 + private MethodHandle getDirectFieldNoSecurityManager(byte refKind, Class<?> refc, MemberName field) throws IllegalAccessException {
23.1671 + final boolean checkSecurity = false; // not needed for reflection or for linking CONSTANT_MH constants
23.1672 + return getDirectFieldCommon(refKind, refc, field, checkSecurity);
23.1673 + }
23.1674 + /** Common code for all fields; do not call directly except from immediately above. */
23.1675 + private MethodHandle getDirectFieldCommon(byte refKind, Class<?> refc, MemberName field,
23.1676 + boolean checkSecurity) throws IllegalAccessException {
23.1677 + checkField(refKind, refc, field);
23.1678 + // Optionally check with the security manager; this isn't needed for unreflect* calls.
23.1679 + if (checkSecurity)
23.1680 + checkSecurityManager(refc, field);
23.1681 + MethodHandle mh = DirectMethodHandle.make(refc, field);
23.1682 + boolean doRestrict = (MethodHandleNatives.refKindHasReceiver(refKind) &&
23.1683 + restrictProtectedReceiver(field));
23.1684 + if (doRestrict)
23.1685 + mh = restrictReceiver(field, mh, lookupClass());
23.1686 + return mh;
23.1687 + }
23.1688 + /** Check access and get the requested constructor. */
23.1689 + private MethodHandle getDirectConstructor(Class<?> refc, MemberName ctor) throws IllegalAccessException {
23.1690 + final boolean checkSecurity = true;
23.1691 + return getDirectConstructorCommon(refc, ctor, checkSecurity);
23.1692 + }
23.1693 + /** Check access and get the requested constructor, eliding security manager checks. */
23.1694 + private MethodHandle getDirectConstructorNoSecurityManager(Class<?> refc, MemberName ctor) throws IllegalAccessException {
23.1695 + final boolean checkSecurity = false; // not needed for reflection or for linking CONSTANT_MH constants
23.1696 + return getDirectConstructorCommon(refc, ctor, checkSecurity);
23.1697 + }
23.1698 + /** Common code for all constructors; do not call directly except from immediately above. */
23.1699 + private MethodHandle getDirectConstructorCommon(Class<?> refc, MemberName ctor,
23.1700 + boolean checkSecurity) throws IllegalAccessException {
23.1701 + assert(ctor.isConstructor());
23.1702 + checkAccess(REF_newInvokeSpecial, refc, ctor);
23.1703 + // Optionally check with the security manager; this isn't needed for unreflect* calls.
23.1704 + if (checkSecurity)
23.1705 + checkSecurityManager(refc, ctor);
23.1706 + assert(!MethodHandleNatives.isCallerSensitive(ctor)); // maybeBindCaller not relevant here
23.1707 + return DirectMethodHandle.make(ctor).setVarargs(ctor);
23.1708 + }
23.1709 +
23.1710 + /** Hook called from the JVM (via MethodHandleNatives) to link MH constants:
23.1711 + */
23.1712 + /*non-public*/
23.1713 + MethodHandle linkMethodHandleConstant(byte refKind, Class<?> defc, String name, Object type) throws ReflectiveOperationException {
23.1714 + if (!(type instanceof Class || type instanceof MethodType))
23.1715 + throw new InternalError("unresolved MemberName");
23.1716 + MemberName member = new MemberName(refKind, defc, name, type);
23.1717 + MethodHandle mh = LOOKASIDE_TABLE.get(member);
23.1718 + if (mh != null) {
23.1719 + checkSymbolicClass(defc);
23.1720 + return mh;
23.1721 + }
23.1722 + // Treat MethodHandle.invoke and invokeExact specially.
23.1723 + if (defc == MethodHandle.class && refKind == REF_invokeVirtual) {
23.1724 + mh = findVirtualForMH(member.getName(), member.getMethodType());
23.1725 + if (mh != null) {
23.1726 + return mh;
23.1727 + }
23.1728 + }
23.1729 + MemberName resolved = resolveOrFail(refKind, member);
23.1730 + mh = getDirectMethodForConstant(refKind, defc, resolved);
23.1731 + if (mh instanceof DirectMethodHandle
23.1732 + && canBeCached(refKind, defc, resolved)) {
23.1733 + MemberName key = mh.internalMemberName();
23.1734 + if (key != null) {
23.1735 + key = key.asNormalOriginal();
23.1736 + }
23.1737 + if (member.equals(key)) { // better safe than sorry
23.1738 + LOOKASIDE_TABLE.put(key, (DirectMethodHandle) mh);
23.1739 + }
23.1740 + }
23.1741 + return mh;
23.1742 + }
23.1743 + private
23.1744 + boolean canBeCached(byte refKind, Class<?> defc, MemberName member) {
23.1745 + if (refKind == REF_invokeSpecial) {
23.1746 + return false;
23.1747 + }
23.1748 + if (!Modifier.isPublic(defc.getModifiers()) ||
23.1749 + !Modifier.isPublic(member.getDeclaringClass().getModifiers()) ||
23.1750 + !member.isPublic() ||
23.1751 + member.isCallerSensitive()) {
23.1752 + return false;
23.1753 + }
23.1754 + ClassLoader loader = defc.getClassLoader();
23.1755 + if (!sun.misc.VM.isSystemDomainLoader(loader)) {
23.1756 + ClassLoader sysl = ClassLoader.getSystemClassLoader();
23.1757 + boolean found = false;
23.1758 + while (sysl != null) {
23.1759 + if (loader == sysl) { found = true; break; }
23.1760 + sysl = sysl.getParent();
23.1761 + }
23.1762 + if (!found) {
23.1763 + return false;
23.1764 + }
23.1765 + }
23.1766 + try {
23.1767 + MemberName resolved2 = publicLookup().resolveOrFail(refKind,
23.1768 + new MemberName(refKind, defc, member.getName(), member.getType()));
23.1769 + checkSecurityManager(defc, resolved2);
23.1770 + } catch (ReflectiveOperationException | SecurityException ex) {
23.1771 + return false;
23.1772 + }
23.1773 + return true;
23.1774 + }
23.1775 + private
23.1776 + MethodHandle getDirectMethodForConstant(byte refKind, Class<?> defc, MemberName member)
23.1777 + throws ReflectiveOperationException {
23.1778 + if (MethodHandleNatives.refKindIsField(refKind)) {
23.1779 + return getDirectFieldNoSecurityManager(refKind, defc, member);
23.1780 + } else if (MethodHandleNatives.refKindIsMethod(refKind)) {
23.1781 + return getDirectMethodNoSecurityManager(refKind, defc, member, lookupClass);
23.1782 + } else if (refKind == REF_newInvokeSpecial) {
23.1783 + return getDirectConstructorNoSecurityManager(defc, member);
23.1784 + }
23.1785 + // oops
23.1786 + throw newIllegalArgumentException("bad MethodHandle constant #"+member);
23.1787 + }
23.1788 +
23.1789 + static ConcurrentHashMap<MemberName, DirectMethodHandle> LOOKASIDE_TABLE = new ConcurrentHashMap<>();
23.1790 + }
23.1791 +
23.1792 + /**
23.1793 + * Produces a method handle giving read access to elements of an array.
23.1794 + * The type of the method handle will have a return type of the array's
23.1795 + * element type. Its first argument will be the array type,
23.1796 + * and the second will be {@code int}.
23.1797 + * @param arrayClass an array type
23.1798 + * @return a method handle which can load values from the given array type
23.1799 + * @throws NullPointerException if the argument is null
23.1800 + * @throws IllegalArgumentException if arrayClass is not an array type
23.1801 + */
23.1802 + public static
23.1803 + MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentException {
23.1804 + return MethodHandleImpl.makeArrayElementAccessor(arrayClass, false);
23.1805 + }
23.1806 +
23.1807 + /**
23.1808 + * Produces a method handle giving write access to elements of an array.
23.1809 + * The type of the method handle will have a void return type.
23.1810 + * Its last argument will be the array's element type.
23.1811 + * The first and second arguments will be the array type and int.
23.1812 + * @param arrayClass the class of an array
23.1813 + * @return a method handle which can store values into the array type
23.1814 + * @throws NullPointerException if the argument is null
23.1815 + * @throws IllegalArgumentException if arrayClass is not an array type
23.1816 + */
23.1817 + public static
23.1818 + MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException {
23.1819 + return MethodHandleImpl.makeArrayElementAccessor(arrayClass, true);
23.1820 + }
23.1821 +
23.1822 + /// method handle invocation (reflective style)
23.1823 +
23.1824 + /**
23.1825 + * Produces a method handle which will invoke any method handle of the
23.1826 + * given {@code type}, with a given number of trailing arguments replaced by
23.1827 + * a single trailing {@code Object[]} array.
23.1828 + * The resulting invoker will be a method handle with the following
23.1829 + * arguments:
23.1830 + * <ul>
23.1831 + * <li>a single {@code MethodHandle} target
23.1832 + * <li>zero or more leading values (counted by {@code leadingArgCount})
23.1833 + * <li>an {@code Object[]} array containing trailing arguments
23.1834 + * </ul>
23.1835 + * <p>
23.1836 + * The invoker will invoke its target like a call to {@link MethodHandle#invoke invoke} with
23.1837 + * the indicated {@code type}.
23.1838 + * That is, if the target is exactly of the given {@code type}, it will behave
23.1839 + * like {@code invokeExact}; otherwise it behave as if {@link MethodHandle#asType asType}
23.1840 + * is used to convert the target to the required {@code type}.
23.1841 + * <p>
23.1842 + * The type of the returned invoker will not be the given {@code type}, but rather
23.1843 + * will have all parameters except the first {@code leadingArgCount}
23.1844 + * replaced by a single array of type {@code Object[]}, which will be
23.1845 + * the final parameter.
23.1846 + * <p>
23.1847 + * Before invoking its target, the invoker will spread the final array, apply
23.1848 + * reference casts as necessary, and unbox and widen primitive arguments.
23.1849 + * If, when the invoker is called, the supplied array argument does
23.1850 + * not have the correct number of elements, the invoker will throw
23.1851 + * an {@link IllegalArgumentException} instead of invoking the target.
23.1852 + * <p>
23.1853 + * This method is equivalent to the following code (though it may be more efficient):
23.1854 + * <blockquote><pre>{@code
23.1855 +MethodHandle invoker = MethodHandles.invoker(type);
23.1856 +int spreadArgCount = type.parameterCount() - leadingArgCount;
23.1857 +invoker = invoker.asSpreader(Object[].class, spreadArgCount);
23.1858 +return invoker;
23.1859 + * }</pre></blockquote>
23.1860 + * This method throws no reflective or security exceptions.
23.1861 + * @param type the desired target type
23.1862 + * @param leadingArgCount number of fixed arguments, to be passed unchanged to the target
23.1863 + * @return a method handle suitable for invoking any method handle of the given type
23.1864 + * @throws NullPointerException if {@code type} is null
23.1865 + * @throws IllegalArgumentException if {@code leadingArgCount} is not in
23.1866 + * the range from 0 to {@code type.parameterCount()} inclusive,
23.1867 + * or if the resulting method handle's type would have
23.1868 + * <a href="MethodHandle.html#maxarity">too many parameters</a>
23.1869 + */
23.1870 + static public
23.1871 + MethodHandle spreadInvoker(MethodType type, int leadingArgCount) {
23.1872 + if (leadingArgCount < 0 || leadingArgCount > type.parameterCount())
23.1873 + throw new IllegalArgumentException("bad argument count "+leadingArgCount);
23.1874 + return type.invokers().spreadInvoker(leadingArgCount);
23.1875 + }
23.1876 +
23.1877 + /**
23.1878 + * Produces a special <em>invoker method handle</em> which can be used to
23.1879 + * invoke any method handle of the given type, as if by {@link MethodHandle#invokeExact invokeExact}.
23.1880 + * The resulting invoker will have a type which is
23.1881 + * exactly equal to the desired type, except that it will accept
23.1882 + * an additional leading argument of type {@code MethodHandle}.
23.1883 + * <p>
23.1884 + * This method is equivalent to the following code (though it may be more efficient):
23.1885 + * {@code publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)}
23.1886 + *
23.1887 + * <p style="font-size:smaller;">
23.1888 + * <em>Discussion:</em>
23.1889 + * Invoker method handles can be useful when working with variable method handles
23.1890 + * of unknown types.
23.1891 + * For example, to emulate an {@code invokeExact} call to a variable method
23.1892 + * handle {@code M}, extract its type {@code T},
23.1893 + * look up the invoker method {@code X} for {@code T},
23.1894 + * and call the invoker method, as {@code X.invoke(T, A...)}.
23.1895 + * (It would not work to call {@code X.invokeExact}, since the type {@code T}
23.1896 + * is unknown.)
23.1897 + * If spreading, collecting, or other argument transformations are required,
23.1898 + * they can be applied once to the invoker {@code X} and reused on many {@code M}
23.1899 + * method handle values, as long as they are compatible with the type of {@code X}.
23.1900 + * <p style="font-size:smaller;">
23.1901 + * <em>(Note: The invoker method is not available via the Core Reflection API.
23.1902 + * An attempt to call {@linkplain java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}
23.1903 + * on the declared {@code invokeExact} or {@code invoke} method will raise an
23.1904 + * {@link java.lang.UnsupportedOperationException UnsupportedOperationException}.)</em>
23.1905 + * <p>
23.1906 + * This method throws no reflective or security exceptions.
23.1907 + * @param type the desired target type
23.1908 + * @return a method handle suitable for invoking any method handle of the given type
23.1909 + * @throws IllegalArgumentException if the resulting method handle's type would have
23.1910 + * <a href="MethodHandle.html#maxarity">too many parameters</a>
23.1911 + */
23.1912 + static public
23.1913 + MethodHandle exactInvoker(MethodType type) {
23.1914 + return type.invokers().exactInvoker();
23.1915 + }
23.1916 +
23.1917 + /**
23.1918 + * Produces a special <em>invoker method handle</em> which can be used to
23.1919 + * invoke any method handle compatible with the given type, as if by {@link MethodHandle#invoke invoke}.
23.1920 + * The resulting invoker will have a type which is
23.1921 + * exactly equal to the desired type, except that it will accept
23.1922 + * an additional leading argument of type {@code MethodHandle}.
23.1923 + * <p>
23.1924 + * Before invoking its target, if the target differs from the expected type,
23.1925 + * the invoker will apply reference casts as
23.1926 + * necessary and box, unbox, or widen primitive values, as if by {@link MethodHandle#asType asType}.
23.1927 + * Similarly, the return value will be converted as necessary.
23.1928 + * If the target is a {@linkplain MethodHandle#asVarargsCollector variable arity method handle},
23.1929 + * the required arity conversion will be made, again as if by {@link MethodHandle#asType asType}.
23.1930 + * <p>
23.1931 + * This method is equivalent to the following code (though it may be more efficient):
23.1932 + * {@code publicLookup().findVirtual(MethodHandle.class, "invoke", type)}
23.1933 + * <p style="font-size:smaller;">
23.1934 + * <em>Discussion:</em>
23.1935 + * A {@linkplain MethodType#genericMethodType general method type} is one which
23.1936 + * mentions only {@code Object} arguments and return values.
23.1937 + * An invoker for such a type is capable of calling any method handle
23.1938 + * of the same arity as the general type.
23.1939 + * <p style="font-size:smaller;">
23.1940 + * <em>(Note: The invoker method is not available via the Core Reflection API.
23.1941 + * An attempt to call {@linkplain java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}
23.1942 + * on the declared {@code invokeExact} or {@code invoke} method will raise an
23.1943 + * {@link java.lang.UnsupportedOperationException UnsupportedOperationException}.)</em>
23.1944 + * <p>
23.1945 + * This method throws no reflective or security exceptions.
23.1946 + * @param type the desired target type
23.1947 + * @return a method handle suitable for invoking any method handle convertible to the given type
23.1948 + * @throws IllegalArgumentException if the resulting method handle's type would have
23.1949 + * <a href="MethodHandle.html#maxarity">too many parameters</a>
23.1950 + */
23.1951 + static public
23.1952 + MethodHandle invoker(MethodType type) {
23.1953 + return type.invokers().generalInvoker();
23.1954 + }
23.1955 +
23.1956 + static /*non-public*/
23.1957 + MethodHandle basicInvoker(MethodType type) {
23.1958 + return type.form().basicInvoker();
23.1959 + }
23.1960 +
23.1961 + /// method handle modification (creation from other method handles)
23.1962 +
23.1963 + /**
23.1964 + * Produces a method handle which adapts the type of the
23.1965 + * given method handle to a new type by pairwise argument and return type conversion.
23.1966 + * The original type and new type must have the same number of arguments.
23.1967 + * The resulting method handle is guaranteed to report a type
23.1968 + * which is equal to the desired new type.
23.1969 + * <p>
23.1970 + * If the original type and new type are equal, returns target.
23.1971 + * <p>
23.1972 + * The same conversions are allowed as for {@link MethodHandle#asType MethodHandle.asType},
23.1973 + * and some additional conversions are also applied if those conversions fail.
23.1974 + * Given types <em>T0</em>, <em>T1</em>, one of the following conversions is applied
23.1975 + * if possible, before or instead of any conversions done by {@code asType}:
23.1976 + * <ul>
23.1977 + * <li>If <em>T0</em> and <em>T1</em> are references, and <em>T1</em> is an interface type,
23.1978 + * then the value of type <em>T0</em> is passed as a <em>T1</em> without a cast.
23.1979 + * (This treatment of interfaces follows the usage of the bytecode verifier.)
23.1980 + * <li>If <em>T0</em> is boolean and <em>T1</em> is another primitive,
23.1981 + * the boolean is converted to a byte value, 1 for true, 0 for false.
23.1982 + * (This treatment follows the usage of the bytecode verifier.)
23.1983 + * <li>If <em>T1</em> is boolean and <em>T0</em> is another primitive,
23.1984 + * <em>T0</em> is converted to byte via Java casting conversion (JLS 5.5),
23.1985 + * and the low order bit of the result is tested, as if by {@code (x & 1) != 0}.
23.1986 + * <li>If <em>T0</em> and <em>T1</em> are primitives other than boolean,
23.1987 + * then a Java casting conversion (JLS 5.5) is applied.
23.1988 + * (Specifically, <em>T0</em> will convert to <em>T1</em> by
23.1989 + * widening and/or narrowing.)
23.1990 + * <li>If <em>T0</em> is a reference and <em>T1</em> a primitive, an unboxing
23.1991 + * conversion will be applied at runtime, possibly followed
23.1992 + * by a Java casting conversion (JLS 5.5) on the primitive value,
23.1993 + * possibly followed by a conversion from byte to boolean by testing
23.1994 + * the low-order bit.
23.1995 + * <li>If <em>T0</em> is a reference and <em>T1</em> a primitive,
23.1996 + * and if the reference is null at runtime, a zero value is introduced.
23.1997 + * </ul>
23.1998 + * @param target the method handle to invoke after arguments are retyped
23.1999 + * @param newType the expected type of the new method handle
23.2000 + * @return a method handle which delegates to the target after performing
23.2001 + * any necessary argument conversions, and arranges for any
23.2002 + * necessary return value conversions
23.2003 + * @throws NullPointerException if either argument is null
23.2004 + * @throws WrongMethodTypeException if the conversion cannot be made
23.2005 + * @see MethodHandle#asType
23.2006 + */
23.2007 + public static
23.2008 + MethodHandle explicitCastArguments(MethodHandle target, MethodType newType) {
23.2009 + if (!target.type().isCastableTo(newType)) {
23.2010 + throw new WrongMethodTypeException("cannot explicitly cast "+target+" to "+newType);
23.2011 + }
23.2012 + return MethodHandleImpl.makePairwiseConvert(target, newType, 2);
23.2013 + }
23.2014 +
23.2015 + /**
23.2016 + * Produces a method handle which adapts the calling sequence of the
23.2017 + * given method handle to a new type, by reordering the arguments.
23.2018 + * The resulting method handle is guaranteed to report a type
23.2019 + * which is equal to the desired new type.
23.2020 + * <p>
23.2021 + * The given array controls the reordering.
23.2022 + * Call {@code #I} the number of incoming parameters (the value
23.2023 + * {@code newType.parameterCount()}, and call {@code #O} the number
23.2024 + * of outgoing parameters (the value {@code target.type().parameterCount()}).
23.2025 + * Then the length of the reordering array must be {@code #O},
23.2026 + * and each element must be a non-negative number less than {@code #I}.
23.2027 + * For every {@code N} less than {@code #O}, the {@code N}-th
23.2028 + * outgoing argument will be taken from the {@code I}-th incoming
23.2029 + * argument, where {@code I} is {@code reorder[N]}.
23.2030 + * <p>
23.2031 + * No argument or return value conversions are applied.
23.2032 + * The type of each incoming argument, as determined by {@code newType},
23.2033 + * must be identical to the type of the corresponding outgoing parameter
23.2034 + * or parameters in the target method handle.
23.2035 + * The return type of {@code newType} must be identical to the return
23.2036 + * type of the original target.
23.2037 + * <p>
23.2038 + * The reordering array need not specify an actual permutation.
23.2039 + * An incoming argument will be duplicated if its index appears
23.2040 + * more than once in the array, and an incoming argument will be dropped
23.2041 + * if its index does not appear in the array.
23.2042 + * As in the case of {@link #dropArguments(MethodHandle,int,List) dropArguments},
23.2043 + * incoming arguments which are not mentioned in the reordering array
23.2044 + * are may be any type, as determined only by {@code newType}.
23.2045 + * <blockquote><pre>{@code
23.2046 +import static java.lang.invoke.MethodHandles.*;
23.2047 +import static java.lang.invoke.MethodType.*;
23.2048 +...
23.2049 +MethodType intfn1 = methodType(int.class, int.class);
23.2050 +MethodType intfn2 = methodType(int.class, int.class, int.class);
23.2051 +MethodHandle sub = ... (int x, int y) -> (x-y) ...;
23.2052 +assert(sub.type().equals(intfn2));
23.2053 +MethodHandle sub1 = permuteArguments(sub, intfn2, 0, 1);
23.2054 +MethodHandle rsub = permuteArguments(sub, intfn2, 1, 0);
23.2055 +assert((int)rsub.invokeExact(1, 100) == 99);
23.2056 +MethodHandle add = ... (int x, int y) -> (x+y) ...;
23.2057 +assert(add.type().equals(intfn2));
23.2058 +MethodHandle twice = permuteArguments(add, intfn1, 0, 0);
23.2059 +assert(twice.type().equals(intfn1));
23.2060 +assert((int)twice.invokeExact(21) == 42);
23.2061 + * }</pre></blockquote>
23.2062 + * @param target the method handle to invoke after arguments are reordered
23.2063 + * @param newType the expected type of the new method handle
23.2064 + * @param reorder an index array which controls the reordering
23.2065 + * @return a method handle which delegates to the target after it
23.2066 + * drops unused arguments and moves and/or duplicates the other arguments
23.2067 + * @throws NullPointerException if any argument is null
23.2068 + * @throws IllegalArgumentException if the index array length is not equal to
23.2069 + * the arity of the target, or if any index array element
23.2070 + * not a valid index for a parameter of {@code newType},
23.2071 + * or if two corresponding parameter types in
23.2072 + * {@code target.type()} and {@code newType} are not identical,
23.2073 + */
23.2074 + public static
23.2075 + MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder) {
23.2076 + checkReorder(reorder, newType, target.type());
23.2077 + return target.permuteArguments(newType, reorder);
23.2078 + }
23.2079 +
23.2080 + private static void checkReorder(int[] reorder, MethodType newType, MethodType oldType) {
23.2081 + if (newType.returnType() != oldType.returnType())
23.2082 + throw newIllegalArgumentException("return types do not match",
23.2083 + oldType, newType);
23.2084 + if (reorder.length == oldType.parameterCount()) {
23.2085 + int limit = newType.parameterCount();
23.2086 + boolean bad = false;
23.2087 + for (int j = 0; j < reorder.length; j++) {
23.2088 + int i = reorder[j];
23.2089 + if (i < 0 || i >= limit) {
23.2090 + bad = true; break;
23.2091 + }
23.2092 + Class<?> src = newType.parameterType(i);
23.2093 + Class<?> dst = oldType.parameterType(j);
23.2094 + if (src != dst)
23.2095 + throw newIllegalArgumentException("parameter types do not match after reorder",
23.2096 + oldType, newType);
23.2097 + }
23.2098 + if (!bad) return;
23.2099 + }
23.2100 + throw newIllegalArgumentException("bad reorder array: "+Arrays.toString(reorder));
23.2101 + }
23.2102 +
23.2103 + /**
23.2104 + * Produces a method handle of the requested return type which returns the given
23.2105 + * constant value every time it is invoked.
23.2106 + * <p>
23.2107 + * Before the method handle is returned, the passed-in value is converted to the requested type.
23.2108 + * If the requested type is primitive, widening primitive conversions are attempted,
23.2109 + * else reference conversions are attempted.
23.2110 + * <p>The returned method handle is equivalent to {@code identity(type).bindTo(value)}.
23.2111 + * @param type the return type of the desired method handle
23.2112 + * @param value the value to return
23.2113 + * @return a method handle of the given return type and no arguments, which always returns the given value
23.2114 + * @throws NullPointerException if the {@code type} argument is null
23.2115 + * @throws ClassCastException if the value cannot be converted to the required return type
23.2116 + * @throws IllegalArgumentException if the given type is {@code void.class}
23.2117 + */
23.2118 + public static
23.2119 + MethodHandle constant(Class<?> type, Object value) {
23.2120 + if (type.isPrimitive()) {
23.2121 + if (type == void.class)
23.2122 + throw newIllegalArgumentException("void type");
23.2123 + Wrapper w = Wrapper.forPrimitiveType(type);
23.2124 + return insertArguments(identity(type), 0, w.convert(value, type));
23.2125 + } else {
23.2126 + return identity(type).bindTo(type.cast(value));
23.2127 + }
23.2128 + }
23.2129 +
23.2130 + /**
23.2131 + * Produces a method handle which returns its sole argument when invoked.
23.2132 + * @param type the type of the sole parameter and return value of the desired method handle
23.2133 + * @return a unary method handle which accepts and returns the given type
23.2134 + * @throws NullPointerException if the argument is null
23.2135 + * @throws IllegalArgumentException if the given type is {@code void.class}
23.2136 + */
23.2137 + public static
23.2138 + MethodHandle identity(Class<?> type) {
23.2139 + if (type == void.class)
23.2140 + throw newIllegalArgumentException("void type");
23.2141 + else if (type == Object.class)
23.2142 + return ValueConversions.identity();
23.2143 + else if (type.isPrimitive())
23.2144 + return ValueConversions.identity(Wrapper.forPrimitiveType(type));
23.2145 + else
23.2146 + return MethodHandleImpl.makeReferenceIdentity(type);
23.2147 + }
23.2148 +
23.2149 + /**
23.2150 + * Provides a target method handle with one or more <em>bound arguments</em>
23.2151 + * in advance of the method handle's invocation.
23.2152 + * The formal parameters to the target corresponding to the bound
23.2153 + * arguments are called <em>bound parameters</em>.
23.2154 + * Returns a new method handle which saves away the bound arguments.
23.2155 + * When it is invoked, it receives arguments for any non-bound parameters,
23.2156 + * binds the saved arguments to their corresponding parameters,
23.2157 + * and calls the original target.
23.2158 + * <p>
23.2159 + * The type of the new method handle will drop the types for the bound
23.2160 + * parameters from the original target type, since the new method handle
23.2161 + * will no longer require those arguments to be supplied by its callers.
23.2162 + * <p>
23.2163 + * Each given argument object must match the corresponding bound parameter type.
23.2164 + * If a bound parameter type is a primitive, the argument object
23.2165 + * must be a wrapper, and will be unboxed to produce the primitive value.
23.2166 + * <p>
23.2167 + * The {@code pos} argument selects which parameters are to be bound.
23.2168 + * It may range between zero and <i>N-L</i> (inclusively),
23.2169 + * where <i>N</i> is the arity of the target method handle
23.2170 + * and <i>L</i> is the length of the values array.
23.2171 + * @param target the method handle to invoke after the argument is inserted
23.2172 + * @param pos where to insert the argument (zero for the first)
23.2173 + * @param values the series of arguments to insert
23.2174 + * @return a method handle which inserts an additional argument,
23.2175 + * before calling the original method handle
23.2176 + * @throws NullPointerException if the target or the {@code values} array is null
23.2177 + * @see MethodHandle#bindTo
23.2178 + */
23.2179 + public static
23.2180 + MethodHandle insertArguments(MethodHandle target, int pos, Object... values) {
23.2181 + int insCount = values.length;
23.2182 + MethodType oldType = target.type();
23.2183 + int outargs = oldType.parameterCount();
23.2184 + int inargs = outargs - insCount;
23.2185 + if (inargs < 0)
23.2186 + throw newIllegalArgumentException("too many values to insert");
23.2187 + if (pos < 0 || pos > inargs)
23.2188 + throw newIllegalArgumentException("no argument type to append");
23.2189 + MethodHandle result = target;
23.2190 + for (int i = 0; i < insCount; i++) {
23.2191 + Object value = values[i];
23.2192 + Class<?> ptype = oldType.parameterType(pos+i);
23.2193 + if (ptype.isPrimitive()) {
23.2194 + char btype = 'I';
23.2195 + Wrapper w = Wrapper.forPrimitiveType(ptype);
23.2196 + switch (w) {
23.2197 + case LONG: btype = 'J'; break;
23.2198 + case FLOAT: btype = 'F'; break;
23.2199 + case DOUBLE: btype = 'D'; break;
23.2200 + }
23.2201 + // perform unboxing and/or primitive conversion
23.2202 + value = w.convert(value, ptype);
23.2203 + result = result.bindArgument(pos, btype, value);
23.2204 + continue;
23.2205 + }
23.2206 + value = ptype.cast(value); // throw CCE if needed
23.2207 + if (pos == 0) {
23.2208 + result = result.bindReceiver(value);
23.2209 + } else {
23.2210 + result = result.bindArgument(pos, 'L', value);
23.2211 + }
23.2212 + }
23.2213 + return result;
23.2214 + }
23.2215 +
23.2216 + /**
23.2217 + * Produces a method handle which will discard some dummy arguments
23.2218 + * before calling some other specified <i>target</i> method handle.
23.2219 + * The type of the new method handle will be the same as the target's type,
23.2220 + * except it will also include the dummy argument types,
23.2221 + * at some given position.
23.2222 + * <p>
23.2223 + * The {@code pos} argument may range between zero and <i>N</i>,
23.2224 + * where <i>N</i> is the arity of the target.
23.2225 + * If {@code pos} is zero, the dummy arguments will precede
23.2226 + * the target's real arguments; if {@code pos} is <i>N</i>
23.2227 + * they will come after.
23.2228 + * <p>
23.2229 + * <b>Example:</b>
23.2230 + * <blockquote><pre>{@code
23.2231 +import static java.lang.invoke.MethodHandles.*;
23.2232 +import static java.lang.invoke.MethodType.*;
23.2233 +...
23.2234 +MethodHandle cat = lookup().findVirtual(String.class,
23.2235 + "concat", methodType(String.class, String.class));
23.2236 +assertEquals("xy", (String) cat.invokeExact("x", "y"));
23.2237 +MethodType bigType = cat.type().insertParameterTypes(0, int.class, String.class);
23.2238 +MethodHandle d0 = dropArguments(cat, 0, bigType.parameterList().subList(0,2));
23.2239 +assertEquals(bigType, d0.type());
23.2240 +assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
23.2241 + * }</pre></blockquote>
23.2242 + * <p>
23.2243 + * This method is also equivalent to the following code:
23.2244 + * <blockquote><pre>
23.2245 + * {@link #dropArguments(MethodHandle,int,Class...) dropArguments}{@code (target, pos, valueTypes.toArray(new Class[0]))}
23.2246 + * </pre></blockquote>
23.2247 + * @param target the method handle to invoke after the arguments are dropped
23.2248 + * @param valueTypes the type(s) of the argument(s) to drop
23.2249 + * @param pos position of first argument to drop (zero for the leftmost)
23.2250 + * @return a method handle which drops arguments of the given types,
23.2251 + * before calling the original method handle
23.2252 + * @throws NullPointerException if the target is null,
23.2253 + * or if the {@code valueTypes} list or any of its elements is null
23.2254 + * @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class},
23.2255 + * or if {@code pos} is negative or greater than the arity of the target,
23.2256 + * or if the new method handle's type would have too many parameters
23.2257 + */
23.2258 + public static
23.2259 + MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes) {
23.2260 + MethodType oldType = target.type(); // get NPE
23.2261 + int dropped = valueTypes.size();
23.2262 + MethodType.checkSlotCount(dropped);
23.2263 + if (dropped == 0) return target;
23.2264 + int outargs = oldType.parameterCount();
23.2265 + int inargs = outargs + dropped;
23.2266 + if (pos < 0 || pos >= inargs)
23.2267 + throw newIllegalArgumentException("no argument type to remove");
23.2268 + ArrayList<Class<?>> ptypes = new ArrayList<>(oldType.parameterList());
23.2269 + ptypes.addAll(pos, valueTypes);
23.2270 + MethodType newType = MethodType.methodType(oldType.returnType(), ptypes);
23.2271 + return target.dropArguments(newType, pos, dropped);
23.2272 + }
23.2273 +
23.2274 + /**
23.2275 + * Produces a method handle which will discard some dummy arguments
23.2276 + * before calling some other specified <i>target</i> method handle.
23.2277 + * The type of the new method handle will be the same as the target's type,
23.2278 + * except it will also include the dummy argument types,
23.2279 + * at some given position.
23.2280 + * <p>
23.2281 + * The {@code pos} argument may range between zero and <i>N</i>,
23.2282 + * where <i>N</i> is the arity of the target.
23.2283 + * If {@code pos} is zero, the dummy arguments will precede
23.2284 + * the target's real arguments; if {@code pos} is <i>N</i>
23.2285 + * they will come after.
23.2286 + * <p>
23.2287 + * <b>Example:</b>
23.2288 + * <blockquote><pre>{@code
23.2289 +import static java.lang.invoke.MethodHandles.*;
23.2290 +import static java.lang.invoke.MethodType.*;
23.2291 +...
23.2292 +MethodHandle cat = lookup().findVirtual(String.class,
23.2293 + "concat", methodType(String.class, String.class));
23.2294 +assertEquals("xy", (String) cat.invokeExact("x", "y"));
23.2295 +MethodHandle d0 = dropArguments(cat, 0, String.class);
23.2296 +assertEquals("yz", (String) d0.invokeExact("x", "y", "z"));
23.2297 +MethodHandle d1 = dropArguments(cat, 1, String.class);
23.2298 +assertEquals("xz", (String) d1.invokeExact("x", "y", "z"));
23.2299 +MethodHandle d2 = dropArguments(cat, 2, String.class);
23.2300 +assertEquals("xy", (String) d2.invokeExact("x", "y", "z"));
23.2301 +MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
23.2302 +assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
23.2303 + * }</pre></blockquote>
23.2304 + * <p>
23.2305 + * This method is also equivalent to the following code:
23.2306 + * <blockquote><pre>
23.2307 + * {@link #dropArguments(MethodHandle,int,List) dropArguments}{@code (target, pos, Arrays.asList(valueTypes))}
23.2308 + * </pre></blockquote>
23.2309 + * @param target the method handle to invoke after the arguments are dropped
23.2310 + * @param valueTypes the type(s) of the argument(s) to drop
23.2311 + * @param pos position of first argument to drop (zero for the leftmost)
23.2312 + * @return a method handle which drops arguments of the given types,
23.2313 + * before calling the original method handle
23.2314 + * @throws NullPointerException if the target is null,
23.2315 + * or if the {@code valueTypes} array or any of its elements is null
23.2316 + * @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class},
23.2317 + * or if {@code pos} is negative or greater than the arity of the target,
23.2318 + * or if the new method handle's type would have
23.2319 + * <a href="MethodHandle.html#maxarity">too many parameters</a>
23.2320 + */
23.2321 + public static
23.2322 + MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes) {
23.2323 + return dropArguments(target, pos, Arrays.asList(valueTypes));
23.2324 + }
23.2325 +
23.2326 + /**
23.2327 + * Adapts a target method handle by pre-processing
23.2328 + * one or more of its arguments, each with its own unary filter function,
23.2329 + * and then calling the target with each pre-processed argument
23.2330 + * replaced by the result of its corresponding filter function.
23.2331 + * <p>
23.2332 + * The pre-processing is performed by one or more method handles,
23.2333 + * specified in the elements of the {@code filters} array.
23.2334 + * The first element of the filter array corresponds to the {@code pos}
23.2335 + * argument of the target, and so on in sequence.
23.2336 + * <p>
23.2337 + * Null arguments in the array are treated as identity functions,
23.2338 + * and the corresponding arguments left unchanged.
23.2339 + * (If there are no non-null elements in the array, the original target is returned.)
23.2340 + * Each filter is applied to the corresponding argument of the adapter.
23.2341 + * <p>
23.2342 + * If a filter {@code F} applies to the {@code N}th argument of
23.2343 + * the target, then {@code F} must be a method handle which
23.2344 + * takes exactly one argument. The type of {@code F}'s sole argument
23.2345 + * replaces the corresponding argument type of the target
23.2346 + * in the resulting adapted method handle.
23.2347 + * The return type of {@code F} must be identical to the corresponding
23.2348 + * parameter type of the target.
23.2349 + * <p>
23.2350 + * It is an error if there are elements of {@code filters}
23.2351 + * (null or not)
23.2352 + * which do not correspond to argument positions in the target.
23.2353 + * <p><b>Example:</b>
23.2354 + * <blockquote><pre>{@code
23.2355 +import static java.lang.invoke.MethodHandles.*;
23.2356 +import static java.lang.invoke.MethodType.*;
23.2357 +...
23.2358 +MethodHandle cat = lookup().findVirtual(String.class,
23.2359 + "concat", methodType(String.class, String.class));
23.2360 +MethodHandle upcase = lookup().findVirtual(String.class,
23.2361 + "toUpperCase", methodType(String.class));
23.2362 +assertEquals("xy", (String) cat.invokeExact("x", "y"));
23.2363 +MethodHandle f0 = filterArguments(cat, 0, upcase);
23.2364 +assertEquals("Xy", (String) f0.invokeExact("x", "y")); // Xy
23.2365 +MethodHandle f1 = filterArguments(cat, 1, upcase);
23.2366 +assertEquals("xY", (String) f1.invokeExact("x", "y")); // xY
23.2367 +MethodHandle f2 = filterArguments(cat, 0, upcase, upcase);
23.2368 +assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
23.2369 + * }</pre></blockquote>
23.2370 + * <p> Here is pseudocode for the resulting adapter:
23.2371 + * <blockquote><pre>{@code
23.2372 + * V target(P... p, A[i]... a[i], B... b);
23.2373 + * A[i] filter[i](V[i]);
23.2374 + * T adapter(P... p, V[i]... v[i], B... b) {
23.2375 + * return target(p..., f[i](v[i])..., b...);
23.2376 + * }
23.2377 + * }</pre></blockquote>
23.2378 + *
23.2379 + * @param target the method handle to invoke after arguments are filtered
23.2380 + * @param pos the position of the first argument to filter
23.2381 + * @param filters method handles to call initially on filtered arguments
23.2382 + * @return method handle which incorporates the specified argument filtering logic
23.2383 + * @throws NullPointerException if the target is null
23.2384 + * or if the {@code filters} array is null
23.2385 + * @throws IllegalArgumentException if a non-null element of {@code filters}
23.2386 + * does not match a corresponding argument type of target as described above,
23.2387 + * or if the {@code pos+filters.length} is greater than {@code target.type().parameterCount()},
23.2388 + * or if the resulting method handle's type would have
23.2389 + * <a href="MethodHandle.html#maxarity">too many parameters</a>
23.2390 + */
23.2391 + public static
23.2392 + MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) {
23.2393 + MethodType targetType = target.type();
23.2394 + MethodHandle adapter = target;
23.2395 + MethodType adapterType = null;
23.2396 + assert((adapterType = targetType) != null);
23.2397 + int maxPos = targetType.parameterCount();
23.2398 + if (pos + filters.length > maxPos)
23.2399 + throw newIllegalArgumentException("too many filters");
23.2400 + int curPos = pos-1; // pre-incremented
23.2401 + for (MethodHandle filter : filters) {
23.2402 + curPos += 1;
23.2403 + if (filter == null) continue; // ignore null elements of filters
23.2404 + adapter = filterArgument(adapter, curPos, filter);
23.2405 + assert((adapterType = adapterType.changeParameterType(curPos, filter.type().parameterType(0))) != null);
23.2406 + }
23.2407 + assert(adapterType.equals(adapter.type()));
23.2408 + return adapter;
23.2409 + }
23.2410 +
23.2411 + /*non-public*/ static
23.2412 + MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) {
23.2413 + MethodType targetType = target.type();
23.2414 + MethodType filterType = filter.type();
23.2415 + if (filterType.parameterCount() != 1
23.2416 + || filterType.returnType() != targetType.parameterType(pos))
23.2417 + throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
23.2418 + return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
23.2419 + }
23.2420 +
23.2421 + /**
23.2422 + * Adapts a target method handle by pre-processing
23.2423 + * a sub-sequence of its arguments with a filter (another method handle).
23.2424 + * The pre-processed arguments are replaced by the result (if any) of the
23.2425 + * filter function.
23.2426 + * The target is then called on the modified (usually shortened) argument list.
23.2427 + * <p>
23.2428 + * If the filter returns a value, the target must accept that value as
23.2429 + * its argument in position {@code pos}, preceded and/or followed by
23.2430 + * any arguments not passed to the filter.
23.2431 + * If the filter returns void, the target must accept all arguments
23.2432 + * not passed to the filter.
23.2433 + * No arguments are reordered, and a result returned from the filter
23.2434 + * replaces (in order) the whole subsequence of arguments originally
23.2435 + * passed to the adapter.
23.2436 + * <p>
23.2437 + * The argument types (if any) of the filter
23.2438 + * replace zero or one argument types of the target, at position {@code pos},
23.2439 + * in the resulting adapted method handle.
23.2440 + * The return type of the filter (if any) must be identical to the
23.2441 + * argument type of the target at position {@code pos}, and that target argument
23.2442 + * is supplied by the return value of the filter.
23.2443 + * <p>
23.2444 + * In all cases, {@code pos} must be greater than or equal to zero, and
23.2445 + * {@code pos} must also be less than or equal to the target's arity.
23.2446 + * <p><b>Example:</b>
23.2447 + * <blockquote><pre>{@code
23.2448 +import static java.lang.invoke.MethodHandles.*;
23.2449 +import static java.lang.invoke.MethodType.*;
23.2450 +...
23.2451 +MethodHandle deepToString = publicLookup()
23.2452 + .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
23.2453 +
23.2454 +MethodHandle ts1 = deepToString.asCollector(String[].class, 1);
23.2455 +assertEquals("[strange]", (String) ts1.invokeExact("strange"));
23.2456 +
23.2457 +MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
23.2458 +assertEquals("[up, down]", (String) ts2.invokeExact("up", "down"));
23.2459 +
23.2460 +MethodHandle ts3 = deepToString.asCollector(String[].class, 3);
23.2461 +MethodHandle ts3_ts2 = collectArguments(ts3, 1, ts2);
23.2462 +assertEquals("[top, [up, down], strange]",
23.2463 + (String) ts3_ts2.invokeExact("top", "up", "down", "strange"));
23.2464 +
23.2465 +MethodHandle ts3_ts2_ts1 = collectArguments(ts3_ts2, 3, ts1);
23.2466 +assertEquals("[top, [up, down], [strange]]",
23.2467 + (String) ts3_ts2_ts1.invokeExact("top", "up", "down", "strange"));
23.2468 +
23.2469 +MethodHandle ts3_ts2_ts3 = collectArguments(ts3_ts2, 1, ts3);
23.2470 +assertEquals("[top, [[up, down, strange], charm], bottom]",
23.2471 + (String) ts3_ts2_ts3.invokeExact("top", "up", "down", "strange", "charm", "bottom"));
23.2472 + * }</pre></blockquote>
23.2473 + * <p> Here is pseudocode for the resulting adapter:
23.2474 + * <blockquote><pre>{@code
23.2475 + * T target(A...,V,C...);
23.2476 + * V filter(B...);
23.2477 + * T adapter(A... a,B... b,C... c) {
23.2478 + * V v = filter(b...);
23.2479 + * return target(a...,v,c...);
23.2480 + * }
23.2481 + * // and if the filter has no arguments:
23.2482 + * T target2(A...,V,C...);
23.2483 + * V filter2();
23.2484 + * T adapter2(A... a,C... c) {
23.2485 + * V v = filter2();
23.2486 + * return target2(a...,v,c...);
23.2487 + * }
23.2488 + * // and if the filter has a void return:
23.2489 + * T target3(A...,C...);
23.2490 + * void filter3(B...);
23.2491 + * void adapter3(A... a,B... b,C... c) {
23.2492 + * filter3(b...);
23.2493 + * return target3(a...,c...);
23.2494 + * }
23.2495 + * }</pre></blockquote>
23.2496 + * <p>
23.2497 + * A collection adapter {@code collectArguments(mh, 0, coll)} is equivalent to
23.2498 + * one which first "folds" the affected arguments, and then drops them, in separate
23.2499 + * steps as follows:
23.2500 + * <blockquote><pre>{@code
23.2501 + * mh = MethodHandles.dropArguments(mh, 1, coll.type().parameterList()); //step 2
23.2502 + * mh = MethodHandles.foldArguments(mh, coll); //step 1
23.2503 + * }</pre></blockquote>
23.2504 + * If the target method handle consumes no arguments besides than the result
23.2505 + * (if any) of the filter {@code coll}, then {@code collectArguments(mh, 0, coll)}
23.2506 + * is equivalent to {@code filterReturnValue(coll, mh)}.
23.2507 + * If the filter method handle {@code coll} consumes one argument and produces
23.2508 + * a non-void result, then {@code collectArguments(mh, N, coll)}
23.2509 + * is equivalent to {@code filterArguments(mh, N, coll)}.
23.2510 + * Other equivalences are possible but would require argument permutation.
23.2511 + *
23.2512 + * @param target the method handle to invoke after filtering the subsequence of arguments
23.2513 + * @param pos the position of the first adapter argument to pass to the filter,
23.2514 + * and/or the target argument which receives the result of the filter
23.2515 + * @param filter method handle to call on the subsequence of arguments
23.2516 + * @return method handle which incorporates the specified argument subsequence filtering logic
23.2517 + * @throws NullPointerException if either argument is null
23.2518 + * @throws IllegalArgumentException if the return type of {@code filter}
23.2519 + * is non-void and is not the same as the {@code pos} argument of the target,
23.2520 + * or if {@code pos} is not between 0 and the target's arity, inclusive,
23.2521 + * or if the resulting method handle's type would have
23.2522 + * <a href="MethodHandle.html#maxarity">too many parameters</a>
23.2523 + * @see MethodHandles#foldArguments
23.2524 + * @see MethodHandles#filterArguments
23.2525 + * @see MethodHandles#filterReturnValue
23.2526 + */
23.2527 + public static
23.2528 + MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter) {
23.2529 + MethodType targetType = target.type();
23.2530 + MethodType filterType = filter.type();
23.2531 + if (filterType.returnType() != void.class &&
23.2532 + filterType.returnType() != targetType.parameterType(pos))
23.2533 + throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
23.2534 + return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
23.2535 + }
23.2536 +
23.2537 + /**
23.2538 + * Adapts a target method handle by post-processing
23.2539 + * its return value (if any) with a filter (another method handle).
23.2540 + * The result of the filter is returned from the adapter.
23.2541 + * <p>
23.2542 + * If the target returns a value, the filter must accept that value as
23.2543 + * its only argument.
23.2544 + * If the target returns void, the filter must accept no arguments.
23.2545 + * <p>
23.2546 + * The return type of the filter
23.2547 + * replaces the return type of the target
23.2548 + * in the resulting adapted method handle.
23.2549 + * The argument type of the filter (if any) must be identical to the
23.2550 + * return type of the target.
23.2551 + * <p><b>Example:</b>
23.2552 + * <blockquote><pre>{@code
23.2553 +import static java.lang.invoke.MethodHandles.*;
23.2554 +import static java.lang.invoke.MethodType.*;
23.2555 +...
23.2556 +MethodHandle cat = lookup().findVirtual(String.class,
23.2557 + "concat", methodType(String.class, String.class));
23.2558 +MethodHandle length = lookup().findVirtual(String.class,
23.2559 + "length", methodType(int.class));
23.2560 +System.out.println((String) cat.invokeExact("x", "y")); // xy
23.2561 +MethodHandle f0 = filterReturnValue(cat, length);
23.2562 +System.out.println((int) f0.invokeExact("x", "y")); // 2
23.2563 + * }</pre></blockquote>
23.2564 + * <p> Here is pseudocode for the resulting adapter:
23.2565 + * <blockquote><pre>{@code
23.2566 + * V target(A...);
23.2567 + * T filter(V);
23.2568 + * T adapter(A... a) {
23.2569 + * V v = target(a...);
23.2570 + * return filter(v);
23.2571 + * }
23.2572 + * // and if the target has a void return:
23.2573 + * void target2(A...);
23.2574 + * T filter2();
23.2575 + * T adapter2(A... a) {
23.2576 + * target2(a...);
23.2577 + * return filter2();
23.2578 + * }
23.2579 + * // and if the filter has a void return:
23.2580 + * V target3(A...);
23.2581 + * void filter3(V);
23.2582 + * void adapter3(A... a) {
23.2583 + * V v = target3(a...);
23.2584 + * filter3(v);
23.2585 + * }
23.2586 + * }</pre></blockquote>
23.2587 + * @param target the method handle to invoke before filtering the return value
23.2588 + * @param filter method handle to call on the return value
23.2589 + * @return method handle which incorporates the specified return value filtering logic
23.2590 + * @throws NullPointerException if either argument is null
23.2591 + * @throws IllegalArgumentException if the argument list of {@code filter}
23.2592 + * does not match the return type of target as described above
23.2593 + */
23.2594 + public static
23.2595 + MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) {
23.2596 + MethodType targetType = target.type();
23.2597 + MethodType filterType = filter.type();
23.2598 + Class<?> rtype = targetType.returnType();
23.2599 + int filterValues = filterType.parameterCount();
23.2600 + if (filterValues == 0
23.2601 + ? (rtype != void.class)
23.2602 + : (rtype != filterType.parameterType(0)))
23.2603 + throw newIllegalArgumentException("target and filter types do not match", target, filter);
23.2604 + // result = fold( lambda(retval, arg...) { filter(retval) },
23.2605 + // lambda( arg...) { target(arg...) } )
23.2606 + return MethodHandleImpl.makeCollectArguments(filter, target, 0, false);
23.2607 + }
23.2608 +
23.2609 + /**
23.2610 + * Adapts a target method handle by pre-processing
23.2611 + * some of its arguments, and then calling the target with
23.2612 + * the result of the pre-processing, inserted into the original
23.2613 + * sequence of arguments.
23.2614 + * <p>
23.2615 + * The pre-processing is performed by {@code combiner}, a second method handle.
23.2616 + * Of the arguments passed to the adapter, the first {@code N} arguments
23.2617 + * are copied to the combiner, which is then called.
23.2618 + * (Here, {@code N} is defined as the parameter count of the combiner.)
23.2619 + * After this, control passes to the target, with any result
23.2620 + * from the combiner inserted before the original {@code N} incoming
23.2621 + * arguments.
23.2622 + * <p>
23.2623 + * If the combiner returns a value, the first parameter type of the target
23.2624 + * must be identical with the return type of the combiner, and the next
23.2625 + * {@code N} parameter types of the target must exactly match the parameters
23.2626 + * of the combiner.
23.2627 + * <p>
23.2628 + * If the combiner has a void return, no result will be inserted,
23.2629 + * and the first {@code N} parameter types of the target
23.2630 + * must exactly match the parameters of the combiner.
23.2631 + * <p>
23.2632 + * The resulting adapter is the same type as the target, except that the
23.2633 + * first parameter type is dropped,
23.2634 + * if it corresponds to the result of the combiner.
23.2635 + * <p>
23.2636 + * (Note that {@link #dropArguments(MethodHandle,int,List) dropArguments} can be used to remove any arguments
23.2637 + * that either the combiner or the target does not wish to receive.
23.2638 + * If some of the incoming arguments are destined only for the combiner,
23.2639 + * consider using {@link MethodHandle#asCollector asCollector} instead, since those
23.2640 + * arguments will not need to be live on the stack on entry to the
23.2641 + * target.)
23.2642 + * <p><b>Example:</b>
23.2643 + * <blockquote><pre>{@code
23.2644 +import static java.lang.invoke.MethodHandles.*;
23.2645 +import static java.lang.invoke.MethodType.*;
23.2646 +...
23.2647 +MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class,
23.2648 + "println", methodType(void.class, String.class))
23.2649 + .bindTo(System.out);
23.2650 +MethodHandle cat = lookup().findVirtual(String.class,
23.2651 + "concat", methodType(String.class, String.class));
23.2652 +assertEquals("boojum", (String) cat.invokeExact("boo", "jum"));
23.2653 +MethodHandle catTrace = foldArguments(cat, trace);
23.2654 +// also prints "boo":
23.2655 +assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
23.2656 + * }</pre></blockquote>
23.2657 + * <p> Here is pseudocode for the resulting adapter:
23.2658 + * <blockquote><pre>{@code
23.2659 + * // there are N arguments in A...
23.2660 + * T target(V, A[N]..., B...);
23.2661 + * V combiner(A...);
23.2662 + * T adapter(A... a, B... b) {
23.2663 + * V v = combiner(a...);
23.2664 + * return target(v, a..., b...);
23.2665 + * }
23.2666 + * // and if the combiner has a void return:
23.2667 + * T target2(A[N]..., B...);
23.2668 + * void combiner2(A...);
23.2669 + * T adapter2(A... a, B... b) {
23.2670 + * combiner2(a...);
23.2671 + * return target2(a..., b...);
23.2672 + * }
23.2673 + * }</pre></blockquote>
23.2674 + * @param target the method handle to invoke after arguments are combined
23.2675 + * @param combiner method handle to call initially on the incoming arguments
23.2676 + * @return method handle which incorporates the specified argument folding logic
23.2677 + * @throws NullPointerException if either argument is null
23.2678 + * @throws IllegalArgumentException if {@code combiner}'s return type
23.2679 + * is non-void and not the same as the first argument type of
23.2680 + * the target, or if the initial {@code N} argument types
23.2681 + * of the target
23.2682 + * (skipping one matching the {@code combiner}'s return type)
23.2683 + * are not identical with the argument types of {@code combiner}
23.2684 + */
23.2685 + public static
23.2686 + MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) {
23.2687 + int pos = 0;
23.2688 + MethodType targetType = target.type();
23.2689 + MethodType combinerType = combiner.type();
23.2690 + int foldPos = pos;
23.2691 + int foldArgs = combinerType.parameterCount();
23.2692 + int foldVals = combinerType.returnType() == void.class ? 0 : 1;
23.2693 + int afterInsertPos = foldPos + foldVals;
23.2694 + boolean ok = (targetType.parameterCount() >= afterInsertPos + foldArgs);
23.2695 + if (ok && !(combinerType.parameterList()
23.2696 + .equals(targetType.parameterList().subList(afterInsertPos,
23.2697 + afterInsertPos + foldArgs))))
23.2698 + ok = false;
23.2699 + if (ok && foldVals != 0 && !combinerType.returnType().equals(targetType.parameterType(0)))
23.2700 + ok = false;
23.2701 + if (!ok)
23.2702 + throw misMatchedTypes("target and combiner types", targetType, combinerType);
23.2703 + MethodType newType = targetType.dropParameterTypes(foldPos, afterInsertPos);
23.2704 + return MethodHandleImpl.makeCollectArguments(target, combiner, foldPos, true);
23.2705 + }
23.2706 +
23.2707 + /**
23.2708 + * Makes a method handle which adapts a target method handle,
23.2709 + * by guarding it with a test, a boolean-valued method handle.
23.2710 + * If the guard fails, a fallback handle is called instead.
23.2711 + * All three method handles must have the same corresponding
23.2712 + * argument and return types, except that the return type
23.2713 + * of the test must be boolean, and the test is allowed
23.2714 + * to have fewer arguments than the other two method handles.
23.2715 + * <p> Here is pseudocode for the resulting adapter:
23.2716 + * <blockquote><pre>{@code
23.2717 + * boolean test(A...);
23.2718 + * T target(A...,B...);
23.2719 + * T fallback(A...,B...);
23.2720 + * T adapter(A... a,B... b) {
23.2721 + * if (test(a...))
23.2722 + * return target(a..., b...);
23.2723 + * else
23.2724 + * return fallback(a..., b...);
23.2725 + * }
23.2726 + * }</pre></blockquote>
23.2727 + * Note that the test arguments ({@code a...} in the pseudocode) cannot
23.2728 + * be modified by execution of the test, and so are passed unchanged
23.2729 + * from the caller to the target or fallback as appropriate.
23.2730 + * @param test method handle used for test, must return boolean
23.2731 + * @param target method handle to call if test passes
23.2732 + * @param fallback method handle to call if test fails
23.2733 + * @return method handle which incorporates the specified if/then/else logic
23.2734 + * @throws NullPointerException if any argument is null
23.2735 + * @throws IllegalArgumentException if {@code test} does not return boolean,
23.2736 + * or if all three method types do not match (with the return
23.2737 + * type of {@code test} changed to match that of the target).
23.2738 + */
23.2739 + public static
23.2740 + MethodHandle guardWithTest(MethodHandle test,
23.2741 + MethodHandle target,
23.2742 + MethodHandle fallback) {
23.2743 + MethodType gtype = test.type();
23.2744 + MethodType ttype = target.type();
23.2745 + MethodType ftype = fallback.type();
23.2746 + if (!ttype.equals(ftype))
23.2747 + throw misMatchedTypes("target and fallback types", ttype, ftype);
23.2748 + if (gtype.returnType() != boolean.class)
23.2749 + throw newIllegalArgumentException("guard type is not a predicate "+gtype);
23.2750 + List<Class<?>> targs = ttype.parameterList();
23.2751 + List<Class<?>> gargs = gtype.parameterList();
23.2752 + if (!targs.equals(gargs)) {
23.2753 + int gpc = gargs.size(), tpc = targs.size();
23.2754 + if (gpc >= tpc || !targs.subList(0, gpc).equals(gargs))
23.2755 + throw misMatchedTypes("target and test types", ttype, gtype);
23.2756 + test = dropArguments(test, gpc, targs.subList(gpc, tpc));
23.2757 + gtype = test.type();
23.2758 + }
23.2759 + return MethodHandleImpl.makeGuardWithTest(test, target, fallback);
23.2760 + }
23.2761 +
23.2762 + static RuntimeException misMatchedTypes(String what, MethodType t1, MethodType t2) {
23.2763 + return newIllegalArgumentException(what + " must match: " + t1 + " != " + t2);
23.2764 + }
23.2765 +
23.2766 + /**
23.2767 + * Makes a method handle which adapts a target method handle,
23.2768 + * by running it inside an exception handler.
23.2769 + * If the target returns normally, the adapter returns that value.
23.2770 + * If an exception matching the specified type is thrown, the fallback
23.2771 + * handle is called instead on the exception, plus the original arguments.
23.2772 + * <p>
23.2773 + * The target and handler must have the same corresponding
23.2774 + * argument and return types, except that handler may omit trailing arguments
23.2775 + * (similarly to the predicate in {@link #guardWithTest guardWithTest}).
23.2776 + * Also, the handler must have an extra leading parameter of {@code exType} or a supertype.
23.2777 + * <p> Here is pseudocode for the resulting adapter:
23.2778 + * <blockquote><pre>{@code
23.2779 + * T target(A..., B...);
23.2780 + * T handler(ExType, A...);
23.2781 + * T adapter(A... a, B... b) {
23.2782 + * try {
23.2783 + * return target(a..., b...);
23.2784 + * } catch (ExType ex) {
23.2785 + * return handler(ex, a...);
23.2786 + * }
23.2787 + * }
23.2788 + * }</pre></blockquote>
23.2789 + * Note that the saved arguments ({@code a...} in the pseudocode) cannot
23.2790 + * be modified by execution of the target, and so are passed unchanged
23.2791 + * from the caller to the handler, if the handler is invoked.
23.2792 + * <p>
23.2793 + * The target and handler must return the same type, even if the handler
23.2794 + * always throws. (This might happen, for instance, because the handler
23.2795 + * is simulating a {@code finally} clause).
23.2796 + * To create such a throwing handler, compose the handler creation logic
23.2797 + * with {@link #throwException throwException},
23.2798 + * in order to create a method handle of the correct return type.
23.2799 + * @param target method handle to call
23.2800 + * @param exType the type of exception which the handler will catch
23.2801 + * @param handler method handle to call if a matching exception is thrown
23.2802 + * @return method handle which incorporates the specified try/catch logic
23.2803 + * @throws NullPointerException if any argument is null
23.2804 + * @throws IllegalArgumentException if {@code handler} does not accept
23.2805 + * the given exception type, or if the method handle types do
23.2806 + * not match in their return types and their
23.2807 + * corresponding parameters
23.2808 + */
23.2809 + public static
23.2810 + MethodHandle catchException(MethodHandle target,
23.2811 + Class<? extends Throwable> exType,
23.2812 + MethodHandle handler) {
23.2813 + MethodType ttype = target.type();
23.2814 + MethodType htype = handler.type();
23.2815 + if (htype.parameterCount() < 1 ||
23.2816 + !htype.parameterType(0).isAssignableFrom(exType))
23.2817 + throw newIllegalArgumentException("handler does not accept exception type "+exType);
23.2818 + if (htype.returnType() != ttype.returnType())
23.2819 + throw misMatchedTypes("target and handler return types", ttype, htype);
23.2820 + List<Class<?>> targs = ttype.parameterList();
23.2821 + List<Class<?>> hargs = htype.parameterList();
23.2822 + hargs = hargs.subList(1, hargs.size()); // omit leading parameter from handler
23.2823 + if (!targs.equals(hargs)) {
23.2824 + int hpc = hargs.size(), tpc = targs.size();
23.2825 + if (hpc >= tpc || !targs.subList(0, hpc).equals(hargs))
23.2826 + throw misMatchedTypes("target and handler types", ttype, htype);
23.2827 + handler = dropArguments(handler, 1+hpc, targs.subList(hpc, tpc));
23.2828 + htype = handler.type();
23.2829 + }
23.2830 + return MethodHandleImpl.makeGuardWithCatch(target, exType, handler);
23.2831 + }
23.2832 +
23.2833 + /**
23.2834 + * Produces a method handle which will throw exceptions of the given {@code exType}.
23.2835 + * The method handle will accept a single argument of {@code exType},
23.2836 + * and immediately throw it as an exception.
23.2837 + * The method type will nominally specify a return of {@code returnType}.
23.2838 + * The return type may be anything convenient: It doesn't matter to the
23.2839 + * method handle's behavior, since it will never return normally.
23.2840 + * @param returnType the return type of the desired method handle
23.2841 + * @param exType the parameter type of the desired method handle
23.2842 + * @return method handle which can throw the given exceptions
23.2843 + * @throws NullPointerException if either argument is null
23.2844 + */
23.2845 + public static
23.2846 + MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType) {
23.2847 + if (!Throwable.class.isAssignableFrom(exType))
23.2848 + throw new ClassCastException(exType.getName());
23.2849 + return MethodHandleImpl.throwException(MethodType.methodType(returnType, exType));
23.2850 + }
23.2851 +}
24.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
24.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/MethodType.java Sat Aug 09 11:12:05 2014 +0200
24.3 @@ -0,0 +1,1149 @@
24.4 +/*
24.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
24.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
24.7 + *
24.8 + * This code is free software; you can redistribute it and/or modify it
24.9 + * under the terms of the GNU General Public License version 2 only, as
24.10 + * published by the Free Software Foundation. Oracle designates this
24.11 + * particular file as subject to the "Classpath" exception as provided
24.12 + * by Oracle in the LICENSE file that accompanied this code.
24.13 + *
24.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
24.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
24.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24.17 + * version 2 for more details (a copy is included in the LICENSE file that
24.18 + * accompanied this code).
24.19 + *
24.20 + * You should have received a copy of the GNU General Public License version
24.21 + * 2 along with this work; if not, write to the Free Software Foundation,
24.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24.23 + *
24.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
24.25 + * or visit www.oracle.com if you need additional information or have any
24.26 + * questions.
24.27 + */
24.28 +
24.29 +package java.lang.invoke;
24.30 +
24.31 +import sun.invoke.util.Wrapper;
24.32 +import java.lang.ref.WeakReference;
24.33 +import java.lang.ref.Reference;
24.34 +import java.lang.ref.ReferenceQueue;
24.35 +import java.util.Arrays;
24.36 +import java.util.Collections;
24.37 +import java.util.List;
24.38 +import java.util.Objects;
24.39 +import java.util.concurrent.ConcurrentMap;
24.40 +import java.util.concurrent.ConcurrentHashMap;
24.41 +import sun.invoke.util.BytecodeDescriptor;
24.42 +import static java.lang.invoke.MethodHandleStatics.*;
24.43 +import sun.invoke.util.VerifyType;
24.44 +
24.45 +/**
24.46 + * A method type represents the arguments and return type accepted and
24.47 + * returned by a method handle, or the arguments and return type passed
24.48 + * and expected by a method handle caller. Method types must be properly
24.49 + * matched between a method handle and all its callers,
24.50 + * and the JVM's operations enforce this matching at, specifically
24.51 + * during calls to {@link MethodHandle#invokeExact MethodHandle.invokeExact}
24.52 + * and {@link MethodHandle#invoke MethodHandle.invoke}, and during execution
24.53 + * of {@code invokedynamic} instructions.
24.54 + * <p>
24.55 + * The structure is a return type accompanied by any number of parameter types.
24.56 + * The types (primitive, {@code void}, and reference) are represented by {@link Class} objects.
24.57 + * (For ease of exposition, we treat {@code void} as if it were a type.
24.58 + * In fact, it denotes the absence of a return type.)
24.59 + * <p>
24.60 + * All instances of {@code MethodType} are immutable.
24.61 + * Two instances are completely interchangeable if they compare equal.
24.62 + * Equality depends on pairwise correspondence of the return and parameter types and on nothing else.
24.63 + * <p>
24.64 + * This type can be created only by factory methods.
24.65 + * All factory methods may cache values, though caching is not guaranteed.
24.66 + * Some factory methods are static, while others are virtual methods which
24.67 + * modify precursor method types, e.g., by changing a selected parameter.
24.68 + * <p>
24.69 + * Factory methods which operate on groups of parameter types
24.70 + * are systematically presented in two versions, so that both Java arrays and
24.71 + * Java lists can be used to work with groups of parameter types.
24.72 + * The query methods {@code parameterArray} and {@code parameterList}
24.73 + * also provide a choice between arrays and lists.
24.74 + * <p>
24.75 + * {@code MethodType} objects are sometimes derived from bytecode instructions
24.76 + * such as {@code invokedynamic}, specifically from the type descriptor strings associated
24.77 + * with the instructions in a class file's constant pool.
24.78 + * <p>
24.79 + * Like classes and strings, method types can also be represented directly
24.80 + * in a class file's constant pool as constants.
24.81 + * A method type may be loaded by an {@code ldc} instruction which refers
24.82 + * to a suitable {@code CONSTANT_MethodType} constant pool entry.
24.83 + * The entry refers to a {@code CONSTANT_Utf8} spelling for the descriptor string.
24.84 + * (For full details on method type constants,
24.85 + * see sections 4.4.8 and 5.4.3.5 of the Java Virtual Machine Specification.)
24.86 + * <p>
24.87 + * When the JVM materializes a {@code MethodType} from a descriptor string,
24.88 + * all classes named in the descriptor must be accessible, and will be loaded.
24.89 + * (But the classes need not be initialized, as is the case with a {@code CONSTANT_Class}.)
24.90 + * This loading may occur at any time before the {@code MethodType} object is first derived.
24.91 + * @author John Rose, JSR 292 EG
24.92 + */
24.93 +public final
24.94 +class MethodType implements java.io.Serializable {
24.95 + private static final long serialVersionUID = 292L; // {rtype, {ptype...}}
24.96 +
24.97 + // The rtype and ptypes fields define the structural identity of the method type:
24.98 + private final Class<?> rtype;
24.99 + private final Class<?>[] ptypes;
24.100 +
24.101 + // The remaining fields are caches of various sorts:
24.102 + private @Stable MethodTypeForm form; // erased form, plus cached data about primitives
24.103 + private @Stable MethodType wrapAlt; // alternative wrapped/unwrapped version
24.104 + private @Stable Invokers invokers; // cache of handy higher-order adapters
24.105 + private @Stable String methodDescriptor; // cache for toMethodDescriptorString
24.106 +
24.107 + /**
24.108 + * Check the given parameters for validity and store them into the final fields.
24.109 + */
24.110 + private MethodType(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
24.111 + checkRtype(rtype);
24.112 + checkPtypes(ptypes);
24.113 + this.rtype = rtype;
24.114 + // defensively copy the array passed in by the user
24.115 + this.ptypes = trusted ? ptypes : Arrays.copyOf(ptypes, ptypes.length);
24.116 + }
24.117 +
24.118 + /**
24.119 + * Construct a temporary unchecked instance of MethodType for use only as a key to the intern table.
24.120 + * Does not check the given parameters for validity, and must be discarded after it is used as a searching key.
24.121 + * The parameters are reversed for this constructor, so that is is not accidentally used.
24.122 + */
24.123 + private MethodType(Class<?>[] ptypes, Class<?> rtype) {
24.124 + this.rtype = rtype;
24.125 + this.ptypes = ptypes;
24.126 + }
24.127 +
24.128 + /*trusted*/ MethodTypeForm form() { return form; }
24.129 + /*trusted*/ Class<?> rtype() { return rtype; }
24.130 + /*trusted*/ Class<?>[] ptypes() { return ptypes; }
24.131 +
24.132 + void setForm(MethodTypeForm f) { form = f; }
24.133 +
24.134 + /** This number, mandated by the JVM spec as 255,
24.135 + * is the maximum number of <em>slots</em>
24.136 + * that any Java method can receive in its argument list.
24.137 + * It limits both JVM signatures and method type objects.
24.138 + * The longest possible invocation will look like
24.139 + * {@code staticMethod(arg1, arg2, ..., arg255)} or
24.140 + * {@code x.virtualMethod(arg1, arg2, ..., arg254)}.
24.141 + */
24.142 + /*non-public*/ static final int MAX_JVM_ARITY = 255; // this is mandated by the JVM spec.
24.143 +
24.144 + /** This number is the maximum arity of a method handle, 254.
24.145 + * It is derived from the absolute JVM-imposed arity by subtracting one,
24.146 + * which is the slot occupied by the method handle itself at the
24.147 + * beginning of the argument list used to invoke the method handle.
24.148 + * The longest possible invocation will look like
24.149 + * {@code mh.invoke(arg1, arg2, ..., arg254)}.
24.150 + */
24.151 + // Issue: Should we allow MH.invokeWithArguments to go to the full 255?
24.152 + /*non-public*/ static final int MAX_MH_ARITY = MAX_JVM_ARITY-1; // deduct one for mh receiver
24.153 +
24.154 + /** This number is the maximum arity of a method handle invoker, 253.
24.155 + * It is derived from the absolute JVM-imposed arity by subtracting two,
24.156 + * which are the slots occupied by invoke method handle, and the
24.157 + * target method handle, which are both at the beginning of the argument
24.158 + * list used to invoke the target method handle.
24.159 + * The longest possible invocation will look like
24.160 + * {@code invokermh.invoke(targetmh, arg1, arg2, ..., arg253)}.
24.161 + */
24.162 + /*non-public*/ static final int MAX_MH_INVOKER_ARITY = MAX_MH_ARITY-1; // deduct one more for invoker
24.163 +
24.164 + private static void checkRtype(Class<?> rtype) {
24.165 + Objects.requireNonNull(rtype);
24.166 + }
24.167 + private static void checkPtype(Class<?> ptype) {
24.168 + Objects.requireNonNull(ptype);
24.169 + if (ptype == void.class)
24.170 + throw newIllegalArgumentException("parameter type cannot be void");
24.171 + }
24.172 + /** Return number of extra slots (count of long/double args). */
24.173 + private static int checkPtypes(Class<?>[] ptypes) {
24.174 + int slots = 0;
24.175 + for (Class<?> ptype : ptypes) {
24.176 + checkPtype(ptype);
24.177 + if (ptype == double.class || ptype == long.class) {
24.178 + slots++;
24.179 + }
24.180 + }
24.181 + checkSlotCount(ptypes.length + slots);
24.182 + return slots;
24.183 + }
24.184 + static void checkSlotCount(int count) {
24.185 + assert((MAX_JVM_ARITY & (MAX_JVM_ARITY+1)) == 0);
24.186 + // MAX_JVM_ARITY must be power of 2 minus 1 for following code trick to work:
24.187 + if ((count & MAX_JVM_ARITY) != count)
24.188 + throw newIllegalArgumentException("bad parameter count "+count);
24.189 + }
24.190 + private static IndexOutOfBoundsException newIndexOutOfBoundsException(Object num) {
24.191 + if (num instanceof Integer) num = "bad index: "+num;
24.192 + return new IndexOutOfBoundsException(num.toString());
24.193 + }
24.194 +
24.195 + static final ConcurrentWeakInternSet<MethodType> internTable = new ConcurrentWeakInternSet<>();
24.196 +
24.197 + static final Class<?>[] NO_PTYPES = {};
24.198 +
24.199 + /**
24.200 + * Finds or creates an instance of the given method type.
24.201 + * @param rtype the return type
24.202 + * @param ptypes the parameter types
24.203 + * @return a method type with the given components
24.204 + * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
24.205 + * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
24.206 + */
24.207 + public static
24.208 + MethodType methodType(Class<?> rtype, Class<?>[] ptypes) {
24.209 + return makeImpl(rtype, ptypes, false);
24.210 + }
24.211 +
24.212 + /**
24.213 + * Finds or creates a method type with the given components.
24.214 + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
24.215 + * @param rtype the return type
24.216 + * @param ptypes the parameter types
24.217 + * @return a method type with the given components
24.218 + * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
24.219 + * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
24.220 + */
24.221 + public static
24.222 + MethodType methodType(Class<?> rtype, List<Class<?>> ptypes) {
24.223 + boolean notrust = false; // random List impl. could return evil ptypes array
24.224 + return makeImpl(rtype, listToArray(ptypes), notrust);
24.225 + }
24.226 +
24.227 + private static Class<?>[] listToArray(List<Class<?>> ptypes) {
24.228 + // sanity check the size before the toArray call, since size might be huge
24.229 + checkSlotCount(ptypes.size());
24.230 + return ptypes.toArray(NO_PTYPES);
24.231 + }
24.232 +
24.233 + /**
24.234 + * Finds or creates a method type with the given components.
24.235 + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
24.236 + * The leading parameter type is prepended to the remaining array.
24.237 + * @param rtype the return type
24.238 + * @param ptype0 the first parameter type
24.239 + * @param ptypes the remaining parameter types
24.240 + * @return a method type with the given components
24.241 + * @throws NullPointerException if {@code rtype} or {@code ptype0} or {@code ptypes} or any element of {@code ptypes} is null
24.242 + * @throws IllegalArgumentException if {@code ptype0} or {@code ptypes} or any element of {@code ptypes} is {@code void.class}
24.243 + */
24.244 + public static
24.245 + MethodType methodType(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) {
24.246 + Class<?>[] ptypes1 = new Class<?>[1+ptypes.length];
24.247 + ptypes1[0] = ptype0;
24.248 + System.arraycopy(ptypes, 0, ptypes1, 1, ptypes.length);
24.249 + return makeImpl(rtype, ptypes1, true);
24.250 + }
24.251 +
24.252 + /**
24.253 + * Finds or creates a method type with the given components.
24.254 + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
24.255 + * The resulting method has no parameter types.
24.256 + * @param rtype the return type
24.257 + * @return a method type with the given return value
24.258 + * @throws NullPointerException if {@code rtype} is null
24.259 + */
24.260 + public static
24.261 + MethodType methodType(Class<?> rtype) {
24.262 + return makeImpl(rtype, NO_PTYPES, true);
24.263 + }
24.264 +
24.265 + /**
24.266 + * Finds or creates a method type with the given components.
24.267 + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
24.268 + * The resulting method has the single given parameter type.
24.269 + * @param rtype the return type
24.270 + * @param ptype0 the parameter type
24.271 + * @return a method type with the given return value and parameter type
24.272 + * @throws NullPointerException if {@code rtype} or {@code ptype0} is null
24.273 + * @throws IllegalArgumentException if {@code ptype0} is {@code void.class}
24.274 + */
24.275 + public static
24.276 + MethodType methodType(Class<?> rtype, Class<?> ptype0) {
24.277 + return makeImpl(rtype, new Class<?>[]{ ptype0 }, true);
24.278 + }
24.279 +
24.280 + /**
24.281 + * Finds or creates a method type with the given components.
24.282 + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
24.283 + * The resulting method has the same parameter types as {@code ptypes},
24.284 + * and the specified return type.
24.285 + * @param rtype the return type
24.286 + * @param ptypes the method type which supplies the parameter types
24.287 + * @return a method type with the given components
24.288 + * @throws NullPointerException if {@code rtype} or {@code ptypes} is null
24.289 + */
24.290 + public static
24.291 + MethodType methodType(Class<?> rtype, MethodType ptypes) {
24.292 + return makeImpl(rtype, ptypes.ptypes, true);
24.293 + }
24.294 +
24.295 + /**
24.296 + * Sole factory method to find or create an interned method type.
24.297 + * @param rtype desired return type
24.298 + * @param ptypes desired parameter types
24.299 + * @param trusted whether the ptypes can be used without cloning
24.300 + * @return the unique method type of the desired structure
24.301 + */
24.302 + /*trusted*/ static
24.303 + MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
24.304 + MethodType mt = internTable.get(new MethodType(ptypes, rtype));
24.305 + if (mt != null)
24.306 + return mt;
24.307 + if (ptypes.length == 0) {
24.308 + ptypes = NO_PTYPES; trusted = true;
24.309 + }
24.310 + mt = new MethodType(rtype, ptypes, trusted);
24.311 + // promote the object to the Real Thing, and reprobe
24.312 + mt.form = MethodTypeForm.findForm(mt);
24.313 + return internTable.add(mt);
24.314 + }
24.315 + private static final MethodType[] objectOnlyTypes = new MethodType[20];
24.316 +
24.317 + /**
24.318 + * Finds or creates a method type whose components are {@code Object} with an optional trailing {@code Object[]} array.
24.319 + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
24.320 + * All parameters and the return type will be {@code Object},
24.321 + * except the final array parameter if any, which will be {@code Object[]}.
24.322 + * @param objectArgCount number of parameters (excluding the final array parameter if any)
24.323 + * @param finalArray whether there will be a trailing array parameter, of type {@code Object[]}
24.324 + * @return a generally applicable method type, for all calls of the given fixed argument count and a collected array of further arguments
24.325 + * @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255 (or 254, if {@code finalArray} is true)
24.326 + * @see #genericMethodType(int)
24.327 + */
24.328 + public static
24.329 + MethodType genericMethodType(int objectArgCount, boolean finalArray) {
24.330 + MethodType mt;
24.331 + checkSlotCount(objectArgCount);
24.332 + int ivarargs = (!finalArray ? 0 : 1);
24.333 + int ootIndex = objectArgCount*2 + ivarargs;
24.334 + if (ootIndex < objectOnlyTypes.length) {
24.335 + mt = objectOnlyTypes[ootIndex];
24.336 + if (mt != null) return mt;
24.337 + }
24.338 + Class<?>[] ptypes = new Class<?>[objectArgCount + ivarargs];
24.339 + Arrays.fill(ptypes, Object.class);
24.340 + if (ivarargs != 0) ptypes[objectArgCount] = Object[].class;
24.341 + mt = makeImpl(Object.class, ptypes, true);
24.342 + if (ootIndex < objectOnlyTypes.length) {
24.343 + objectOnlyTypes[ootIndex] = mt; // cache it here also!
24.344 + }
24.345 + return mt;
24.346 + }
24.347 +
24.348 + /**
24.349 + * Finds or creates a method type whose components are all {@code Object}.
24.350 + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
24.351 + * All parameters and the return type will be Object.
24.352 + * @param objectArgCount number of parameters
24.353 + * @return a generally applicable method type, for all calls of the given argument count
24.354 + * @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255
24.355 + * @see #genericMethodType(int, boolean)
24.356 + */
24.357 + public static
24.358 + MethodType genericMethodType(int objectArgCount) {
24.359 + return genericMethodType(objectArgCount, false);
24.360 + }
24.361 +
24.362 + /**
24.363 + * Finds or creates a method type with a single different parameter type.
24.364 + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
24.365 + * @param num the index (zero-based) of the parameter type to change
24.366 + * @param nptype a new parameter type to replace the old one with
24.367 + * @return the same type, except with the selected parameter changed
24.368 + * @throws IndexOutOfBoundsException if {@code num} is not a valid index into {@code parameterArray()}
24.369 + * @throws IllegalArgumentException if {@code nptype} is {@code void.class}
24.370 + * @throws NullPointerException if {@code nptype} is null
24.371 + */
24.372 + public MethodType changeParameterType(int num, Class<?> nptype) {
24.373 + if (parameterType(num) == nptype) return this;
24.374 + checkPtype(nptype);
24.375 + Class<?>[] nptypes = ptypes.clone();
24.376 + nptypes[num] = nptype;
24.377 + return makeImpl(rtype, nptypes, true);
24.378 + }
24.379 +
24.380 + /**
24.381 + * Finds or creates a method type with additional parameter types.
24.382 + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
24.383 + * @param num the position (zero-based) of the inserted parameter type(s)
24.384 + * @param ptypesToInsert zero or more new parameter types to insert into the parameter list
24.385 + * @return the same type, except with the selected parameter(s) inserted
24.386 + * @throws IndexOutOfBoundsException if {@code num} is negative or greater than {@code parameterCount()}
24.387 + * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
24.388 + * or if the resulting method type would have more than 255 parameter slots
24.389 + * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
24.390 + */
24.391 + public MethodType insertParameterTypes(int num, Class<?>... ptypesToInsert) {
24.392 + int len = ptypes.length;
24.393 + if (num < 0 || num > len)
24.394 + throw newIndexOutOfBoundsException(num);
24.395 + int ins = checkPtypes(ptypesToInsert);
24.396 + checkSlotCount(parameterSlotCount() + ptypesToInsert.length + ins);
24.397 + int ilen = ptypesToInsert.length;
24.398 + if (ilen == 0) return this;
24.399 + Class<?>[] nptypes = Arrays.copyOfRange(ptypes, 0, len+ilen);
24.400 + System.arraycopy(nptypes, num, nptypes, num+ilen, len-num);
24.401 + System.arraycopy(ptypesToInsert, 0, nptypes, num, ilen);
24.402 + return makeImpl(rtype, nptypes, true);
24.403 + }
24.404 +
24.405 + /**
24.406 + * Finds or creates a method type with additional parameter types.
24.407 + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
24.408 + * @param ptypesToInsert zero or more new parameter types to insert after the end of the parameter list
24.409 + * @return the same type, except with the selected parameter(s) appended
24.410 + * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
24.411 + * or if the resulting method type would have more than 255 parameter slots
24.412 + * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
24.413 + */
24.414 + public MethodType appendParameterTypes(Class<?>... ptypesToInsert) {
24.415 + return insertParameterTypes(parameterCount(), ptypesToInsert);
24.416 + }
24.417 +
24.418 + /**
24.419 + * Finds or creates a method type with additional parameter types.
24.420 + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
24.421 + * @param num the position (zero-based) of the inserted parameter type(s)
24.422 + * @param ptypesToInsert zero or more new parameter types to insert into the parameter list
24.423 + * @return the same type, except with the selected parameter(s) inserted
24.424 + * @throws IndexOutOfBoundsException if {@code num} is negative or greater than {@code parameterCount()}
24.425 + * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
24.426 + * or if the resulting method type would have more than 255 parameter slots
24.427 + * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
24.428 + */
24.429 + public MethodType insertParameterTypes(int num, List<Class<?>> ptypesToInsert) {
24.430 + return insertParameterTypes(num, listToArray(ptypesToInsert));
24.431 + }
24.432 +
24.433 + /**
24.434 + * Finds or creates a method type with additional parameter types.
24.435 + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
24.436 + * @param ptypesToInsert zero or more new parameter types to insert after the end of the parameter list
24.437 + * @return the same type, except with the selected parameter(s) appended
24.438 + * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
24.439 + * or if the resulting method type would have more than 255 parameter slots
24.440 + * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
24.441 + */
24.442 + public MethodType appendParameterTypes(List<Class<?>> ptypesToInsert) {
24.443 + return insertParameterTypes(parameterCount(), ptypesToInsert);
24.444 + }
24.445 +
24.446 + /**
24.447 + * Finds or creates a method type with modified parameter types.
24.448 + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
24.449 + * @param start the position (zero-based) of the first replaced parameter type(s)
24.450 + * @param end the position (zero-based) after the last replaced parameter type(s)
24.451 + * @param ptypesToInsert zero or more new parameter types to insert into the parameter list
24.452 + * @return the same type, except with the selected parameter(s) replaced
24.453 + * @throws IndexOutOfBoundsException if {@code start} is negative or greater than {@code parameterCount()}
24.454 + * or if {@code end} is negative or greater than {@code parameterCount()}
24.455 + * or if {@code start} is greater than {@code end}
24.456 + * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
24.457 + * or if the resulting method type would have more than 255 parameter slots
24.458 + * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
24.459 + */
24.460 + /*non-public*/ MethodType replaceParameterTypes(int start, int end, Class<?>... ptypesToInsert) {
24.461 + if (start == end)
24.462 + return insertParameterTypes(start, ptypesToInsert);
24.463 + int len = ptypes.length;
24.464 + if (!(0 <= start && start <= end && end <= len))
24.465 + throw newIndexOutOfBoundsException("start="+start+" end="+end);
24.466 + int ilen = ptypesToInsert.length;
24.467 + if (ilen == 0)
24.468 + return dropParameterTypes(start, end);
24.469 + return dropParameterTypes(start, end).insertParameterTypes(start, ptypesToInsert);
24.470 + }
24.471 +
24.472 + /**
24.473 + * Finds or creates a method type with some parameter types omitted.
24.474 + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
24.475 + * @param start the index (zero-based) of the first parameter type to remove
24.476 + * @param end the index (greater than {@code start}) of the first parameter type after not to remove
24.477 + * @return the same type, except with the selected parameter(s) removed
24.478 + * @throws IndexOutOfBoundsException if {@code start} is negative or greater than {@code parameterCount()}
24.479 + * or if {@code end} is negative or greater than {@code parameterCount()}
24.480 + * or if {@code start} is greater than {@code end}
24.481 + */
24.482 + public MethodType dropParameterTypes(int start, int end) {
24.483 + int len = ptypes.length;
24.484 + if (!(0 <= start && start <= end && end <= len))
24.485 + throw newIndexOutOfBoundsException("start="+start+" end="+end);
24.486 + if (start == end) return this;
24.487 + Class<?>[] nptypes;
24.488 + if (start == 0) {
24.489 + if (end == len) {
24.490 + // drop all parameters
24.491 + nptypes = NO_PTYPES;
24.492 + } else {
24.493 + // drop initial parameter(s)
24.494 + nptypes = Arrays.copyOfRange(ptypes, end, len);
24.495 + }
24.496 + } else {
24.497 + if (end == len) {
24.498 + // drop trailing parameter(s)
24.499 + nptypes = Arrays.copyOfRange(ptypes, 0, start);
24.500 + } else {
24.501 + int tail = len - end;
24.502 + nptypes = Arrays.copyOfRange(ptypes, 0, start + tail);
24.503 + System.arraycopy(ptypes, end, nptypes, start, tail);
24.504 + }
24.505 + }
24.506 + return makeImpl(rtype, nptypes, true);
24.507 + }
24.508 +
24.509 + /**
24.510 + * Finds or creates a method type with a different return type.
24.511 + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
24.512 + * @param nrtype a return parameter type to replace the old one with
24.513 + * @return the same type, except with the return type change
24.514 + * @throws NullPointerException if {@code nrtype} is null
24.515 + */
24.516 + public MethodType changeReturnType(Class<?> nrtype) {
24.517 + if (returnType() == nrtype) return this;
24.518 + return makeImpl(nrtype, ptypes, true);
24.519 + }
24.520 +
24.521 + /**
24.522 + * Reports if this type contains a primitive argument or return value.
24.523 + * The return type {@code void} counts as a primitive.
24.524 + * @return true if any of the types are primitives
24.525 + */
24.526 + public boolean hasPrimitives() {
24.527 + return form.hasPrimitives();
24.528 + }
24.529 +
24.530 + /**
24.531 + * Reports if this type contains a wrapper argument or return value.
24.532 + * Wrappers are types which box primitive values, such as {@link Integer}.
24.533 + * The reference type {@code java.lang.Void} counts as a wrapper,
24.534 + * if it occurs as a return type.
24.535 + * @return true if any of the types are wrappers
24.536 + */
24.537 + public boolean hasWrappers() {
24.538 + return unwrap() != this;
24.539 + }
24.540 +
24.541 + /**
24.542 + * Erases all reference types to {@code Object}.
24.543 + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
24.544 + * All primitive types (including {@code void}) will remain unchanged.
24.545 + * @return a version of the original type with all reference types replaced
24.546 + */
24.547 + public MethodType erase() {
24.548 + return form.erasedType();
24.549 + }
24.550 +
24.551 + /**
24.552 + * Erases all reference types to {@code Object}, and all subword types to {@code int}.
24.553 + * This is the reduced type polymorphism used by private methods
24.554 + * such as {@link MethodHandle#invokeBasic invokeBasic}.
24.555 + * @return a version of the original type with all reference and subword types replaced
24.556 + */
24.557 + /*non-public*/ MethodType basicType() {
24.558 + return form.basicType();
24.559 + }
24.560 +
24.561 + /**
24.562 + * @return a version of the original type with MethodHandle prepended as the first argument
24.563 + */
24.564 + /*non-public*/ MethodType invokerType() {
24.565 + return insertParameterTypes(0, MethodHandle.class);
24.566 + }
24.567 +
24.568 + /**
24.569 + * Converts all types, both reference and primitive, to {@code Object}.
24.570 + * Convenience method for {@link #genericMethodType(int) genericMethodType}.
24.571 + * The expression {@code type.wrap().erase()} produces the same value
24.572 + * as {@code type.generic()}.
24.573 + * @return a version of the original type with all types replaced
24.574 + */
24.575 + public MethodType generic() {
24.576 + return genericMethodType(parameterCount());
24.577 + }
24.578 +
24.579 + /**
24.580 + * Converts all primitive types to their corresponding wrapper types.
24.581 + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
24.582 + * All reference types (including wrapper types) will remain unchanged.
24.583 + * A {@code void} return type is changed to the type {@code java.lang.Void}.
24.584 + * The expression {@code type.wrap().erase()} produces the same value
24.585 + * as {@code type.generic()}.
24.586 + * @return a version of the original type with all primitive types replaced
24.587 + */
24.588 + public MethodType wrap() {
24.589 + return hasPrimitives() ? wrapWithPrims(this) : this;
24.590 + }
24.591 +
24.592 + /**
24.593 + * Converts all wrapper types to their corresponding primitive types.
24.594 + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
24.595 + * All primitive types (including {@code void}) will remain unchanged.
24.596 + * A return type of {@code java.lang.Void} is changed to {@code void}.
24.597 + * @return a version of the original type with all wrapper types replaced
24.598 + */
24.599 + public MethodType unwrap() {
24.600 + MethodType noprims = !hasPrimitives() ? this : wrapWithPrims(this);
24.601 + return unwrapWithNoPrims(noprims);
24.602 + }
24.603 +
24.604 + private static MethodType wrapWithPrims(MethodType pt) {
24.605 + assert(pt.hasPrimitives());
24.606 + MethodType wt = pt.wrapAlt;
24.607 + if (wt == null) {
24.608 + // fill in lazily
24.609 + wt = MethodTypeForm.canonicalize(pt, MethodTypeForm.WRAP, MethodTypeForm.WRAP);
24.610 + assert(wt != null);
24.611 + pt.wrapAlt = wt;
24.612 + }
24.613 + return wt;
24.614 + }
24.615 +
24.616 + private static MethodType unwrapWithNoPrims(MethodType wt) {
24.617 + assert(!wt.hasPrimitives());
24.618 + MethodType uwt = wt.wrapAlt;
24.619 + if (uwt == null) {
24.620 + // fill in lazily
24.621 + uwt = MethodTypeForm.canonicalize(wt, MethodTypeForm.UNWRAP, MethodTypeForm.UNWRAP);
24.622 + if (uwt == null)
24.623 + uwt = wt; // type has no wrappers or prims at all
24.624 + wt.wrapAlt = uwt;
24.625 + }
24.626 + return uwt;
24.627 + }
24.628 +
24.629 + /**
24.630 + * Returns the parameter type at the specified index, within this method type.
24.631 + * @param num the index (zero-based) of the desired parameter type
24.632 + * @return the selected parameter type
24.633 + * @throws IndexOutOfBoundsException if {@code num} is not a valid index into {@code parameterArray()}
24.634 + */
24.635 + public Class<?> parameterType(int num) {
24.636 + return ptypes[num];
24.637 + }
24.638 + /**
24.639 + * Returns the number of parameter types in this method type.
24.640 + * @return the number of parameter types
24.641 + */
24.642 + public int parameterCount() {
24.643 + return ptypes.length;
24.644 + }
24.645 + /**
24.646 + * Returns the return type of this method type.
24.647 + * @return the return type
24.648 + */
24.649 + public Class<?> returnType() {
24.650 + return rtype;
24.651 + }
24.652 +
24.653 + /**
24.654 + * Presents the parameter types as a list (a convenience method).
24.655 + * The list will be immutable.
24.656 + * @return the parameter types (as an immutable list)
24.657 + */
24.658 + public List<Class<?>> parameterList() {
24.659 + return Collections.unmodifiableList(Arrays.asList(ptypes));
24.660 + }
24.661 +
24.662 + /*non-public*/ Class<?> lastParameterType() {
24.663 + int len = ptypes.length;
24.664 + return len == 0 ? void.class : ptypes[len-1];
24.665 + }
24.666 +
24.667 + /**
24.668 + * Presents the parameter types as an array (a convenience method).
24.669 + * Changes to the array will not result in changes to the type.
24.670 + * @return the parameter types (as a fresh copy if necessary)
24.671 + */
24.672 + public Class<?>[] parameterArray() {
24.673 + return ptypes.clone();
24.674 + }
24.675 +
24.676 + /**
24.677 + * Compares the specified object with this type for equality.
24.678 + * That is, it returns <tt>true</tt> if and only if the specified object
24.679 + * is also a method type with exactly the same parameters and return type.
24.680 + * @param x object to compare
24.681 + * @see Object#equals(Object)
24.682 + */
24.683 + @Override
24.684 + public boolean equals(Object x) {
24.685 + return this == x || x instanceof MethodType && equals((MethodType)x);
24.686 + }
24.687 +
24.688 + private boolean equals(MethodType that) {
24.689 + return this.rtype == that.rtype
24.690 + && Arrays.equals(this.ptypes, that.ptypes);
24.691 + }
24.692 +
24.693 + /**
24.694 + * Returns the hash code value for this method type.
24.695 + * It is defined to be the same as the hashcode of a List
24.696 + * whose elements are the return type followed by the
24.697 + * parameter types.
24.698 + * @return the hash code value for this method type
24.699 + * @see Object#hashCode()
24.700 + * @see #equals(Object)
24.701 + * @see List#hashCode()
24.702 + */
24.703 + @Override
24.704 + public int hashCode() {
24.705 + int hashCode = 31 + rtype.hashCode();
24.706 + for (Class<?> ptype : ptypes)
24.707 + hashCode = 31*hashCode + ptype.hashCode();
24.708 + return hashCode;
24.709 + }
24.710 +
24.711 + /**
24.712 + * Returns a string representation of the method type,
24.713 + * of the form {@code "(PT0,PT1...)RT"}.
24.714 + * The string representation of a method type is a
24.715 + * parenthesis enclosed, comma separated list of type names,
24.716 + * followed immediately by the return type.
24.717 + * <p>
24.718 + * Each type is represented by its
24.719 + * {@link java.lang.Class#getSimpleName simple name}.
24.720 + */
24.721 + @Override
24.722 + public String toString() {
24.723 + StringBuilder sb = new StringBuilder();
24.724 + sb.append("(");
24.725 + for (int i = 0; i < ptypes.length; i++) {
24.726 + if (i > 0) sb.append(",");
24.727 + sb.append(ptypes[i].getSimpleName());
24.728 + }
24.729 + sb.append(")");
24.730 + sb.append(rtype.getSimpleName());
24.731 + return sb.toString();
24.732 + }
24.733 +
24.734 +
24.735 + /*non-public*/
24.736 + boolean isViewableAs(MethodType newType) {
24.737 + if (!VerifyType.isNullConversion(returnType(), newType.returnType()))
24.738 + return false;
24.739 + int argc = parameterCount();
24.740 + if (argc != newType.parameterCount())
24.741 + return false;
24.742 + for (int i = 0; i < argc; i++) {
24.743 + if (!VerifyType.isNullConversion(newType.parameterType(i), parameterType(i)))
24.744 + return false;
24.745 + }
24.746 + return true;
24.747 + }
24.748 + /*non-public*/
24.749 + boolean isCastableTo(MethodType newType) {
24.750 + int argc = parameterCount();
24.751 + if (argc != newType.parameterCount())
24.752 + return false;
24.753 + return true;
24.754 + }
24.755 + /*non-public*/
24.756 + boolean isConvertibleTo(MethodType newType) {
24.757 + if (!canConvert(returnType(), newType.returnType()))
24.758 + return false;
24.759 + int argc = parameterCount();
24.760 + if (argc != newType.parameterCount())
24.761 + return false;
24.762 + for (int i = 0; i < argc; i++) {
24.763 + if (!canConvert(newType.parameterType(i), parameterType(i)))
24.764 + return false;
24.765 + }
24.766 + return true;
24.767 + }
24.768 + /*non-public*/
24.769 + static boolean canConvert(Class<?> src, Class<?> dst) {
24.770 + // short-circuit a few cases:
24.771 + if (src == dst || dst == Object.class) return true;
24.772 + // the remainder of this logic is documented in MethodHandle.asType
24.773 + if (src.isPrimitive()) {
24.774 + // can force void to an explicit null, a la reflect.Method.invoke
24.775 + // can also force void to a primitive zero, by analogy
24.776 + if (src == void.class) return true; //or !dst.isPrimitive()?
24.777 + Wrapper sw = Wrapper.forPrimitiveType(src);
24.778 + if (dst.isPrimitive()) {
24.779 + // P->P must widen
24.780 + return Wrapper.forPrimitiveType(dst).isConvertibleFrom(sw);
24.781 + } else {
24.782 + // P->R must box and widen
24.783 + return dst.isAssignableFrom(sw.wrapperType());
24.784 + }
24.785 + } else if (dst.isPrimitive()) {
24.786 + // any value can be dropped
24.787 + if (dst == void.class) return true;
24.788 + Wrapper dw = Wrapper.forPrimitiveType(dst);
24.789 + // R->P must be able to unbox (from a dynamically chosen type) and widen
24.790 + // For example:
24.791 + // Byte/Number/Comparable/Object -> dw:Byte -> byte.
24.792 + // Character/Comparable/Object -> dw:Character -> char
24.793 + // Boolean/Comparable/Object -> dw:Boolean -> boolean
24.794 + // This means that dw must be cast-compatible with src.
24.795 + if (src.isAssignableFrom(dw.wrapperType())) {
24.796 + return true;
24.797 + }
24.798 + // The above does not work if the source reference is strongly typed
24.799 + // to a wrapper whose primitive must be widened. For example:
24.800 + // Byte -> unbox:byte -> short/int/long/float/double
24.801 + // Character -> unbox:char -> int/long/float/double
24.802 + if (Wrapper.isWrapperType(src) &&
24.803 + dw.isConvertibleFrom(Wrapper.forWrapperType(src))) {
24.804 + // can unbox from src and then widen to dst
24.805 + return true;
24.806 + }
24.807 + // We have already covered cases which arise due to runtime unboxing
24.808 + // of a reference type which covers several wrapper types:
24.809 + // Object -> cast:Integer -> unbox:int -> long/float/double
24.810 + // Serializable -> cast:Byte -> unbox:byte -> byte/short/int/long/float/double
24.811 + // An marginal case is Number -> dw:Character -> char, which would be OK if there were a
24.812 + // subclass of Number which wraps a value that can convert to char.
24.813 + // Since there is none, we don't need an extra check here to cover char or boolean.
24.814 + return false;
24.815 + } else {
24.816 + // R->R always works, since null is always valid dynamically
24.817 + return true;
24.818 + }
24.819 + }
24.820 +
24.821 + /// Queries which have to do with the bytecode architecture
24.822 +
24.823 + /** Reports the number of JVM stack slots required to invoke a method
24.824 + * of this type. Note that (for historical reasons) the JVM requires
24.825 + * a second stack slot to pass long and double arguments.
24.826 + * So this method returns {@link #parameterCount() parameterCount} plus the
24.827 + * number of long and double parameters (if any).
24.828 + * <p>
24.829 + * This method is included for the benefit of applications that must
24.830 + * generate bytecodes that process method handles and invokedynamic.
24.831 + * @return the number of JVM stack slots for this type's parameters
24.832 + */
24.833 + /*non-public*/ int parameterSlotCount() {
24.834 + return form.parameterSlotCount();
24.835 + }
24.836 +
24.837 + /*non-public*/ Invokers invokers() {
24.838 + Invokers inv = invokers;
24.839 + if (inv != null) return inv;
24.840 + invokers = inv = new Invokers(this);
24.841 + return inv;
24.842 + }
24.843 +
24.844 + /** Reports the number of JVM stack slots which carry all parameters including and after
24.845 + * the given position, which must be in the range of 0 to
24.846 + * {@code parameterCount} inclusive. Successive parameters are
24.847 + * more shallowly stacked, and parameters are indexed in the bytecodes
24.848 + * according to their trailing edge. Thus, to obtain the depth
24.849 + * in the outgoing call stack of parameter {@code N}, obtain
24.850 + * the {@code parameterSlotDepth} of its trailing edge
24.851 + * at position {@code N+1}.
24.852 + * <p>
24.853 + * Parameters of type {@code long} and {@code double} occupy
24.854 + * two stack slots (for historical reasons) and all others occupy one.
24.855 + * Therefore, the number returned is the number of arguments
24.856 + * <em>including</em> and <em>after</em> the given parameter,
24.857 + * <em>plus</em> the number of long or double arguments
24.858 + * at or after after the argument for the given parameter.
24.859 + * <p>
24.860 + * This method is included for the benefit of applications that must
24.861 + * generate bytecodes that process method handles and invokedynamic.
24.862 + * @param num an index (zero-based, inclusive) within the parameter types
24.863 + * @return the index of the (shallowest) JVM stack slot transmitting the
24.864 + * given parameter
24.865 + * @throws IllegalArgumentException if {@code num} is negative or greater than {@code parameterCount()}
24.866 + */
24.867 + /*non-public*/ int parameterSlotDepth(int num) {
24.868 + if (num < 0 || num > ptypes.length)
24.869 + parameterType(num); // force a range check
24.870 + return form.parameterToArgSlot(num-1);
24.871 + }
24.872 +
24.873 + /** Reports the number of JVM stack slots required to receive a return value
24.874 + * from a method of this type.
24.875 + * If the {@link #returnType() return type} is void, it will be zero,
24.876 + * else if the return type is long or double, it will be two, else one.
24.877 + * <p>
24.878 + * This method is included for the benefit of applications that must
24.879 + * generate bytecodes that process method handles and invokedynamic.
24.880 + * @return the number of JVM stack slots (0, 1, or 2) for this type's return value
24.881 + * Will be removed for PFD.
24.882 + */
24.883 + /*non-public*/ int returnSlotCount() {
24.884 + return form.returnSlotCount();
24.885 + }
24.886 +
24.887 + /**
24.888 + * Finds or creates an instance of a method type, given the spelling of its bytecode descriptor.
24.889 + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
24.890 + * Any class or interface name embedded in the descriptor string
24.891 + * will be resolved by calling {@link ClassLoader#loadClass(java.lang.String)}
24.892 + * on the given loader (or if it is null, on the system class loader).
24.893 + * <p>
24.894 + * Note that it is possible to encounter method types which cannot be
24.895 + * constructed by this method, because their component types are
24.896 + * not all reachable from a common class loader.
24.897 + * <p>
24.898 + * This method is included for the benefit of applications that must
24.899 + * generate bytecodes that process method handles and {@code invokedynamic}.
24.900 + * @param descriptor a bytecode-level type descriptor string "(T...)T"
24.901 + * @param loader the class loader in which to look up the types
24.902 + * @return a method type matching the bytecode-level type descriptor
24.903 + * @throws NullPointerException if the string is null
24.904 + * @throws IllegalArgumentException if the string is not well-formed
24.905 + * @throws TypeNotPresentException if a named type cannot be found
24.906 + */
24.907 + public static MethodType fromMethodDescriptorString(String descriptor, ClassLoader loader)
24.908 + throws IllegalArgumentException, TypeNotPresentException
24.909 + {
24.910 + if (!descriptor.startsWith("(") || // also generates NPE if needed
24.911 + descriptor.indexOf(')') < 0 ||
24.912 + descriptor.indexOf('.') >= 0)
24.913 + throw new IllegalArgumentException("not a method descriptor: "+descriptor);
24.914 + List<Class<?>> types = BytecodeDescriptor.parseMethod(descriptor, loader);
24.915 + Class<?> rtype = types.remove(types.size() - 1);
24.916 + checkSlotCount(types.size());
24.917 + Class<?>[] ptypes = listToArray(types);
24.918 + return makeImpl(rtype, ptypes, true);
24.919 + }
24.920 +
24.921 + /**
24.922 + * Produces a bytecode descriptor representation of the method type.
24.923 + * <p>
24.924 + * Note that this is not a strict inverse of {@link #fromMethodDescriptorString fromMethodDescriptorString}.
24.925 + * Two distinct classes which share a common name but have different class loaders
24.926 + * will appear identical when viewed within descriptor strings.
24.927 + * <p>
24.928 + * This method is included for the benefit of applications that must
24.929 + * generate bytecodes that process method handles and {@code invokedynamic}.
24.930 + * {@link #fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader) fromMethodDescriptorString},
24.931 + * because the latter requires a suitable class loader argument.
24.932 + * @return the bytecode type descriptor representation
24.933 + */
24.934 + public String toMethodDescriptorString() {
24.935 + String desc = methodDescriptor;
24.936 + if (desc == null) {
24.937 + desc = BytecodeDescriptor.unparse(this);
24.938 + methodDescriptor = desc;
24.939 + }
24.940 + return desc;
24.941 + }
24.942 +
24.943 + /*non-public*/ static String toFieldDescriptorString(Class<?> cls) {
24.944 + return BytecodeDescriptor.unparse(cls);
24.945 + }
24.946 +
24.947 + /// Serialization.
24.948 +
24.949 + /**
24.950 + * There are no serializable fields for {@code MethodType}.
24.951 + */
24.952 + private static final java.io.ObjectStreamField[] serialPersistentFields = { };
24.953 +
24.954 + /**
24.955 + * Save the {@code MethodType} instance to a stream.
24.956 + *
24.957 + * @serialData
24.958 + * For portability, the serialized format does not refer to named fields.
24.959 + * Instead, the return type and parameter type arrays are written directly
24.960 + * from the {@code writeObject} method, using two calls to {@code s.writeObject}
24.961 + * as follows:
24.962 + * <blockquote><pre>{@code
24.963 +s.writeObject(this.returnType());
24.964 +s.writeObject(this.parameterArray());
24.965 + * }</pre></blockquote>
24.966 + * <p>
24.967 + * The deserialized field values are checked as if they were
24.968 + * provided to the factory method {@link #methodType(Class,Class[]) methodType}.
24.969 + * For example, null values, or {@code void} parameter types,
24.970 + * will lead to exceptions during deserialization.
24.971 + * @param s the stream to write the object to
24.972 + * @throws java.io.IOException if there is a problem writing the object
24.973 + */
24.974 + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
24.975 + s.defaultWriteObject(); // requires serialPersistentFields to be an empty array
24.976 + s.writeObject(returnType());
24.977 + s.writeObject(parameterArray());
24.978 + }
24.979 +
24.980 + /**
24.981 + * Reconstitute the {@code MethodType} instance from a stream (that is,
24.982 + * deserialize it).
24.983 + * This instance is a scratch object with bogus final fields.
24.984 + * It provides the parameters to the factory method called by
24.985 + * {@link #readResolve readResolve}.
24.986 + * After that call it is discarded.
24.987 + * @param s the stream to read the object from
24.988 + * @throws java.io.IOException if there is a problem reading the object
24.989 + * @throws ClassNotFoundException if one of the component classes cannot be resolved
24.990 + * @see #MethodType()
24.991 + * @see #readResolve
24.992 + * @see #writeObject
24.993 + */
24.994 + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
24.995 + s.defaultReadObject(); // requires serialPersistentFields to be an empty array
24.996 +
24.997 + Class<?> returnType = (Class<?>) s.readObject();
24.998 + Class<?>[] parameterArray = (Class<?>[]) s.readObject();
24.999 +
24.1000 + // Probably this object will never escape, but let's check
24.1001 + // the field values now, just to be sure.
24.1002 + checkRtype(returnType);
24.1003 + checkPtypes(parameterArray);
24.1004 +
24.1005 + parameterArray = parameterArray.clone(); // make sure it is unshared
24.1006 + MethodType_init(returnType, parameterArray);
24.1007 + }
24.1008 +
24.1009 + /**
24.1010 + * For serialization only.
24.1011 + * Sets the final fields to null, pending {@code Unsafe.putObject}.
24.1012 + */
24.1013 + private MethodType() {
24.1014 + this.rtype = null;
24.1015 + this.ptypes = null;
24.1016 + }
24.1017 + private void MethodType_init(Class<?> rtype, Class<?>[] ptypes) {
24.1018 + // In order to communicate these values to readResolve, we must
24.1019 + // store them into the implementation-specific final fields.
24.1020 + checkRtype(rtype);
24.1021 + checkPtypes(ptypes);
24.1022 + UNSAFE.putObject(this, rtypeOffset, rtype);
24.1023 + UNSAFE.putObject(this, ptypesOffset, ptypes);
24.1024 + }
24.1025 +
24.1026 + // Support for resetting final fields while deserializing
24.1027 + private static final long rtypeOffset, ptypesOffset;
24.1028 + static {
24.1029 + try {
24.1030 + rtypeOffset = UNSAFE.objectFieldOffset
24.1031 + (MethodType.class.getDeclaredField("rtype"));
24.1032 + ptypesOffset = UNSAFE.objectFieldOffset
24.1033 + (MethodType.class.getDeclaredField("ptypes"));
24.1034 + } catch (Exception ex) {
24.1035 + throw new Error(ex);
24.1036 + }
24.1037 + }
24.1038 +
24.1039 + /**
24.1040 + * Resolves and initializes a {@code MethodType} object
24.1041 + * after serialization.
24.1042 + * @return the fully initialized {@code MethodType} object
24.1043 + */
24.1044 + private Object readResolve() {
24.1045 + // Do not use a trusted path for deserialization:
24.1046 + //return makeImpl(rtype, ptypes, true);
24.1047 + // Verify all operands, and make sure ptypes is unshared:
24.1048 + return methodType(rtype, ptypes);
24.1049 + }
24.1050 +
24.1051 + /**
24.1052 + * Simple implementation of weak concurrent intern set.
24.1053 + *
24.1054 + * @param <T> interned type
24.1055 + */
24.1056 + private static class ConcurrentWeakInternSet<T> {
24.1057 +
24.1058 + private final ConcurrentMap<WeakEntry<T>, WeakEntry<T>> map;
24.1059 + private final ReferenceQueue<T> stale;
24.1060 +
24.1061 + public ConcurrentWeakInternSet() {
24.1062 + this.map = new ConcurrentHashMap<>();
24.1063 + this.stale = new ReferenceQueue<>();
24.1064 + }
24.1065 +
24.1066 + /**
24.1067 + * Get the existing interned element.
24.1068 + * This method returns null if no element is interned.
24.1069 + *
24.1070 + * @param elem element to look up
24.1071 + * @return the interned element
24.1072 + */
24.1073 + public T get(T elem) {
24.1074 + if (elem == null) throw new NullPointerException();
24.1075 + expungeStaleElements();
24.1076 +
24.1077 + WeakEntry<T> value = map.get(new WeakEntry<>(elem));
24.1078 + if (value != null) {
24.1079 + T res = value.get();
24.1080 + if (res != null) {
24.1081 + return res;
24.1082 + }
24.1083 + }
24.1084 + return null;
24.1085 + }
24.1086 +
24.1087 + /**
24.1088 + * Interns the element.
24.1089 + * Always returns non-null element, matching the one in the intern set.
24.1090 + * Under the race against another add(), it can return <i>different</i>
24.1091 + * element, if another thread beats us to interning it.
24.1092 + *
24.1093 + * @param elem element to add
24.1094 + * @return element that was actually added
24.1095 + */
24.1096 + public T add(T elem) {
24.1097 + if (elem == null) throw new NullPointerException();
24.1098 +
24.1099 + // Playing double race here, and so spinloop is required.
24.1100 + // First race is with two concurrent updaters.
24.1101 + // Second race is with GC purging weak ref under our feet.
24.1102 + // Hopefully, we almost always end up with a single pass.
24.1103 + T interned;
24.1104 + WeakEntry<T> e = new WeakEntry<>(elem, stale);
24.1105 + do {
24.1106 + expungeStaleElements();
24.1107 + WeakEntry<T> exist = map.putIfAbsent(e, e);
24.1108 + interned = (exist == null) ? elem : exist.get();
24.1109 + } while (interned == null);
24.1110 + return interned;
24.1111 + }
24.1112 +
24.1113 + private void expungeStaleElements() {
24.1114 + Reference<? extends T> reference;
24.1115 + while ((reference = stale.poll()) != null) {
24.1116 + map.remove(reference);
24.1117 + }
24.1118 + }
24.1119 +
24.1120 + private static class WeakEntry<T> extends WeakReference<T> {
24.1121 +
24.1122 + public final int hashcode;
24.1123 +
24.1124 + public WeakEntry(T key, ReferenceQueue<T> queue) {
24.1125 + super(key, queue);
24.1126 + hashcode = key.hashCode();
24.1127 + }
24.1128 +
24.1129 + public WeakEntry(T key) {
24.1130 + super(key);
24.1131 + hashcode = key.hashCode();
24.1132 + }
24.1133 +
24.1134 + @Override
24.1135 + public boolean equals(Object obj) {
24.1136 + if (obj instanceof WeakEntry) {
24.1137 + Object that = ((WeakEntry) obj).get();
24.1138 + Object mine = get();
24.1139 + return (that == null || mine == null) ? (this == obj) : mine.equals(that);
24.1140 + }
24.1141 + return false;
24.1142 + }
24.1143 +
24.1144 + @Override
24.1145 + public int hashCode() {
24.1146 + return hashcode;
24.1147 + }
24.1148 +
24.1149 + }
24.1150 + }
24.1151 +
24.1152 +}
25.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
25.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/MethodTypeForm.java Sat Aug 09 11:12:05 2014 +0200
25.3 @@ -0,0 +1,388 @@
25.4 +/*
25.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
25.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
25.7 + *
25.8 + * This code is free software; you can redistribute it and/or modify it
25.9 + * under the terms of the GNU General Public License version 2 only, as
25.10 + * published by the Free Software Foundation. Oracle designates this
25.11 + * particular file as subject to the "Classpath" exception as provided
25.12 + * by Oracle in the LICENSE file that accompanied this code.
25.13 + *
25.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
25.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
25.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25.17 + * version 2 for more details (a copy is included in the LICENSE file that
25.18 + * accompanied this code).
25.19 + *
25.20 + * You should have received a copy of the GNU General Public License version
25.21 + * 2 along with this work; if not, write to the Free Software Foundation,
25.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
25.23 + *
25.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
25.25 + * or visit www.oracle.com if you need additional information or have any
25.26 + * questions.
25.27 + */
25.28 +
25.29 +package java.lang.invoke;
25.30 +
25.31 +import sun.invoke.util.Wrapper;
25.32 +import static java.lang.invoke.MethodHandleStatics.*;
25.33 +import static java.lang.invoke.MethodHandleNatives.Constants.*;
25.34 + import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
25.35 +
25.36 +/**
25.37 + * Shared information for a group of method types, which differ
25.38 + * only by reference types, and therefore share a common erasure
25.39 + * and wrapping.
25.40 + * <p>
25.41 + * For an empirical discussion of the structure of method types,
25.42 + * see <a href="http://groups.google.com/group/jvm-languages/browse_thread/thread/ac9308ae74da9b7e/">
25.43 + * the thread "Avoiding Boxing" on jvm-languages</a>.
25.44 + * There are approximately 2000 distinct erased method types in the JDK.
25.45 + * There are a little over 10 times that number of unerased types.
25.46 + * No more than half of these are likely to be loaded at once.
25.47 + * @author John Rose
25.48 + */
25.49 +final class MethodTypeForm {
25.50 + final int[] argToSlotTable, slotToArgTable;
25.51 + final long argCounts; // packed slot & value counts
25.52 + final long primCounts; // packed prim & double counts
25.53 + final int vmslots; // total number of parameter slots
25.54 + final MethodType erasedType; // the canonical erasure
25.55 + final MethodType basicType; // the canonical erasure, with primitives simplified
25.56 +
25.57 + // Cached adapter information:
25.58 + @Stable String typeString; // argument type signature characters
25.59 + @Stable MethodHandle genericInvoker; // JVM hook for inexact invoke
25.60 + @Stable MethodHandle basicInvoker; // cached instance of MH.invokeBasic
25.61 + @Stable MethodHandle namedFunctionInvoker; // cached helper for LF.NamedFunction
25.62 +
25.63 + // Cached lambda form information, for basic types only:
25.64 + final @Stable LambdaForm[] lambdaForms;
25.65 + // Indexes into lambdaForms:
25.66 + static final int
25.67 + LF_INVVIRTUAL = 0, // DMH invokeVirtual
25.68 + LF_INVSTATIC = 1,
25.69 + LF_INVSPECIAL = 2,
25.70 + LF_NEWINVSPECIAL = 3,
25.71 + LF_INVINTERFACE = 4,
25.72 + LF_INVSTATIC_INIT = 5, // DMH invokeStatic with <clinit> barrier
25.73 + LF_INTERPRET = 6, // LF interpreter
25.74 + LF_COUNTER = 7, // CMH wrapper
25.75 + LF_REINVOKE = 8, // other wrapper
25.76 + LF_EX_LINKER = 9, // invokeExact_MT
25.77 + LF_EX_INVOKER = 10, // invokeExact MH
25.78 + LF_GEN_LINKER = 11,
25.79 + LF_GEN_INVOKER = 12,
25.80 + LF_CS_LINKER = 13, // linkToCallSite_CS
25.81 + LF_MH_LINKER = 14, // linkToCallSite_MH
25.82 + LF_LIMIT = 15;
25.83 +
25.84 + public MethodType erasedType() {
25.85 + return erasedType;
25.86 + }
25.87 +
25.88 + public MethodType basicType() {
25.89 + return basicType;
25.90 + }
25.91 +
25.92 + public LambdaForm cachedLambdaForm(int which) {
25.93 + return lambdaForms[which];
25.94 + }
25.95 +
25.96 + public LambdaForm setCachedLambdaForm(int which, LambdaForm form) {
25.97 + // Should we perform some sort of CAS, to avoid racy duplication?
25.98 + return lambdaForms[which] = form;
25.99 + }
25.100 +
25.101 + public MethodHandle basicInvoker() {
25.102 + assert(erasedType == basicType) : "erasedType: " + erasedType + " != basicType: " + basicType; // primitives must be flattened also
25.103 + MethodHandle invoker = basicInvoker;
25.104 + if (invoker != null) return invoker;
25.105 + invoker = DirectMethodHandle.make(invokeBasicMethod(basicType));
25.106 + basicInvoker = invoker;
25.107 + return invoker;
25.108 + }
25.109 +
25.110 + // This next one is called from LambdaForm.NamedFunction.<init>.
25.111 + /*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) {
25.112 + assert(basicType == basicType.basicType());
25.113 + try {
25.114 + // Do approximately the same as this public API call:
25.115 + // Lookup.findVirtual(MethodHandle.class, name, type);
25.116 + // But bypass access and corner case checks, since we know exactly what we need.
25.117 + return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType);
25.118 + } catch (ReflectiveOperationException ex) {
25.119 + throw newInternalError("JVM cannot find invoker for "+basicType, ex);
25.120 + }
25.121 + }
25.122 +
25.123 + /**
25.124 + * Build an MTF for a given type, which must have all references erased to Object.
25.125 + * This MTF will stand for that type and all un-erased variations.
25.126 + * Eagerly compute some basic properties of the type, common to all variations.
25.127 + */
25.128 + protected MethodTypeForm(MethodType erasedType) {
25.129 + this.erasedType = erasedType;
25.130 +
25.131 + Class<?>[] ptypes = erasedType.ptypes();
25.132 + int ptypeCount = ptypes.length;
25.133 + int pslotCount = ptypeCount; // temp. estimate
25.134 + int rtypeCount = 1; // temp. estimate
25.135 + int rslotCount = 1; // temp. estimate
25.136 +
25.137 + int[] argToSlotTab = null, slotToArgTab = null;
25.138 +
25.139 + // Walk the argument types, looking for primitives.
25.140 + int pac = 0, lac = 0, prc = 0, lrc = 0;
25.141 + Class<?>[] epts = ptypes;
25.142 + Class<?>[] bpts = epts;
25.143 + for (int i = 0; i < epts.length; i++) {
25.144 + Class<?> pt = epts[i];
25.145 + if (pt != Object.class) {
25.146 + ++pac;
25.147 + Wrapper w = Wrapper.forPrimitiveType(pt);
25.148 + if (w.isDoubleWord()) ++lac;
25.149 + if (w.isSubwordOrInt() && pt != int.class) {
25.150 + if (bpts == epts)
25.151 + bpts = bpts.clone();
25.152 + bpts[i] = int.class;
25.153 + }
25.154 + }
25.155 + }
25.156 + pslotCount += lac; // #slots = #args + #longs
25.157 + Class<?> rt = erasedType.returnType();
25.158 + Class<?> bt = rt;
25.159 + if (rt != Object.class) {
25.160 + ++prc; // even void.class counts as a prim here
25.161 + Wrapper w = Wrapper.forPrimitiveType(rt);
25.162 + if (w.isDoubleWord()) ++lrc;
25.163 + if (w.isSubwordOrInt() && rt != int.class)
25.164 + bt = int.class;
25.165 + // adjust #slots, #args
25.166 + if (rt == void.class)
25.167 + rtypeCount = rslotCount = 0;
25.168 + else
25.169 + rslotCount += lrc;
25.170 + }
25.171 + if (epts == bpts && bt == rt) {
25.172 + this.basicType = erasedType;
25.173 + } else {
25.174 + this.basicType = MethodType.makeImpl(bt, bpts, true);
25.175 + }
25.176 + if (lac != 0) {
25.177 + int slot = ptypeCount + lac;
25.178 + slotToArgTab = new int[slot+1];
25.179 + argToSlotTab = new int[1+ptypeCount];
25.180 + argToSlotTab[0] = slot; // argument "-1" is past end of slots
25.181 + for (int i = 0; i < epts.length; i++) {
25.182 + Class<?> pt = epts[i];
25.183 + Wrapper w = Wrapper.forBasicType(pt);
25.184 + if (w.isDoubleWord()) --slot;
25.185 + --slot;
25.186 + slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
25.187 + argToSlotTab[1+i] = slot;
25.188 + }
25.189 + assert(slot == 0); // filled the table
25.190 + }
25.191 + this.primCounts = pack(lrc, prc, lac, pac);
25.192 + this.argCounts = pack(rslotCount, rtypeCount, pslotCount, ptypeCount);
25.193 + if (slotToArgTab == null) {
25.194 + int slot = ptypeCount; // first arg is deepest in stack
25.195 + slotToArgTab = new int[slot+1];
25.196 + argToSlotTab = new int[1+ptypeCount];
25.197 + argToSlotTab[0] = slot; // argument "-1" is past end of slots
25.198 + for (int i = 0; i < ptypeCount; i++) {
25.199 + --slot;
25.200 + slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
25.201 + argToSlotTab[1+i] = slot;
25.202 + }
25.203 + }
25.204 + this.argToSlotTable = argToSlotTab;
25.205 + this.slotToArgTable = slotToArgTab;
25.206 +
25.207 + if (pslotCount >= 256) throw newIllegalArgumentException("too many arguments");
25.208 +
25.209 + // send a few bits down to the JVM:
25.210 + this.vmslots = parameterSlotCount();
25.211 +
25.212 + if (basicType == erasedType) {
25.213 + lambdaForms = new LambdaForm[LF_LIMIT];
25.214 + } else {
25.215 + lambdaForms = null; // could be basicType.form().lambdaForms;
25.216 + }
25.217 + }
25.218 +
25.219 + private static long pack(int a, int b, int c, int d) {
25.220 + assert(((a|b|c|d) & ~0xFFFF) == 0);
25.221 + long hw = ((a << 16) | b), lw = ((c << 16) | d);
25.222 + return (hw << 32) | lw;
25.223 + }
25.224 + private static char unpack(long packed, int word) { // word==0 => return a, ==3 => return d
25.225 + assert(word <= 3);
25.226 + return (char)(packed >> ((3-word) * 16));
25.227 + }
25.228 +
25.229 + public int parameterCount() { // # outgoing values
25.230 + return unpack(argCounts, 3);
25.231 + }
25.232 + public int parameterSlotCount() { // # outgoing interpreter slots
25.233 + return unpack(argCounts, 2);
25.234 + }
25.235 + public int returnCount() { // = 0 (V), or 1
25.236 + return unpack(argCounts, 1);
25.237 + }
25.238 + public int returnSlotCount() { // = 0 (V), 2 (J/D), or 1
25.239 + return unpack(argCounts, 0);
25.240 + }
25.241 + public int primitiveParameterCount() {
25.242 + return unpack(primCounts, 3);
25.243 + }
25.244 + public int longPrimitiveParameterCount() {
25.245 + return unpack(primCounts, 2);
25.246 + }
25.247 + public int primitiveReturnCount() { // = 0 (obj), or 1
25.248 + return unpack(primCounts, 1);
25.249 + }
25.250 + public int longPrimitiveReturnCount() { // = 1 (J/D), or 0
25.251 + return unpack(primCounts, 0);
25.252 + }
25.253 + public boolean hasPrimitives() {
25.254 + return primCounts != 0;
25.255 + }
25.256 + public boolean hasNonVoidPrimitives() {
25.257 + if (primCounts == 0) return false;
25.258 + if (primitiveParameterCount() != 0) return true;
25.259 + return (primitiveReturnCount() != 0 && returnCount() != 0);
25.260 + }
25.261 + public boolean hasLongPrimitives() {
25.262 + return (longPrimitiveParameterCount() | longPrimitiveReturnCount()) != 0;
25.263 + }
25.264 + public int parameterToArgSlot(int i) {
25.265 + return argToSlotTable[1+i];
25.266 + }
25.267 + public int argSlotToParameter(int argSlot) {
25.268 + // Note: Empty slots are represented by zero in this table.
25.269 + // Valid arguments slots contain incremented entries, so as to be non-zero.
25.270 + // We return -1 the caller to mean an empty slot.
25.271 + return slotToArgTable[argSlot] - 1;
25.272 + }
25.273 +
25.274 + static MethodTypeForm findForm(MethodType mt) {
25.275 + MethodType erased = canonicalize(mt, ERASE, ERASE);
25.276 + if (erased == null) {
25.277 + // It is already erased. Make a new MethodTypeForm.
25.278 + return new MethodTypeForm(mt);
25.279 + } else {
25.280 + // Share the MethodTypeForm with the erased version.
25.281 + return erased.form();
25.282 + }
25.283 + }
25.284 +
25.285 + /** Codes for {@link #canonicalize(java.lang.Class, int)}.
25.286 + * ERASE means change every reference to {@code Object}.
25.287 + * WRAP means convert primitives (including {@code void} to their
25.288 + * corresponding wrapper types. UNWRAP means the reverse of WRAP.
25.289 + * INTS means convert all non-void primitive types to int or long,
25.290 + * according to size. LONGS means convert all non-void primitives
25.291 + * to long, regardless of size. RAW_RETURN means convert a type
25.292 + * (assumed to be a return type) to int if it is smaller than an int,
25.293 + * or if it is void.
25.294 + */
25.295 + public static final int NO_CHANGE = 0, ERASE = 1, WRAP = 2, UNWRAP = 3, INTS = 4, LONGS = 5, RAW_RETURN = 6;
25.296 +
25.297 + /** Canonicalize the types in the given method type.
25.298 + * If any types change, intern the new type, and return it.
25.299 + * Otherwise return null.
25.300 + */
25.301 + public static MethodType canonicalize(MethodType mt, int howRet, int howArgs) {
25.302 + Class<?>[] ptypes = mt.ptypes();
25.303 + Class<?>[] ptc = MethodTypeForm.canonicalizes(ptypes, howArgs);
25.304 + Class<?> rtype = mt.returnType();
25.305 + Class<?> rtc = MethodTypeForm.canonicalize(rtype, howRet);
25.306 + if (ptc == null && rtc == null) {
25.307 + // It is already canonical.
25.308 + return null;
25.309 + }
25.310 + // Find the erased version of the method type:
25.311 + if (rtc == null) rtc = rtype;
25.312 + if (ptc == null) ptc = ptypes;
25.313 + return MethodType.makeImpl(rtc, ptc, true);
25.314 + }
25.315 +
25.316 + /** Canonicalize the given return or param type.
25.317 + * Return null if the type is already canonicalized.
25.318 + */
25.319 + static Class<?> canonicalize(Class<?> t, int how) {
25.320 + Class<?> ct;
25.321 + if (t == Object.class) {
25.322 + // no change, ever
25.323 + } else if (!t.isPrimitive()) {
25.324 + switch (how) {
25.325 + case UNWRAP:
25.326 + ct = Wrapper.asPrimitiveType(t);
25.327 + if (ct != t) return ct;
25.328 + break;
25.329 + case RAW_RETURN:
25.330 + case ERASE:
25.331 + return Object.class;
25.332 + }
25.333 + } else if (t == void.class) {
25.334 + // no change, usually
25.335 + switch (how) {
25.336 + case RAW_RETURN:
25.337 + return int.class;
25.338 + case WRAP:
25.339 + return Void.class;
25.340 + }
25.341 + } else {
25.342 + // non-void primitive
25.343 + switch (how) {
25.344 + case WRAP:
25.345 + return Wrapper.asWrapperType(t);
25.346 + case INTS:
25.347 + if (t == int.class || t == long.class)
25.348 + return null; // no change
25.349 + if (t == double.class)
25.350 + return long.class;
25.351 + return int.class;
25.352 + case LONGS:
25.353 + if (t == long.class)
25.354 + return null; // no change
25.355 + return long.class;
25.356 + case RAW_RETURN:
25.357 + if (t == int.class || t == long.class ||
25.358 + t == float.class || t == double.class)
25.359 + return null; // no change
25.360 + // everything else returns as an int
25.361 + return int.class;
25.362 + }
25.363 + }
25.364 + // no change; return null to signify
25.365 + return null;
25.366 + }
25.367 +
25.368 + /** Canonicalize each param type in the given array.
25.369 + * Return null if all types are already canonicalized.
25.370 + */
25.371 + static Class<?>[] canonicalizes(Class<?>[] ts, int how) {
25.372 + Class<?>[] cs = null;
25.373 + for (int imax = ts.length, i = 0; i < imax; i++) {
25.374 + Class<?> c = canonicalize(ts[i], how);
25.375 + if (c == void.class)
25.376 + c = null; // a Void parameter was unwrapped to void; ignore
25.377 + if (c != null) {
25.378 + if (cs == null)
25.379 + cs = ts.clone();
25.380 + cs[i] = c;
25.381 + }
25.382 + }
25.383 + return cs;
25.384 + }
25.385 +
25.386 + @Override
25.387 + public String toString() {
25.388 + return "Form"+erasedType;
25.389 + }
25.390 +
25.391 +}
26.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
26.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/MutableCallSite.java Sat Aug 09 11:12:05 2014 +0200
26.3 @@ -0,0 +1,283 @@
26.4 +/*
26.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
26.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
26.7 + *
26.8 + * This code is free software; you can redistribute it and/or modify it
26.9 + * under the terms of the GNU General Public License version 2 only, as
26.10 + * published by the Free Software Foundation. Oracle designates this
26.11 + * particular file as subject to the "Classpath" exception as provided
26.12 + * by Oracle in the LICENSE file that accompanied this code.
26.13 + *
26.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
26.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
26.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26.17 + * version 2 for more details (a copy is included in the LICENSE file that
26.18 + * accompanied this code).
26.19 + *
26.20 + * You should have received a copy of the GNU General Public License version
26.21 + * 2 along with this work; if not, write to the Free Software Foundation,
26.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26.23 + *
26.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
26.25 + * or visit www.oracle.com if you need additional information or have any
26.26 + * questions.
26.27 + */
26.28 +
26.29 +package java.lang.invoke;
26.30 +
26.31 +import java.util.concurrent.atomic.AtomicInteger;
26.32 +
26.33 +/**
26.34 + * A {@code MutableCallSite} is a {@link CallSite} whose target variable
26.35 + * behaves like an ordinary field.
26.36 + * An {@code invokedynamic} instruction linked to a {@code MutableCallSite} delegates
26.37 + * all calls to the site's current target.
26.38 + * The {@linkplain CallSite#dynamicInvoker dynamic invoker} of a mutable call site
26.39 + * also delegates each call to the site's current target.
26.40 + * <p>
26.41 + * Here is an example of a mutable call site which introduces a
26.42 + * state variable into a method handle chain.
26.43 + * <!-- JavaDocExamplesTest.testMutableCallSite -->
26.44 + * <blockquote><pre>{@code
26.45 +MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class));
26.46 +MethodHandle MH_name = name.dynamicInvoker();
26.47 +MethodType MT_str1 = MethodType.methodType(String.class);
26.48 +MethodHandle MH_upcase = MethodHandles.lookup()
26.49 + .findVirtual(String.class, "toUpperCase", MT_str1);
26.50 +MethodHandle worker1 = MethodHandles.filterReturnValue(MH_name, MH_upcase);
26.51 +name.setTarget(MethodHandles.constant(String.class, "Rocky"));
26.52 +assertEquals("ROCKY", (String) worker1.invokeExact());
26.53 +name.setTarget(MethodHandles.constant(String.class, "Fred"));
26.54 +assertEquals("FRED", (String) worker1.invokeExact());
26.55 +// (mutation can be continued indefinitely)
26.56 + * }</pre></blockquote>
26.57 + * <p>
26.58 + * The same call site may be used in several places at once.
26.59 + * <blockquote><pre>{@code
26.60 +MethodType MT_str2 = MethodType.methodType(String.class, String.class);
26.61 +MethodHandle MH_cat = lookup().findVirtual(String.class,
26.62 + "concat", methodType(String.class, String.class));
26.63 +MethodHandle MH_dear = MethodHandles.insertArguments(MH_cat, 1, ", dear?");
26.64 +MethodHandle worker2 = MethodHandles.filterReturnValue(MH_name, MH_dear);
26.65 +assertEquals("Fred, dear?", (String) worker2.invokeExact());
26.66 +name.setTarget(MethodHandles.constant(String.class, "Wilma"));
26.67 +assertEquals("WILMA", (String) worker1.invokeExact());
26.68 +assertEquals("Wilma, dear?", (String) worker2.invokeExact());
26.69 + * }</pre></blockquote>
26.70 + * <p>
26.71 + * <em>Non-synchronization of target values:</em>
26.72 + * A write to a mutable call site's target does not force other threads
26.73 + * to become aware of the updated value. Threads which do not perform
26.74 + * suitable synchronization actions relative to the updated call site
26.75 + * may cache the old target value and delay their use of the new target
26.76 + * value indefinitely.
26.77 + * (This is a normal consequence of the Java Memory Model as applied
26.78 + * to object fields.)
26.79 + * <p>
26.80 + * The {@link #syncAll syncAll} operation provides a way to force threads
26.81 + * to accept a new target value, even if there is no other synchronization.
26.82 + * <p>
26.83 + * For target values which will be frequently updated, consider using
26.84 + * a {@linkplain VolatileCallSite volatile call site} instead.
26.85 + * @author John Rose, JSR 292 EG
26.86 + */
26.87 +public class MutableCallSite extends CallSite {
26.88 + /**
26.89 + * Creates a blank call site object with the given method type.
26.90 + * The initial target is set to a method handle of the given type
26.91 + * which will throw an {@link IllegalStateException} if called.
26.92 + * <p>
26.93 + * The type of the call site is permanently set to the given type.
26.94 + * <p>
26.95 + * Before this {@code CallSite} object is returned from a bootstrap method,
26.96 + * or invoked in some other manner,
26.97 + * it is usually provided with a more useful target method,
26.98 + * via a call to {@link CallSite#setTarget(MethodHandle) setTarget}.
26.99 + * @param type the method type that this call site will have
26.100 + * @throws NullPointerException if the proposed type is null
26.101 + */
26.102 + public MutableCallSite(MethodType type) {
26.103 + super(type);
26.104 + }
26.105 +
26.106 + /**
26.107 + * Creates a call site object with an initial target method handle.
26.108 + * The type of the call site is permanently set to the initial target's type.
26.109 + * @param target the method handle that will be the initial target of the call site
26.110 + * @throws NullPointerException if the proposed target is null
26.111 + */
26.112 + public MutableCallSite(MethodHandle target) {
26.113 + super(target);
26.114 + }
26.115 +
26.116 + /**
26.117 + * Returns the target method of the call site, which behaves
26.118 + * like a normal field of the {@code MutableCallSite}.
26.119 + * <p>
26.120 + * The interactions of {@code getTarget} with memory are the same
26.121 + * as of a read from an ordinary variable, such as an array element or a
26.122 + * non-volatile, non-final field.
26.123 + * <p>
26.124 + * In particular, the current thread may choose to reuse the result
26.125 + * of a previous read of the target from memory, and may fail to see
26.126 + * a recent update to the target by another thread.
26.127 + *
26.128 + * @return the linkage state of this call site, a method handle which can change over time
26.129 + * @see #setTarget
26.130 + */
26.131 + @Override public final MethodHandle getTarget() {
26.132 + return target;
26.133 + }
26.134 +
26.135 + /**
26.136 + * Updates the target method of this call site, as a normal variable.
26.137 + * The type of the new target must agree with the type of the old target.
26.138 + * <p>
26.139 + * The interactions with memory are the same
26.140 + * as of a write to an ordinary variable, such as an array element or a
26.141 + * non-volatile, non-final field.
26.142 + * <p>
26.143 + * In particular, unrelated threads may fail to see the updated target
26.144 + * until they perform a read from memory.
26.145 + * Stronger guarantees can be created by putting appropriate operations
26.146 + * into the bootstrap method and/or the target methods used
26.147 + * at any given call site.
26.148 + *
26.149 + * @param newTarget the new target
26.150 + * @throws NullPointerException if the proposed new target is null
26.151 + * @throws WrongMethodTypeException if the proposed new target
26.152 + * has a method type that differs from the previous target
26.153 + * @see #getTarget
26.154 + */
26.155 + @Override public void setTarget(MethodHandle newTarget) {
26.156 + checkTargetChange(this.target, newTarget);
26.157 + setTargetNormal(newTarget);
26.158 + }
26.159 +
26.160 + /**
26.161 + * {@inheritDoc}
26.162 + */
26.163 + @Override
26.164 + public final MethodHandle dynamicInvoker() {
26.165 + return makeDynamicInvoker();
26.166 + }
26.167 +
26.168 + /**
26.169 + * Performs a synchronization operation on each call site in the given array,
26.170 + * forcing all other threads to throw away any cached values previously
26.171 + * loaded from the target of any of the call sites.
26.172 + * <p>
26.173 + * This operation does not reverse any calls that have already started
26.174 + * on an old target value.
26.175 + * (Java supports {@linkplain java.lang.Object#wait() forward time travel} only.)
26.176 + * <p>
26.177 + * The overall effect is to force all future readers of each call site's target
26.178 + * to accept the most recently stored value.
26.179 + * ("Most recently" is reckoned relative to the {@code syncAll} itself.)
26.180 + * Conversely, the {@code syncAll} call may block until all readers have
26.181 + * (somehow) decached all previous versions of each call site's target.
26.182 + * <p>
26.183 + * To avoid race conditions, calls to {@code setTarget} and {@code syncAll}
26.184 + * should generally be performed under some sort of mutual exclusion.
26.185 + * Note that reader threads may observe an updated target as early
26.186 + * as the {@code setTarget} call that install the value
26.187 + * (and before the {@code syncAll} that confirms the value).
26.188 + * On the other hand, reader threads may observe previous versions of
26.189 + * the target until the {@code syncAll} call returns
26.190 + * (and after the {@code setTarget} that attempts to convey the updated version).
26.191 + * <p>
26.192 + * This operation is likely to be expensive and should be used sparingly.
26.193 + * If possible, it should be buffered for batch processing on sets of call sites.
26.194 + * <p>
26.195 + * If {@code sites} contains a null element,
26.196 + * a {@code NullPointerException} will be raised.
26.197 + * In this case, some non-null elements in the array may be
26.198 + * processed before the method returns abnormally.
26.199 + * Which elements these are (if any) is implementation-dependent.
26.200 + *
26.201 + * <h1>Java Memory Model details</h1>
26.202 + * In terms of the Java Memory Model, this operation performs a synchronization
26.203 + * action which is comparable in effect to the writing of a volatile variable
26.204 + * by the current thread, and an eventual volatile read by every other thread
26.205 + * that may access one of the affected call sites.
26.206 + * <p>
26.207 + * The following effects are apparent, for each individual call site {@code S}:
26.208 + * <ul>
26.209 + * <li>A new volatile variable {@code V} is created, and written by the current thread.
26.210 + * As defined by the JMM, this write is a global synchronization event.
26.211 + * <li>As is normal with thread-local ordering of write events,
26.212 + * every action already performed by the current thread is
26.213 + * taken to happen before the volatile write to {@code V}.
26.214 + * (In some implementations, this means that the current thread
26.215 + * performs a global release operation.)
26.216 + * <li>Specifically, the write to the current target of {@code S} is
26.217 + * taken to happen before the volatile write to {@code V}.
26.218 + * <li>The volatile write to {@code V} is placed
26.219 + * (in an implementation specific manner)
26.220 + * in the global synchronization order.
26.221 + * <li>Consider an arbitrary thread {@code T} (other than the current thread).
26.222 + * If {@code T} executes a synchronization action {@code A}
26.223 + * after the volatile write to {@code V} (in the global synchronization order),
26.224 + * it is therefore required to see either the current target
26.225 + * of {@code S}, or a later write to that target,
26.226 + * if it executes a read on the target of {@code S}.
26.227 + * (This constraint is called "synchronization-order consistency".)
26.228 + * <li>The JMM specifically allows optimizing compilers to elide
26.229 + * reads or writes of variables that are known to be useless.
26.230 + * Such elided reads and writes have no effect on the happens-before
26.231 + * relation. Regardless of this fact, the volatile {@code V}
26.232 + * will not be elided, even though its written value is
26.233 + * indeterminate and its read value is not used.
26.234 + * </ul>
26.235 + * Because of the last point, the implementation behaves as if a
26.236 + * volatile read of {@code V} were performed by {@code T}
26.237 + * immediately after its action {@code A}. In the local ordering
26.238 + * of actions in {@code T}, this read happens before any future
26.239 + * read of the target of {@code S}. It is as if the
26.240 + * implementation arbitrarily picked a read of {@code S}'s target
26.241 + * by {@code T}, and forced a read of {@code V} to precede it,
26.242 + * thereby ensuring communication of the new target value.
26.243 + * <p>
26.244 + * As long as the constraints of the Java Memory Model are obeyed,
26.245 + * implementations may delay the completion of a {@code syncAll}
26.246 + * operation while other threads ({@code T} above) continue to
26.247 + * use previous values of {@code S}'s target.
26.248 + * However, implementations are (as always) encouraged to avoid
26.249 + * livelock, and to eventually require all threads to take account
26.250 + * of the updated target.
26.251 + *
26.252 + * <p style="font-size:smaller;">
26.253 + * <em>Discussion:</em>
26.254 + * For performance reasons, {@code syncAll} is not a virtual method
26.255 + * on a single call site, but rather applies to a set of call sites.
26.256 + * Some implementations may incur a large fixed overhead cost
26.257 + * for processing one or more synchronization operations,
26.258 + * but a small incremental cost for each additional call site.
26.259 + * In any case, this operation is likely to be costly, since
26.260 + * other threads may have to be somehow interrupted
26.261 + * in order to make them notice the updated target value.
26.262 + * However, it may be observed that a single call to synchronize
26.263 + * several sites has the same formal effect as many calls,
26.264 + * each on just one of the sites.
26.265 + *
26.266 + * <p style="font-size:smaller;">
26.267 + * <em>Implementation Note:</em>
26.268 + * Simple implementations of {@code MutableCallSite} may use
26.269 + * a volatile variable for the target of a mutable call site.
26.270 + * In such an implementation, the {@code syncAll} method can be a no-op,
26.271 + * and yet it will conform to the JMM behavior documented above.
26.272 + *
26.273 + * @param sites an array of call sites to be synchronized
26.274 + * @throws NullPointerException if the {@code sites} array reference is null
26.275 + * or the array contains a null
26.276 + */
26.277 + public static void syncAll(MutableCallSite[] sites) {
26.278 + if (sites.length == 0) return;
26.279 + STORE_BARRIER.lazySet(0);
26.280 + for (int i = 0; i < sites.length; i++) {
26.281 + sites[i].getClass(); // trigger NPE on first null
26.282 + }
26.283 + // FIXME: NYI
26.284 + }
26.285 + private static final AtomicInteger STORE_BARRIER = new AtomicInteger();
26.286 +}
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
27.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/ProxyClassesDumper.java Sat Aug 09 11:12:05 2014 +0200
27.3 @@ -0,0 +1,147 @@
27.4 +/*
27.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
27.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
27.7 + *
27.8 + * This code is free software; you can redistribute it and/or modify it
27.9 + * under the terms of the GNU General Public License version 2 only, as
27.10 + * published by the Free Software Foundation. Oracle designates this
27.11 + * particular file as subject to the "Classpath" exception as provided
27.12 + * by Oracle in the LICENSE file that accompanied this code.
27.13 + *
27.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
27.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
27.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27.17 + * version 2 for more details (a copy is included in the LICENSE file that
27.18 + * accompanied this code).
27.19 + *
27.20 + * You should have received a copy of the GNU General Public License version
27.21 + * 2 along with this work; if not, write to the Free Software Foundation,
27.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27.23 + *
27.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
27.25 + * or visit www.oracle.com if you need additional information or have any
27.26 + * questions.
27.27 + */
27.28 +package java.lang.invoke;
27.29 +
27.30 +import sun.util.logging.PlatformLogger;
27.31 +
27.32 +import java.io.FilePermission;
27.33 +import java.nio.file.Files;
27.34 +import java.nio.file.InvalidPathException;
27.35 +import java.nio.file.Path;
27.36 +import java.nio.file.Paths;
27.37 +import java.security.AccessController;
27.38 +import java.security.PrivilegedAction;
27.39 +import java.util.Objects;
27.40 +import java.util.concurrent.atomic.AtomicBoolean;
27.41 +
27.42 +/**
27.43 + * Helper class used by InnerClassLambdaMetafactory to log generated classes
27.44 + *
27.45 + * @implNote
27.46 + * <p> Because this class is called by LambdaMetafactory, make use
27.47 + * of lambda lead to recursive calls cause stack overflow.
27.48 + */
27.49 +final class ProxyClassesDumper {
27.50 + private static final char[] HEX = {
27.51 + '0', '1', '2', '3', '4', '5', '6', '7',
27.52 + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
27.53 + };
27.54 + private static final char[] BAD_CHARS = {
27.55 + '\\', ':', '*', '?', '"', '<', '>', '|'
27.56 + };
27.57 + private static final String[] REPLACEMENT = {
27.58 + "%5C", "%3A", "%2A", "%3F", "%22", "%3C", "%3E", "%7C"
27.59 + };
27.60 +
27.61 + private final Path dumpDir;
27.62 +
27.63 + public static ProxyClassesDumper getInstance(String path) {
27.64 + if (null == path) {
27.65 + return null;
27.66 + }
27.67 + try {
27.68 + path = path.trim();
27.69 + final Path dir = Paths.get(path.length() == 0 ? "." : path);
27.70 + AccessController.doPrivileged(new PrivilegedAction<Void>() {
27.71 + @Override
27.72 + public Void run() {
27.73 + validateDumpDir(dir);
27.74 + return null;
27.75 + }
27.76 + }, null, new FilePermission("<<ALL FILES>>", "read, write"));
27.77 + return new ProxyClassesDumper(dir);
27.78 + } catch (InvalidPathException ex) {
27.79 + PlatformLogger.getLogger(ProxyClassesDumper.class.getName())
27.80 + .warning("Path " + path + " is not valid - dumping disabled", ex);
27.81 + } catch (IllegalArgumentException iae) {
27.82 + PlatformLogger.getLogger(ProxyClassesDumper.class.getName())
27.83 + .warning(iae.getMessage() + " - dumping disabled");
27.84 + }
27.85 + return null;
27.86 + }
27.87 +
27.88 + private ProxyClassesDumper(Path path) {
27.89 + dumpDir = Objects.requireNonNull(path);
27.90 + }
27.91 +
27.92 + private static void validateDumpDir(Path path) {
27.93 + if (!Files.exists(path)) {
27.94 + throw new IllegalArgumentException("Directory " + path + " does not exist");
27.95 + } else if (!Files.isDirectory(path)) {
27.96 + throw new IllegalArgumentException("Path " + path + " is not a directory");
27.97 + } else if (!Files.isWritable(path)) {
27.98 + throw new IllegalArgumentException("Directory " + path + " is not writable");
27.99 + }
27.100 + }
27.101 +
27.102 + public static String encodeForFilename(String className) {
27.103 + final int len = className.length();
27.104 + StringBuilder sb = new StringBuilder(len);
27.105 +
27.106 + for (int i = 0; i < len; i++) {
27.107 + char c = className.charAt(i);
27.108 + // control characters
27.109 + if (c <= 31) {
27.110 + sb.append('%');
27.111 + sb.append(HEX[c >> 4 & 0x0F]);
27.112 + sb.append(HEX[c & 0x0F]);
27.113 + } else {
27.114 + int j = 0;
27.115 + for (; j < BAD_CHARS.length; j++) {
27.116 + if (c == BAD_CHARS[j]) {
27.117 + sb.append(REPLACEMENT[j]);
27.118 + break;
27.119 + }
27.120 + }
27.121 + if (j >= BAD_CHARS.length) {
27.122 + sb.append(c);
27.123 + }
27.124 + }
27.125 + }
27.126 +
27.127 + return sb.toString();
27.128 + }
27.129 +
27.130 + public void dumpClass(String className, final byte[] classBytes) {
27.131 + Path file;
27.132 + try {
27.133 + file = dumpDir.resolve(encodeForFilename(className) + ".class");
27.134 + } catch (InvalidPathException ex) {
27.135 + PlatformLogger.getLogger(ProxyClassesDumper.class.getName())
27.136 + .warning("Invalid path for class " + className);
27.137 + return;
27.138 + }
27.139 +
27.140 + try {
27.141 + Path dir = file.getParent();
27.142 + Files.createDirectories(dir);
27.143 + Files.write(file, classBytes);
27.144 + } catch (Exception ignore) {
27.145 + PlatformLogger.getLogger(ProxyClassesDumper.class.getName())
27.146 + .warning("Exception writing to path at " + file.toString());
27.147 + // simply don't care if this operation failed
27.148 + }
27.149 + }
27.150 +}
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
28.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/SerializedLambda.java Sat Aug 09 11:12:05 2014 +0200
28.3 @@ -0,0 +1,258 @@
28.4 +/*
28.5 + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
28.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
28.7 + *
28.8 + * This code is free software; you can redistribute it and/or modify it
28.9 + * under the terms of the GNU General Public License version 2 only, as
28.10 + * published by the Free Software Foundation. Oracle designates this
28.11 + * particular file as subject to the "Classpath" exception as provided
28.12 + * by Oracle in the LICENSE file that accompanied this code.
28.13 + *
28.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
28.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
28.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
28.17 + * version 2 for more details (a copy is included in the LICENSE file that
28.18 + * accompanied this code).
28.19 + *
28.20 + * You should have received a copy of the GNU General Public License version
28.21 + * 2 along with this work; if not, write to the Free Software Foundation,
28.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
28.23 + *
28.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
28.25 + * or visit www.oracle.com if you need additional information or have any
28.26 + * questions.
28.27 + */
28.28 +package java.lang.invoke;
28.29 +
28.30 +import java.io.Serializable;
28.31 +import java.lang.reflect.Method;
28.32 +import java.security.AccessController;
28.33 +import java.security.PrivilegedActionException;
28.34 +import java.security.PrivilegedExceptionAction;
28.35 +import java.util.Objects;
28.36 +
28.37 +/**
28.38 + * Serialized form of a lambda expression. The properties of this class
28.39 + * represent the information that is present at the lambda factory site, including
28.40 + * static metafactory arguments such as the identity of the primary functional
28.41 + * interface method and the identity of the implementation method, as well as
28.42 + * dynamic metafactory arguments such as values captured from the lexical scope
28.43 + * at the time of lambda capture.
28.44 + *
28.45 + * <p>Implementors of serializable lambdas, such as compilers or language
28.46 + * runtime libraries, are expected to ensure that instances deserialize properly.
28.47 + * One means to do so is to ensure that the {@code writeReplace} method returns
28.48 + * an instance of {@code SerializedLambda}, rather than allowing default
28.49 + * serialization to proceed.
28.50 + *
28.51 + * <p>{@code SerializedLambda} has a {@code readResolve} method that looks for
28.52 + * a (possibly private) static method called
28.53 + * {@code $deserializeLambda$(SerializedLambda)} in the capturing class, invokes
28.54 + * that with itself as the first argument, and returns the result. Lambda classes
28.55 + * implementing {@code $deserializeLambda$} are responsible for validating
28.56 + * that the properties of the {@code SerializedLambda} are consistent with a
28.57 + * lambda actually captured by that class.
28.58 + *
28.59 + * @see LambdaMetafactory
28.60 + */
28.61 +public final class SerializedLambda implements Serializable {
28.62 + private static final long serialVersionUID = 8025925345765570181L;
28.63 + private final Class<?> capturingClass;
28.64 + private final String functionalInterfaceClass;
28.65 + private final String functionalInterfaceMethodName;
28.66 + private final String functionalInterfaceMethodSignature;
28.67 + private final String implClass;
28.68 + private final String implMethodName;
28.69 + private final String implMethodSignature;
28.70 + private final int implMethodKind;
28.71 + private final String instantiatedMethodType;
28.72 + private final Object[] capturedArgs;
28.73 +
28.74 + /**
28.75 + * Create a {@code SerializedLambda} from the low-level information present
28.76 + * at the lambda factory site.
28.77 + *
28.78 + * @param capturingClass The class in which the lambda expression appears
28.79 + * @param functionalInterfaceClass Name, in slash-delimited form, of static
28.80 + * type of the returned lambda object
28.81 + * @param functionalInterfaceMethodName Name of the functional interface
28.82 + * method for the present at the
28.83 + * lambda factory site
28.84 + * @param functionalInterfaceMethodSignature Signature of the functional
28.85 + * interface method present at
28.86 + * the lambda factory site
28.87 + * @param implMethodKind Method handle kind for the implementation method
28.88 + * @param implClass Name, in slash-delimited form, for the class holding
28.89 + * the implementation method
28.90 + * @param implMethodName Name of the implementation method
28.91 + * @param implMethodSignature Signature of the implementation method
28.92 + * @param instantiatedMethodType The signature of the primary functional
28.93 + * interface method after type variables
28.94 + * are substituted with their instantiation
28.95 + * from the capture site
28.96 + * @param capturedArgs The dynamic arguments to the lambda factory site,
28.97 + * which represent variables captured by
28.98 + * the lambda
28.99 + */
28.100 + public SerializedLambda(Class<?> capturingClass,
28.101 + String functionalInterfaceClass,
28.102 + String functionalInterfaceMethodName,
28.103 + String functionalInterfaceMethodSignature,
28.104 + int implMethodKind,
28.105 + String implClass,
28.106 + String implMethodName,
28.107 + String implMethodSignature,
28.108 + String instantiatedMethodType,
28.109 + Object[] capturedArgs) {
28.110 + this.capturingClass = capturingClass;
28.111 + this.functionalInterfaceClass = functionalInterfaceClass;
28.112 + this.functionalInterfaceMethodName = functionalInterfaceMethodName;
28.113 + this.functionalInterfaceMethodSignature = functionalInterfaceMethodSignature;
28.114 + this.implMethodKind = implMethodKind;
28.115 + this.implClass = implClass;
28.116 + this.implMethodName = implMethodName;
28.117 + this.implMethodSignature = implMethodSignature;
28.118 + this.instantiatedMethodType = instantiatedMethodType;
28.119 + this.capturedArgs = Objects.requireNonNull(capturedArgs).clone();
28.120 + }
28.121 +
28.122 + /**
28.123 + * Get the name of the class that captured this lambda.
28.124 + * @return the name of the class that captured this lambda
28.125 + */
28.126 + public String getCapturingClass() {
28.127 + return capturingClass.getName().replace('.', '/');
28.128 + }
28.129 +
28.130 + /**
28.131 + * Get the name of the invoked type to which this
28.132 + * lambda has been converted
28.133 + * @return the name of the functional interface class to which
28.134 + * this lambda has been converted
28.135 + */
28.136 + public String getFunctionalInterfaceClass() {
28.137 + return functionalInterfaceClass;
28.138 + }
28.139 +
28.140 + /**
28.141 + * Get the name of the primary method for the functional interface
28.142 + * to which this lambda has been converted.
28.143 + * @return the name of the primary methods of the functional interface
28.144 + */
28.145 + public String getFunctionalInterfaceMethodName() {
28.146 + return functionalInterfaceMethodName;
28.147 + }
28.148 +
28.149 + /**
28.150 + * Get the signature of the primary method for the functional
28.151 + * interface to which this lambda has been converted.
28.152 + * @return the signature of the primary method of the functional
28.153 + * interface
28.154 + */
28.155 + public String getFunctionalInterfaceMethodSignature() {
28.156 + return functionalInterfaceMethodSignature;
28.157 + }
28.158 +
28.159 + /**
28.160 + * Get the name of the class containing the implementation
28.161 + * method.
28.162 + * @return the name of the class containing the implementation
28.163 + * method
28.164 + */
28.165 + public String getImplClass() {
28.166 + return implClass;
28.167 + }
28.168 +
28.169 + /**
28.170 + * Get the name of the implementation method.
28.171 + * @return the name of the implementation method
28.172 + */
28.173 + public String getImplMethodName() {
28.174 + return implMethodName;
28.175 + }
28.176 +
28.177 + /**
28.178 + * Get the signature of the implementation method.
28.179 + * @return the signature of the implementation method
28.180 + */
28.181 + public String getImplMethodSignature() {
28.182 + return implMethodSignature;
28.183 + }
28.184 +
28.185 + /**
28.186 + * Get the method handle kind (see {@link MethodHandleInfo}) of
28.187 + * the implementation method.
28.188 + * @return the method handle kind of the implementation method
28.189 + */
28.190 + public int getImplMethodKind() {
28.191 + return implMethodKind;
28.192 + }
28.193 +
28.194 + /**
28.195 + * Get the signature of the primary functional interface method
28.196 + * after type variables are substituted with their instantiation
28.197 + * from the capture site.
28.198 + * @return the signature of the primary functional interface method
28.199 + * after type variable processing
28.200 + */
28.201 + public final String getInstantiatedMethodType() {
28.202 + return instantiatedMethodType;
28.203 + }
28.204 +
28.205 + /**
28.206 + * Get the count of dynamic arguments to the lambda capture site.
28.207 + * @return the count of dynamic arguments to the lambda capture site
28.208 + */
28.209 + public int getCapturedArgCount() {
28.210 + return capturedArgs.length;
28.211 + }
28.212 +
28.213 + /**
28.214 + * Get a dynamic argument to the lambda capture site.
28.215 + * @param i the argument to capture
28.216 + * @return a dynamic argument to the lambda capture site
28.217 + */
28.218 + public Object getCapturedArg(int i) {
28.219 + return capturedArgs[i];
28.220 + }
28.221 +
28.222 + private Object readResolve() throws ReflectiveOperationException {
28.223 + try {
28.224 + Method deserialize = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
28.225 + @Override
28.226 + public Method run() throws Exception {
28.227 + Method m = capturingClass.getDeclaredMethod("$deserializeLambda$", SerializedLambda.class);
28.228 + m.setAccessible(true);
28.229 + return m;
28.230 + }
28.231 + });
28.232 +
28.233 + return deserialize.invoke(null, this);
28.234 + }
28.235 + catch (PrivilegedActionException e) {
28.236 + Exception cause = e.getException();
28.237 + if (cause instanceof ReflectiveOperationException)
28.238 + throw (ReflectiveOperationException) cause;
28.239 + else if (cause instanceof RuntimeException)
28.240 + throw (RuntimeException) cause;
28.241 + else
28.242 + throw new RuntimeException("Exception in SerializedLambda.readResolve", e);
28.243 + }
28.244 + }
28.245 +
28.246 + @Override
28.247 + public String toString() {
28.248 + String implKind=MethodHandleInfo.referenceKindToString(implMethodKind);
28.249 + return String.format("SerializedLambda[%s=%s, %s=%s.%s:%s, " +
28.250 + "%s=%s %s.%s:%s, %s=%s, %s=%d]",
28.251 + "capturingClass", capturingClass,
28.252 + "functionalInterfaceMethod", functionalInterfaceClass,
28.253 + functionalInterfaceMethodName,
28.254 + functionalInterfaceMethodSignature,
28.255 + "implementation",
28.256 + implKind,
28.257 + implClass, implMethodName, implMethodSignature,
28.258 + "instantiatedMethodType", instantiatedMethodType,
28.259 + "numCaptured", capturedArgs.length);
28.260 + }
28.261 +}
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
29.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/SimpleMethodHandle.java Sat Aug 09 11:12:05 2014 +0200
29.3 @@ -0,0 +1,70 @@
29.4 +/*
29.5 + * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
29.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
29.7 + *
29.8 + * This code is free software; you can redistribute it and/or modify it
29.9 + * under the terms of the GNU General Public License version 2 only, as
29.10 + * published by the Free Software Foundation. Oracle designates this
29.11 + * particular file as subject to the "Classpath" exception as provided
29.12 + * by Oracle in the LICENSE file that accompanied this code.
29.13 + *
29.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
29.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
29.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
29.17 + * version 2 for more details (a copy is included in the LICENSE file that
29.18 + * accompanied this code).
29.19 + *
29.20 + * You should have received a copy of the GNU General Public License version
29.21 + * 2 along with this work; if not, write to the Free Software Foundation,
29.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
29.23 + *
29.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
29.25 + * or visit www.oracle.com if you need additional information or have any
29.26 + * questions.
29.27 + */
29.28 +
29.29 +package java.lang.invoke;
29.30 +
29.31 +import static java.lang.invoke.LambdaForm.*;
29.32 +import static java.lang.invoke.MethodHandleNatives.Constants.*;
29.33 +import java.util.logging.Level;
29.34 +import java.util.logging.Logger;
29.35 +
29.36 +/**
29.37 + * A method handle whose behavior is determined only by its LambdaForm.
29.38 + * @author jrose
29.39 + */
29.40 +final class SimpleMethodHandle extends MethodHandle {
29.41 + private SimpleMethodHandle(MethodType type, LambdaForm form) {
29.42 + super(type, form);
29.43 + }
29.44 +
29.45 + /*non-public*/ static SimpleMethodHandle make(MethodType type, LambdaForm form) {
29.46 + return new SimpleMethodHandle(type, form);
29.47 + }
29.48 +
29.49 + @Override
29.50 + MethodHandle bindArgument(int pos, char basicType, Object value) {
29.51 + MethodType type2 = type().dropParameterTypes(pos, pos+1);
29.52 + LambdaForm form2 = internalForm().bind(1+pos, BoundMethodHandle.SpeciesData.EMPTY);
29.53 + return BoundMethodHandle.bindSingle(type2, form2, basicType, value);
29.54 + }
29.55 +
29.56 + @Override
29.57 + MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
29.58 + LambdaForm newForm = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos+drops));
29.59 + return new SimpleMethodHandle(srcType, newForm);
29.60 + }
29.61 +
29.62 + @Override
29.63 + MethodHandle permuteArguments(MethodType newType, int[] reorder) {
29.64 + LambdaForm form2 = internalForm().permuteArguments(1, reorder, basicTypes(newType.parameterList()));
29.65 + return new SimpleMethodHandle(newType, form2);
29.66 + }
29.67 +
29.68 + @Override
29.69 + MethodHandle copyWith(MethodType mt, LambdaForm lf) {
29.70 + return new SimpleMethodHandle(mt, lf);
29.71 + }
29.72 +
29.73 +}
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
30.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/Stable.java Sat Aug 09 11:12:05 2014 +0200
30.3 @@ -0,0 +1,73 @@
30.4 +/*
30.5 + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
30.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
30.7 + *
30.8 + * This code is free software; you can redistribute it and/or modify it
30.9 + * under the terms of the GNU General Public License version 2 only, as
30.10 + * published by the Free Software Foundation. Oracle designates this
30.11 + * particular file as subject to the "Classpath" exception as provided
30.12 + * by Oracle in the LICENSE file that accompanied this code.
30.13 + *
30.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
30.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
30.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
30.17 + * version 2 for more details (a copy is included in the LICENSE file that
30.18 + * accompanied this code).
30.19 + *
30.20 + * You should have received a copy of the GNU General Public License version
30.21 + * 2 along with this work; if not, write to the Free Software Foundation,
30.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
30.23 + *
30.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
30.25 + * or visit www.oracle.com if you need additional information or have any
30.26 + * questions.
30.27 + */
30.28 +
30.29 +package java.lang.invoke;
30.30 +
30.31 +import java.lang.annotation.*;
30.32 +
30.33 +/**
30.34 + * A field may be annotated as stable if all of its component variables
30.35 + * changes value at most once.
30.36 + * A field's value counts as its component value.
30.37 + * If the field is typed as an array, then all the non-null components
30.38 + * of the array, of depth up to the rank of the field's array type,
30.39 + * also count as component values.
30.40 + * By extension, any variable (either array or field) which has annotated
30.41 + * as stable is called a stable variable, and its non-null or non-zero
30.42 + * value is called a stable value.
30.43 + * <p>
30.44 + * Since all fields begin with a default value of null for references
30.45 + * (resp., zero for primitives), it follows that this annotation indicates
30.46 + * that the first non-null (resp., non-zero) value stored in the field
30.47 + * will never be changed.
30.48 + * <p>
30.49 + * If the field is not of an array type, there are no array elements,
30.50 + * then the value indicated as stable is simply the value of the field.
30.51 + * If the dynamic type of the field value is an array but the static type
30.52 + * is not, the components of the array are <em>not</em> regarded as stable.
30.53 + * <p>
30.54 + * If the field is an array type, then both the field value and
30.55 + * all the components of the field value (if the field value is non-null)
30.56 + * are indicated to be stable.
30.57 + * If the field type is an array type with rank {@code N > 1},
30.58 + * then each component of the field value (if the field value is non-null),
30.59 + * is regarded as a stable array of rank {@code N-1}.
30.60 + * <p>
30.61 + * Fields which are declared {@code final} may also be annotated as stable.
30.62 + * Since final fields already behave as stable values, such an annotation
30.63 + * indicates no additional information, unless the type of the field is
30.64 + * an array type.
30.65 + * <p>
30.66 + * It is (currently) undefined what happens if a field annotated as stable
30.67 + * is given a third value. In practice, if the JVM relies on this annotation
30.68 + * to promote a field reference to a constant, it may be that the Java memory
30.69 + * model would appear to be broken, if such a constant (the second value of the field)
30.70 + * is used as the value of the field even after the field value has changed.
30.71 + */
30.72 +/* package-private */
30.73 +@Target(ElementType.FIELD)
30.74 +@Retention(RetentionPolicy.RUNTIME)
30.75 +@interface Stable {
30.76 +}
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
31.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/SwitchPoint.java Sat Aug 09 11:12:05 2014 +0200
31.3 @@ -0,0 +1,228 @@
31.4 +/*
31.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
31.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
31.7 + *
31.8 + * This code is free software; you can redistribute it and/or modify it
31.9 + * under the terms of the GNU General Public License version 2 only, as
31.10 + * published by the Free Software Foundation. Oracle designates this
31.11 + * particular file as subject to the "Classpath" exception as provided
31.12 + * by Oracle in the LICENSE file that accompanied this code.
31.13 + *
31.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
31.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
31.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
31.17 + * version 2 for more details (a copy is included in the LICENSE file that
31.18 + * accompanied this code).
31.19 + *
31.20 + * You should have received a copy of the GNU General Public License version
31.21 + * 2 along with this work; if not, write to the Free Software Foundation,
31.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
31.23 + *
31.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
31.25 + * or visit www.oracle.com if you need additional information or have any
31.26 + * questions.
31.27 + */
31.28 +
31.29 +package java.lang.invoke;
31.30 +
31.31 +/**
31.32 + * <p>
31.33 + * A {@code SwitchPoint} is an object which can publish state transitions to other threads.
31.34 + * A switch point is initially in the <em>valid</em> state, but may at any time be
31.35 + * changed to the <em>invalid</em> state. Invalidation cannot be reversed.
31.36 + * A switch point can combine a <em>guarded pair</em> of method handles into a
31.37 + * <em>guarded delegator</em>.
31.38 + * The guarded delegator is a method handle which delegates to one of the old method handles.
31.39 + * The state of the switch point determines which of the two gets the delegation.
31.40 + * <p>
31.41 + * A single switch point may be used to control any number of method handles.
31.42 + * (Indirectly, therefore, it can control any number of call sites.)
31.43 + * This is done by using the single switch point as a factory for combining
31.44 + * any number of guarded method handle pairs into guarded delegators.
31.45 + * <p>
31.46 + * When a guarded delegator is created from a guarded pair, the pair
31.47 + * is wrapped in a new method handle {@code M},
31.48 + * which is permanently associated with the switch point that created it.
31.49 + * Each pair consists of a target {@code T} and a fallback {@code F}.
31.50 + * While the switch point is valid, invocations to {@code M} are delegated to {@code T}.
31.51 + * After it is invalidated, invocations are delegated to {@code F}.
31.52 + * <p>
31.53 + * Invalidation is global and immediate, as if the switch point contained a
31.54 + * volatile boolean variable consulted on every call to {@code M}.
31.55 + * The invalidation is also permanent, which means the switch point
31.56 + * can change state only once.
31.57 + * The switch point will always delegate to {@code F} after being invalidated.
31.58 + * At that point {@code guardWithTest} may ignore {@code T} and return {@code F}.
31.59 + * <p>
31.60 + * Here is an example of a switch point in action:
31.61 + * <blockquote><pre>{@code
31.62 +MethodHandle MH_strcat = MethodHandles.lookup()
31.63 + .findVirtual(String.class, "concat", MethodType.methodType(String.class, String.class));
31.64 +SwitchPoint spt = new SwitchPoint();
31.65 +assert(!spt.hasBeenInvalidated());
31.66 +// the following steps may be repeated to re-use the same switch point:
31.67 +MethodHandle worker1 = MH_strcat;
31.68 +MethodHandle worker2 = MethodHandles.permuteArguments(MH_strcat, MH_strcat.type(), 1, 0);
31.69 +MethodHandle worker = spt.guardWithTest(worker1, worker2);
31.70 +assertEquals("method", (String) worker.invokeExact("met", "hod"));
31.71 +SwitchPoint.invalidateAll(new SwitchPoint[]{ spt });
31.72 +assert(spt.hasBeenInvalidated());
31.73 +assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
31.74 + * }</pre></blockquote>
31.75 + * <p style="font-size:smaller;">
31.76 + * <em>Discussion:</em>
31.77 + * Switch points are useful without subclassing. They may also be subclassed.
31.78 + * This may be useful in order to associate application-specific invalidation logic
31.79 + * with the switch point.
31.80 + * Notice that there is no permanent association between a switch point and
31.81 + * the method handles it produces and consumes.
31.82 + * The garbage collector may collect method handles produced or consumed
31.83 + * by a switch point independently of the lifetime of the switch point itself.
31.84 + * <p style="font-size:smaller;">
31.85 + * <em>Implementation Note:</em>
31.86 + * A switch point behaves as if implemented on top of {@link MutableCallSite},
31.87 + * approximately as follows:
31.88 + * <blockquote><pre>{@code
31.89 +public class SwitchPoint {
31.90 + private static final MethodHandle
31.91 + K_true = MethodHandles.constant(boolean.class, true),
31.92 + K_false = MethodHandles.constant(boolean.class, false);
31.93 + private final MutableCallSite mcs;
31.94 + private final MethodHandle mcsInvoker;
31.95 + public SwitchPoint() {
31.96 + this.mcs = new MutableCallSite(K_true);
31.97 + this.mcsInvoker = mcs.dynamicInvoker();
31.98 + }
31.99 + public MethodHandle guardWithTest(
31.100 + MethodHandle target, MethodHandle fallback) {
31.101 + // Note: mcsInvoker is of type ()boolean.
31.102 + // Target and fallback may take any arguments, but must have the same type.
31.103 + return MethodHandles.guardWithTest(this.mcsInvoker, target, fallback);
31.104 + }
31.105 + public static void invalidateAll(SwitchPoint[] spts) {
31.106 + List<MutableCallSite> mcss = new ArrayList<>();
31.107 + for (SwitchPoint spt : spts) mcss.add(spt.mcs);
31.108 + for (MutableCallSite mcs : mcss) mcs.setTarget(K_false);
31.109 + MutableCallSite.syncAll(mcss.toArray(new MutableCallSite[0]));
31.110 + }
31.111 +}
31.112 + * }</pre></blockquote>
31.113 + * @author Remi Forax, JSR 292 EG
31.114 + */
31.115 +public class SwitchPoint {
31.116 + private static final MethodHandle
31.117 + K_true = MethodHandles.constant(boolean.class, true),
31.118 + K_false = MethodHandles.constant(boolean.class, false);
31.119 +
31.120 + private final MutableCallSite mcs;
31.121 + private final MethodHandle mcsInvoker;
31.122 +
31.123 + /**
31.124 + * Creates a new switch point.
31.125 + */
31.126 + public SwitchPoint() {
31.127 + this.mcs = new MutableCallSite(K_true);
31.128 + this.mcsInvoker = mcs.dynamicInvoker();
31.129 + }
31.130 +
31.131 + /**
31.132 + * Determines if this switch point has been invalidated yet.
31.133 + *
31.134 + * <p style="font-size:smaller;">
31.135 + * <em>Discussion:</em>
31.136 + * Because of the one-way nature of invalidation, once a switch point begins
31.137 + * to return true for {@code hasBeenInvalidated},
31.138 + * it will always do so in the future.
31.139 + * On the other hand, a valid switch point visible to other threads may
31.140 + * be invalidated at any moment, due to a request by another thread.
31.141 + * <p style="font-size:smaller;">
31.142 + * Since invalidation is a global and immediate operation,
31.143 + * the execution of this query, on a valid switchpoint,
31.144 + * must be internally sequenced with any
31.145 + * other threads that could cause invalidation.
31.146 + * This query may therefore be expensive.
31.147 + * The recommended way to build a boolean-valued method handle
31.148 + * which queries the invalidation state of a switch point {@code s} is
31.149 + * to call {@code s.guardWithTest} on
31.150 + * {@link MethodHandles#constant constant} true and false method handles.
31.151 + *
31.152 + * @return true if this switch point has been invalidated
31.153 + */
31.154 + public boolean hasBeenInvalidated() {
31.155 + return (mcs.getTarget() != K_true);
31.156 + }
31.157 +
31.158 + /**
31.159 + * Returns a method handle which always delegates either to the target or the fallback.
31.160 + * The method handle will delegate to the target exactly as long as the switch point is valid.
31.161 + * After that, it will permanently delegate to the fallback.
31.162 + * <p>
31.163 + * The target and fallback must be of exactly the same method type,
31.164 + * and the resulting combined method handle will also be of this type.
31.165 + *
31.166 + * @param target the method handle selected by the switch point as long as it is valid
31.167 + * @param fallback the method handle selected by the switch point after it is invalidated
31.168 + * @return a combined method handle which always calls either the target or fallback
31.169 + * @throws NullPointerException if either argument is null
31.170 + * @throws IllegalArgumentException if the two method types do not match
31.171 + * @see MethodHandles#guardWithTest
31.172 + */
31.173 + public MethodHandle guardWithTest(MethodHandle target, MethodHandle fallback) {
31.174 + if (mcs.getTarget() == K_false)
31.175 + return fallback; // already invalid
31.176 + return MethodHandles.guardWithTest(mcsInvoker, target, fallback);
31.177 + }
31.178 +
31.179 + /**
31.180 + * Sets all of the given switch points into the invalid state.
31.181 + * After this call executes, no thread will observe any of the
31.182 + * switch points to be in a valid state.
31.183 + * <p>
31.184 + * This operation is likely to be expensive and should be used sparingly.
31.185 + * If possible, it should be buffered for batch processing on sets of switch points.
31.186 + * <p>
31.187 + * If {@code switchPoints} contains a null element,
31.188 + * a {@code NullPointerException} will be raised.
31.189 + * In this case, some non-null elements in the array may be
31.190 + * processed before the method returns abnormally.
31.191 + * Which elements these are (if any) is implementation-dependent.
31.192 + *
31.193 + * <p style="font-size:smaller;">
31.194 + * <em>Discussion:</em>
31.195 + * For performance reasons, {@code invalidateAll} is not a virtual method
31.196 + * on a single switch point, but rather applies to a set of switch points.
31.197 + * Some implementations may incur a large fixed overhead cost
31.198 + * for processing one or more invalidation operations,
31.199 + * but a small incremental cost for each additional invalidation.
31.200 + * In any case, this operation is likely to be costly, since
31.201 + * other threads may have to be somehow interrupted
31.202 + * in order to make them notice the updated switch point state.
31.203 + * However, it may be observed that a single call to invalidate
31.204 + * several switch points has the same formal effect as many calls,
31.205 + * each on just one of the switch points.
31.206 + *
31.207 + * <p style="font-size:smaller;">
31.208 + * <em>Implementation Note:</em>
31.209 + * Simple implementations of {@code SwitchPoint} may use
31.210 + * a private {@link MutableCallSite} to publish the state of a switch point.
31.211 + * In such an implementation, the {@code invalidateAll} method can
31.212 + * simply change the call site's target, and issue one call to
31.213 + * {@linkplain MutableCallSite#syncAll synchronize} all the
31.214 + * private call sites.
31.215 + *
31.216 + * @param switchPoints an array of call sites to be synchronized
31.217 + * @throws NullPointerException if the {@code switchPoints} array reference is null
31.218 + * or the array contains a null
31.219 + */
31.220 + public static void invalidateAll(SwitchPoint[] switchPoints) {
31.221 + if (switchPoints.length == 0) return;
31.222 + MutableCallSite[] sites = new MutableCallSite[switchPoints.length];
31.223 + for (int i = 0; i < switchPoints.length; i++) {
31.224 + SwitchPoint spt = switchPoints[i];
31.225 + if (spt == null) break; // MSC.syncAll will trigger a NPE
31.226 + sites[i] = spt.mcs;
31.227 + spt.mcs.setTarget(K_false);
31.228 + }
31.229 + MutableCallSite.syncAll(sites);
31.230 + }
31.231 +}
32.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
32.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/TypeConvertingMethodAdapter.java Sat Aug 09 11:12:05 2014 +0200
32.3 @@ -0,0 +1,302 @@
32.4 +/*
32.5 + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
32.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
32.7 + *
32.8 + * This code is free software; you can redistribute it and/or modify it
32.9 + * under the terms of the GNU General Public License version 2 only, as
32.10 + * published by the Free Software Foundation. Oracle designates this
32.11 + * particular file as subject to the "Classpath" exception as provided
32.12 + * by Oracle in the LICENSE file that accompanied this code.
32.13 + *
32.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
32.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
32.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
32.17 + * version 2 for more details (a copy is included in the LICENSE file that
32.18 + * accompanied this code).
32.19 + *
32.20 + * You should have received a copy of the GNU General Public License version
32.21 + * 2 along with this work; if not, write to the Free Software Foundation,
32.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
32.23 + *
32.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
32.25 + * or visit www.oracle.com if you need additional information or have any
32.26 + * questions.
32.27 + */
32.28 +
32.29 +package java.lang.invoke;
32.30 +
32.31 +import jdk.internal.org.objectweb.asm.MethodVisitor;
32.32 +import jdk.internal.org.objectweb.asm.Opcodes;
32.33 +import jdk.internal.org.objectweb.asm.Type;
32.34 +import sun.invoke.util.BytecodeDescriptor;
32.35 +import sun.invoke.util.Wrapper;
32.36 +import static sun.invoke.util.Wrapper.*;
32.37 +
32.38 +class TypeConvertingMethodAdapter extends MethodVisitor {
32.39 +
32.40 + TypeConvertingMethodAdapter(MethodVisitor mv) {
32.41 + super(Opcodes.ASM5, mv);
32.42 + }
32.43 +
32.44 + private static final int NUM_WRAPPERS = Wrapper.values().length;
32.45 +
32.46 + private static final String NAME_OBJECT = "java/lang/Object";
32.47 + private static final String WRAPPER_PREFIX = "Ljava/lang/";
32.48 +
32.49 + // Same for all primitives; name of the boxing method
32.50 + private static final String NAME_BOX_METHOD = "valueOf";
32.51 +
32.52 + // Table of opcodes for widening primitive conversions; NOP = no conversion
32.53 + private static final int[][] wideningOpcodes = new int[NUM_WRAPPERS][NUM_WRAPPERS];
32.54 +
32.55 + private static final Wrapper[] FROM_WRAPPER_NAME = new Wrapper[16];
32.56 +
32.57 + // Table of wrappers for primitives, indexed by ASM type sorts
32.58 + private static final Wrapper[] FROM_TYPE_SORT = new Wrapper[16];
32.59 +
32.60 + static {
32.61 + for (Wrapper w : Wrapper.values()) {
32.62 + if (w.basicTypeChar() != 'L') {
32.63 + int wi = hashWrapperName(w.wrapperSimpleName());
32.64 + assert (FROM_WRAPPER_NAME[wi] == null);
32.65 + FROM_WRAPPER_NAME[wi] = w;
32.66 + }
32.67 + }
32.68 +
32.69 + for (int i = 0; i < NUM_WRAPPERS; i++) {
32.70 + for (int j = 0; j < NUM_WRAPPERS; j++) {
32.71 + wideningOpcodes[i][j] = Opcodes.NOP;
32.72 + }
32.73 + }
32.74 +
32.75 + initWidening(LONG, Opcodes.I2L, BYTE, SHORT, INT, CHAR);
32.76 + initWidening(LONG, Opcodes.F2L, FLOAT);
32.77 + initWidening(FLOAT, Opcodes.I2F, BYTE, SHORT, INT, CHAR);
32.78 + initWidening(FLOAT, Opcodes.L2F, LONG);
32.79 + initWidening(DOUBLE, Opcodes.I2D, BYTE, SHORT, INT, CHAR);
32.80 + initWidening(DOUBLE, Opcodes.F2D, FLOAT);
32.81 + initWidening(DOUBLE, Opcodes.L2D, LONG);
32.82 +
32.83 + FROM_TYPE_SORT[Type.BYTE] = Wrapper.BYTE;
32.84 + FROM_TYPE_SORT[Type.SHORT] = Wrapper.SHORT;
32.85 + FROM_TYPE_SORT[Type.INT] = Wrapper.INT;
32.86 + FROM_TYPE_SORT[Type.LONG] = Wrapper.LONG;
32.87 + FROM_TYPE_SORT[Type.CHAR] = Wrapper.CHAR;
32.88 + FROM_TYPE_SORT[Type.FLOAT] = Wrapper.FLOAT;
32.89 + FROM_TYPE_SORT[Type.DOUBLE] = Wrapper.DOUBLE;
32.90 + FROM_TYPE_SORT[Type.BOOLEAN] = Wrapper.BOOLEAN;
32.91 + }
32.92 +
32.93 + private static void initWidening(Wrapper to, int opcode, Wrapper... from) {
32.94 + for (Wrapper f : from) {
32.95 + wideningOpcodes[f.ordinal()][to.ordinal()] = opcode;
32.96 + }
32.97 + }
32.98 +
32.99 + /**
32.100 + * Class name to Wrapper hash, derived from Wrapper.hashWrap()
32.101 + * @param xn
32.102 + * @return The hash code 0-15
32.103 + */
32.104 + private static int hashWrapperName(String xn) {
32.105 + if (xn.length() < 3) {
32.106 + return 0;
32.107 + }
32.108 + return (3 * xn.charAt(1) + xn.charAt(2)) % 16;
32.109 + }
32.110 +
32.111 + private Wrapper wrapperOrNullFromDescriptor(String desc) {
32.112 + if (!desc.startsWith(WRAPPER_PREFIX)) {
32.113 + // Not a class type (array or method), so not a boxed type
32.114 + // or not in the right package
32.115 + return null;
32.116 + }
32.117 + // Pare it down to the simple class name
32.118 + String cname = desc.substring(WRAPPER_PREFIX.length(), desc.length() - 1);
32.119 + // Hash to a Wrapper
32.120 + Wrapper w = FROM_WRAPPER_NAME[hashWrapperName(cname)];
32.121 + if (w == null || w.wrapperSimpleName().equals(cname)) {
32.122 + return w;
32.123 + } else {
32.124 + return null;
32.125 + }
32.126 + }
32.127 +
32.128 + private static String wrapperName(Wrapper w) {
32.129 + return "java/lang/" + w.wrapperSimpleName();
32.130 + }
32.131 +
32.132 + private static String unboxMethod(Wrapper w) {
32.133 + return w.primitiveSimpleName() + "Value";
32.134 + }
32.135 +
32.136 + private static String boxingDescriptor(Wrapper w) {
32.137 + return String.format("(%s)L%s;", w.basicTypeChar(), wrapperName(w));
32.138 + }
32.139 +
32.140 + private static String unboxingDescriptor(Wrapper w) {
32.141 + return "()" + w.basicTypeChar();
32.142 + }
32.143 +
32.144 + void boxIfTypePrimitive(Type t) {
32.145 + Wrapper w = FROM_TYPE_SORT[t.getSort()];
32.146 + if (w != null) {
32.147 + box(w);
32.148 + }
32.149 + }
32.150 +
32.151 + void widen(Wrapper ws, Wrapper wt) {
32.152 + if (ws != wt) {
32.153 + int opcode = wideningOpcodes[ws.ordinal()][wt.ordinal()];
32.154 + if (opcode != Opcodes.NOP) {
32.155 + visitInsn(opcode);
32.156 + }
32.157 + }
32.158 + }
32.159 +
32.160 + void box(Wrapper w) {
32.161 + visitMethodInsn(Opcodes.INVOKESTATIC,
32.162 + wrapperName(w),
32.163 + NAME_BOX_METHOD,
32.164 + boxingDescriptor(w));
32.165 + }
32.166 +
32.167 + /**
32.168 + * Convert types by unboxing. The source type is known to be a primitive wrapper.
32.169 + * @param ws A primitive wrapper corresponding to wrapped reference source type
32.170 + * @param wt A primitive wrapper being converted to
32.171 + */
32.172 + void unbox(String sname, Wrapper wt) {
32.173 + visitMethodInsn(Opcodes.INVOKEVIRTUAL,
32.174 + sname,
32.175 + unboxMethod(wt),
32.176 + unboxingDescriptor(wt));
32.177 + }
32.178 +
32.179 + private String descriptorToName(String desc) {
32.180 + int last = desc.length() - 1;
32.181 + if (desc.charAt(0) == 'L' && desc.charAt(last) == ';') {
32.182 + // In descriptor form
32.183 + return desc.substring(1, last);
32.184 + } else {
32.185 + // Already in internal name form
32.186 + return desc;
32.187 + }
32.188 + }
32.189 +
32.190 + void cast(String ds, String dt) {
32.191 + String ns = descriptorToName(ds);
32.192 + String nt = descriptorToName(dt);
32.193 + if (!nt.equals(ns) && !nt.equals(NAME_OBJECT)) {
32.194 + visitTypeInsn(Opcodes.CHECKCAST, nt);
32.195 + }
32.196 + }
32.197 +
32.198 + private boolean isPrimitive(Wrapper w) {
32.199 + return w != OBJECT;
32.200 + }
32.201 +
32.202 + private Wrapper toWrapper(String desc) {
32.203 + char first = desc.charAt(0);
32.204 + if (first == '[' || first == '(') {
32.205 + first = 'L';
32.206 + }
32.207 + return Wrapper.forBasicType(first);
32.208 + }
32.209 +
32.210 + /**
32.211 + * Convert an argument of type 'arg' to be passed to 'target' assuring that it is 'functional'.
32.212 + * Insert the needed conversion instructions in the method code.
32.213 + * @param arg
32.214 + * @param target
32.215 + * @param functional
32.216 + */
32.217 + void convertType(Class<?> arg, Class<?> target, Class<?> functional) {
32.218 + if (arg.equals(target) && arg.equals(functional)) {
32.219 + return;
32.220 + }
32.221 + if (arg == Void.TYPE || target == Void.TYPE) {
32.222 + return;
32.223 + }
32.224 + if (arg.isPrimitive()) {
32.225 + Wrapper wArg = Wrapper.forPrimitiveType(arg);
32.226 + if (target.isPrimitive()) {
32.227 + // Both primitives: widening
32.228 + widen(wArg, Wrapper.forPrimitiveType(target));
32.229 + } else {
32.230 + // Primitive argument to reference target
32.231 + String dTarget = BytecodeDescriptor.unparse(target);
32.232 + Wrapper wPrimTarget = wrapperOrNullFromDescriptor(dTarget);
32.233 + if (wPrimTarget != null) {
32.234 + // The target is a boxed primitive type, widen to get there before boxing
32.235 + widen(wArg, wPrimTarget);
32.236 + box(wPrimTarget);
32.237 + } else {
32.238 + // Otherwise, box and cast
32.239 + box(wArg);
32.240 + cast(wrapperName(wArg), dTarget);
32.241 + }
32.242 + }
32.243 + } else {
32.244 + String dArg = BytecodeDescriptor.unparse(arg);
32.245 + String dSrc;
32.246 + if (functional.isPrimitive()) {
32.247 + dSrc = dArg;
32.248 + } else {
32.249 + // Cast to convert to possibly more specific type, and generate CCE for invalid arg
32.250 + dSrc = BytecodeDescriptor.unparse(functional);
32.251 + cast(dArg, dSrc);
32.252 + }
32.253 + String dTarget = BytecodeDescriptor.unparse(target);
32.254 + if (target.isPrimitive()) {
32.255 + Wrapper wTarget = toWrapper(dTarget);
32.256 + // Reference argument to primitive target
32.257 + Wrapper wps = wrapperOrNullFromDescriptor(dSrc);
32.258 + if (wps != null) {
32.259 + if (wps.isSigned() || wps.isFloating()) {
32.260 + // Boxed number to primitive
32.261 + unbox(wrapperName(wps), wTarget);
32.262 + } else {
32.263 + // Character or Boolean
32.264 + unbox(wrapperName(wps), wps);
32.265 + widen(wps, wTarget);
32.266 + }
32.267 + } else {
32.268 + // Source type is reference type, but not boxed type,
32.269 + // assume it is super type of target type
32.270 + String intermediate;
32.271 + if (wTarget.isSigned() || wTarget.isFloating()) {
32.272 + // Boxed number to primitive
32.273 + intermediate = "java/lang/Number";
32.274 + } else {
32.275 + // Character or Boolean
32.276 + intermediate = wrapperName(wTarget);
32.277 + }
32.278 + cast(dSrc, intermediate);
32.279 + unbox(intermediate, wTarget);
32.280 + }
32.281 + } else {
32.282 + // Both reference types: just case to target type
32.283 + cast(dSrc, dTarget);
32.284 + }
32.285 + }
32.286 + }
32.287 +
32.288 + /**
32.289 + * The following method is copied from
32.290 + * org.objectweb.asm.commons.InstructionAdapter. Part of ASM: a very small
32.291 + * and fast Java bytecode manipulation framework.
32.292 + * Copyright (c) 2000-2005 INRIA, France Telecom All rights reserved.
32.293 + */
32.294 + void iconst(final int cst) {
32.295 + if (cst >= -1 && cst <= 5) {
32.296 + mv.visitInsn(Opcodes.ICONST_0 + cst);
32.297 + } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) {
32.298 + mv.visitIntInsn(Opcodes.BIPUSH, cst);
32.299 + } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) {
32.300 + mv.visitIntInsn(Opcodes.SIPUSH, cst);
32.301 + } else {
32.302 + mv.visitLdcInsn(cst);
32.303 + }
32.304 + }
32.305 +}
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
33.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/VolatileCallSite.java Sat Aug 09 11:12:05 2014 +0200
33.3 @@ -0,0 +1,109 @@
33.4 +/*
33.5 + * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
33.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33.7 + *
33.8 + * This code is free software; you can redistribute it and/or modify it
33.9 + * under the terms of the GNU General Public License version 2 only, as
33.10 + * published by the Free Software Foundation. Oracle designates this
33.11 + * particular file as subject to the "Classpath" exception as provided
33.12 + * by Oracle in the LICENSE file that accompanied this code.
33.13 + *
33.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
33.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
33.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
33.17 + * version 2 for more details (a copy is included in the LICENSE file that
33.18 + * accompanied this code).
33.19 + *
33.20 + * You should have received a copy of the GNU General Public License version
33.21 + * 2 along with this work; if not, write to the Free Software Foundation,
33.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
33.23 + *
33.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
33.25 + * or visit www.oracle.com if you need additional information or have any
33.26 + * questions.
33.27 + */
33.28 +
33.29 +package java.lang.invoke;
33.30 +
33.31 +/**
33.32 + * A {@code VolatileCallSite} is a {@link CallSite} whose target acts like a volatile variable.
33.33 + * An {@code invokedynamic} instruction linked to a {@code VolatileCallSite} sees updates
33.34 + * to its call site target immediately, even if the update occurs in another thread.
33.35 + * There may be a performance penalty for such tight coupling between threads.
33.36 + * <p>
33.37 + * Unlike {@code MutableCallSite}, there is no
33.38 + * {@linkplain MutableCallSite#syncAll syncAll operation} on volatile
33.39 + * call sites, since every write to a volatile variable is implicitly
33.40 + * synchronized with reader threads.
33.41 + * <p>
33.42 + * In other respects, a {@code VolatileCallSite} is interchangeable
33.43 + * with {@code MutableCallSite}.
33.44 + * @see MutableCallSite
33.45 + * @author John Rose, JSR 292 EG
33.46 + */
33.47 +public class VolatileCallSite extends CallSite {
33.48 + /**
33.49 + * Creates a call site with a volatile binding to its target.
33.50 + * The initial target is set to a method handle
33.51 + * of the given type which will throw an {@code IllegalStateException} if called.
33.52 + * @param type the method type that this call site will have
33.53 + * @throws NullPointerException if the proposed type is null
33.54 + */
33.55 + public VolatileCallSite(MethodType type) {
33.56 + super(type);
33.57 + }
33.58 +
33.59 + /**
33.60 + * Creates a call site with a volatile binding to its target.
33.61 + * The target is set to the given value.
33.62 + * @param target the method handle that will be the initial target of the call site
33.63 + * @throws NullPointerException if the proposed target is null
33.64 + */
33.65 + public VolatileCallSite(MethodHandle target) {
33.66 + super(target);
33.67 + }
33.68 +
33.69 + /**
33.70 + * Returns the target method of the call site, which behaves
33.71 + * like a {@code volatile} field of the {@code VolatileCallSite}.
33.72 + * <p>
33.73 + * The interactions of {@code getTarget} with memory are the same
33.74 + * as of a read from a {@code volatile} field.
33.75 + * <p>
33.76 + * In particular, the current thread is required to issue a fresh
33.77 + * read of the target from memory, and must not fail to see
33.78 + * a recent update to the target by another thread.
33.79 + *
33.80 + * @return the linkage state of this call site, a method handle which can change over time
33.81 + * @see #setTarget
33.82 + */
33.83 + @Override public final MethodHandle getTarget() {
33.84 + return getTargetVolatile();
33.85 + }
33.86 +
33.87 + /**
33.88 + * Updates the target method of this call site, as a volatile variable.
33.89 + * The type of the new target must agree with the type of the old target.
33.90 + * <p>
33.91 + * The interactions with memory are the same as of a write to a volatile field.
33.92 + * In particular, any threads is guaranteed to see the updated target
33.93 + * the next time it calls {@code getTarget}.
33.94 + * @param newTarget the new target
33.95 + * @throws NullPointerException if the proposed new target is null
33.96 + * @throws WrongMethodTypeException if the proposed new target
33.97 + * has a method type that differs from the previous target
33.98 + * @see #getTarget
33.99 + */
33.100 + @Override public void setTarget(MethodHandle newTarget) {
33.101 + checkTargetChange(getTargetVolatile(), newTarget);
33.102 + setTargetVolatile(newTarget);
33.103 + }
33.104 +
33.105 + /**
33.106 + * {@inheritDoc}
33.107 + */
33.108 + @Override
33.109 + public final MethodHandle dynamicInvoker() {
33.110 + return makeDynamicInvoker();
33.111 + }
33.112 +}
34.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
34.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/WrongMethodTypeException.java Sat Aug 09 11:12:05 2014 +0200
34.3 @@ -0,0 +1,85 @@
34.4 +/*
34.5 + * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
34.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
34.7 + *
34.8 + * This code is free software; you can redistribute it and/or modify it
34.9 + * under the terms of the GNU General Public License version 2 only, as
34.10 + * published by the Free Software Foundation. Oracle designates this
34.11 + * particular file as subject to the "Classpath" exception as provided
34.12 + * by Oracle in the LICENSE file that accompanied this code.
34.13 + *
34.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
34.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
34.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
34.17 + * version 2 for more details (a copy is included in the LICENSE file that
34.18 + * accompanied this code).
34.19 + *
34.20 + * You should have received a copy of the GNU General Public License version
34.21 + * 2 along with this work; if not, write to the Free Software Foundation,
34.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
34.23 + *
34.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
34.25 + * or visit www.oracle.com if you need additional information or have any
34.26 + * questions.
34.27 + */
34.28 +
34.29 +package java.lang.invoke;
34.30 +
34.31 +/**
34.32 + * Thrown to indicate that code has attempted to call a method handle
34.33 + * via the wrong method type. As with the bytecode representation of
34.34 + * normal Java method calls, method handle calls are strongly typed
34.35 + * to a specific type descriptor associated with a call site.
34.36 + * <p>
34.37 + * This exception may also be thrown when two method handles are
34.38 + * composed, and the system detects that their types cannot be
34.39 + * matched up correctly. This amounts to an early evaluation
34.40 + * of the type mismatch, at method handle construction time,
34.41 + * instead of when the mismatched method handle is called.
34.42 + *
34.43 + * @author John Rose, JSR 292 EG
34.44 + * @since 1.7
34.45 + */
34.46 +public class WrongMethodTypeException extends RuntimeException {
34.47 + private static final long serialVersionUID = 292L;
34.48 +
34.49 + /**
34.50 + * Constructs a {@code WrongMethodTypeException} with no detail message.
34.51 + */
34.52 + public WrongMethodTypeException() {
34.53 + super();
34.54 + }
34.55 +
34.56 + /**
34.57 + * Constructs a {@code WrongMethodTypeException} with the specified
34.58 + * detail message.
34.59 + *
34.60 + * @param s the detail message.
34.61 + */
34.62 + public WrongMethodTypeException(String s) {
34.63 + super(s);
34.64 + }
34.65 +
34.66 + /**
34.67 + * Constructs a {@code WrongMethodTypeException} with the specified
34.68 + * detail message and cause.
34.69 + *
34.70 + * @param s the detail message.
34.71 + * @param cause the cause of the exception, or null.
34.72 + */
34.73 + //FIXME: make this public in MR1
34.74 + /*non-public*/ WrongMethodTypeException(String s, Throwable cause) {
34.75 + super(s, cause);
34.76 + }
34.77 +
34.78 + /**
34.79 + * Constructs a {@code WrongMethodTypeException} with the specified
34.80 + * cause.
34.81 + *
34.82 + * @param cause the cause of the exception, or null.
34.83 + */
34.84 + //FIXME: make this public in MR1
34.85 + /*non-public*/ WrongMethodTypeException(Throwable cause) {
34.86 + super(cause);
34.87 + }
34.88 +}
35.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
35.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/package-info.java Sat Aug 09 11:12:05 2014 +0200
35.3 @@ -0,0 +1,211 @@
35.4 +/*
35.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
35.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
35.7 + *
35.8 + * This code is free software; you can redistribute it and/or modify it
35.9 + * under the terms of the GNU General Public License version 2 only, as
35.10 + * published by the Free Software Foundation. Oracle designates this
35.11 + * particular file as subject to the "Classpath" exception as provided
35.12 + * by Oracle in the LICENSE file that accompanied this code.
35.13 + *
35.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
35.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
35.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
35.17 + * version 2 for more details (a copy is included in the LICENSE file that
35.18 + * accompanied this code).
35.19 + *
35.20 + * You should have received a copy of the GNU General Public License version
35.21 + * 2 along with this work; if not, write to the Free Software Foundation,
35.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
35.23 + *
35.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
35.25 + * or visit www.oracle.com if you need additional information or have any
35.26 + * questions.
35.27 + */
35.28 +
35.29 +/**
35.30 + * The {@code java.lang.invoke} package contains dynamic language support provided directly by
35.31 + * the Java core class libraries and virtual machine.
35.32 + *
35.33 + * <p>
35.34 + * As described in the Java Virtual Machine Specification,
35.35 + * certain types in this package have special relations to dynamic
35.36 + * language support in the virtual machine:
35.37 + * <ul>
35.38 + * <li>The class {@link java.lang.invoke.MethodHandle MethodHandle} contains
35.39 + * <a href="MethodHandle.html#sigpoly">signature polymorphic methods</a>
35.40 + * which can be linked regardless of their type descriptor.
35.41 + * Normally, method linkage requires exact matching of type descriptors.
35.42 + * </li>
35.43 + *
35.44 + * <li>The JVM bytecode format supports immediate constants of
35.45 + * the classes {@link java.lang.invoke.MethodHandle MethodHandle} and {@link java.lang.invoke.MethodType MethodType}.
35.46 + * </li>
35.47 + * </ul>
35.48 + *
35.49 + * <h1><a name="jvm_mods"></a>Summary of relevant Java Virtual Machine changes</h1>
35.50 + * The following low-level information summarizes relevant parts of the
35.51 + * Java Virtual Machine specification. For full details, please see the
35.52 + * current version of that specification.
35.53 + *
35.54 + * Each occurrence of an {@code invokedynamic} instruction is called a <em>dynamic call site</em>.
35.55 + * <h2><a name="indyinsn"></a>{@code invokedynamic} instructions</h2>
35.56 + * A dynamic call site is originally in an unlinked state. In this state, there is
35.57 + * no target method for the call site to invoke.
35.58 + * <p>
35.59 + * Before the JVM can execute a dynamic call site (an {@code invokedynamic} instruction),
35.60 + * the call site must first be <em>linked</em>.
35.61 + * Linking is accomplished by calling a <em>bootstrap method</em>
35.62 + * which is given the static information content of the call site,
35.63 + * and which must produce a {@link java.lang.invoke.MethodHandle method handle}
35.64 + * that gives the behavior of the call site.
35.65 + * <p>
35.66 + * Each {@code invokedynamic} instruction statically specifies its own
35.67 + * bootstrap method as a constant pool reference.
35.68 + * The constant pool reference also specifies the call site's name and type descriptor,
35.69 + * just like {@code invokevirtual} and the other invoke instructions.
35.70 + * <p>
35.71 + * Linking starts with resolving the constant pool entry for the
35.72 + * bootstrap method, and resolving a {@link java.lang.invoke.MethodType MethodType} object for
35.73 + * the type descriptor of the dynamic call site.
35.74 + * This resolution process may trigger class loading.
35.75 + * It may therefore throw an error if a class fails to load.
35.76 + * This error becomes the abnormal termination of the dynamic
35.77 + * call site execution.
35.78 + * Linkage does not trigger class initialization.
35.79 + * <p>
35.80 + * The bootstrap method is invoked on at least three values:
35.81 + * <ul>
35.82 + * <li>a {@code MethodHandles.Lookup}, a lookup object on the <em>caller class</em> in which dynamic call site occurs </li>
35.83 + * <li>a {@code String}, the method name mentioned in the call site </li>
35.84 + * <li>a {@code MethodType}, the resolved type descriptor of the call </li>
35.85 + * <li>optionally, between 1 and 251 additional static arguments taken from the constant pool </li>
35.86 + * </ul>
35.87 + * Invocation is as if by
35.88 + * {@link java.lang.invoke.MethodHandle#invoke MethodHandle.invoke}.
35.89 + * The returned result must be a {@link java.lang.invoke.CallSite CallSite} (or a subclass).
35.90 + * The type of the call site's target must be exactly equal to the type
35.91 + * derived from the dynamic call site's type descriptor and passed to
35.92 + * the bootstrap method.
35.93 + * The call site then becomes permanently linked to the dynamic call site.
35.94 + * <p>
35.95 + * As documented in the JVM specification, all failures arising from
35.96 + * the linkage of a dynamic call site are reported
35.97 + * by a {@link java.lang.BootstrapMethodError BootstrapMethodError},
35.98 + * which is thrown as the abnormal termination of the dynamic call
35.99 + * site execution.
35.100 + * If this happens, the same error will the thrown for all subsequent
35.101 + * attempts to execute the dynamic call site.
35.102 + *
35.103 + * <h2>timing of linkage</h2>
35.104 + * A dynamic call site is linked just before its first execution.
35.105 + * The bootstrap method call implementing the linkage occurs within
35.106 + * a thread that is attempting a first execution.
35.107 + * <p>
35.108 + * If there are several such threads, the bootstrap method may be
35.109 + * invoked in several threads concurrently.
35.110 + * Therefore, bootstrap methods which access global application
35.111 + * data must take the usual precautions against race conditions.
35.112 + * In any case, every {@code invokedynamic} instruction is either
35.113 + * unlinked or linked to a unique {@code CallSite} object.
35.114 + * <p>
35.115 + * In an application which requires dynamic call sites with individually
35.116 + * mutable behaviors, their bootstrap methods should produce distinct
35.117 + * {@link java.lang.invoke.CallSite CallSite} objects, one for each linkage request.
35.118 + * Alternatively, an application can link a single {@code CallSite} object
35.119 + * to several {@code invokedynamic} instructions, in which case
35.120 + * a change to the target method will become visible at each of
35.121 + * the instructions.
35.122 + * <p>
35.123 + * If several threads simultaneously execute a bootstrap method for a single dynamic
35.124 + * call site, the JVM must choose one {@code CallSite} object and install it visibly to
35.125 + * all threads. Any other bootstrap method calls are allowed to complete, but their
35.126 + * results are ignored, and their dynamic call site invocations proceed with the originally
35.127 + * chosen target object.
35.128 +
35.129 + * <p style="font-size:smaller;">
35.130 + * <em>Discussion:</em>
35.131 + * These rules do not enable the JVM to duplicate dynamic call sites,
35.132 + * or to issue “causeless” bootstrap method calls.
35.133 + * Every dynamic call site transitions at most once from unlinked to linked,
35.134 + * just before its first invocation.
35.135 + * There is no way to undo the effect of a completed bootstrap method call.
35.136 + *
35.137 + * <h2>types of bootstrap methods</h2>
35.138 + * As long as each bootstrap method can be correctly invoked
35.139 + * by {@code MethodHandle.invoke}, its detailed type is arbitrary.
35.140 + * For example, the first argument could be {@code Object}
35.141 + * instead of {@code MethodHandles.Lookup}, and the return type
35.142 + * could also be {@code Object} instead of {@code CallSite}.
35.143 + * (Note that the types and number of the stacked arguments limit
35.144 + * the legal kinds of bootstrap methods to appropriately typed
35.145 + * static methods and constructors of {@code CallSite} subclasses.)
35.146 + * <p>
35.147 + * If a given {@code invokedynamic} instruction specifies no static arguments,
35.148 + * the instruction's bootstrap method will be invoked on three arguments,
35.149 + * conveying the instruction's caller class, name, and method type.
35.150 + * If the {@code invokedynamic} instruction specifies one or more static arguments,
35.151 + * those values will be passed as additional arguments to the method handle.
35.152 + * (Note that because there is a limit of 255 arguments to any method,
35.153 + * at most 251 extra arguments can be supplied, since the bootstrap method
35.154 + * handle itself and its first three arguments must also be stacked.)
35.155 + * The bootstrap method will be invoked as if by either {@code MethodHandle.invoke}
35.156 + * or {@code invokeWithArguments}. (There is no way to tell the difference.)
35.157 + * <p>
35.158 + * The normal argument conversion rules for {@code MethodHandle.invoke} apply to all stacked arguments.
35.159 + * For example, if a pushed value is a primitive type, it may be converted to a reference by boxing conversion.
35.160 + * If the bootstrap method is a variable arity method (its modifier bit {@code 0x0080} is set),
35.161 + * then some or all of the arguments specified here may be collected into a trailing array parameter.
35.162 + * (This is not a special rule, but rather a useful consequence of the interaction
35.163 + * between {@code CONSTANT_MethodHandle} constants, the modifier bit for variable arity methods,
35.164 + * and the {@link java.lang.invoke.MethodHandle#asVarargsCollector asVarargsCollector} transformation.)
35.165 + * <p>
35.166 + * Given these rules, here are examples of legal bootstrap method declarations,
35.167 + * given various numbers {@code N} of extra arguments.
35.168 + * The first rows (marked {@code *}) will work for any number of extra arguments.
35.169 + * <table border=1 cellpadding=5 summary="Static argument types">
35.170 + * <tr><th>N</th><th>sample bootstrap method</th></tr>
35.171 + * <tr><td>*</td><td><code>CallSite bootstrap(Lookup caller, String name, MethodType type, Object... args)</code></td></tr>
35.172 + * <tr><td>*</td><td><code>CallSite bootstrap(Object... args)</code></td></tr>
35.173 + * <tr><td>*</td><td><code>CallSite bootstrap(Object caller, Object... nameAndTypeWithArgs)</code></td></tr>
35.174 + * <tr><td>0</td><td><code>CallSite bootstrap(Lookup caller, String name, MethodType type)</code></td></tr>
35.175 + * <tr><td>0</td><td><code>CallSite bootstrap(Lookup caller, Object... nameAndType)</code></td></tr>
35.176 + * <tr><td>1</td><td><code>CallSite bootstrap(Lookup caller, String name, MethodType type, Object arg)</code></td></tr>
35.177 + * <tr><td>2</td><td><code>CallSite bootstrap(Lookup caller, String name, MethodType type, Object... args)</code></td></tr>
35.178 + * <tr><td>2</td><td><code>CallSite bootstrap(Lookup caller, String name, MethodType type, String... args)</code></td></tr>
35.179 + * <tr><td>2</td><td><code>CallSite bootstrap(Lookup caller, String name, MethodType type, String x, int y)</code></td></tr>
35.180 + * </table>
35.181 + * The last example assumes that the extra arguments are of type
35.182 + * {@code CONSTANT_String} and {@code CONSTANT_Integer}, respectively.
35.183 + * The second-to-last example assumes that all extra arguments are of type
35.184 + * {@code CONSTANT_String}.
35.185 + * The other examples work with all types of extra arguments.
35.186 + * <p>
35.187 + * As noted above, the actual method type of the bootstrap method can vary.
35.188 + * For example, the fourth argument could be {@code MethodHandle},
35.189 + * if that is the type of the corresponding constant in
35.190 + * the {@code CONSTANT_InvokeDynamic} entry.
35.191 + * In that case, the {@code MethodHandle.invoke} call will pass the extra method handle
35.192 + * constant as an {@code Object}, but the type matching machinery of {@code MethodHandle.invoke}
35.193 + * will cast the reference back to {@code MethodHandle} before invoking the bootstrap method.
35.194 + * (If a string constant were passed instead, by badly generated code, that cast would then fail,
35.195 + * resulting in a {@code BootstrapMethodError}.)
35.196 + * <p>
35.197 + * Note that, as a consequence of the above rules, the bootstrap method may accept a primitive
35.198 + * argument, if it can be represented by a constant pool entry.
35.199 + * However, arguments of type {@code boolean}, {@code byte}, {@code short}, or {@code char}
35.200 + * cannot be created for bootstrap methods, since such constants cannot be directly
35.201 + * represented in the constant pool, and the invocation of the bootstrap method will
35.202 + * not perform the necessary narrowing primitive conversions.
35.203 + * <p>
35.204 + * Extra bootstrap method arguments are intended to allow language implementors
35.205 + * to safely and compactly encode metadata.
35.206 + * In principle, the name and extra arguments are redundant,
35.207 + * since each call site could be given its own unique bootstrap method.
35.208 + * Such a practice is likely to produce large class files and constant pools.
35.209 + *
35.210 + * @author John Rose, JSR 292 EG
35.211 + * @since 1.7
35.212 + */
35.213 +
35.214 +package java.lang.invoke;
36.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
36.2 +++ b/rt/emul/compact/src/main/java/sun/invoke/WrapperInstance.java Sat Aug 09 11:12:05 2014 +0200
36.3 @@ -0,0 +1,48 @@
36.4 +/*
36.5 + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
36.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
36.7 + *
36.8 + * This code is free software; you can redistribute it and/or modify it
36.9 + * under the terms of the GNU General Public License version 2 only, as
36.10 + * published by the Free Software Foundation. Oracle designates this
36.11 + * particular file as subject to the "Classpath" exception as provided
36.12 + * by Oracle in the LICENSE file that accompanied this code.
36.13 + *
36.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
36.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
36.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
36.17 + * version 2 for more details (a copy is included in the LICENSE file that
36.18 + * accompanied this code).
36.19 + *
36.20 + * You should have received a copy of the GNU General Public License version
36.21 + * 2 along with this work; if not, write to the Free Software Foundation,
36.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
36.23 + *
36.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
36.25 + * or visit www.oracle.com if you need additional information or have any
36.26 + * questions.
36.27 + */
36.28 +
36.29 +package sun.invoke;
36.30 +
36.31 +import java.lang.invoke.MethodHandle;
36.32 +
36.33 +/**
36.34 + * Private API used inside of java.lang.invoke.MethodHandles.
36.35 + * Interface implemented by every object which is produced by
36.36 + * {@link java.lang.invoke.MethodHandleProxies#asInterfaceInstance MethodHandleProxies.asInterfaceInstance}.
36.37 + * The methods of this interface allow a caller to recover the parameters
36.38 + * to {@code asInstance}.
36.39 + * This allows applications to repeatedly convert between method handles
36.40 + * and SAM objects, without the risk of creating unbounded delegation chains.
36.41 + */
36.42 +public interface WrapperInstance {
36.43 + /** Produce or recover a target method handle which is behaviorally
36.44 + * equivalent to the SAM method of this object.
36.45 + */
36.46 + public MethodHandle getWrapperInstanceTarget();
36.47 + /** Recover the SAM type for which this object was created.
36.48 + */
36.49 + public Class<?> getWrapperInstanceType();
36.50 +}
36.51 +
37.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
37.2 +++ b/rt/emul/compact/src/main/java/sun/invoke/anon/AnonymousClassLoader.java Sat Aug 09 11:12:05 2014 +0200
37.3 @@ -0,0 +1,230 @@
37.4 +/*
37.5 + * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
37.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
37.7 + *
37.8 + * This code is free software; you can redistribute it and/or modify it
37.9 + * under the terms of the GNU General Public License version 2 only, as
37.10 + * published by the Free Software Foundation. Oracle designates this
37.11 + * particular file as subject to the "Classpath" exception as provided
37.12 + * by Oracle in the LICENSE file that accompanied this code.
37.13 + *
37.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
37.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
37.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
37.17 + * version 2 for more details (a copy is included in the LICENSE file that
37.18 + * accompanied this code).
37.19 + *
37.20 + * You should have received a copy of the GNU General Public License version
37.21 + * 2 along with this work; if not, write to the Free Software Foundation,
37.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
37.23 + *
37.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
37.25 + * or visit www.oracle.com if you need additional information or have any
37.26 + * questions.
37.27 + */
37.28 +
37.29 +package sun.invoke.anon;
37.30 +
37.31 +import java.io.IOException;
37.32 +import java.lang.reflect.InvocationTargetException;
37.33 +import java.lang.reflect.Method;
37.34 +import sun.misc.IOUtils;
37.35 +
37.36 +/**
37.37 + * Anonymous class loader. Will load any valid classfile, producing
37.38 + * a {@link Class} metaobject, without installing that class in the
37.39 + * system dictionary. Therefore, {@link Class#forName(String)} will never
37.40 + * produce a reference to an anonymous class.
37.41 + * <p>
37.42 + * The access permissions of the anonymous class are borrowed from
37.43 + * a <em>host class</em>. The new class behaves as if it were an
37.44 + * inner class of the host class. It can access the host's private
37.45 + * members, if the creator of the class loader has permission to
37.46 + * do so (or to create accessible reflective objects).
37.47 + * <p>
37.48 + * When the anonymous class is loaded, elements of its constant pool
37.49 + * can be patched to new values. This provides a hook to pre-resolve
37.50 + * named classes in the constant pool to other classes, including
37.51 + * anonymous ones. Also, string constants can be pre-resolved to
37.52 + * any reference. (The verifier treats non-string, non-class reference
37.53 + * constants as plain objects.)
37.54 + * <p>
37.55 + * Why include the patching function? It makes some use cases much easier.
37.56 + * Second, the constant pool needed some internal patching anyway,
37.57 + * to anonymize the loaded class itself. Finally, if you are going
37.58 + * to use this seriously, you'll want to build anonymous classes
37.59 + * on top of pre-existing anonymous classes, and that requires patching.
37.60 + *
37.61 + * <p>%%% TO-DO:
37.62 + * <ul>
37.63 + * <li>needs better documentation</li>
37.64 + * <li>needs more security work (for safe delegation)</li>
37.65 + * <li>needs a clearer story about error processing</li>
37.66 + * <li>patch member references also (use ';' as delimiter char)</li>
37.67 + * <li>patch method references to (conforming) method handles</li>
37.68 + * </ul>
37.69 + *
37.70 + * @author jrose
37.71 + * @author Remi Forax
37.72 + * @see <a href="http://blogs.sun.com/jrose/entry/anonymous_classes_in_the_vm">
37.73 + * http://blogs.sun.com/jrose/entry/anonymous_classes_in_the_vm</a>
37.74 + */
37.75 +
37.76 +public class AnonymousClassLoader {
37.77 + final Class<?> hostClass;
37.78 +
37.79 + // Privileged constructor.
37.80 + private AnonymousClassLoader(Class<?> hostClass) {
37.81 + this.hostClass = hostClass;
37.82 + }
37.83 +
37.84 + public static AnonymousClassLoader make(sun.misc.Unsafe unsafe, Class<?> hostClass) {
37.85 + if (unsafe == null) throw new NullPointerException();
37.86 + return new AnonymousClassLoader(hostClass);
37.87 + }
37.88 +
37.89 + public Class<?> loadClass(byte[] classFile) {
37.90 + if (defineAnonymousClass == null) {
37.91 + // no JVM support; try to fake an approximation
37.92 + try {
37.93 + return fakeLoadClass(new ConstantPoolParser(classFile).createPatch());
37.94 + } catch (InvalidConstantPoolFormatException ee) {
37.95 + throw new IllegalArgumentException(ee);
37.96 + }
37.97 + }
37.98 + return loadClass(classFile, null);
37.99 + }
37.100 +
37.101 + public Class<?> loadClass(ConstantPoolPatch classPatch) {
37.102 + if (defineAnonymousClass == null) {
37.103 + // no JVM support; try to fake an approximation
37.104 + return fakeLoadClass(classPatch);
37.105 + }
37.106 + Object[] patches = classPatch.patchArray;
37.107 + // Convert class names (this late in the game)
37.108 + // to use slash '/' instead of dot '.'.
37.109 + // Java likes dots, but the JVM likes slashes.
37.110 + for (int i = 0; i < patches.length; i++) {
37.111 + Object value = patches[i];
37.112 + if (value != null) {
37.113 + byte tag = classPatch.getTag(i);
37.114 + switch (tag) {
37.115 + case ConstantPoolVisitor.CONSTANT_Class:
37.116 + if (value instanceof String) {
37.117 + if (patches == classPatch.patchArray)
37.118 + patches = patches.clone();
37.119 + patches[i] = ((String)value).replace('.', '/');
37.120 + }
37.121 + break;
37.122 + case ConstantPoolVisitor.CONSTANT_Fieldref:
37.123 + case ConstantPoolVisitor.CONSTANT_Methodref:
37.124 + case ConstantPoolVisitor.CONSTANT_InterfaceMethodref:
37.125 + case ConstantPoolVisitor.CONSTANT_NameAndType:
37.126 + // When/if the JVM supports these patches,
37.127 + // we'll probably need to reformat them also.
37.128 + // Meanwhile, let the class loader create the error.
37.129 + break;
37.130 + }
37.131 + }
37.132 + }
37.133 + return loadClass(classPatch.outer.classFile, classPatch.patchArray);
37.134 + }
37.135 +
37.136 + private Class<?> loadClass(byte[] classFile, Object[] patchArray) {
37.137 + try {
37.138 + return (Class<?>)
37.139 + defineAnonymousClass.invoke(unsafe,
37.140 + hostClass, classFile, patchArray);
37.141 + } catch (Exception ex) {
37.142 + throwReflectedException(ex);
37.143 + throw new RuntimeException("error loading into "+hostClass, ex);
37.144 + }
37.145 + }
37.146 +
37.147 + private static void throwReflectedException(Exception ex) {
37.148 + if (ex instanceof InvocationTargetException) {
37.149 + Throwable tex = ((InvocationTargetException)ex).getTargetException();
37.150 + if (tex instanceof Error)
37.151 + throw (Error) tex;
37.152 + ex = (Exception) tex;
37.153 + }
37.154 + if (ex instanceof RuntimeException) {
37.155 + throw (RuntimeException) ex;
37.156 + }
37.157 + }
37.158 +
37.159 + private Class<?> fakeLoadClass(ConstantPoolPatch classPatch) {
37.160 + // Implementation:
37.161 + // 1. Make up a new name nobody has used yet.
37.162 + // 2. Inspect the tail-header of the class to find the this_class index.
37.163 + // 3. Patch the CONSTANT_Class for this_class to the new name.
37.164 + // 4. Add other CP entries required by (e.g.) string patches.
37.165 + // 5. Flatten Class constants down to their names, making sure that
37.166 + // the host class loader can pick them up again accurately.
37.167 + // 6. Generate the edited class file bytes.
37.168 + //
37.169 + // Potential limitations:
37.170 + // * The class won't be truly anonymous, and may interfere with others.
37.171 + // * Flattened class constants might not work, because of loader issues.
37.172 + // * Pseudo-string constants will not flatten down to real strings.
37.173 + // * Method handles will (of course) fail to flatten to linkage strings.
37.174 + if (true) throw new UnsupportedOperationException("NYI");
37.175 + Object[] cpArray;
37.176 + try {
37.177 + cpArray = classPatch.getOriginalCP();
37.178 + } catch (InvalidConstantPoolFormatException ex) {
37.179 + throw new RuntimeException(ex);
37.180 + }
37.181 + int thisClassIndex = classPatch.getParser().getThisClassIndex();
37.182 + String thisClassName = (String) cpArray[thisClassIndex];
37.183 + synchronized (AnonymousClassLoader.class) {
37.184 + thisClassName = thisClassName+"\\|"+(++fakeNameCounter);
37.185 + }
37.186 + classPatch.putUTF8(thisClassIndex, thisClassName);
37.187 + byte[] classFile = null;
37.188 + return unsafe.defineClass(null, classFile, 0, classFile.length,
37.189 + hostClass.getClassLoader(),
37.190 + hostClass.getProtectionDomain());
37.191 + }
37.192 + private static int fakeNameCounter = 99999;
37.193 +
37.194 + // ignore two warnings on this line:
37.195 + private static sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
37.196 + // preceding line requires that this class be on the boot class path
37.197 +
37.198 + static private final Method defineAnonymousClass;
37.199 + static {
37.200 + Method dac = null;
37.201 + Class<? extends sun.misc.Unsafe> unsafeClass = unsafe.getClass();
37.202 + try {
37.203 + dac = unsafeClass.getMethod("defineAnonymousClass",
37.204 + Class.class,
37.205 + byte[].class,
37.206 + Object[].class);
37.207 + } catch (Exception ee) {
37.208 + dac = null;
37.209 + }
37.210 + defineAnonymousClass = dac;
37.211 + }
37.212 +
37.213 + private static void noJVMSupport() {
37.214 + throw new UnsupportedOperationException("no JVM support for anonymous classes");
37.215 + }
37.216 +
37.217 +
37.218 + private static native Class<?> loadClassInternal(Class<?> hostClass,
37.219 + byte[] classFile,
37.220 + Object[] patchArray);
37.221 +
37.222 + public static byte[] readClassFile(Class<?> templateClass) throws IOException {
37.223 + String templateName = templateClass.getName();
37.224 + int lastDot = templateName.lastIndexOf('.');
37.225 + java.net.URL url = templateClass.getResource(templateName.substring(lastDot+1)+".class");
37.226 + java.net.URLConnection connection = url.openConnection();
37.227 + int contentLength = connection.getContentLength();
37.228 + if (contentLength < 0)
37.229 + throw new IOException("invalid content length "+contentLength);
37.230 +
37.231 + return IOUtils.readFully(connection.getInputStream(), contentLength, true);
37.232 + }
37.233 +}
38.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
38.2 +++ b/rt/emul/compact/src/main/java/sun/invoke/anon/ConstantPoolParser.java Sat Aug 09 11:12:05 2014 +0200
38.3 @@ -0,0 +1,368 @@
38.4 +/*
38.5 + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
38.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
38.7 + *
38.8 + * This code is free software; you can redistribute it and/or modify it
38.9 + * under the terms of the GNU General Public License version 2 only, as
38.10 + * published by the Free Software Foundation. Oracle designates this
38.11 + * particular file as subject to the "Classpath" exception as provided
38.12 + * by Oracle in the LICENSE file that accompanied this code.
38.13 + *
38.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
38.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
38.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
38.17 + * version 2 for more details (a copy is included in the LICENSE file that
38.18 + * accompanied this code).
38.19 + *
38.20 + * You should have received a copy of the GNU General Public License version
38.21 + * 2 along with this work; if not, write to the Free Software Foundation,
38.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
38.23 + *
38.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
38.25 + * or visit www.oracle.com if you need additional information or have any
38.26 + * questions.
38.27 + */
38.28 +
38.29 +package sun.invoke.anon;
38.30 +
38.31 +import java.io.IOException;
38.32 +import java.io.OutputStream;
38.33 +import java.nio.BufferUnderflowException;
38.34 +import java.nio.ByteBuffer;
38.35 +
38.36 +import static sun.invoke.anon.ConstantPoolVisitor.*;
38.37 +
38.38 +/** A constant pool parser.
38.39 + */
38.40 +public class ConstantPoolParser {
38.41 + final byte[] classFile;
38.42 + final byte[] tags;
38.43 + final char[] firstHeader; // maghi, maglo, minor, major, cplen
38.44 +
38.45 + // these are filled in on first parse:
38.46 + int endOffset;
38.47 + char[] secondHeader; // flags, this_class, super_class, intlen
38.48 +
38.49 + // used to decode UTF8 array
38.50 + private char[] charArray = new char[80];
38.51 +
38.52 + /** Creates a constant pool parser.
38.53 + * @param classFile an array of bytes containing a class.
38.54 + * @throws InvalidConstantPoolFormatException if the header of the class has errors.
38.55 + */
38.56 + public ConstantPoolParser(byte[] classFile) throws InvalidConstantPoolFormatException {
38.57 + this.classFile = classFile;
38.58 + this.firstHeader = parseHeader(classFile);
38.59 + this.tags = new byte[firstHeader[4]];
38.60 + }
38.61 +
38.62 + /** Create a constant pool parser by loading the bytecodes of the
38.63 + * class taken as argument.
38.64 + *
38.65 + * @param templateClass the class to parse.
38.66 + *
38.67 + * @throws IOException raised if an I/O occurs when loading
38.68 + * the bytecode of the template class.
38.69 + * @throws InvalidConstantPoolFormatException if the header of the class has errors.
38.70 + *
38.71 + * @see #ConstantPoolParser(byte[])
38.72 + * @see AnonymousClassLoader#readClassFile(Class)
38.73 + */
38.74 + public ConstantPoolParser(Class<?> templateClass) throws IOException, InvalidConstantPoolFormatException {
38.75 + this(AnonymousClassLoader.readClassFile(templateClass));
38.76 + }
38.77 +
38.78 + /** Creates an empty patch to patch the class file
38.79 + * used by the current parser.
38.80 + * @return a new class patch.
38.81 + */
38.82 + public ConstantPoolPatch createPatch() {
38.83 + return new ConstantPoolPatch(this);
38.84 + }
38.85 +
38.86 + /** Report the tag of the indicated CP entry.
38.87 + * @param index
38.88 + * @return one of {@link ConstantPoolVisitor#CONSTANT_Utf8}, etc.
38.89 + */
38.90 + public byte getTag(int index) {
38.91 + getEndOffset(); // trigger an exception if we haven't parsed yet
38.92 + return tags[index];
38.93 + }
38.94 +
38.95 + /** Report the length of the constant pool. */
38.96 + public int getLength() {
38.97 + return firstHeader[4];
38.98 + }
38.99 +
38.100 + /** Report the offset, within the class file, of the start of the constant pool. */
38.101 + public int getStartOffset() {
38.102 + return firstHeader.length * 2;
38.103 + }
38.104 +
38.105 + /** Report the offset, within the class file, of the end of the constant pool. */
38.106 + public int getEndOffset() {
38.107 + if (endOffset == 0)
38.108 + throw new IllegalStateException("class file has not yet been parsed");
38.109 + return endOffset;
38.110 + }
38.111 +
38.112 + /** Report the CP index of this class's own name. */
38.113 + public int getThisClassIndex() {
38.114 + getEndOffset(); // provoke exception if not yet parsed
38.115 + return secondHeader[1];
38.116 + }
38.117 +
38.118 + /** Report the total size of the class file. */
38.119 + public int getTailLength() {
38.120 + return classFile.length - getEndOffset();
38.121 + }
38.122 +
38.123 + /** Write the head (header plus constant pool)
38.124 + * of the class file to the indicated stream.
38.125 + */
38.126 + public void writeHead(OutputStream out) throws IOException {
38.127 + out.write(classFile, 0, getEndOffset());
38.128 + }
38.129 +
38.130 + /** Write the head (header plus constant pool)
38.131 + * of the class file to the indicated stream,
38.132 + * incorporating the non-null entries of the given array
38.133 + * as patches.
38.134 + */
38.135 + void writePatchedHead(OutputStream out, Object[] patchArray) {
38.136 + // this will be useful to partially emulate the class loader on old JVMs
38.137 + throw new UnsupportedOperationException("Not yet implemented");
38.138 + }
38.139 +
38.140 + /** Write the tail (everything after the constant pool)
38.141 + * of the class file to the indicated stream.
38.142 + */
38.143 + public void writeTail(OutputStream out) throws IOException {
38.144 + out.write(classFile, getEndOffset(), getTailLength());
38.145 + }
38.146 +
38.147 + private static char[] parseHeader(byte[] classFile) throws InvalidConstantPoolFormatException {
38.148 + char[] result = new char[5];
38.149 + ByteBuffer buffer = ByteBuffer.wrap(classFile);
38.150 + for (int i = 0; i < result.length; i++)
38.151 + result[i] = (char) getUnsignedShort(buffer);
38.152 + int magic = result[0] << 16 | result[1] << 0;
38.153 + if (magic != 0xCAFEBABE)
38.154 + throw new InvalidConstantPoolFormatException("invalid magic number "+magic);
38.155 + // skip major, minor version
38.156 + int len = result[4];
38.157 + if (len < 1)
38.158 + throw new InvalidConstantPoolFormatException("constant pool length < 1");
38.159 + return result;
38.160 + }
38.161 +
38.162 + /** Parse the constant pool of the class
38.163 + * calling a method visit* each time a constant pool entry is parsed.
38.164 + *
38.165 + * The order of the calls to visit* is not guaranteed to be the same
38.166 + * than the order of the constant pool entry in the bytecode array.
38.167 + *
38.168 + * @param visitor
38.169 + * @throws InvalidConstantPoolFormatException
38.170 + */
38.171 + public void parse(ConstantPoolVisitor visitor) throws InvalidConstantPoolFormatException {
38.172 + ByteBuffer buffer = ByteBuffer.wrap(classFile);
38.173 + buffer.position(getStartOffset()); //skip header
38.174 +
38.175 + Object[] values = new Object[getLength()];
38.176 + try {
38.177 + parseConstantPool(buffer, values, visitor);
38.178 + } catch(BufferUnderflowException e) {
38.179 + throw new InvalidConstantPoolFormatException(e);
38.180 + }
38.181 + if (endOffset == 0) {
38.182 + endOffset = buffer.position();
38.183 + secondHeader = new char[4];
38.184 + for (int i = 0; i < secondHeader.length; i++) {
38.185 + secondHeader[i] = (char) getUnsignedShort(buffer);
38.186 + }
38.187 + }
38.188 + resolveConstantPool(values, visitor);
38.189 + }
38.190 +
38.191 + private char[] getCharArray(int utfLength) {
38.192 + if (utfLength <= charArray.length)
38.193 + return charArray;
38.194 + return charArray = new char[utfLength];
38.195 + }
38.196 +
38.197 + private void parseConstantPool(ByteBuffer buffer, Object[] values, ConstantPoolVisitor visitor) throws InvalidConstantPoolFormatException {
38.198 + for (int i = 1; i < tags.length; ) {
38.199 + byte tag = (byte) getUnsignedByte(buffer);
38.200 + assert(tags[i] == 0 || tags[i] == tag);
38.201 + tags[i] = tag;
38.202 + switch (tag) {
38.203 + case CONSTANT_Utf8:
38.204 + int utfLen = getUnsignedShort(buffer);
38.205 + String value = getUTF8(buffer, utfLen, getCharArray(utfLen));
38.206 + visitor.visitUTF8(i, CONSTANT_Utf8, value);
38.207 + tags[i] = tag;
38.208 + values[i++] = value;
38.209 + break;
38.210 + case CONSTANT_Integer:
38.211 + visitor.visitConstantValue(i, tag, buffer.getInt());
38.212 + i++;
38.213 + break;
38.214 + case CONSTANT_Float:
38.215 + visitor.visitConstantValue(i, tag, buffer.getFloat());
38.216 + i++;
38.217 + break;
38.218 + case CONSTANT_Long:
38.219 + visitor.visitConstantValue(i, tag, buffer.getLong());
38.220 + i+=2;
38.221 + break;
38.222 + case CONSTANT_Double:
38.223 + visitor.visitConstantValue(i, tag, buffer.getDouble());
38.224 + i+=2;
38.225 + break;
38.226 +
38.227 + case CONSTANT_Class: // fall through:
38.228 + case CONSTANT_String:
38.229 + tags[i] = tag;
38.230 + values[i++] = new int[] { getUnsignedShort(buffer) };
38.231 + break;
38.232 +
38.233 + case CONSTANT_Fieldref: // fall through:
38.234 + case CONSTANT_Methodref: // fall through:
38.235 + case CONSTANT_InterfaceMethodref: // fall through:
38.236 + case CONSTANT_NameAndType:
38.237 + tags[i] = tag;
38.238 + values[i++] = new int[] { getUnsignedShort(buffer), getUnsignedShort(buffer) };
38.239 + break;
38.240 + default:
38.241 + throw new AssertionError("invalid constant "+tag);
38.242 + }
38.243 + }
38.244 + }
38.245 +
38.246 + private void resolveConstantPool(Object[] values, ConstantPoolVisitor visitor) {
38.247 + // clean out the int[] values, which are temporary
38.248 + for (int beg = 1, end = values.length-1, beg2, end2;
38.249 + beg <= end;
38.250 + beg = beg2, end = end2) {
38.251 + beg2 = end; end2 = beg-1;
38.252 + //System.out.println("CP resolve pass: "+beg+".."+end);
38.253 + for (int i = beg; i <= end; i++) {
38.254 + Object value = values[i];
38.255 + if (!(value instanceof int[]))
38.256 + continue;
38.257 + int[] array = (int[]) value;
38.258 + byte tag = tags[i];
38.259 + switch (tag) {
38.260 + case CONSTANT_String:
38.261 + String stringBody = (String) values[array[0]];
38.262 + visitor.visitConstantString(i, tag, stringBody, array[0]);
38.263 + values[i] = null;
38.264 + break;
38.265 + case CONSTANT_Class: {
38.266 + String className = (String) values[array[0]];
38.267 + // use the external form favored by Class.forName:
38.268 + className = className.replace('/', '.');
38.269 + visitor.visitConstantString(i, tag, className, array[0]);
38.270 + values[i] = className;
38.271 + break;
38.272 + }
38.273 + case CONSTANT_NameAndType: {
38.274 + String memberName = (String) values[array[0]];
38.275 + String signature = (String) values[array[1]];
38.276 + visitor.visitDescriptor(i, tag, memberName, signature,
38.277 + array[0], array[1]);
38.278 + values[i] = new String[] {memberName, signature};
38.279 + break;
38.280 + }
38.281 + case CONSTANT_Fieldref: // fall through:
38.282 + case CONSTANT_Methodref: // fall through:
38.283 + case CONSTANT_InterfaceMethodref: {
38.284 + Object className = values[array[0]];
38.285 + Object nameAndType = values[array[1]];
38.286 + if (!(className instanceof String) ||
38.287 + !(nameAndType instanceof String[])) {
38.288 + // one more pass is needed
38.289 + if (beg2 > i) beg2 = i;
38.290 + if (end2 < i) end2 = i;
38.291 + continue;
38.292 + }
38.293 + String[] nameAndTypeArray = (String[]) nameAndType;
38.294 + visitor.visitMemberRef(i, tag,
38.295 + (String)className,
38.296 + nameAndTypeArray[0],
38.297 + nameAndTypeArray[1],
38.298 + array[0], array[1]);
38.299 + values[i] = null;
38.300 + }
38.301 + break;
38.302 + default:
38.303 + continue;
38.304 + }
38.305 + }
38.306 + }
38.307 + }
38.308 +
38.309 + private static int getUnsignedByte(ByteBuffer buffer) {
38.310 + return buffer.get() & 0xFF;
38.311 + }
38.312 +
38.313 + private static int getUnsignedShort(ByteBuffer buffer) {
38.314 + int b1 = getUnsignedByte(buffer);
38.315 + int b2 = getUnsignedByte(buffer);
38.316 + return (b1 << 8) + (b2 << 0);
38.317 + }
38.318 +
38.319 + private static String getUTF8(ByteBuffer buffer, int utfLen, char[] charArray) throws InvalidConstantPoolFormatException {
38.320 + int utfLimit = buffer.position() + utfLen;
38.321 + int index = 0;
38.322 + while (buffer.position() < utfLimit) {
38.323 + int c = buffer.get() & 0xff;
38.324 + if (c > 127) {
38.325 + buffer.position(buffer.position() - 1);
38.326 + return getUTF8Extended(buffer, utfLimit, charArray, index);
38.327 + }
38.328 + charArray[index++] = (char)c;
38.329 + }
38.330 + return new String(charArray, 0, index);
38.331 + }
38.332 +
38.333 + private static String getUTF8Extended(ByteBuffer buffer, int utfLimit, char[] charArray, int index) throws InvalidConstantPoolFormatException {
38.334 + int c, c2, c3;
38.335 + while (buffer.position() < utfLimit) {
38.336 + c = buffer.get() & 0xff;
38.337 + switch (c >> 4) {
38.338 + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
38.339 + /* 0xxxxxxx*/
38.340 + charArray[index++] = (char)c;
38.341 + break;
38.342 + case 12: case 13:
38.343 + /* 110x xxxx 10xx xxxx*/
38.344 + c2 = buffer.get();
38.345 + if ((c2 & 0xC0) != 0x80)
38.346 + throw new InvalidConstantPoolFormatException(
38.347 + "malformed input around byte " + buffer.position());
38.348 + charArray[index++] = (char)(((c & 0x1F) << 6) |
38.349 + (c2 & 0x3F));
38.350 + break;
38.351 + case 14:
38.352 + /* 1110 xxxx 10xx xxxx 10xx xxxx */
38.353 + c2 = buffer.get();
38.354 + c3 = buffer.get();
38.355 + if (((c2 & 0xC0) != 0x80) || ((c3 & 0xC0) != 0x80))
38.356 + throw new InvalidConstantPoolFormatException(
38.357 + "malformed input around byte " + (buffer.position()));
38.358 + charArray[index++] = (char)(((c & 0x0F) << 12) |
38.359 + ((c2 & 0x3F) << 6) |
38.360 + ((c3 & 0x3F) << 0));
38.361 + break;
38.362 + default:
38.363 + /* 10xx xxxx, 1111 xxxx */
38.364 + throw new InvalidConstantPoolFormatException(
38.365 + "malformed input around byte " + buffer.position());
38.366 + }
38.367 + }
38.368 + // The number of chars produced may be less than utflen
38.369 + return new String(charArray, 0, index);
38.370 + }
38.371 +}
39.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
39.2 +++ b/rt/emul/compact/src/main/java/sun/invoke/anon/ConstantPoolPatch.java Sat Aug 09 11:12:05 2014 +0200
39.3 @@ -0,0 +1,503 @@
39.4 +/*
39.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
39.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
39.7 + *
39.8 + * This code is free software; you can redistribute it and/or modify it
39.9 + * under the terms of the GNU General Public License version 2 only, as
39.10 + * published by the Free Software Foundation. Oracle designates this
39.11 + * particular file as subject to the "Classpath" exception as provided
39.12 + * by Oracle in the LICENSE file that accompanied this code.
39.13 + *
39.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
39.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
39.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
39.17 + * version 2 for more details (a copy is included in the LICENSE file that
39.18 + * accompanied this code).
39.19 + *
39.20 + * You should have received a copy of the GNU General Public License version
39.21 + * 2 along with this work; if not, write to the Free Software Foundation,
39.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
39.23 + *
39.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
39.25 + * or visit www.oracle.com if you need additional information or have any
39.26 + * questions.
39.27 + */
39.28 +
39.29 +package sun.invoke.anon;
39.30 +
39.31 +import java.io.IOException;
39.32 +import java.io.OutputStream;
39.33 +import java.util.Arrays;
39.34 +import java.util.HashSet;
39.35 +import java.util.IdentityHashMap;
39.36 +import java.util.Map;
39.37 +
39.38 +import static sun.invoke.anon.ConstantPoolVisitor.*;
39.39 +
39.40 +/** A class and its patched constant pool.
39.41 + *
39.42 + * This class allow to modify (patch) a constant pool
39.43 + * by changing the value of its entry.
39.44 + * Entry are referenced using index that can be get
39.45 + * by parsing the constant pool using
39.46 + * {@link ConstantPoolParser#parse(ConstantPoolVisitor)}.
39.47 + *
39.48 + * @see ConstantPoolVisitor
39.49 + * @see ConstantPoolParser#createPatch()
39.50 + */
39.51 +public class ConstantPoolPatch {
39.52 + final ConstantPoolParser outer;
39.53 + final Object[] patchArray;
39.54 +
39.55 + ConstantPoolPatch(ConstantPoolParser outer) {
39.56 + this.outer = outer;
39.57 + this.patchArray = new Object[outer.getLength()];
39.58 + }
39.59 +
39.60 + /** Create a {@link ConstantPoolParser} and
39.61 + * a {@link ConstantPoolPatch} in one step.
39.62 + * Equivalent to {@code new ConstantPoolParser(classFile).createPatch()}.
39.63 + *
39.64 + * @param classFile an array of bytes containing a class.
39.65 + * @see #ConstantPoolParser(Class)
39.66 + */
39.67 + public ConstantPoolPatch(byte[] classFile) throws InvalidConstantPoolFormatException {
39.68 + this(new ConstantPoolParser(classFile));
39.69 + }
39.70 +
39.71 + /** Create a {@link ConstantPoolParser} and
39.72 + * a {@link ConstantPoolPatch} in one step.
39.73 + * Equivalent to {@code new ConstantPoolParser(templateClass).createPatch()}.
39.74 + *
39.75 + * @param templateClass the class to parse.
39.76 + * @see #ConstantPoolParser(Class)
39.77 + */
39.78 + public ConstantPoolPatch(Class<?> templateClass) throws IOException, InvalidConstantPoolFormatException {
39.79 + this(new ConstantPoolParser(templateClass));
39.80 + }
39.81 +
39.82 +
39.83 + /** Creates a patch from an existing patch.
39.84 + * All changes are copied from that patch.
39.85 + * @param patch a patch
39.86 + *
39.87 + * @see ConstantPoolParser#createPatch()
39.88 + */
39.89 + public ConstantPoolPatch(ConstantPoolPatch patch) {
39.90 + outer = patch.outer;
39.91 + patchArray = patch.patchArray.clone();
39.92 + }
39.93 +
39.94 + /** Which parser built this patch? */
39.95 + public ConstantPoolParser getParser() {
39.96 + return outer;
39.97 + }
39.98 +
39.99 + /** Report the tag at the given index in the constant pool. */
39.100 + public byte getTag(int index) {
39.101 + return outer.getTag(index);
39.102 + }
39.103 +
39.104 + /** Report the current patch at the given index of the constant pool.
39.105 + * Null means no patch will be made.
39.106 + * To observe the unpatched entry at the given index, use
39.107 + * {@link #getParser()}{@code .}@link ConstantPoolParser#parse(ConstantPoolVisitor)}
39.108 + */
39.109 + public Object getPatch(int index) {
39.110 + Object value = patchArray[index];
39.111 + if (value == null) return null;
39.112 + switch (getTag(index)) {
39.113 + case CONSTANT_Fieldref:
39.114 + case CONSTANT_Methodref:
39.115 + case CONSTANT_InterfaceMethodref:
39.116 + if (value instanceof String)
39.117 + value = stripSemis(2, (String) value);
39.118 + break;
39.119 + case CONSTANT_NameAndType:
39.120 + if (value instanceof String)
39.121 + value = stripSemis(1, (String) value);
39.122 + break;
39.123 + }
39.124 + return value;
39.125 + }
39.126 +
39.127 + /** Clear all patches. */
39.128 + public void clear() {
39.129 + Arrays.fill(patchArray, null);
39.130 + }
39.131 +
39.132 + /** Clear one patch. */
39.133 + public void clear(int index) {
39.134 + patchArray[index] = null;
39.135 + }
39.136 +
39.137 + /** Produce the patches as an array. */
39.138 + public Object[] getPatches() {
39.139 + return patchArray.clone();
39.140 + }
39.141 +
39.142 + /** Produce the original constant pool as an array. */
39.143 + public Object[] getOriginalCP() throws InvalidConstantPoolFormatException {
39.144 + return getOriginalCP(0, patchArray.length, -1);
39.145 + }
39.146 +
39.147 + /** Walk the constant pool, applying patches using the given map.
39.148 + *
39.149 + * @param utf8Map Utf8 strings to modify, if encountered
39.150 + * @param classMap Classes (or their names) to modify, if encountered
39.151 + * @param valueMap Constant values to modify, if encountered
39.152 + * @param deleteUsedEntries if true, delete map entries that are used
39.153 + */
39.154 + public void putPatches(final Map<String,String> utf8Map,
39.155 + final Map<String,Object> classMap,
39.156 + final Map<Object,Object> valueMap,
39.157 + boolean deleteUsedEntries) throws InvalidConstantPoolFormatException {
39.158 + final HashSet<String> usedUtf8Keys;
39.159 + final HashSet<String> usedClassKeys;
39.160 + final HashSet<Object> usedValueKeys;
39.161 + if (deleteUsedEntries) {
39.162 + usedUtf8Keys = (utf8Map == null) ? null : new HashSet<String>();
39.163 + usedClassKeys = (classMap == null) ? null : new HashSet<String>();
39.164 + usedValueKeys = (valueMap == null) ? null : new HashSet<Object>();
39.165 + } else {
39.166 + usedUtf8Keys = null;
39.167 + usedClassKeys = null;
39.168 + usedValueKeys = null;
39.169 + }
39.170 +
39.171 + outer.parse(new ConstantPoolVisitor() {
39.172 +
39.173 + @Override
39.174 + public void visitUTF8(int index, byte tag, String utf8) {
39.175 + putUTF8(index, utf8Map.get(utf8));
39.176 + if (usedUtf8Keys != null) usedUtf8Keys.add(utf8);
39.177 + }
39.178 +
39.179 + @Override
39.180 + public void visitConstantValue(int index, byte tag, Object value) {
39.181 + putConstantValue(index, tag, valueMap.get(value));
39.182 + if (usedValueKeys != null) usedValueKeys.add(value);
39.183 + }
39.184 +
39.185 + @Override
39.186 + public void visitConstantString(int index, byte tag, String name, int nameIndex) {
39.187 + if (tag == CONSTANT_Class) {
39.188 + putConstantValue(index, tag, classMap.get(name));
39.189 + if (usedClassKeys != null) usedClassKeys.add(name);
39.190 + } else {
39.191 + assert(tag == CONSTANT_String);
39.192 + visitConstantValue(index, tag, name);
39.193 + }
39.194 + }
39.195 + });
39.196 + if (usedUtf8Keys != null) utf8Map.keySet().removeAll(usedUtf8Keys);
39.197 + if (usedClassKeys != null) classMap.keySet().removeAll(usedClassKeys);
39.198 + if (usedValueKeys != null) valueMap.keySet().removeAll(usedValueKeys);
39.199 + }
39.200 +
39.201 + Object[] getOriginalCP(final int startIndex,
39.202 + final int endIndex,
39.203 + final int tagMask) throws InvalidConstantPoolFormatException {
39.204 + final Object[] cpArray = new Object[endIndex - startIndex];
39.205 + outer.parse(new ConstantPoolVisitor() {
39.206 +
39.207 + void show(int index, byte tag, Object value) {
39.208 + if (index < startIndex || index >= endIndex) return;
39.209 + if (((1 << tag) & tagMask) == 0) return;
39.210 + cpArray[index - startIndex] = value;
39.211 + }
39.212 +
39.213 + @Override
39.214 + public void visitUTF8(int index, byte tag, String utf8) {
39.215 + show(index, tag, utf8);
39.216 + }
39.217 +
39.218 + @Override
39.219 + public void visitConstantValue(int index, byte tag, Object value) {
39.220 + assert(tag != CONSTANT_String);
39.221 + show(index, tag, value);
39.222 + }
39.223 +
39.224 + @Override
39.225 + public void visitConstantString(int index, byte tag,
39.226 + String value, int j) {
39.227 + show(index, tag, value);
39.228 + }
39.229 +
39.230 + @Override
39.231 + public void visitMemberRef(int index, byte tag,
39.232 + String className, String memberName,
39.233 + String signature,
39.234 + int j, int k) {
39.235 + show(index, tag, new String[]{ className, memberName, signature });
39.236 + }
39.237 +
39.238 + @Override
39.239 + public void visitDescriptor(int index, byte tag,
39.240 + String memberName, String signature,
39.241 + int j, int k) {
39.242 + show(index, tag, new String[]{ memberName, signature });
39.243 + }
39.244 + });
39.245 + return cpArray;
39.246 + }
39.247 +
39.248 + /** Write the head (header plus constant pool)
39.249 + * of the patched class file to the indicated stream.
39.250 + */
39.251 + void writeHead(OutputStream out) throws IOException {
39.252 + outer.writePatchedHead(out, patchArray);
39.253 + }
39.254 +
39.255 + /** Write the tail (everything after the constant pool)
39.256 + * of the patched class file to the indicated stream.
39.257 + */
39.258 + void writeTail(OutputStream out) throws IOException {
39.259 + outer.writeTail(out);
39.260 + }
39.261 +
39.262 + private void checkConstantTag(byte tag, Object value) {
39.263 + if (value == null)
39.264 + throw new IllegalArgumentException(
39.265 + "invalid null constant value");
39.266 + if (classForTag(tag) != value.getClass())
39.267 + throw new IllegalArgumentException(
39.268 + "invalid constant value"
39.269 + + (tag == CONSTANT_None ? ""
39.270 + : " for tag "+tagName(tag))
39.271 + + " of class "+value.getClass());
39.272 + }
39.273 +
39.274 + private void checkTag(int index, byte putTag) {
39.275 + byte tag = outer.tags[index];
39.276 + if (tag != putTag)
39.277 + throw new IllegalArgumentException(
39.278 + "invalid put operation"
39.279 + + " for " + tagName(putTag)
39.280 + + " at index " + index + " found " + tagName(tag));
39.281 + }
39.282 +
39.283 + private void checkTagMask(int index, int tagBitMask) {
39.284 + byte tag = outer.tags[index];
39.285 + int tagBit = ((tag & 0x1F) == tag) ? (1 << tag) : 0;
39.286 + if ((tagBit & tagBitMask) == 0)
39.287 + throw new IllegalArgumentException(
39.288 + "invalid put operation"
39.289 + + " at index " + index + " found " + tagName(tag));
39.290 + }
39.291 +
39.292 + private static void checkMemberName(String memberName) {
39.293 + if (memberName.indexOf(';') >= 0)
39.294 + throw new IllegalArgumentException("memberName " + memberName + " contains a ';'");
39.295 + }
39.296 +
39.297 + /** Set the entry of the constant pool indexed by index to
39.298 + * a new string.
39.299 + *
39.300 + * @param index an index to a constant pool entry containing a
39.301 + * {@link ConstantPoolVisitor#CONSTANT_Utf8} value.
39.302 + * @param utf8 a string
39.303 + *
39.304 + * @see ConstantPoolVisitor#visitUTF8(int, byte, String)
39.305 + */
39.306 + public void putUTF8(int index, String utf8) {
39.307 + if (utf8 == null) { clear(index); return; }
39.308 + checkTag(index, CONSTANT_Utf8);
39.309 + patchArray[index] = utf8;
39.310 + }
39.311 +
39.312 + /** Set the entry of the constant pool indexed by index to
39.313 + * a new value, depending on its dynamic type.
39.314 + *
39.315 + * @param index an index to a constant pool entry containing a
39.316 + * one of the following structures:
39.317 + * {@link ConstantPoolVisitor#CONSTANT_Integer},
39.318 + * {@link ConstantPoolVisitor#CONSTANT_Float},
39.319 + * {@link ConstantPoolVisitor#CONSTANT_Long},
39.320 + * {@link ConstantPoolVisitor#CONSTANT_Double},
39.321 + * {@link ConstantPoolVisitor#CONSTANT_String}, or
39.322 + * {@link ConstantPoolVisitor#CONSTANT_Class}
39.323 + * @param value a boxed int, float, long or double; or a string or class object
39.324 + * @throws IllegalArgumentException if the type of the constant does not
39.325 + * match the constant pool entry type,
39.326 + * as reported by {@link #getTag(int)}
39.327 + *
39.328 + * @see #putConstantValue(int, byte, Object)
39.329 + * @see ConstantPoolVisitor#visitConstantValue(int, byte, Object)
39.330 + * @see ConstantPoolVisitor#visitConstantString(int, byte, String, int)
39.331 + */
39.332 + public void putConstantValue(int index, Object value) {
39.333 + if (value == null) { clear(index); return; }
39.334 + byte tag = tagForConstant(value.getClass());
39.335 + checkConstantTag(tag, value);
39.336 + checkTag(index, tag);
39.337 + patchArray[index] = value;
39.338 + }
39.339 +
39.340 + /** Set the entry of the constant pool indexed by index to
39.341 + * a new value.
39.342 + *
39.343 + * @param index an index to a constant pool entry matching the given tag
39.344 + * @param tag one of the following values:
39.345 + * {@link ConstantPoolVisitor#CONSTANT_Integer},
39.346 + * {@link ConstantPoolVisitor#CONSTANT_Float},
39.347 + * {@link ConstantPoolVisitor#CONSTANT_Long},
39.348 + * {@link ConstantPoolVisitor#CONSTANT_Double},
39.349 + * {@link ConstantPoolVisitor#CONSTANT_String}, or
39.350 + * {@link ConstantPoolVisitor#CONSTANT_Class}
39.351 + * @param value a boxed number, string, or class object
39.352 + * @throws IllegalArgumentException if the type of the constant does not
39.353 + * match the constant pool entry type, or if a class name contains
39.354 + * '/' or ';'
39.355 + *
39.356 + * @see #putConstantValue(int, Object)
39.357 + * @see ConstantPoolVisitor#visitConstantValue(int, byte, Object)
39.358 + * @see ConstantPoolVisitor#visitConstantString(int, byte, String, int)
39.359 + */
39.360 + public void putConstantValue(int index, byte tag, Object value) {
39.361 + if (value == null) { clear(index); return; }
39.362 + checkTag(index, tag);
39.363 + if (tag == CONSTANT_Class && value instanceof String) {
39.364 + checkClassName((String) value);
39.365 + } else if (tag == CONSTANT_String) {
39.366 + // the JVM accepts any object as a patch for a string
39.367 + } else {
39.368 + // make sure the incoming value is the right type
39.369 + checkConstantTag(tag, value);
39.370 + }
39.371 + checkTag(index, tag);
39.372 + patchArray[index] = value;
39.373 + }
39.374 +
39.375 + /** Set the entry of the constant pool indexed by index to
39.376 + * a new {@link ConstantPoolVisitor#CONSTANT_NameAndType} value.
39.377 + *
39.378 + * @param index an index to a constant pool entry containing a
39.379 + * {@link ConstantPoolVisitor#CONSTANT_NameAndType} value.
39.380 + * @param memberName a memberName
39.381 + * @param signature a signature
39.382 + * @throws IllegalArgumentException if memberName contains the character ';'
39.383 + *
39.384 + * @see ConstantPoolVisitor#visitDescriptor(int, byte, String, String, int, int)
39.385 + */
39.386 + public void putDescriptor(int index, String memberName, String signature) {
39.387 + checkTag(index, CONSTANT_NameAndType);
39.388 + checkMemberName(memberName);
39.389 + patchArray[index] = addSemis(memberName, signature);
39.390 + }
39.391 +
39.392 + /** Set the entry of the constant pool indexed by index to
39.393 + * a new {@link ConstantPoolVisitor#CONSTANT_Fieldref},
39.394 + * {@link ConstantPoolVisitor#CONSTANT_Methodref}, or
39.395 + * {@link ConstantPoolVisitor#CONSTANT_InterfaceMethodref} value.
39.396 + *
39.397 + * @param index an index to a constant pool entry containing a member reference
39.398 + * @param className a class name
39.399 + * @param memberName a field or method name
39.400 + * @param signature a field or method signature
39.401 + * @throws IllegalArgumentException if memberName contains the character ';'
39.402 + * or signature is not a correct signature
39.403 + *
39.404 + * @see ConstantPoolVisitor#visitMemberRef(int, byte, String, String, String, int, int)
39.405 + */
39.406 + public void putMemberRef(int index, byte tag,
39.407 + String className, String memberName, String signature) {
39.408 + checkTagMask(tag, CONSTANT_MemberRef_MASK);
39.409 + checkTag(index, tag);
39.410 + checkClassName(className);
39.411 + checkMemberName(memberName);
39.412 + if (signature.startsWith("(") == (tag == CONSTANT_Fieldref))
39.413 + throw new IllegalArgumentException("bad signature: "+signature);
39.414 + patchArray[index] = addSemis(className, memberName, signature);
39.415 + }
39.416 +
39.417 + static private final int CONSTANT_MemberRef_MASK =
39.418 + CONSTANT_Fieldref
39.419 + | CONSTANT_Methodref
39.420 + | CONSTANT_InterfaceMethodref;
39.421 +
39.422 + private static final Map<Class<?>, Byte> CONSTANT_VALUE_CLASS_TAG
39.423 + = new IdentityHashMap<Class<?>, Byte>();
39.424 + private static final Class<?>[] CONSTANT_VALUE_CLASS = new Class<?>[16];
39.425 + static {
39.426 + Object[][] values = {
39.427 + {Integer.class, CONSTANT_Integer},
39.428 + {Long.class, CONSTANT_Long},
39.429 + {Float.class, CONSTANT_Float},
39.430 + {Double.class, CONSTANT_Double},
39.431 + {String.class, CONSTANT_String},
39.432 + {Class.class, CONSTANT_Class}
39.433 + };
39.434 + for (Object[] value : values) {
39.435 + Class<?> cls = (Class<?>)value[0];
39.436 + Byte tag = (Byte) value[1];
39.437 + CONSTANT_VALUE_CLASS_TAG.put(cls, tag);
39.438 + CONSTANT_VALUE_CLASS[(byte)tag] = cls;
39.439 + }
39.440 + }
39.441 +
39.442 + static Class<?> classForTag(byte tag) {
39.443 + if ((tag & 0xFF) >= CONSTANT_VALUE_CLASS.length)
39.444 + return null;
39.445 + return CONSTANT_VALUE_CLASS[tag];
39.446 + }
39.447 +
39.448 + static byte tagForConstant(Class<?> cls) {
39.449 + Byte tag = CONSTANT_VALUE_CLASS_TAG.get(cls);
39.450 + return (tag == null) ? CONSTANT_None : (byte)tag;
39.451 + }
39.452 +
39.453 + private static void checkClassName(String className) {
39.454 + if (className.indexOf('/') >= 0 || className.indexOf(';') >= 0)
39.455 + throw new IllegalArgumentException("invalid class name " + className);
39.456 + }
39.457 +
39.458 + static String addSemis(String name, String... names) {
39.459 + StringBuilder buf = new StringBuilder(name.length() * 5);
39.460 + buf.append(name);
39.461 + for (String name2 : names) {
39.462 + buf.append(';').append(name2);
39.463 + }
39.464 + String res = buf.toString();
39.465 + assert(stripSemis(names.length, res)[0].equals(name));
39.466 + assert(stripSemis(names.length, res)[1].equals(names[0]));
39.467 + assert(names.length == 1 ||
39.468 + stripSemis(names.length, res)[2].equals(names[1]));
39.469 + return res;
39.470 + }
39.471 +
39.472 + static String[] stripSemis(int count, String string) {
39.473 + String[] res = new String[count+1];
39.474 + int pos = 0;
39.475 + for (int i = 0; i < count; i++) {
39.476 + int pos2 = string.indexOf(';', pos);
39.477 + if (pos2 < 0) pos2 = string.length(); // yuck
39.478 + res[i] = string.substring(pos, pos2);
39.479 + pos = pos2;
39.480 + }
39.481 + res[count] = string.substring(pos);
39.482 + return res;
39.483 + }
39.484 +
39.485 + public String toString() {
39.486 + StringBuilder buf = new StringBuilder(this.getClass().getName());
39.487 + buf.append("{");
39.488 + Object[] origCP = null;
39.489 + for (int i = 0; i < patchArray.length; i++) {
39.490 + if (patchArray[i] == null) continue;
39.491 + if (origCP != null) {
39.492 + buf.append(", ");
39.493 + } else {
39.494 + try {
39.495 + origCP = getOriginalCP();
39.496 + } catch (InvalidConstantPoolFormatException ee) {
39.497 + origCP = new Object[0];
39.498 + }
39.499 + }
39.500 + Object orig = (i < origCP.length) ? origCP[i] : "?";
39.501 + buf.append(orig).append("=").append(patchArray[i]);
39.502 + }
39.503 + buf.append("}");
39.504 + return buf.toString();
39.505 + }
39.506 +}
40.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
40.2 +++ b/rt/emul/compact/src/main/java/sun/invoke/anon/ConstantPoolVisitor.java Sat Aug 09 11:12:05 2014 +0200
40.3 @@ -0,0 +1,192 @@
40.4 +/*
40.5 + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
40.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
40.7 + *
40.8 + * This code is free software; you can redistribute it and/or modify it
40.9 + * under the terms of the GNU General Public License version 2 only, as
40.10 + * published by the Free Software Foundation. Oracle designates this
40.11 + * particular file as subject to the "Classpath" exception as provided
40.12 + * by Oracle in the LICENSE file that accompanied this code.
40.13 + *
40.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
40.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
40.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
40.17 + * version 2 for more details (a copy is included in the LICENSE file that
40.18 + * accompanied this code).
40.19 + *
40.20 + * You should have received a copy of the GNU General Public License version
40.21 + * 2 along with this work; if not, write to the Free Software Foundation,
40.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
40.23 + *
40.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
40.25 + * or visit www.oracle.com if you need additional information or have any
40.26 + * questions.
40.27 + */
40.28 +
40.29 +package sun.invoke.anon;
40.30 +
40.31 +/**
40.32 + * A visitor called by {@link ConstantPoolParser#parse(ConstantPoolVisitor)}
40.33 + * when a constant pool entry is parsed.
40.34 + * <p>
40.35 + * A visit* method is called when a constant pool entry is parsed.
40.36 + * The first argument is always the constant pool index.
40.37 + * The second argument is always the constant pool tag,
40.38 + * even for methods like {@link #visitUTF8(int, byte, String)} which only apply to one tag.
40.39 + * String arguments refer to Utf8 or NameAndType entries declared elsewhere,
40.40 + * and are always accompanied by the indexes of those entries.
40.41 + * <p>
40.42 + * The order of the calls to the visit* methods is not necessarily related
40.43 + * to the order of the entries in the constant pool.
40.44 + * If one entry has a reference to another entry, the latter (lower-level)
40.45 + * entry will be visited first.
40.46 + * <p>
40.47 + * The following table shows the relation between constant pool entry
40.48 + * types and the corresponding visit* methods:
40.49 + *
40.50 + * <table border=1 cellpadding=5 summary="constant pool visitor methods">
40.51 + * <tr><th>Tag(s)</th><th>Method</th></tr>
40.52 + * <tr>
40.53 + * <td>{@link #CONSTANT_Utf8}</td>
40.54 + * <td>{@link #visitUTF8(int, byte, String)}</td>
40.55 + * </tr><tr>
40.56 + * <td>{@link #CONSTANT_Integer}, {@link #CONSTANT_Float},
40.57 + * {@link #CONSTANT_Long}, {@link #CONSTANT_Double}</td>
40.58 + * <td>{@link #visitConstantValue(int, byte, Object)}</td>
40.59 + * </tr><tr>
40.60 + * <td>{@link #CONSTANT_String}, {@link #CONSTANT_Class}</td>
40.61 + * <td>{@link #visitConstantString(int, byte, String, int)}</td>
40.62 + * </tr><tr>
40.63 + * <td>{@link #CONSTANT_NameAndType}</td>
40.64 + * <td>{@link #visitDescriptor(int, byte, String, String, int, int)}</td>
40.65 + * </tr><tr>
40.66 + * <td>{@link #CONSTANT_Fieldref},
40.67 + * {@link #CONSTANT_Methodref},
40.68 + * {@link #CONSTANT_InterfaceMethodref}</td>
40.69 + * <td>{@link #visitMemberRef(int, byte, String, String, String, int, int)}</td>
40.70 + * </tr>
40.71 + * </table>
40.72 + *
40.73 + * @see ConstantPoolPatch
40.74 + * @author Remi Forax
40.75 + * @author jrose
40.76 + */
40.77 +public class ConstantPoolVisitor {
40.78 + /** Called each time an UTF8 constant pool entry is found.
40.79 + * @param index the constant pool index
40.80 + * @param tag always {@link #CONSTANT_Utf8}
40.81 + * @param utf8 string encoded in modified UTF-8 format passed as a {@code String}
40.82 + *
40.83 + * @see ConstantPoolPatch#putUTF8(int, String)
40.84 + */
40.85 + public void visitUTF8(int index, byte tag, String utf8) {
40.86 + // do nothing
40.87 + }
40.88 +
40.89 + /** Called for each constant pool entry that encodes an integer,
40.90 + * a float, a long, or a double.
40.91 + * Constant strings and classes are not managed by this method but
40.92 + * by {@link #visitConstantString(int, byte, String, int)}.
40.93 + *
40.94 + * @param index the constant pool index
40.95 + * @param tag one of {@link #CONSTANT_Integer},
40.96 + * {@link #CONSTANT_Float},
40.97 + * {@link #CONSTANT_Long},
40.98 + * or {@link #CONSTANT_Double}
40.99 + * @param value encoded value
40.100 + *
40.101 + * @see ConstantPoolPatch#putConstantValue(int, Object)
40.102 + */
40.103 + public void visitConstantValue(int index, byte tag, Object value) {
40.104 + // do nothing
40.105 + }
40.106 +
40.107 + /** Called for each constant pool entry that encodes a string or a class.
40.108 + * @param index the constant pool index
40.109 + * @param tag one of {@link #CONSTANT_String},
40.110 + * {@link #CONSTANT_Class},
40.111 + * @param name string body or class name (using dot separator)
40.112 + * @param nameIndex the index of the Utf8 string for the name
40.113 + *
40.114 + * @see ConstantPoolPatch#putConstantValue(int, byte, Object)
40.115 + */
40.116 + public void visitConstantString(int index, byte tag,
40.117 + String name, int nameIndex) {
40.118 + // do nothing
40.119 + }
40.120 +
40.121 + /** Called for each constant pool entry that encodes a name and type.
40.122 + * @param index the constant pool index
40.123 + * @param tag always {@link #CONSTANT_NameAndType}
40.124 + * @param memberName a field or method name
40.125 + * @param signature the member signature
40.126 + * @param memberNameIndex index of the Utf8 string for the member name
40.127 + * @param signatureIndex index of the Utf8 string for the signature
40.128 + *
40.129 + * @see ConstantPoolPatch#putDescriptor(int, String, String)
40.130 + */
40.131 + public void visitDescriptor(int index, byte tag,
40.132 + String memberName, String signature,
40.133 + int memberNameIndex, int signatureIndex) {
40.134 + // do nothing
40.135 + }
40.136 +
40.137 + /** Called for each constant pool entry that encodes a field or method.
40.138 + * @param index the constant pool index
40.139 + * @param tag one of {@link #CONSTANT_Fieldref},
40.140 + * or {@link #CONSTANT_Methodref},
40.141 + * or {@link #CONSTANT_InterfaceMethodref}
40.142 + * @param className the class name (using dot separator)
40.143 + * @param memberName name of the field or method
40.144 + * @param signature the field or method signature
40.145 + * @param classNameIndex index of the Utf8 string for the class name
40.146 + * @param descriptorIndex index of the NameAndType descriptor constant
40.147 + *
40.148 + * @see ConstantPoolPatch#putMemberRef(int, byte, String, String, String)
40.149 + */
40.150 + public void visitMemberRef(int index, byte tag,
40.151 + String className, String memberName, String signature,
40.152 + int classNameIndex, int descriptorIndex) {
40.153 + // do nothing
40.154 + }
40.155 +
40.156 + public static final byte
40.157 + CONSTANT_None = 0,
40.158 + CONSTANT_Utf8 = 1,
40.159 + //CONSTANT_Unicode = 2, /* unused */
40.160 + CONSTANT_Integer = 3,
40.161 + CONSTANT_Float = 4,
40.162 + CONSTANT_Long = 5,
40.163 + CONSTANT_Double = 6,
40.164 + CONSTANT_Class = 7,
40.165 + CONSTANT_String = 8,
40.166 + CONSTANT_Fieldref = 9,
40.167 + CONSTANT_Methodref = 10,
40.168 + CONSTANT_InterfaceMethodref = 11,
40.169 + CONSTANT_NameAndType = 12;
40.170 +
40.171 + private static String[] TAG_NAMES = {
40.172 + "Empty",
40.173 + "Utf8",
40.174 + null, //"Unicode",
40.175 + "Integer",
40.176 + "Float",
40.177 + "Long",
40.178 + "Double",
40.179 + "Class",
40.180 + "String",
40.181 + "Fieldref",
40.182 + "Methodref",
40.183 + "InterfaceMethodref",
40.184 + "NameAndType"
40.185 + };
40.186 +
40.187 + public static String tagName(byte tag) {
40.188 + String name = null;
40.189 + if ((tag & 0xFF) < TAG_NAMES.length)
40.190 + name = TAG_NAMES[tag];
40.191 + if (name == null)
40.192 + name = "Unknown#"+(tag&0xFF);
40.193 + return name;
40.194 + }
40.195 +}
41.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
41.2 +++ b/rt/emul/compact/src/main/java/sun/invoke/anon/InvalidConstantPoolFormatException.java Sat Aug 09 11:12:05 2014 +0200
41.3 @@ -0,0 +1,45 @@
41.4 +/*
41.5 + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
41.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
41.7 + *
41.8 + * This code is free software; you can redistribute it and/or modify it
41.9 + * under the terms of the GNU General Public License version 2 only, as
41.10 + * published by the Free Software Foundation. Oracle designates this
41.11 + * particular file as subject to the "Classpath" exception as provided
41.12 + * by Oracle in the LICENSE file that accompanied this code.
41.13 + *
41.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
41.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
41.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
41.17 + * version 2 for more details (a copy is included in the LICENSE file that
41.18 + * accompanied this code).
41.19 + *
41.20 + * You should have received a copy of the GNU General Public License version
41.21 + * 2 along with this work; if not, write to the Free Software Foundation,
41.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
41.23 + *
41.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
41.25 + * or visit www.oracle.com if you need additional information or have any
41.26 + * questions.
41.27 + */
41.28 +
41.29 +package sun.invoke.anon;
41.30 +
41.31 +/** Exception used when there is an error in the constant pool
41.32 + * format.
41.33 + */
41.34 +public class InvalidConstantPoolFormatException extends Exception {
41.35 + private static final long serialVersionUID=-6103888330523770949L;
41.36 +
41.37 + public InvalidConstantPoolFormatException(String message,Throwable cause) {
41.38 + super(message,cause);
41.39 + }
41.40 +
41.41 + public InvalidConstantPoolFormatException(String message) {
41.42 + super(message);
41.43 + }
41.44 +
41.45 + public InvalidConstantPoolFormatException(Throwable cause) {
41.46 + super(cause);
41.47 + }
41.48 +}
42.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
42.2 +++ b/rt/emul/compact/src/main/java/sun/invoke/empty/Empty.java Sat Aug 09 11:12:05 2014 +0200
42.3 @@ -0,0 +1,40 @@
42.4 +/*
42.5 + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
42.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
42.7 + *
42.8 + * This code is free software; you can redistribute it and/or modify it
42.9 + * under the terms of the GNU General Public License version 2 only, as
42.10 + * published by the Free Software Foundation. Oracle designates this
42.11 + * particular file as subject to the "Classpath" exception as provided
42.12 + * by Oracle in the LICENSE file that accompanied this code.
42.13 + *
42.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
42.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
42.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
42.17 + * version 2 for more details (a copy is included in the LICENSE file that
42.18 + * accompanied this code).
42.19 + *
42.20 + * You should have received a copy of the GNU General Public License version
42.21 + * 2 along with this work; if not, write to the Free Software Foundation,
42.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
42.23 + *
42.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
42.25 + * or visit www.oracle.com if you need additional information or have any
42.26 + * questions.
42.27 + */
42.28 +
42.29 +package sun.invoke.empty;
42.30 +
42.31 +/**
42.32 + * An empty class in an empty package.
42.33 + * Used as a proxy for unprivileged code, since making access checks
42.34 + * against it will only succeed against public methods in public types.
42.35 + * <p>
42.36 + * This class also stands (internally to sun.invoke) for the type of a
42.37 + * value that cannot be produced, because the expression of this type
42.38 + * always returns abnormally. (Cf. Nothing in the closures proposal.)
42.39 + * @author jrose
42.40 + */
42.41 +public class Empty {
42.42 + private Empty() { throw new InternalError(); }
42.43 +}
43.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
43.2 +++ b/rt/emul/compact/src/main/java/sun/invoke/package-info.java Sat Aug 09 11:12:05 2014 +0200
43.3 @@ -0,0 +1,31 @@
43.4 +/*
43.5 + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
43.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
43.7 + *
43.8 + * This code is free software; you can redistribute it and/or modify it
43.9 + * under the terms of the GNU General Public License version 2 only, as
43.10 + * published by the Free Software Foundation. Oracle designates this
43.11 + * particular file as subject to the "Classpath" exception as provided
43.12 + * by Oracle in the LICENSE file that accompanied this code.
43.13 + *
43.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
43.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
43.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
43.17 + * version 2 for more details (a copy is included in the LICENSE file that
43.18 + * accompanied this code).
43.19 + *
43.20 + * You should have received a copy of the GNU General Public License version
43.21 + * 2 along with this work; if not, write to the Free Software Foundation,
43.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
43.23 + *
43.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
43.25 + * or visit www.oracle.com if you need additional information or have any
43.26 + * questions.
43.27 + */
43.28 +
43.29 +/**
43.30 + * Implementation details for JSR 292 RI, package java.lang.invoke.
43.31 + * @author jrose
43.32 + */
43.33 +
43.34 +package sun.invoke;
44.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
44.2 +++ b/rt/emul/compact/src/main/java/sun/invoke/util/BytecodeDescriptor.java Sat Aug 09 11:12:05 2014 +0200
44.3 @@ -0,0 +1,137 @@
44.4 +/*
44.5 + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
44.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44.7 + *
44.8 + * This code is free software; you can redistribute it and/or modify it
44.9 + * under the terms of the GNU General Public License version 2 only, as
44.10 + * published by the Free Software Foundation. Oracle designates this
44.11 + * particular file as subject to the "Classpath" exception as provided
44.12 + * by Oracle in the LICENSE file that accompanied this code.
44.13 + *
44.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
44.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
44.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
44.17 + * version 2 for more details (a copy is included in the LICENSE file that
44.18 + * accompanied this code).
44.19 + *
44.20 + * You should have received a copy of the GNU General Public License version
44.21 + * 2 along with this work; if not, write to the Free Software Foundation,
44.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
44.23 + *
44.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
44.25 + * or visit www.oracle.com if you need additional information or have any
44.26 + * questions.
44.27 + */
44.28 +
44.29 +package sun.invoke.util;
44.30 +
44.31 +import java.lang.invoke.MethodType;
44.32 +import java.util.ArrayList;
44.33 +import java.util.List;
44.34 +
44.35 +/**
44.36 + * Utility routines for dealing with bytecode-level signatures.
44.37 + * @author jrose
44.38 + */
44.39 +public class BytecodeDescriptor {
44.40 +
44.41 + private BytecodeDescriptor() { } // cannot instantiate
44.42 +
44.43 + public static List<Class<?>> parseMethod(String bytecodeSignature, ClassLoader loader) {
44.44 + return parseMethod(bytecodeSignature, 0, bytecodeSignature.length(), loader);
44.45 + }
44.46 +
44.47 + static List<Class<?>> parseMethod(String bytecodeSignature,
44.48 + int start, int end, ClassLoader loader) {
44.49 + if (loader == null)
44.50 + loader = ClassLoader.getSystemClassLoader();
44.51 + String str = bytecodeSignature;
44.52 + int[] i = {start};
44.53 + ArrayList<Class<?>> ptypes = new ArrayList<Class<?>>();
44.54 + if (i[0] < end && str.charAt(i[0]) == '(') {
44.55 + ++i[0]; // skip '('
44.56 + while (i[0] < end && str.charAt(i[0]) != ')') {
44.57 + Class<?> pt = parseSig(str, i, end, loader);
44.58 + if (pt == null || pt == void.class)
44.59 + parseError(str, "bad argument type");
44.60 + ptypes.add(pt);
44.61 + }
44.62 + ++i[0]; // skip ')'
44.63 + } else {
44.64 + parseError(str, "not a method type");
44.65 + }
44.66 + Class<?> rtype = parseSig(str, i, end, loader);
44.67 + if (rtype == null || i[0] != end)
44.68 + parseError(str, "bad return type");
44.69 + ptypes.add(rtype);
44.70 + return ptypes;
44.71 + }
44.72 +
44.73 + static private void parseError(String str, String msg) {
44.74 + throw new IllegalArgumentException("bad signature: "+str+": "+msg);
44.75 + }
44.76 +
44.77 + static private Class<?> parseSig(String str, int[] i, int end, ClassLoader loader) {
44.78 + if (i[0] == end) return null;
44.79 + char c = str.charAt(i[0]++);
44.80 + if (c == 'L') {
44.81 + int begc = i[0], endc = str.indexOf(';', begc);
44.82 + if (endc < 0) return null;
44.83 + i[0] = endc+1;
44.84 + String name = str.substring(begc, endc).replace('/', '.');
44.85 + try {
44.86 + return loader.loadClass(name);
44.87 + } catch (ClassNotFoundException ex) {
44.88 + throw new TypeNotPresentException(name, ex);
44.89 + }
44.90 + } else if (c == '[') {
44.91 + Class<?> t = parseSig(str, i, end, loader);
44.92 + if (t != null)
44.93 + t = java.lang.reflect.Array.newInstance(t, 0).getClass();
44.94 + return t;
44.95 + } else {
44.96 + return Wrapper.forBasicType(c).primitiveType();
44.97 + }
44.98 + }
44.99 +
44.100 + public static String unparse(Class<?> type) {
44.101 + StringBuilder sb = new StringBuilder();
44.102 + unparseSig(type, sb);
44.103 + return sb.toString();
44.104 + }
44.105 +
44.106 + public static String unparse(MethodType type) {
44.107 + return unparseMethod(type.returnType(), type.parameterList());
44.108 + }
44.109 +
44.110 + public static String unparse(Object type) {
44.111 + if (type instanceof Class<?>)
44.112 + return unparse((Class<?>) type);
44.113 + if (type instanceof MethodType)
44.114 + return unparse((MethodType) type);
44.115 + return (String) type;
44.116 + }
44.117 +
44.118 + public static String unparseMethod(Class<?> rtype, List<Class<?>> ptypes) {
44.119 + StringBuilder sb = new StringBuilder();
44.120 + sb.append('(');
44.121 + for (Class<?> pt : ptypes)
44.122 + unparseSig(pt, sb);
44.123 + sb.append(')');
44.124 + unparseSig(rtype, sb);
44.125 + return sb.toString();
44.126 + }
44.127 +
44.128 + static private void unparseSig(Class<?> t, StringBuilder sb) {
44.129 + char c = Wrapper.forBasicType(t).basicTypeChar();
44.130 + if (c != 'L') {
44.131 + sb.append(c);
44.132 + } else {
44.133 + boolean lsemi = (!t.isArray());
44.134 + if (lsemi) sb.append('L');
44.135 + sb.append(t.getName().replace('.', '/'));
44.136 + if (lsemi) sb.append(';');
44.137 + }
44.138 + }
44.139 +
44.140 +}
45.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
45.2 +++ b/rt/emul/compact/src/main/java/sun/invoke/util/BytecodeName.java Sat Aug 09 11:12:05 2014 +0200
45.3 @@ -0,0 +1,627 @@
45.4 +/*
45.5 + * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
45.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
45.7 + *
45.8 + * This code is free software; you can redistribute it and/or modify it
45.9 + * under the terms of the GNU General Public License version 2 only, as
45.10 + * published by the Free Software Foundation. Oracle designates this
45.11 + * particular file as subject to the "Classpath" exception as provided
45.12 + * by Oracle in the LICENSE file that accompanied this code.
45.13 + *
45.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
45.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
45.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
45.17 + * version 2 for more details (a copy is included in the LICENSE file that
45.18 + * accompanied this code).
45.19 + *
45.20 + * You should have received a copy of the GNU General Public License version
45.21 + * 2 along with this work; if not, write to the Free Software Foundation,
45.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
45.23 + *
45.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
45.25 + * or visit www.oracle.com if you need additional information or have any
45.26 + * questions.
45.27 + */
45.28 +
45.29 +package sun.invoke.util;
45.30 +
45.31 +/**
45.32 + * Utility routines for dealing with bytecode-level names.
45.33 + * Includes universal mangling rules for the JVM.
45.34 + *
45.35 + * <h3>Avoiding Dangerous Characters </h3>
45.36 + *
45.37 + * <p>
45.38 + * The JVM defines a very small set of characters which are illegal
45.39 + * in name spellings. We will slightly extend and regularize this set
45.40 + * into a group of <cite>dangerous characters</cite>.
45.41 + * These characters will then be replaced, in mangled names, by escape sequences.
45.42 + * In addition, accidental escape sequences must be further escaped.
45.43 + * Finally, a special prefix will be applied if and only if
45.44 + * the mangling would otherwise fail to begin with the escape character.
45.45 + * This happens to cover the corner case of the null string,
45.46 + * and also clearly marks symbols which need demangling.
45.47 + * </p>
45.48 + * <p>
45.49 + * Dangerous characters are the union of all characters forbidden
45.50 + * or otherwise restricted by the JVM specification,
45.51 + * plus their mates, if they are brackets
45.52 + * (<code><big><b>[</b></big></code> and <code><big><b>]</b></big></code>,
45.53 + * <code><big><b><</b></big></code> and <code><big><b>></b></big></code>),
45.54 + * plus, arbitrarily, the colon character <code><big><b>:</b></big></code>.
45.55 + * There is no distinction between type, method, and field names.
45.56 + * This makes it easier to convert between mangled names of different
45.57 + * types, since they do not need to be decoded (demangled).
45.58 + * </p>
45.59 + * <p>
45.60 + * The escape character is backslash <code><big><b>\</b></big></code>
45.61 + * (also known as reverse solidus).
45.62 + * This character is, until now, unheard of in bytecode names,
45.63 + * but traditional in the proposed role.
45.64 + *
45.65 + * </p>
45.66 + * <h3> Replacement Characters </h3>
45.67 + *
45.68 + *
45.69 + * <p>
45.70 + * Every escape sequence is two characters
45.71 + * (in fact, two UTF8 bytes) beginning with
45.72 + * the escape character and followed by a
45.73 + * <cite>replacement character</cite>.
45.74 + * (Since the replacement character is never a backslash,
45.75 + * iterated manglings do not double in size.)
45.76 + * </p>
45.77 + * <p>
45.78 + * Each dangerous character has some rough visual similarity
45.79 + * to its corresponding replacement character.
45.80 + * This makes mangled symbols easier to recognize by sight.
45.81 + * </p>
45.82 + * <p>
45.83 + * The dangerous characters are
45.84 + * <code><big><b>/</b></big></code> (forward slash, used to delimit package components),
45.85 + * <code><big><b>.</b></big></code> (dot, also a package delimiter),
45.86 + * <code><big><b>;</b></big></code> (semicolon, used in signatures),
45.87 + * <code><big><b>$</b></big></code> (dollar, used in inner classes and synthetic members),
45.88 + * <code><big><b><</b></big></code> (left angle),
45.89 + * <code><big><b>></b></big></code> (right angle),
45.90 + * <code><big><b>[</b></big></code> (left square bracket, used in array types),
45.91 + * <code><big><b>]</b></big></code> (right square bracket, reserved in this scheme for language use),
45.92 + * and <code><big><b>:</b></big></code> (colon, reserved in this scheme for language use).
45.93 + * Their replacements are, respectively,
45.94 + * <code><big><b>|</b></big></code> (vertical bar),
45.95 + * <code><big><b>,</b></big></code> (comma),
45.96 + * <code><big><b>?</b></big></code> (question mark),
45.97 + * <code><big><b>%</b></big></code> (percent),
45.98 + * <code><big><b>^</b></big></code> (caret),
45.99 + * <code><big><b>_</b></big></code> (underscore), and
45.100 + * <code><big><b>{</b></big></code> (left curly bracket),
45.101 + * <code><big><b>}</b></big></code> (right curly bracket),
45.102 + * <code><big><b>!</b></big></code> (exclamation mark).
45.103 + * In addition, the replacement character for the escape character itself is
45.104 + * <code><big><b>-</b></big></code> (hyphen),
45.105 + * and the replacement character for the null prefix is
45.106 + * <code><big><b>=</b></big></code> (equal sign).
45.107 + * </p>
45.108 + * <p>
45.109 + * An escape character <code><big><b>\</b></big></code>
45.110 + * followed by any of these replacement characters
45.111 + * is an escape sequence, and there are no other escape sequences.
45.112 + * An equal sign is only part of an escape sequence
45.113 + * if it is the second character in the whole string, following a backslash.
45.114 + * Two consecutive backslashes do <em>not</em> form an escape sequence.
45.115 + * </p>
45.116 + * <p>
45.117 + * Each escape sequence replaces a so-called <cite>original character</cite>
45.118 + * which is either one of the dangerous characters or the escape character.
45.119 + * A null prefix replaces an initial null string, not a character.
45.120 + * </p>
45.121 + * <p>
45.122 + * All this implies that escape sequences cannot overlap and may be
45.123 + * determined all at once for a whole string. Note that a spelling
45.124 + * string can contain <cite>accidental escapes</cite>, apparent escape
45.125 + * sequences which must not be interpreted as manglings.
45.126 + * These are disabled by replacing their leading backslash with an
45.127 + * escape sequence (<code><big><b>\-</b></big></code>). To mangle a string, three logical steps
45.128 + * are required, though they may be carried out in one pass:
45.129 + * </p>
45.130 + * <ol>
45.131 + * <li>In each accidental escape, replace the backslash with an escape sequence
45.132 + * (<code><big><b>\-</b></big></code>).</li>
45.133 + * <li>Replace each dangerous character with an escape sequence
45.134 + * (<code><big><b>\|</b></big></code> for <code><big><b>/</b></big></code>, etc.).</li>
45.135 + * <li>If the first two steps introduced any change, <em>and</em>
45.136 + * if the string does not already begin with a backslash, prepend a null prefix (<code><big><b>\=</b></big></code>).</li>
45.137 + * </ol>
45.138 + *
45.139 + * To demangle a mangled string that begins with an escape,
45.140 + * remove any null prefix, and then replace (in parallel)
45.141 + * each escape sequence by its original character.
45.142 + * <p>Spelling strings which contain accidental
45.143 + * escapes <em>must</em> have them replaced, even if those
45.144 + * strings do not contain dangerous characters.
45.145 + * This restriction means that mangling a string always
45.146 + * requires a scan of the string for escapes.
45.147 + * But then, a scan would be required anyway,
45.148 + * to check for dangerous characters.
45.149 + *
45.150 + * </p>
45.151 + * <h3> Nice Properties </h3>
45.152 + *
45.153 + * <p>
45.154 + * If a bytecode name does not contain any escape sequence,
45.155 + * demangling is a no-op: The string demangles to itself.
45.156 + * Such a string is called <cite>self-mangling</cite>.
45.157 + * Almost all strings are self-mangling.
45.158 + * In practice, to demangle almost any name “found in nature”,
45.159 + * simply verify that it does not begin with a backslash.
45.160 + * </p>
45.161 + * <p>
45.162 + * Mangling is a one-to-one function, while demangling
45.163 + * is a many-to-one function.
45.164 + * A mangled string is defined as <cite>validly mangled</cite> if
45.165 + * it is in fact the unique mangling of its spelling string.
45.166 + * Three examples of invalidly mangled strings are <code><big><b>\=foo</b></big></code>,
45.167 + * <code><big><b>\-bar</b></big></code>, and <code><big><b>baz\!</b></big></code>, which demangle to <code><big><b>foo</b></big></code>, <code><big><b>\bar</b></big></code>, and
45.168 + * <code><big><b>baz\!</b></big></code>, but then remangle to <code><big><b>foo</b></big></code>, <code><big><b>\bar</b></big></code>, and <code><big><b>\=baz\-!</b></big></code>.
45.169 + * If a language back-end or runtime is using mangled names,
45.170 + * it should never present an invalidly mangled bytecode
45.171 + * name to the JVM. If the runtime encounters one,
45.172 + * it should also report an error, since such an occurrence
45.173 + * probably indicates a bug in name encoding which
45.174 + * will lead to errors in linkage.
45.175 + * However, this note does not propose that the JVM verifier
45.176 + * detect invalidly mangled names.
45.177 + * </p>
45.178 + * <p>
45.179 + * As a result of these rules, it is a simple matter to
45.180 + * compute validly mangled substrings and concatenations
45.181 + * of validly mangled strings, and (with a little care)
45.182 + * these correspond to corresponding operations on their
45.183 + * spelling strings.
45.184 + * </p>
45.185 + * <ul>
45.186 + * <li>Any prefix of a validly mangled string is also validly mangled,
45.187 + * although a null prefix may need to be removed.</li>
45.188 + * <li>Any suffix of a validly mangled string is also validly mangled,
45.189 + * although a null prefix may need to be added.</li>
45.190 + * <li>Two validly mangled strings, when concatenated,
45.191 + * are also validly mangled, although any null prefix
45.192 + * must be removed from the second string,
45.193 + * and a trailing backslash on the first string may need escaping,
45.194 + * if it would participate in an accidental escape when followed
45.195 + * by the first character of the second string.</li>
45.196 + * </ul>
45.197 + * <p>If languages that include non-Java symbol spellings use this
45.198 + * mangling convention, they will enjoy the following advantages:
45.199 + * </p>
45.200 + * <ul>
45.201 + * <li>They can interoperate via symbols they share in common.</li>
45.202 + * <li>Low-level tools, such as backtrace printers, will have readable displays.</li>
45.203 + * <li>Future JVM and language extensions can safely use the dangerous characters
45.204 + * for structuring symbols, but will never interfere with valid spellings.</li>
45.205 + * <li>Runtimes and compilers can use standard libraries for mangling and demangling.</li>
45.206 + * <li>Occasional transliterations and name composition will be simple and regular,
45.207 + * for classes, methods, and fields.</li>
45.208 + * <li>Bytecode names will continue to be compact.
45.209 + * When mangled, spellings will at most double in length, either in
45.210 + * UTF8 or UTF16 format, and most will not change at all.</li>
45.211 + * </ul>
45.212 + *
45.213 + *
45.214 + * <h3> Suggestions for Human Readable Presentations </h3>
45.215 + *
45.216 + *
45.217 + * <p>
45.218 + * For human readable displays of symbols,
45.219 + * it will be better to present a string-like quoted
45.220 + * representation of the spelling, because JVM users
45.221 + * are generally familiar with such tokens.
45.222 + * We suggest using single or double quotes before and after
45.223 + * mangled symbols which are not valid Java identifiers,
45.224 + * with quotes, backslashes, and non-printing characters
45.225 + * escaped as if for literals in the Java language.
45.226 + * </p>
45.227 + * <p>
45.228 + * For example, an HTML-like spelling
45.229 + * <code><big><b><pre></b></big></code> mangles to
45.230 + * <code><big><b>\^pre\_</b></big></code> and could
45.231 + * display more cleanly as
45.232 + * <code><big><b>'<pre>'</b></big></code>,
45.233 + * with the quotes included.
45.234 + * Such string-like conventions are <em>not</em> suitable
45.235 + * for mangled bytecode names, in part because
45.236 + * dangerous characters must be eliminated, rather
45.237 + * than just quoted. Otherwise internally structured
45.238 + * strings like package prefixes and method signatures
45.239 + * could not be reliably parsed.
45.240 + * </p>
45.241 + * <p>
45.242 + * In such human-readable displays, invalidly mangled
45.243 + * names should <em>not</em> be demangled and quoted,
45.244 + * for this would be misleading. Likewise, JVM symbols
45.245 + * which contain dangerous characters (like dots in field
45.246 + * names or brackets in method names) should not be
45.247 + * simply quoted. The bytecode names
45.248 + * <code><big><b>\=phase\,1</b></big></code> and
45.249 + * <code><big><b>phase.1</b></big></code> are distinct,
45.250 + * and in demangled displays they should be presented as
45.251 + * <code><big><b>'phase.1'</b></big></code> and something like
45.252 + * <code><big><b>'phase'.1</b></big></code>, respectively.
45.253 + * </p>
45.254 + *
45.255 + * @author John Rose
45.256 + * @version 1.2, 02/06/2008
45.257 + * @see http://blogs.sun.com/jrose/entry/symbolic_freedom_in_the_vm
45.258 + */
45.259 +public class BytecodeName {
45.260 + private BytecodeName() { } // static only class
45.261 +
45.262 + /** Given a source name, produce the corresponding bytecode name.
45.263 + * The source name should not be qualified, because any syntactic
45.264 + * markers (dots, slashes, dollar signs, colons, etc.) will be mangled.
45.265 + * @param s the source name
45.266 + * @return a valid bytecode name which represents the source name
45.267 + */
45.268 + public static String toBytecodeName(String s) {
45.269 + String bn = mangle(s);
45.270 + assert((Object)bn == s || looksMangled(bn)) : bn;
45.271 + assert(s.equals(toSourceName(bn))) : s;
45.272 + return bn;
45.273 + }
45.274 +
45.275 + /** Given an unqualified bytecode name, produce the corresponding source name.
45.276 + * The bytecode name must not contain dangerous characters.
45.277 + * In particular, it must not be qualified or segmented by colon {@code ':'}.
45.278 + * @param s the bytecode name
45.279 + * @return the source name, which may possibly have unsafe characters
45.280 + * @throws IllegalArgumentException if the bytecode name is not {@link #isSafeBytecodeName safe}
45.281 + * @see #isSafeBytecodeName(java.lang.String)
45.282 + */
45.283 + public static String toSourceName(String s) {
45.284 + checkSafeBytecodeName(s);
45.285 + String sn = s;
45.286 + if (looksMangled(s)) {
45.287 + sn = demangle(s);
45.288 + assert(s.equals(mangle(sn))) : s+" => "+sn+" => "+mangle(sn);
45.289 + }
45.290 + return sn;
45.291 + }
45.292 +
45.293 + /**
45.294 + * Given a bytecode name from a classfile, separate it into
45.295 + * components delimited by dangerous characters.
45.296 + * Each resulting array element will be either a dangerous character,
45.297 + * or else a safe bytecode name.
45.298 + * (The safe name might possibly be mangled to hide further dangerous characters.)
45.299 + * For example, the qualified class name {@code java/lang/String}
45.300 + * will be parsed into the array {@code {"java", '/', "lang", '/', "String"}}.
45.301 + * The name {@code <init>} will be parsed into { '<', "init", '>'}}
45.302 + * The name {@code foo/bar$:baz} will be parsed into
45.303 + * {@code {"foo", '/', "bar", '$', ':', "baz"}}.
45.304 + * The name {@code ::\=:foo:\=bar\!baz} will be parsed into
45.305 + * {@code {':', ':', "", ':', "foo", ':', "bar:baz"}}.
45.306 + */
45.307 + public static Object[] parseBytecodeName(String s) {
45.308 + int slen = s.length();
45.309 + Object[] res = null;
45.310 + for (int pass = 0; pass <= 1; pass++) {
45.311 + int fillp = 0;
45.312 + int lasti = 0;
45.313 + for (int i = 0; i <= slen; i++) {
45.314 + int whichDC = -1;
45.315 + if (i < slen) {
45.316 + whichDC = DANGEROUS_CHARS.indexOf(s.charAt(i));
45.317 + if (whichDC < DANGEROUS_CHAR_FIRST_INDEX) continue;
45.318 + }
45.319 + // got to end of string or next dangerous char
45.320 + if (lasti < i) {
45.321 + // normal component
45.322 + if (pass != 0)
45.323 + res[fillp] = toSourceName(s.substring(lasti, i));
45.324 + fillp++;
45.325 + lasti = i+1;
45.326 + }
45.327 + if (whichDC >= DANGEROUS_CHAR_FIRST_INDEX) {
45.328 + if (pass != 0)
45.329 + res[fillp] = DANGEROUS_CHARS_CA[whichDC];
45.330 + fillp++;
45.331 + lasti = i+1;
45.332 + }
45.333 + }
45.334 + if (pass != 0) break;
45.335 + // between passes, build the result array
45.336 + res = new Object[fillp];
45.337 + if (fillp <= 1 && lasti == 0) {
45.338 + if (fillp != 0) res[0] = toSourceName(s);
45.339 + break;
45.340 + }
45.341 + }
45.342 + return res;
45.343 + }
45.344 +
45.345 + /**
45.346 + * Given a series of components, create a bytecode name for a classfile.
45.347 + * This is the inverse of {@link #parseBytecodeName(java.lang.String)}.
45.348 + * Each component must either be an interned one-character string of
45.349 + * a dangerous character, or else a safe bytecode name.
45.350 + * @param components a series of name components
45.351 + * @return the concatenation of all components
45.352 + * @throws IllegalArgumentException if any component contains an unsafe
45.353 + * character, and is not an interned one-character string
45.354 + * @throws NullPointerException if any component is null
45.355 + */
45.356 + public static String unparseBytecodeName(Object[] components) {
45.357 + Object[] components0 = components;
45.358 + for (int i = 0; i < components.length; i++) {
45.359 + Object c = components[i];
45.360 + if (c instanceof String) {
45.361 + String mc = toBytecodeName((String) c);
45.362 + if (i == 0 && components.length == 1)
45.363 + return mc; // usual case
45.364 + if ((Object)mc != c) {
45.365 + if (components == components0)
45.366 + components = components.clone();
45.367 + components[i] = c = mc;
45.368 + }
45.369 + }
45.370 + }
45.371 + return appendAll(components);
45.372 + }
45.373 + private static String appendAll(Object[] components) {
45.374 + if (components.length <= 1) {
45.375 + if (components.length == 1) {
45.376 + return String.valueOf(components[0]);
45.377 + }
45.378 + return "";
45.379 + }
45.380 + int slen = 0;
45.381 + for (Object c : components) {
45.382 + if (c instanceof String)
45.383 + slen += String.valueOf(c).length();
45.384 + else
45.385 + slen += 1;
45.386 + }
45.387 + StringBuilder sb = new StringBuilder(slen);
45.388 + for (Object c : components) {
45.389 + sb.append(c);
45.390 + }
45.391 + return sb.toString();
45.392 + }
45.393 +
45.394 + /**
45.395 + * Given a bytecode name, produce the corresponding display name.
45.396 + * This is the source name, plus quotes if needed.
45.397 + * If the bytecode name contains dangerous characters,
45.398 + * assume that they are being used as punctuation,
45.399 + * and pass them through unchanged.
45.400 + * Non-empty runs of non-dangerous characters are demangled
45.401 + * if necessary, and the resulting names are quoted if
45.402 + * they are not already valid Java identifiers, or if
45.403 + * they contain a dangerous character (i.e., dollar sign "$").
45.404 + * Single quotes are used when quoting.
45.405 + * Within quoted names, embedded single quotes and backslashes
45.406 + * are further escaped by prepended backslashes.
45.407 + *
45.408 + * @param s the original bytecode name (which may be qualified)
45.409 + * @return a human-readable presentation
45.410 + */
45.411 + public static String toDisplayName(String s) {
45.412 + Object[] components = parseBytecodeName(s);
45.413 + for (int i = 0; i < components.length; i++) {
45.414 + if (!(components[i] instanceof String))
45.415 + continue;
45.416 + String sn = (String) components[i];
45.417 + // note that the name is already demangled!
45.418 + //sn = toSourceName(sn);
45.419 + if (!isJavaIdent(sn) || sn.indexOf('$') >=0 ) {
45.420 + components[i] = quoteDisplay(sn);
45.421 + }
45.422 + }
45.423 + return appendAll(components);
45.424 + }
45.425 + private static boolean isJavaIdent(String s) {
45.426 + int slen = s.length();
45.427 + if (slen == 0) return false;
45.428 + if (!Character.isJavaIdentifierStart(s.charAt(0)))
45.429 + return false;
45.430 + for (int i = 1; i < slen; i++) {
45.431 + if (!Character.isJavaIdentifierPart(s.charAt(i)))
45.432 + return false;
45.433 + }
45.434 + return true;
45.435 + }
45.436 + private static String quoteDisplay(String s) {
45.437 + // TO DO: Replace wierd characters in s by C-style escapes.
45.438 + return "'"+s.replaceAll("['\\\\]", "\\\\$0")+"'";
45.439 + }
45.440 +
45.441 + private static void checkSafeBytecodeName(String s)
45.442 + throws IllegalArgumentException {
45.443 + if (!isSafeBytecodeName(s)) {
45.444 + throw new IllegalArgumentException(s);
45.445 + }
45.446 + }
45.447 +
45.448 + /**
45.449 + * Report whether a simple name is safe as a bytecode name.
45.450 + * Such names are acceptable in class files as class, method, and field names.
45.451 + * Additionally, they are free of "dangerous" characters, even if those
45.452 + * characters are legal in some (or all) names in class files.
45.453 + * @param s the proposed bytecode name
45.454 + * @return true if the name is non-empty and all of its characters are safe
45.455 + */
45.456 + public static boolean isSafeBytecodeName(String s) {
45.457 + if (s.length() == 0) return false;
45.458 + // check occurrences of each DANGEROUS char
45.459 + for (char xc : DANGEROUS_CHARS_A) {
45.460 + if (xc == ESCAPE_C) continue; // not really that dangerous
45.461 + if (s.indexOf(xc) >= 0) return false;
45.462 + }
45.463 + return true;
45.464 + }
45.465 +
45.466 + /**
45.467 + * Report whether a character is safe in a bytecode name.
45.468 + * This is true of any unicode character except the following
45.469 + * <em>dangerous characters</em>: {@code ".;:$[]<>/"}.
45.470 + * @param s the proposed character
45.471 + * @return true if the character is safe to use in classfiles
45.472 + */
45.473 + public static boolean isSafeBytecodeChar(char c) {
45.474 + return DANGEROUS_CHARS.indexOf(c) < DANGEROUS_CHAR_FIRST_INDEX;
45.475 + }
45.476 +
45.477 + private static boolean looksMangled(String s) {
45.478 + return s.charAt(0) == ESCAPE_C;
45.479 + }
45.480 +
45.481 + private static String mangle(String s) {
45.482 + if (s.length() == 0)
45.483 + return NULL_ESCAPE;
45.484 +
45.485 + // build this lazily, when we first need an escape:
45.486 + StringBuilder sb = null;
45.487 +
45.488 + for (int i = 0, slen = s.length(); i < slen; i++) {
45.489 + char c = s.charAt(i);
45.490 +
45.491 + boolean needEscape = false;
45.492 + if (c == ESCAPE_C) {
45.493 + if (i+1 < slen) {
45.494 + char c1 = s.charAt(i+1);
45.495 + if ((i == 0 && c1 == NULL_ESCAPE_C)
45.496 + || c1 != originalOfReplacement(c1)) {
45.497 + // an accidental escape
45.498 + needEscape = true;
45.499 + }
45.500 + }
45.501 + } else {
45.502 + needEscape = isDangerous(c);
45.503 + }
45.504 +
45.505 + if (!needEscape) {
45.506 + if (sb != null) sb.append(c);
45.507 + continue;
45.508 + }
45.509 +
45.510 + // build sb if this is the first escape
45.511 + if (sb == null) {
45.512 + sb = new StringBuilder(s.length()+10);
45.513 + // mangled names must begin with a backslash:
45.514 + if (s.charAt(0) != ESCAPE_C && i > 0)
45.515 + sb.append(NULL_ESCAPE);
45.516 + // append the string so far, which is unremarkable:
45.517 + sb.append(s.substring(0, i));
45.518 + }
45.519 +
45.520 + // rewrite \ to \-, / to \|, etc.
45.521 + sb.append(ESCAPE_C);
45.522 + sb.append(replacementOf(c));
45.523 + }
45.524 +
45.525 + if (sb != null) return sb.toString();
45.526 +
45.527 + return s;
45.528 + }
45.529 +
45.530 + private static String demangle(String s) {
45.531 + // build this lazily, when we first meet an escape:
45.532 + StringBuilder sb = null;
45.533 +
45.534 + int stringStart = 0;
45.535 + if (s.startsWith(NULL_ESCAPE))
45.536 + stringStart = 2;
45.537 +
45.538 + for (int i = stringStart, slen = s.length(); i < slen; i++) {
45.539 + char c = s.charAt(i);
45.540 +
45.541 + if (c == ESCAPE_C && i+1 < slen) {
45.542 + // might be an escape sequence
45.543 + char rc = s.charAt(i+1);
45.544 + char oc = originalOfReplacement(rc);
45.545 + if (oc != rc) {
45.546 + // build sb if this is the first escape
45.547 + if (sb == null) {
45.548 + sb = new StringBuilder(s.length());
45.549 + // append the string so far, which is unremarkable:
45.550 + sb.append(s.substring(stringStart, i));
45.551 + }
45.552 + ++i; // skip both characters
45.553 + c = oc;
45.554 + }
45.555 + }
45.556 +
45.557 + if (sb != null)
45.558 + sb.append(c);
45.559 + }
45.560 +
45.561 + if (sb != null) return sb.toString();
45.562 +
45.563 + return s.substring(stringStart);
45.564 + }
45.565 +
45.566 + static char ESCAPE_C = '\\';
45.567 + // empty escape sequence to avoid a null name or illegal prefix
45.568 + static char NULL_ESCAPE_C = '=';
45.569 + static String NULL_ESCAPE = ESCAPE_C+""+NULL_ESCAPE_C;
45.570 +
45.571 + static final String DANGEROUS_CHARS = "\\/.;:$[]<>"; // \\ must be first
45.572 + static final String REPLACEMENT_CHARS = "-|,?!%{}^_";
45.573 + static final int DANGEROUS_CHAR_FIRST_INDEX = 1; // index after \\
45.574 + static char[] DANGEROUS_CHARS_A = DANGEROUS_CHARS.toCharArray();
45.575 + static char[] REPLACEMENT_CHARS_A = REPLACEMENT_CHARS.toCharArray();
45.576 + static final Character[] DANGEROUS_CHARS_CA;
45.577 + static {
45.578 + Character[] dcca = new Character[DANGEROUS_CHARS.length()];
45.579 + for (int i = 0; i < dcca.length; i++)
45.580 + dcca[i] = Character.valueOf(DANGEROUS_CHARS.charAt(i));
45.581 + DANGEROUS_CHARS_CA = dcca;
45.582 + }
45.583 +
45.584 + static final long[] SPECIAL_BITMAP = new long[2]; // 128 bits
45.585 + static {
45.586 + String SPECIAL = DANGEROUS_CHARS + REPLACEMENT_CHARS;
45.587 + //System.out.println("SPECIAL = "+SPECIAL);
45.588 + for (char c : SPECIAL.toCharArray()) {
45.589 + SPECIAL_BITMAP[c >>> 6] |= 1L << c;
45.590 + }
45.591 + }
45.592 + static boolean isSpecial(char c) {
45.593 + if ((c >>> 6) < SPECIAL_BITMAP.length)
45.594 + return ((SPECIAL_BITMAP[c >>> 6] >> c) & 1) != 0;
45.595 + else
45.596 + return false;
45.597 + }
45.598 + static char replacementOf(char c) {
45.599 + if (!isSpecial(c)) return c;
45.600 + int i = DANGEROUS_CHARS.indexOf(c);
45.601 + if (i < 0) return c;
45.602 + return REPLACEMENT_CHARS.charAt(i);
45.603 + }
45.604 + static char originalOfReplacement(char c) {
45.605 + if (!isSpecial(c)) return c;
45.606 + int i = REPLACEMENT_CHARS.indexOf(c);
45.607 + if (i < 0) return c;
45.608 + return DANGEROUS_CHARS.charAt(i);
45.609 + }
45.610 + static boolean isDangerous(char c) {
45.611 + if (!isSpecial(c)) return false;
45.612 + return (DANGEROUS_CHARS.indexOf(c) >= DANGEROUS_CHAR_FIRST_INDEX);
45.613 + }
45.614 + static int indexOfDangerousChar(String s, int from) {
45.615 + for (int i = from, slen = s.length(); i < slen; i++) {
45.616 + if (isDangerous(s.charAt(i)))
45.617 + return i;
45.618 + }
45.619 + return -1;
45.620 + }
45.621 + static int lastIndexOfDangerousChar(String s, int from) {
45.622 + for (int i = Math.min(from, s.length()-1); i >= 0; i--) {
45.623 + if (isDangerous(s.charAt(i)))
45.624 + return i;
45.625 + }
45.626 + return -1;
45.627 + }
45.628 +
45.629 +
45.630 +}
46.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
46.2 +++ b/rt/emul/compact/src/main/java/sun/invoke/util/ValueConversions.java Sat Aug 09 11:12:05 2014 +0200
46.3 @@ -0,0 +1,1188 @@
46.4 +/*
46.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
46.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
46.7 + *
46.8 + * This code is free software; you can redistribute it and/or modify it
46.9 + * under the terms of the GNU General Public License version 2 only, as
46.10 + * published by the Free Software Foundation. Oracle designates this
46.11 + * particular file as subject to the "Classpath" exception as provided
46.12 + * by Oracle in the LICENSE file that accompanied this code.
46.13 + *
46.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
46.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
46.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
46.17 + * version 2 for more details (a copy is included in the LICENSE file that
46.18 + * accompanied this code).
46.19 + *
46.20 + * You should have received a copy of the GNU General Public License version
46.21 + * 2 along with this work; if not, write to the Free Software Foundation,
46.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
46.23 + *
46.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
46.25 + * or visit www.oracle.com if you need additional information or have any
46.26 + * questions.
46.27 + */
46.28 +
46.29 +package sun.invoke.util;
46.30 +
46.31 +import java.lang.invoke.MethodHandle;
46.32 +import java.lang.invoke.MethodHandles;
46.33 +import java.lang.invoke.MethodHandles.Lookup;
46.34 +import java.lang.invoke.MethodType;
46.35 +import java.security.AccessController;
46.36 +import java.security.PrivilegedAction;
46.37 +import java.util.ArrayList;
46.38 +import java.util.Arrays;
46.39 +import java.util.Collections;
46.40 +import java.util.EnumMap;
46.41 +import java.util.List;
46.42 +
46.43 +public class ValueConversions {
46.44 + private static final Class<?> THIS_CLASS = ValueConversions.class;
46.45 + // Do not adjust this except for special platforms:
46.46 + private static final int MAX_ARITY;
46.47 + static {
46.48 + final Object[] values = { 255 };
46.49 + AccessController.doPrivileged(new PrivilegedAction<Void>() {
46.50 + @Override
46.51 + public Void run() {
46.52 + values[0] = Integer.getInteger(THIS_CLASS.getName()+".MAX_ARITY", 255);
46.53 + return null;
46.54 + }
46.55 + });
46.56 + MAX_ARITY = (Integer) values[0];
46.57 + }
46.58 +
46.59 + private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
46.60 +
46.61 + private static EnumMap<Wrapper, MethodHandle>[] newWrapperCaches(int n) {
46.62 + @SuppressWarnings("unchecked") // generic array creation
46.63 + EnumMap<Wrapper, MethodHandle>[] caches
46.64 + = (EnumMap<Wrapper, MethodHandle>[]) new EnumMap<?,?>[n];
46.65 + for (int i = 0; i < n; i++)
46.66 + caches[i] = new EnumMap<>(Wrapper.class);
46.67 + return caches;
46.68 + }
46.69 +
46.70 + /// Converting references to values.
46.71 +
46.72 + // There are several levels of this unboxing conversions:
46.73 + // no conversions: exactly Integer.valueOf, etc.
46.74 + // implicit conversions sanctioned by JLS 5.1.2, etc.
46.75 + // explicit conversions as allowed by explicitCastArguments
46.76 +
46.77 + static int unboxInteger(Object x, boolean cast) {
46.78 + if (x instanceof Integer)
46.79 + return ((Integer) x).intValue();
46.80 + return primitiveConversion(Wrapper.INT, x, cast).intValue();
46.81 + }
46.82 +
46.83 + static byte unboxByte(Object x, boolean cast) {
46.84 + if (x instanceof Byte)
46.85 + return ((Byte) x).byteValue();
46.86 + return primitiveConversion(Wrapper.BYTE, x, cast).byteValue();
46.87 + }
46.88 +
46.89 + static short unboxShort(Object x, boolean cast) {
46.90 + if (x instanceof Short)
46.91 + return ((Short) x).shortValue();
46.92 + return primitiveConversion(Wrapper.SHORT, x, cast).shortValue();
46.93 + }
46.94 +
46.95 + static boolean unboxBoolean(Object x, boolean cast) {
46.96 + if (x instanceof Boolean)
46.97 + return ((Boolean) x).booleanValue();
46.98 + return (primitiveConversion(Wrapper.BOOLEAN, x, cast).intValue() & 1) != 0;
46.99 + }
46.100 +
46.101 + static char unboxCharacter(Object x, boolean cast) {
46.102 + if (x instanceof Character)
46.103 + return ((Character) x).charValue();
46.104 + return (char) primitiveConversion(Wrapper.CHAR, x, cast).intValue();
46.105 + }
46.106 +
46.107 + static long unboxLong(Object x, boolean cast) {
46.108 + if (x instanceof Long)
46.109 + return ((Long) x).longValue();
46.110 + return primitiveConversion(Wrapper.LONG, x, cast).longValue();
46.111 + }
46.112 +
46.113 + static float unboxFloat(Object x, boolean cast) {
46.114 + if (x instanceof Float)
46.115 + return ((Float) x).floatValue();
46.116 + return primitiveConversion(Wrapper.FLOAT, x, cast).floatValue();
46.117 + }
46.118 +
46.119 + static double unboxDouble(Object x, boolean cast) {
46.120 + if (x instanceof Double)
46.121 + return ((Double) x).doubleValue();
46.122 + return primitiveConversion(Wrapper.DOUBLE, x, cast).doubleValue();
46.123 + }
46.124 +
46.125 + private static MethodType unboxType(Wrapper wrap) {
46.126 + return MethodType.methodType(wrap.primitiveType(), Object.class, boolean.class);
46.127 + }
46.128 +
46.129 + private static final EnumMap<Wrapper, MethodHandle>[]
46.130 + UNBOX_CONVERSIONS = newWrapperCaches(2);
46.131 +
46.132 + private static MethodHandle unbox(Wrapper wrap, boolean cast) {
46.133 + EnumMap<Wrapper, MethodHandle> cache = UNBOX_CONVERSIONS[(cast?1:0)];
46.134 + MethodHandle mh = cache.get(wrap);
46.135 + if (mh != null) {
46.136 + return mh;
46.137 + }
46.138 + // slow path
46.139 + switch (wrap) {
46.140 + case OBJECT:
46.141 + mh = IDENTITY; break;
46.142 + case VOID:
46.143 + mh = IGNORE; break;
46.144 + }
46.145 + if (mh != null) {
46.146 + cache.put(wrap, mh);
46.147 + return mh;
46.148 + }
46.149 + // look up the method
46.150 + String name = "unbox" + wrap.wrapperSimpleName();
46.151 + MethodType type = unboxType(wrap);
46.152 + try {
46.153 + mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
46.154 + } catch (ReflectiveOperationException ex) {
46.155 + mh = null;
46.156 + }
46.157 + if (mh != null) {
46.158 + mh = MethodHandles.insertArguments(mh, 1, cast);
46.159 + cache.put(wrap, mh);
46.160 + return mh;
46.161 + }
46.162 + throw new IllegalArgumentException("cannot find unbox adapter for " + wrap
46.163 + + (cast ? " (cast)" : ""));
46.164 + }
46.165 +
46.166 + public static MethodHandle unboxCast(Wrapper type) {
46.167 + return unbox(type, true);
46.168 + }
46.169 +
46.170 + public static MethodHandle unbox(Class<?> type) {
46.171 + return unbox(Wrapper.forPrimitiveType(type), false);
46.172 + }
46.173 +
46.174 + public static MethodHandle unboxCast(Class<?> type) {
46.175 + return unbox(Wrapper.forPrimitiveType(type), true);
46.176 + }
46.177 +
46.178 + static private final Integer ZERO_INT = 0, ONE_INT = 1;
46.179 +
46.180 + /// Primitive conversions
46.181 + /**
46.182 + * Produce a Number which represents the given value {@code x}
46.183 + * according to the primitive type of the given wrapper {@code wrap}.
46.184 + * Caller must invoke intValue, byteValue, longValue (etc.) on the result
46.185 + * to retrieve the desired primitive value.
46.186 + */
46.187 + public static Number primitiveConversion(Wrapper wrap, Object x, boolean cast) {
46.188 + // Maybe merge this code with Wrapper.convert/cast.
46.189 + Number res;
46.190 + if (x == null) {
46.191 + if (!cast) return null;
46.192 + return ZERO_INT;
46.193 + }
46.194 + if (x instanceof Number) {
46.195 + res = (Number) x;
46.196 + } else if (x instanceof Boolean) {
46.197 + res = ((boolean)x ? ONE_INT : ZERO_INT);
46.198 + } else if (x instanceof Character) {
46.199 + res = (int)(char)x;
46.200 + } else {
46.201 + // this will fail with the required ClassCastException:
46.202 + res = (Number) x;
46.203 + }
46.204 + Wrapper xwrap = Wrapper.findWrapperType(x.getClass());
46.205 + if (xwrap == null || !cast && !wrap.isConvertibleFrom(xwrap))
46.206 + // this will fail with the required ClassCastException:
46.207 + return (Number) wrap.wrapperType().cast(x);
46.208 + return res;
46.209 + }
46.210 +
46.211 + /**
46.212 + * The JVM verifier allows boolean, byte, short, or char to widen to int.
46.213 + * Support exactly this conversion, from a boxed value type Boolean,
46.214 + * Byte, Short, Character, or Integer.
46.215 + */
46.216 + public static int widenSubword(Object x) {
46.217 + if (x instanceof Integer)
46.218 + return (int) x;
46.219 + else if (x instanceof Boolean)
46.220 + return fromBoolean((boolean) x);
46.221 + else if (x instanceof Character)
46.222 + return (char) x;
46.223 + else if (x instanceof Short)
46.224 + return (short) x;
46.225 + else if (x instanceof Byte)
46.226 + return (byte) x;
46.227 + else
46.228 + // Fail with a ClassCastException.
46.229 + return (int) x;
46.230 + }
46.231 +
46.232 + /// Converting primitives to references
46.233 +
46.234 + static Integer boxInteger(int x) {
46.235 + return x;
46.236 + }
46.237 +
46.238 + static Byte boxByte(byte x) {
46.239 + return x;
46.240 + }
46.241 +
46.242 + static Short boxShort(short x) {
46.243 + return x;
46.244 + }
46.245 +
46.246 + static Boolean boxBoolean(boolean x) {
46.247 + return x;
46.248 + }
46.249 +
46.250 + static Character boxCharacter(char x) {
46.251 + return x;
46.252 + }
46.253 +
46.254 + static Long boxLong(long x) {
46.255 + return x;
46.256 + }
46.257 +
46.258 + static Float boxFloat(float x) {
46.259 + return x;
46.260 + }
46.261 +
46.262 + static Double boxDouble(double x) {
46.263 + return x;
46.264 + }
46.265 +
46.266 + private static MethodType boxType(Wrapper wrap) {
46.267 + // be exact, since return casts are hard to compose
46.268 + Class<?> boxType = wrap.wrapperType();
46.269 + return MethodType.methodType(boxType, wrap.primitiveType());
46.270 + }
46.271 +
46.272 + private static final EnumMap<Wrapper, MethodHandle>[]
46.273 + BOX_CONVERSIONS = newWrapperCaches(2);
46.274 +
46.275 + private static MethodHandle box(Wrapper wrap, boolean exact) {
46.276 + EnumMap<Wrapper, MethodHandle> cache = BOX_CONVERSIONS[(exact?1:0)];
46.277 + MethodHandle mh = cache.get(wrap);
46.278 + if (mh != null) {
46.279 + return mh;
46.280 + }
46.281 + // slow path
46.282 + switch (wrap) {
46.283 + case OBJECT:
46.284 + mh = IDENTITY; break;
46.285 + case VOID:
46.286 + mh = ZERO_OBJECT;
46.287 + break;
46.288 + }
46.289 + if (mh != null) {
46.290 + cache.put(wrap, mh);
46.291 + return mh;
46.292 + }
46.293 + // look up the method
46.294 + String name = "box" + wrap.wrapperSimpleName();
46.295 + MethodType type = boxType(wrap);
46.296 + if (exact) {
46.297 + try {
46.298 + mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
46.299 + } catch (ReflectiveOperationException ex) {
46.300 + mh = null;
46.301 + }
46.302 + } else {
46.303 + mh = box(wrap, !exact).asType(type.erase());
46.304 + }
46.305 + if (mh != null) {
46.306 + cache.put(wrap, mh);
46.307 + return mh;
46.308 + }
46.309 + throw new IllegalArgumentException("cannot find box adapter for "
46.310 + + wrap + (exact ? " (exact)" : ""));
46.311 + }
46.312 +
46.313 + public static MethodHandle box(Class<?> type) {
46.314 + boolean exact = false;
46.315 + // e.g., boxShort(short)Short if exact,
46.316 + // e.g., boxShort(short)Object if !exact
46.317 + return box(Wrapper.forPrimitiveType(type), exact);
46.318 + }
46.319 +
46.320 + public static MethodHandle box(Wrapper type) {
46.321 + boolean exact = false;
46.322 + return box(type, exact);
46.323 + }
46.324 +
46.325 + /// Constant functions
46.326 +
46.327 + static void ignore(Object x) {
46.328 + // no value to return; this is an unbox of null
46.329 + }
46.330 +
46.331 + static void empty() {
46.332 + }
46.333 +
46.334 + static Object zeroObject() {
46.335 + return null;
46.336 + }
46.337 +
46.338 + static int zeroInteger() {
46.339 + return 0;
46.340 + }
46.341 +
46.342 + static long zeroLong() {
46.343 + return 0;
46.344 + }
46.345 +
46.346 + static float zeroFloat() {
46.347 + return 0;
46.348 + }
46.349 +
46.350 + static double zeroDouble() {
46.351 + return 0;
46.352 + }
46.353 +
46.354 + private static final EnumMap<Wrapper, MethodHandle>[]
46.355 + CONSTANT_FUNCTIONS = newWrapperCaches(2);
46.356 +
46.357 + public static MethodHandle zeroConstantFunction(Wrapper wrap) {
46.358 + EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[0];
46.359 + MethodHandle mh = cache.get(wrap);
46.360 + if (mh != null) {
46.361 + return mh;
46.362 + }
46.363 + // slow path
46.364 + MethodType type = MethodType.methodType(wrap.primitiveType());
46.365 + switch (wrap) {
46.366 + case VOID:
46.367 + mh = EMPTY;
46.368 + break;
46.369 + case OBJECT:
46.370 + case INT: case LONG: case FLOAT: case DOUBLE:
46.371 + try {
46.372 + mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "zero"+wrap.wrapperSimpleName(), type);
46.373 + } catch (ReflectiveOperationException ex) {
46.374 + mh = null;
46.375 + }
46.376 + break;
46.377 + }
46.378 + if (mh != null) {
46.379 + cache.put(wrap, mh);
46.380 + return mh;
46.381 + }
46.382 +
46.383 + // use zeroInt and cast the result
46.384 + if (wrap.isSubwordOrInt() && wrap != Wrapper.INT) {
46.385 + mh = MethodHandles.explicitCastArguments(zeroConstantFunction(Wrapper.INT), type);
46.386 + cache.put(wrap, mh);
46.387 + return mh;
46.388 + }
46.389 + throw new IllegalArgumentException("cannot find zero constant for " + wrap);
46.390 + }
46.391 +
46.392 + /// Converting references to references.
46.393 +
46.394 + /**
46.395 + * Identity function.
46.396 + * @param x an arbitrary reference value
46.397 + * @return the same value x
46.398 + */
46.399 + static <T> T identity(T x) {
46.400 + return x;
46.401 + }
46.402 +
46.403 + static <T> T[] identity(T[] x) {
46.404 + return x;
46.405 + }
46.406 +
46.407 + /**
46.408 + * Identity function on ints.
46.409 + * @param x an arbitrary int value
46.410 + * @return the same value x
46.411 + */
46.412 + static int identity(int x) {
46.413 + return x;
46.414 + }
46.415 +
46.416 + static byte identity(byte x) {
46.417 + return x;
46.418 + }
46.419 +
46.420 + static short identity(short x) {
46.421 + return x;
46.422 + }
46.423 +
46.424 + static boolean identity(boolean x) {
46.425 + return x;
46.426 + }
46.427 +
46.428 + static char identity(char x) {
46.429 + return x;
46.430 + }
46.431 +
46.432 + /**
46.433 + * Identity function on longs.
46.434 + * @param x an arbitrary long value
46.435 + * @return the same value x
46.436 + */
46.437 + static long identity(long x) {
46.438 + return x;
46.439 + }
46.440 +
46.441 + static float identity(float x) {
46.442 + return x;
46.443 + }
46.444 +
46.445 + static double identity(double x) {
46.446 + return x;
46.447 + }
46.448 +
46.449 + /**
46.450 + * Identity function, with reference cast.
46.451 + * @param t an arbitrary reference type
46.452 + * @param x an arbitrary reference value
46.453 + * @return the same value x
46.454 + */
46.455 + @SuppressWarnings("unchecked")
46.456 + static <T,U> T castReference(Class<? extends T> t, U x) {
46.457 + // inlined Class.cast because we can't ForceInline it
46.458 + if (x != null && !t.isInstance(x))
46.459 + throw newClassCastException(t, x);
46.460 + return (T) x;
46.461 + }
46.462 +
46.463 + private static ClassCastException newClassCastException(Class<?> t, Object obj) {
46.464 + return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName());
46.465 + }
46.466 +
46.467 + private static final MethodHandle IDENTITY, CAST_REFERENCE, ZERO_OBJECT, IGNORE, EMPTY,
46.468 + ARRAY_IDENTITY, FILL_NEW_TYPED_ARRAY, FILL_NEW_ARRAY;
46.469 + static {
46.470 + try {
46.471 + MethodType idType = MethodType.genericMethodType(1);
46.472 + MethodType castType = idType.insertParameterTypes(0, Class.class);
46.473 + MethodType ignoreType = idType.changeReturnType(void.class);
46.474 + MethodType zeroObjectType = MethodType.genericMethodType(0);
46.475 + IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", idType);
46.476 + //CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType);
46.477 + CAST_REFERENCE = IMPL_LOOKUP.findStatic(THIS_CLASS, "castReference", castType);
46.478 + ZERO_OBJECT = IMPL_LOOKUP.findStatic(THIS_CLASS, "zeroObject", zeroObjectType);
46.479 + IGNORE = IMPL_LOOKUP.findStatic(THIS_CLASS, "ignore", ignoreType);
46.480 + EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1));
46.481 + ARRAY_IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", MethodType.methodType(Object[].class, Object[].class));
46.482 + FILL_NEW_ARRAY = IMPL_LOOKUP
46.483 + .findStatic(THIS_CLASS, "fillNewArray",
46.484 + MethodType.methodType(Object[].class, Integer.class, Object[].class));
46.485 + FILL_NEW_TYPED_ARRAY = IMPL_LOOKUP
46.486 + .findStatic(THIS_CLASS, "fillNewTypedArray",
46.487 + MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
46.488 + } catch (NoSuchMethodException | IllegalAccessException ex) {
46.489 + throw newInternalError("uncaught exception", ex);
46.490 + }
46.491 + }
46.492 +
46.493 + // Varargs methods need to be in a separately initialized class, to avoid bootstrapping problems.
46.494 + static class LazyStatics {
46.495 + private static final MethodHandle COPY_AS_REFERENCE_ARRAY, COPY_AS_PRIMITIVE_ARRAY, MAKE_LIST;
46.496 + static {
46.497 + try {
46.498 + //MAKE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeArray", MethodType.methodType(Object[].class, Object[].class));
46.499 + COPY_AS_REFERENCE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "copyAsReferenceArray", MethodType.methodType(Object[].class, Class.class, Object[].class));
46.500 + COPY_AS_PRIMITIVE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "copyAsPrimitiveArray", MethodType.methodType(Object.class, Wrapper.class, Object[].class));
46.501 + MAKE_LIST = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeList", MethodType.methodType(List.class, Object[].class));
46.502 + } catch (ReflectiveOperationException ex) {
46.503 + throw newInternalError("uncaught exception", ex);
46.504 + }
46.505 + }
46.506 + }
46.507 +
46.508 + private static final EnumMap<Wrapper, MethodHandle>[] WRAPPER_CASTS
46.509 + = newWrapperCaches(1);
46.510 +
46.511 + /** Return a method that casts its sole argument (an Object) to the given type
46.512 + * and returns it as the given type.
46.513 + */
46.514 + public static MethodHandle cast(Class<?> type) {
46.515 + if (type.isPrimitive()) throw new IllegalArgumentException("cannot cast primitive type "+type);
46.516 + MethodHandle mh;
46.517 + Wrapper wrap = null;
46.518 + EnumMap<Wrapper, MethodHandle> cache = null;
46.519 + if (Wrapper.isWrapperType(type)) {
46.520 + wrap = Wrapper.forWrapperType(type);
46.521 + cache = WRAPPER_CASTS[0];
46.522 + mh = cache.get(wrap);
46.523 + if (mh != null) return mh;
46.524 + }
46.525 + mh = MethodHandles.insertArguments(CAST_REFERENCE, 0, type);
46.526 + if (cache != null)
46.527 + cache.put(wrap, mh);
46.528 + return mh;
46.529 + }
46.530 +
46.531 + public static MethodHandle identity() {
46.532 + return IDENTITY;
46.533 + }
46.534 +
46.535 + public static MethodHandle identity(Class<?> type) {
46.536 + if (!type.isPrimitive())
46.537 + // Reference identity has been moved into MethodHandles:
46.538 + return MethodHandles.identity(type);
46.539 + return identity(Wrapper.findPrimitiveType(type));
46.540 + }
46.541 +
46.542 + public static MethodHandle identity(Wrapper wrap) {
46.543 + EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[1];
46.544 + MethodHandle mh = cache.get(wrap);
46.545 + if (mh != null) {
46.546 + return mh;
46.547 + }
46.548 + // slow path
46.549 + MethodType type = MethodType.methodType(wrap.primitiveType());
46.550 + if (wrap != Wrapper.VOID)
46.551 + type = type.appendParameterTypes(wrap.primitiveType());
46.552 + try {
46.553 + mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", type);
46.554 + } catch (ReflectiveOperationException ex) {
46.555 + mh = null;
46.556 + }
46.557 + if (mh == null && wrap == Wrapper.VOID) {
46.558 + mh = EMPTY; // #(){} : #()void
46.559 + }
46.560 + if (mh != null) {
46.561 + cache.put(wrap, mh);
46.562 + return mh;
46.563 + }
46.564 +
46.565 + if (mh != null) {
46.566 + cache.put(wrap, mh);
46.567 + return mh;
46.568 + }
46.569 + throw new IllegalArgumentException("cannot find identity for " + wrap);
46.570 + }
46.571 +
46.572 + /// Primitive conversions.
46.573 + // These are supported directly by the JVM, usually by a single instruction.
46.574 + // In the case of narrowing to a subword, there may be a pair of instructions.
46.575 + // In the case of booleans, there may be a helper routine to manage a 1-bit value.
46.576 + // This is the full 8x8 matrix (minus the diagonal).
46.577 +
46.578 + // narrow double to all other types:
46.579 + static float doubleToFloat(double x) { // bytecode: d2f
46.580 + return (float) x;
46.581 + }
46.582 + static long doubleToLong(double x) { // bytecode: d2l
46.583 + return (long) x;
46.584 + }
46.585 + static int doubleToInt(double x) { // bytecode: d2i
46.586 + return (int) x;
46.587 + }
46.588 + static short doubleToShort(double x) { // bytecodes: d2i, i2s
46.589 + return (short) x;
46.590 + }
46.591 + static char doubleToChar(double x) { // bytecodes: d2i, i2c
46.592 + return (char) x;
46.593 + }
46.594 + static byte doubleToByte(double x) { // bytecodes: d2i, i2b
46.595 + return (byte) x;
46.596 + }
46.597 + static boolean doubleToBoolean(double x) {
46.598 + return toBoolean((byte) x);
46.599 + }
46.600 +
46.601 + // widen float:
46.602 + static double floatToDouble(float x) { // bytecode: f2d
46.603 + return x;
46.604 + }
46.605 + // narrow float:
46.606 + static long floatToLong(float x) { // bytecode: f2l
46.607 + return (long) x;
46.608 + }
46.609 + static int floatToInt(float x) { // bytecode: f2i
46.610 + return (int) x;
46.611 + }
46.612 + static short floatToShort(float x) { // bytecodes: f2i, i2s
46.613 + return (short) x;
46.614 + }
46.615 + static char floatToChar(float x) { // bytecodes: f2i, i2c
46.616 + return (char) x;
46.617 + }
46.618 + static byte floatToByte(float x) { // bytecodes: f2i, i2b
46.619 + return (byte) x;
46.620 + }
46.621 + static boolean floatToBoolean(float x) {
46.622 + return toBoolean((byte) x);
46.623 + }
46.624 +
46.625 + // widen long:
46.626 + static double longToDouble(long x) { // bytecode: l2d
46.627 + return x;
46.628 + }
46.629 + static float longToFloat(long x) { // bytecode: l2f
46.630 + return x;
46.631 + }
46.632 + // narrow long:
46.633 + static int longToInt(long x) { // bytecode: l2i
46.634 + return (int) x;
46.635 + }
46.636 + static short longToShort(long x) { // bytecodes: f2i, i2s
46.637 + return (short) x;
46.638 + }
46.639 + static char longToChar(long x) { // bytecodes: f2i, i2c
46.640 + return (char) x;
46.641 + }
46.642 + static byte longToByte(long x) { // bytecodes: f2i, i2b
46.643 + return (byte) x;
46.644 + }
46.645 + static boolean longToBoolean(long x) {
46.646 + return toBoolean((byte) x);
46.647 + }
46.648 +
46.649 + // widen int:
46.650 + static double intToDouble(int x) { // bytecode: i2d
46.651 + return x;
46.652 + }
46.653 + static float intToFloat(int x) { // bytecode: i2f
46.654 + return x;
46.655 + }
46.656 + static long intToLong(int x) { // bytecode: i2l
46.657 + return x;
46.658 + }
46.659 + // narrow int:
46.660 + static short intToShort(int x) { // bytecode: i2s
46.661 + return (short) x;
46.662 + }
46.663 + static char intToChar(int x) { // bytecode: i2c
46.664 + return (char) x;
46.665 + }
46.666 + static byte intToByte(int x) { // bytecode: i2b
46.667 + return (byte) x;
46.668 + }
46.669 + static boolean intToBoolean(int x) {
46.670 + return toBoolean((byte) x);
46.671 + }
46.672 +
46.673 + // widen short:
46.674 + static double shortToDouble(short x) { // bytecode: i2d (implicit 's2i')
46.675 + return x;
46.676 + }
46.677 + static float shortToFloat(short x) { // bytecode: i2f (implicit 's2i')
46.678 + return x;
46.679 + }
46.680 + static long shortToLong(short x) { // bytecode: i2l (implicit 's2i')
46.681 + return x;
46.682 + }
46.683 + static int shortToInt(short x) { // (implicit 's2i')
46.684 + return x;
46.685 + }
46.686 + // narrow short:
46.687 + static char shortToChar(short x) { // bytecode: i2c (implicit 's2i')
46.688 + return (char)x;
46.689 + }
46.690 + static byte shortToByte(short x) { // bytecode: i2b (implicit 's2i')
46.691 + return (byte)x;
46.692 + }
46.693 + static boolean shortToBoolean(short x) {
46.694 + return toBoolean((byte) x);
46.695 + }
46.696 +
46.697 + // widen char:
46.698 + static double charToDouble(char x) { // bytecode: i2d (implicit 'c2i')
46.699 + return x;
46.700 + }
46.701 + static float charToFloat(char x) { // bytecode: i2f (implicit 'c2i')
46.702 + return x;
46.703 + }
46.704 + static long charToLong(char x) { // bytecode: i2l (implicit 'c2i')
46.705 + return x;
46.706 + }
46.707 + static int charToInt(char x) { // (implicit 'c2i')
46.708 + return x;
46.709 + }
46.710 + // narrow char:
46.711 + static short charToShort(char x) { // bytecode: i2s (implicit 'c2i')
46.712 + return (short)x;
46.713 + }
46.714 + static byte charToByte(char x) { // bytecode: i2b (implicit 'c2i')
46.715 + return (byte)x;
46.716 + }
46.717 + static boolean charToBoolean(char x) {
46.718 + return toBoolean((byte) x);
46.719 + }
46.720 +
46.721 + // widen byte:
46.722 + static double byteToDouble(byte x) { // bytecode: i2d (implicit 'b2i')
46.723 + return x;
46.724 + }
46.725 + static float byteToFloat(byte x) { // bytecode: i2f (implicit 'b2i')
46.726 + return x;
46.727 + }
46.728 + static long byteToLong(byte x) { // bytecode: i2l (implicit 'b2i')
46.729 + return x;
46.730 + }
46.731 + static int byteToInt(byte x) { // (implicit 'b2i')
46.732 + return x;
46.733 + }
46.734 + static short byteToShort(byte x) { // bytecode: i2s (implicit 'b2i')
46.735 + return (short)x;
46.736 + }
46.737 + static char byteToChar(byte x) { // bytecode: i2b (implicit 'b2i')
46.738 + return (char)x;
46.739 + }
46.740 + // narrow byte to boolean:
46.741 + static boolean byteToBoolean(byte x) {
46.742 + return toBoolean(x);
46.743 + }
46.744 +
46.745 + // widen boolean to all types:
46.746 + static double booleanToDouble(boolean x) {
46.747 + return fromBoolean(x);
46.748 + }
46.749 + static float booleanToFloat(boolean x) {
46.750 + return fromBoolean(x);
46.751 + }
46.752 + static long booleanToLong(boolean x) {
46.753 + return fromBoolean(x);
46.754 + }
46.755 + static int booleanToInt(boolean x) {
46.756 + return fromBoolean(x);
46.757 + }
46.758 + static short booleanToShort(boolean x) {
46.759 + return fromBoolean(x);
46.760 + }
46.761 + static char booleanToChar(boolean x) {
46.762 + return (char)fromBoolean(x);
46.763 + }
46.764 + static byte booleanToByte(boolean x) {
46.765 + return fromBoolean(x);
46.766 + }
46.767 +
46.768 + // helpers to force boolean into the conversion scheme:
46.769 + static boolean toBoolean(byte x) {
46.770 + // see javadoc for MethodHandles.explicitCastArguments
46.771 + return ((x & 1) != 0);
46.772 + }
46.773 + static byte fromBoolean(boolean x) {
46.774 + // see javadoc for MethodHandles.explicitCastArguments
46.775 + return (x ? (byte)1 : (byte)0);
46.776 + }
46.777 +
46.778 + private static final EnumMap<Wrapper, MethodHandle>[]
46.779 + CONVERT_PRIMITIVE_FUNCTIONS = newWrapperCaches(Wrapper.values().length);
46.780 +
46.781 + public static MethodHandle convertPrimitive(Wrapper wsrc, Wrapper wdst) {
46.782 + EnumMap<Wrapper, MethodHandle> cache = CONVERT_PRIMITIVE_FUNCTIONS[wsrc.ordinal()];
46.783 + MethodHandle mh = cache.get(wdst);
46.784 + if (mh != null) {
46.785 + return mh;
46.786 + }
46.787 + // slow path
46.788 + Class<?> src = wsrc.primitiveType();
46.789 + Class<?> dst = wdst.primitiveType();
46.790 + MethodType type = src == void.class ? MethodType.methodType(dst) : MethodType.methodType(dst, src);
46.791 + if (wsrc == wdst) {
46.792 + mh = identity(src);
46.793 + } else if (wsrc == Wrapper.VOID) {
46.794 + mh = zeroConstantFunction(wdst);
46.795 + } else if (wdst == Wrapper.VOID) {
46.796 + mh = MethodHandles.dropArguments(EMPTY, 0, src); // Defer back to MethodHandles.
46.797 + } else if (wsrc == Wrapper.OBJECT) {
46.798 + mh = unboxCast(dst);
46.799 + } else if (wdst == Wrapper.OBJECT) {
46.800 + mh = box(src);
46.801 + } else {
46.802 + assert(src.isPrimitive() && dst.isPrimitive());
46.803 + try {
46.804 + mh = IMPL_LOOKUP.findStatic(THIS_CLASS, src.getSimpleName()+"To"+capitalize(dst.getSimpleName()), type);
46.805 + } catch (ReflectiveOperationException ex) {
46.806 + mh = null;
46.807 + }
46.808 + }
46.809 + if (mh != null) {
46.810 + assert(mh.type() == type) : mh;
46.811 + cache.put(wdst, mh);
46.812 + return mh;
46.813 + }
46.814 +
46.815 + throw new IllegalArgumentException("cannot find primitive conversion function for " +
46.816 + src.getSimpleName()+" -> "+dst.getSimpleName());
46.817 + }
46.818 +
46.819 + public static MethodHandle convertPrimitive(Class<?> src, Class<?> dst) {
46.820 + return convertPrimitive(Wrapper.forPrimitiveType(src), Wrapper.forPrimitiveType(dst));
46.821 + }
46.822 +
46.823 + private static String capitalize(String x) {
46.824 + return Character.toUpperCase(x.charAt(0))+x.substring(1);
46.825 + }
46.826 +
46.827 + /// Collection of multiple arguments.
46.828 +
46.829 + public static Object convertArrayElements(Class<?> arrayType, Object array) {
46.830 + Class<?> src = array.getClass().getComponentType();
46.831 + Class<?> dst = arrayType.getComponentType();
46.832 + if (src == null || dst == null) throw new IllegalArgumentException("not array type");
46.833 + Wrapper sw = (src.isPrimitive() ? Wrapper.forPrimitiveType(src) : null);
46.834 + Wrapper dw = (dst.isPrimitive() ? Wrapper.forPrimitiveType(dst) : null);
46.835 + int length;
46.836 + if (sw == null) {
46.837 + Object[] a = (Object[]) array;
46.838 + length = a.length;
46.839 + if (dw == null)
46.840 + return Arrays.copyOf(a, length, arrayType.asSubclass(Object[].class));
46.841 + Object res = dw.makeArray(length);
46.842 + dw.copyArrayUnboxing(a, 0, res, 0, length);
46.843 + return res;
46.844 + }
46.845 + length = java.lang.reflect.Array.getLength(array);
46.846 + Object[] res;
46.847 + if (dw == null) {
46.848 + res = Arrays.copyOf(NO_ARGS_ARRAY, length, arrayType.asSubclass(Object[].class));
46.849 + } else {
46.850 + res = new Object[length];
46.851 + }
46.852 + sw.copyArrayBoxing(array, 0, res, 0, length);
46.853 + if (dw == null) return res;
46.854 + Object a = dw.makeArray(length);
46.855 + dw.copyArrayUnboxing(res, 0, a, 0, length);
46.856 + return a;
46.857 + }
46.858 +
46.859 + private static MethodHandle findCollector(String name, int nargs, Class<?> rtype, Class<?>... ptypes) {
46.860 + MethodType type = MethodType.genericMethodType(nargs)
46.861 + .changeReturnType(rtype)
46.862 + .insertParameterTypes(0, ptypes);
46.863 + try {
46.864 + return IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
46.865 + } catch (ReflectiveOperationException ex) {
46.866 + return null;
46.867 + }
46.868 + }
46.869 +
46.870 + private static final Object[] NO_ARGS_ARRAY = {};
46.871 + private static Object[] makeArray(Object... args) { return args; }
46.872 + private static Object[] array() { return NO_ARGS_ARRAY; }
46.873 + private static Object[] array(Object a0)
46.874 + { return makeArray(a0); }
46.875 + private static Object[] array(Object a0, Object a1)
46.876 + { return makeArray(a0, a1); }
46.877 + private static Object[] array(Object a0, Object a1, Object a2)
46.878 + { return makeArray(a0, a1, a2); }
46.879 + private static Object[] array(Object a0, Object a1, Object a2, Object a3)
46.880 + { return makeArray(a0, a1, a2, a3); }
46.881 + private static Object[] array(Object a0, Object a1, Object a2, Object a3,
46.882 + Object a4)
46.883 + { return makeArray(a0, a1, a2, a3, a4); }
46.884 + private static Object[] array(Object a0, Object a1, Object a2, Object a3,
46.885 + Object a4, Object a5)
46.886 + { return makeArray(a0, a1, a2, a3, a4, a5); }
46.887 + private static Object[] array(Object a0, Object a1, Object a2, Object a3,
46.888 + Object a4, Object a5, Object a6)
46.889 + { return makeArray(a0, a1, a2, a3, a4, a5, a6); }
46.890 + private static Object[] array(Object a0, Object a1, Object a2, Object a3,
46.891 + Object a4, Object a5, Object a6, Object a7)
46.892 + { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); }
46.893 + private static Object[] array(Object a0, Object a1, Object a2, Object a3,
46.894 + Object a4, Object a5, Object a6, Object a7,
46.895 + Object a8)
46.896 + { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
46.897 + private static Object[] array(Object a0, Object a1, Object a2, Object a3,
46.898 + Object a4, Object a5, Object a6, Object a7,
46.899 + Object a8, Object a9)
46.900 + { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
46.901 + private static MethodHandle[] makeArrays() {
46.902 + ArrayList<MethodHandle> mhs = new ArrayList<>();
46.903 + for (;;) {
46.904 + MethodHandle mh = findCollector("array", mhs.size(), Object[].class);
46.905 + if (mh == null) break;
46.906 + mhs.add(mh);
46.907 + }
46.908 + assert(mhs.size() == 11); // current number of methods
46.909 + return mhs.toArray(new MethodHandle[MAX_ARITY+1]);
46.910 + }
46.911 + private static final MethodHandle[] ARRAYS = makeArrays();
46.912 +
46.913 + // filling versions of the above:
46.914 + // using Integer len instead of int len and no varargs to avoid bootstrapping problems
46.915 + private static Object[] fillNewArray(Integer len, Object[] /*not ...*/ args) {
46.916 + Object[] a = new Object[len];
46.917 + fillWithArguments(a, 0, args);
46.918 + return a;
46.919 + }
46.920 + private static Object[] fillNewTypedArray(Object[] example, Integer len, Object[] /*not ...*/ args) {
46.921 + Object[] a = Arrays.copyOf(example, len);
46.922 + fillWithArguments(a, 0, args);
46.923 + return a;
46.924 + }
46.925 + private static void fillWithArguments(Object[] a, int pos, Object... args) {
46.926 + System.arraycopy(args, 0, a, pos, args.length);
46.927 + }
46.928 + // using Integer pos instead of int pos to avoid bootstrapping problems
46.929 + private static Object[] fillArray(Integer pos, Object[] a, Object a0)
46.930 + { fillWithArguments(a, pos, a0); return a; }
46.931 + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1)
46.932 + { fillWithArguments(a, pos, a0, a1); return a; }
46.933 + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2)
46.934 + { fillWithArguments(a, pos, a0, a1, a2); return a; }
46.935 + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3)
46.936 + { fillWithArguments(a, pos, a0, a1, a2, a3); return a; }
46.937 + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
46.938 + Object a4)
46.939 + { fillWithArguments(a, pos, a0, a1, a2, a3, a4); return a; }
46.940 + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
46.941 + Object a4, Object a5)
46.942 + { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5); return a; }
46.943 + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
46.944 + Object a4, Object a5, Object a6)
46.945 + { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6); return a; }
46.946 + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
46.947 + Object a4, Object a5, Object a6, Object a7)
46.948 + { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7); return a; }
46.949 + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
46.950 + Object a4, Object a5, Object a6, Object a7,
46.951 + Object a8)
46.952 + { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8); return a; }
46.953 + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
46.954 + Object a4, Object a5, Object a6, Object a7,
46.955 + Object a8, Object a9)
46.956 + { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; }
46.957 + private static MethodHandle[] makeFillArrays() {
46.958 + ArrayList<MethodHandle> mhs = new ArrayList<>();
46.959 + mhs.add(null); // there is no empty fill; at least a0 is required
46.960 + for (;;) {
46.961 + MethodHandle mh = findCollector("fillArray", mhs.size(), Object[].class, Integer.class, Object[].class);
46.962 + if (mh == null) break;
46.963 + mhs.add(mh);
46.964 + }
46.965 + assert(mhs.size() == 11); // current number of methods
46.966 + return mhs.toArray(new MethodHandle[0]);
46.967 + }
46.968 + private static final MethodHandle[] FILL_ARRAYS = makeFillArrays();
46.969 +
46.970 + private static Object[] copyAsReferenceArray(Class<? extends Object[]> arrayType, Object... a) {
46.971 + return Arrays.copyOf(a, a.length, arrayType);
46.972 + }
46.973 + private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) {
46.974 + Object a = w.makeArray(boxes.length);
46.975 + w.copyArrayUnboxing(boxes, 0, a, 0, boxes.length);
46.976 + return a;
46.977 + }
46.978 +
46.979 + /** Return a method handle that takes the indicated number of Object
46.980 + * arguments and returns an Object array of them, as if for varargs.
46.981 + */
46.982 + public static MethodHandle varargsArray(int nargs) {
46.983 + MethodHandle mh = ARRAYS[nargs];
46.984 + if (mh != null) return mh;
46.985 + mh = findCollector("array", nargs, Object[].class);
46.986 + if (mh != null) return ARRAYS[nargs] = mh;
46.987 + mh = buildVarargsArray(FILL_NEW_ARRAY, ARRAY_IDENTITY, nargs);
46.988 + assert(assertCorrectArity(mh, nargs));
46.989 + return ARRAYS[nargs] = mh;
46.990 + }
46.991 +
46.992 + private static boolean assertCorrectArity(MethodHandle mh, int arity) {
46.993 + assert(mh.type().parameterCount() == arity) : "arity != "+arity+": "+mh;
46.994 + return true;
46.995 + }
46.996 +
46.997 + private static MethodHandle buildVarargsArray(MethodHandle newArray, MethodHandle finisher, int nargs) {
46.998 + // Build up the result mh as a sequence of fills like this:
46.999 + // finisher(fill(fill(newArrayWA(23,x1..x10),10,x11..x20),20,x21..x23))
46.1000 + // The various fill(_,10*I,___*[J]) are reusable.
46.1001 + int leftLen = Math.min(nargs, LEFT_ARGS); // absorb some arguments immediately
46.1002 + int rightLen = nargs - leftLen;
46.1003 + MethodHandle leftCollector = newArray.bindTo(nargs);
46.1004 + leftCollector = leftCollector.asCollector(Object[].class, leftLen);
46.1005 + MethodHandle mh = finisher;
46.1006 + if (rightLen > 0) {
46.1007 + MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen);
46.1008 + if (mh == ARRAY_IDENTITY)
46.1009 + mh = rightFiller;
46.1010 + else
46.1011 + mh = MethodHandles.collectArguments(mh, 0, rightFiller);
46.1012 + }
46.1013 + if (mh == ARRAY_IDENTITY)
46.1014 + mh = leftCollector;
46.1015 + else
46.1016 + mh = MethodHandles.collectArguments(mh, 0, leftCollector);
46.1017 + return mh;
46.1018 + }
46.1019 +
46.1020 + private static final int LEFT_ARGS = (FILL_ARRAYS.length - 1);
46.1021 + private static final MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1];
46.1022 + /** fill_array_to_right(N).invoke(a, argL..arg[N-1])
46.1023 + * fills a[L]..a[N-1] with corresponding arguments,
46.1024 + * and then returns a. The value L is a global constant (LEFT_ARGS).
46.1025 + */
46.1026 + private static MethodHandle fillToRight(int nargs) {
46.1027 + MethodHandle filler = FILL_ARRAY_TO_RIGHT[nargs];
46.1028 + if (filler != null) return filler;
46.1029 + filler = buildFiller(nargs);
46.1030 + assert(assertCorrectArity(filler, nargs - LEFT_ARGS + 1));
46.1031 + return FILL_ARRAY_TO_RIGHT[nargs] = filler;
46.1032 + }
46.1033 + private static MethodHandle buildFiller(int nargs) {
46.1034 + if (nargs <= LEFT_ARGS)
46.1035 + return ARRAY_IDENTITY; // no args to fill; return the array unchanged
46.1036 + // we need room for both mh and a in mh.invoke(a, arg*[nargs])
46.1037 + final int CHUNK = LEFT_ARGS;
46.1038 + int rightLen = nargs % CHUNK;
46.1039 + int midLen = nargs - rightLen;
46.1040 + if (rightLen == 0) {
46.1041 + midLen = nargs - (rightLen = CHUNK);
46.1042 + if (FILL_ARRAY_TO_RIGHT[midLen] == null) {
46.1043 + // build some precursors from left to right
46.1044 + for (int j = LEFT_ARGS % CHUNK; j < midLen; j += CHUNK)
46.1045 + if (j > LEFT_ARGS) fillToRight(j);
46.1046 + }
46.1047 + }
46.1048 + if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS);
46.1049 + assert(rightLen > 0);
46.1050 + MethodHandle midFill = fillToRight(midLen); // recursive fill
46.1051 + MethodHandle rightFill = FILL_ARRAYS[rightLen].bindTo(midLen); // [midLen..nargs-1]
46.1052 + assert(midFill.type().parameterCount() == 1 + midLen - LEFT_ARGS);
46.1053 + assert(rightFill.type().parameterCount() == 1 + rightLen);
46.1054 +
46.1055 + // Combine the two fills:
46.1056 + // right(mid(a, x10..x19), x20..x23)
46.1057 + // The final product will look like this:
46.1058 + // right(mid(newArrayLeft(24, x0..x9), x10..x19), x20..x23)
46.1059 + if (midLen == LEFT_ARGS)
46.1060 + return rightFill;
46.1061 + else
46.1062 + return MethodHandles.collectArguments(rightFill, 0, midFill);
46.1063 + }
46.1064 +
46.1065 + // Type-polymorphic version of varargs maker.
46.1066 + private static final ClassValue<MethodHandle[]> TYPED_COLLECTORS
46.1067 + = new ClassValue<MethodHandle[]>() {
46.1068 + @Override
46.1069 + protected MethodHandle[] computeValue(Class<?> type) {
46.1070 + return new MethodHandle[256];
46.1071 + }
46.1072 + };
46.1073 +
46.1074 + static final int MAX_JVM_ARITY = 255; // limit imposed by the JVM
46.1075 +
46.1076 + /** Return a method handle that takes the indicated number of
46.1077 + * typed arguments and returns an array of them.
46.1078 + * The type argument is the array type.
46.1079 + */
46.1080 + public static MethodHandle varargsArray(Class<?> arrayType, int nargs) {
46.1081 + Class<?> elemType = arrayType.getComponentType();
46.1082 + if (elemType == null) throw new IllegalArgumentException("not an array: "+arrayType);
46.1083 + // FIXME: Need more special casing and caching here.
46.1084 + if (nargs >= MAX_JVM_ARITY/2 - 1) {
46.1085 + int slots = nargs;
46.1086 + final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1; // 1 for receiver MH
46.1087 + if (arrayType == double[].class || arrayType == long[].class)
46.1088 + slots *= 2;
46.1089 + if (slots > MAX_ARRAY_SLOTS)
46.1090 + throw new IllegalArgumentException("too many arguments: "+arrayType.getSimpleName()+", length "+nargs);
46.1091 + }
46.1092 + if (elemType == Object.class)
46.1093 + return varargsArray(nargs);
46.1094 + // other cases: primitive arrays, subtypes of Object[]
46.1095 + MethodHandle cache[] = TYPED_COLLECTORS.get(elemType);
46.1096 + MethodHandle mh = nargs < cache.length ? cache[nargs] : null;
46.1097 + if (mh != null) return mh;
46.1098 + if (elemType.isPrimitive()) {
46.1099 + MethodHandle builder = FILL_NEW_ARRAY;
46.1100 + MethodHandle producer = buildArrayProducer(arrayType);
46.1101 + mh = buildVarargsArray(builder, producer, nargs);
46.1102 + } else {
46.1103 + @SuppressWarnings("unchecked")
46.1104 + Class<? extends Object[]> objArrayType = (Class<? extends Object[]>) arrayType;
46.1105 + Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType);
46.1106 + MethodHandle builder = FILL_NEW_TYPED_ARRAY.bindTo(example);
46.1107 + MethodHandle producer = ARRAY_IDENTITY;
46.1108 + mh = buildVarargsArray(builder, producer, nargs);
46.1109 + }
46.1110 + mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)));
46.1111 + assert(assertCorrectArity(mh, nargs));
46.1112 + if (nargs < cache.length)
46.1113 + cache[nargs] = mh;
46.1114 + return mh;
46.1115 + }
46.1116 +
46.1117 + private static MethodHandle buildArrayProducer(Class<?> arrayType) {
46.1118 + Class<?> elemType = arrayType.getComponentType();
46.1119 + if (elemType.isPrimitive())
46.1120 + return LazyStatics.COPY_AS_PRIMITIVE_ARRAY.bindTo(Wrapper.forPrimitiveType(elemType));
46.1121 + else
46.1122 + return LazyStatics.COPY_AS_REFERENCE_ARRAY.bindTo(arrayType);
46.1123 + }
46.1124 +
46.1125 + // List version of varargs maker.
46.1126 +
46.1127 + private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY);
46.1128 + private static List<Object> makeList(Object... args) { return Arrays.asList(args); }
46.1129 + private static List<Object> list() { return NO_ARGS_LIST; }
46.1130 + private static List<Object> list(Object a0)
46.1131 + { return makeList(a0); }
46.1132 + private static List<Object> list(Object a0, Object a1)
46.1133 + { return makeList(a0, a1); }
46.1134 + private static List<Object> list(Object a0, Object a1, Object a2)
46.1135 + { return makeList(a0, a1, a2); }
46.1136 + private static List<Object> list(Object a0, Object a1, Object a2, Object a3)
46.1137 + { return makeList(a0, a1, a2, a3); }
46.1138 + private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
46.1139 + Object a4)
46.1140 + { return makeList(a0, a1, a2, a3, a4); }
46.1141 + private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
46.1142 + Object a4, Object a5)
46.1143 + { return makeList(a0, a1, a2, a3, a4, a5); }
46.1144 + private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
46.1145 + Object a4, Object a5, Object a6)
46.1146 + { return makeList(a0, a1, a2, a3, a4, a5, a6); }
46.1147 + private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
46.1148 + Object a4, Object a5, Object a6, Object a7)
46.1149 + { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); }
46.1150 + private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
46.1151 + Object a4, Object a5, Object a6, Object a7,
46.1152 + Object a8)
46.1153 + { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
46.1154 + private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
46.1155 + Object a4, Object a5, Object a6, Object a7,
46.1156 + Object a8, Object a9)
46.1157 + { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
46.1158 + private static MethodHandle[] makeLists() {
46.1159 + ArrayList<MethodHandle> mhs = new ArrayList<>();
46.1160 + for (;;) {
46.1161 + MethodHandle mh = findCollector("list", mhs.size(), List.class);
46.1162 + if (mh == null) break;
46.1163 + mhs.add(mh);
46.1164 + }
46.1165 + assert(mhs.size() == 11); // current number of methods
46.1166 + return mhs.toArray(new MethodHandle[MAX_ARITY+1]);
46.1167 + }
46.1168 + private static final MethodHandle[] LISTS = makeLists();
46.1169 +
46.1170 + /** Return a method handle that takes the indicated number of Object
46.1171 + * arguments and returns a List.
46.1172 + */
46.1173 + public static MethodHandle varargsList(int nargs) {
46.1174 + MethodHandle mh = LISTS[nargs];
46.1175 + if (mh != null) return mh;
46.1176 + mh = findCollector("list", nargs, List.class);
46.1177 + if (mh != null) return LISTS[nargs] = mh;
46.1178 + return LISTS[nargs] = buildVarargsList(nargs);
46.1179 + }
46.1180 + private static MethodHandle buildVarargsList(int nargs) {
46.1181 + return MethodHandles.filterReturnValue(varargsArray(nargs), LazyStatics.MAKE_LIST);
46.1182 + }
46.1183 +
46.1184 + // handy shared exception makers (they simplify the common case code)
46.1185 + private static InternalError newInternalError(String message, Throwable cause) {
46.1186 + return new InternalError(message, cause);
46.1187 + }
46.1188 + private static InternalError newInternalError(Throwable cause) {
46.1189 + return new InternalError(cause);
46.1190 + }
46.1191 +}
47.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
47.2 +++ b/rt/emul/compact/src/main/java/sun/invoke/util/VerifyAccess.java Sat Aug 09 11:12:05 2014 +0200
47.3 @@ -0,0 +1,301 @@
47.4 +/*
47.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
47.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
47.7 + *
47.8 + * This code is free software; you can redistribute it and/or modify it
47.9 + * under the terms of the GNU General Public License version 2 only, as
47.10 + * published by the Free Software Foundation. Oracle designates this
47.11 + * particular file as subject to the "Classpath" exception as provided
47.12 + * by Oracle in the LICENSE file that accompanied this code.
47.13 + *
47.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
47.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
47.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
47.17 + * version 2 for more details (a copy is included in the LICENSE file that
47.18 + * accompanied this code).
47.19 + *
47.20 + * You should have received a copy of the GNU General Public License version
47.21 + * 2 along with this work; if not, write to the Free Software Foundation,
47.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
47.23 + *
47.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
47.25 + * or visit www.oracle.com if you need additional information or have any
47.26 + * questions.
47.27 + */
47.28 +
47.29 +package sun.invoke.util;
47.30 +
47.31 +import java.lang.reflect.Modifier;
47.32 +import static java.lang.reflect.Modifier.*;
47.33 +import sun.reflect.Reflection;
47.34 +
47.35 +/**
47.36 + * This class centralizes information about the JVM's linkage access control.
47.37 + * @author jrose
47.38 + */
47.39 +public class VerifyAccess {
47.40 +
47.41 + private VerifyAccess() { } // cannot instantiate
47.42 +
47.43 + private static final int PACKAGE_ONLY = 0;
47.44 + private static final int PACKAGE_ALLOWED = java.lang.invoke.MethodHandles.Lookup.PACKAGE;
47.45 + private static final int PROTECTED_OR_PACKAGE_ALLOWED = (PACKAGE_ALLOWED|PROTECTED);
47.46 + private static final int ALL_ACCESS_MODES = (PUBLIC|PRIVATE|PROTECTED|PACKAGE_ONLY);
47.47 + private static final boolean ALLOW_NESTMATE_ACCESS = false;
47.48 +
47.49 + /**
47.50 + * Evaluate the JVM linkage rules for access to the given method
47.51 + * on behalf of a caller class which proposes to perform the access.
47.52 + * Return true if the caller class has privileges to invoke a method
47.53 + * or access a field with the given properties.
47.54 + * This requires an accessibility check of the referencing class,
47.55 + * plus an accessibility check of the member within the class,
47.56 + * which depends on the member's modifier flags.
47.57 + * <p>
47.58 + * The relevant properties include the defining class ({@code defc})
47.59 + * of the member, and its modifier flags ({@code mods}).
47.60 + * Also relevant is the class used to make the initial symbolic reference
47.61 + * to the member ({@code refc}). If this latter class is not distinguished,
47.62 + * the defining class should be passed for both arguments ({@code defc == refc}).
47.63 + * <h3>JVM Specification, 5.4.4 "Access Control"</h3>
47.64 + * A field or method R is accessible to a class or interface D if
47.65 + * and only if any of the following conditions is true:<ul>
47.66 + * <li>R is public.
47.67 + * <li>R is protected and is declared in a class C, and D is either
47.68 + * a subclass of C or C itself. Furthermore, if R is not
47.69 + * static, then the symbolic reference to R must contain a
47.70 + * symbolic reference to a class T, such that T is either a
47.71 + * subclass of D, a superclass of D or D itself.
47.72 + * <li>R is either protected or has default access (that is,
47.73 + * neither public nor protected nor private), and is declared
47.74 + * by a class in the same runtime package as D.
47.75 + * <li>R is private and is declared in D.
47.76 + * </ul>
47.77 + * This discussion of access control omits a related restriction
47.78 + * on the target of a protected field access or method invocation
47.79 + * (the target must be of class D or a subtype of D). That
47.80 + * requirement is checked as part of the verification process
47.81 + * (5.4.1); it is not part of link-time access control.
47.82 + * @param refc the class used in the symbolic reference to the proposed member
47.83 + * @param defc the class in which the proposed member is actually defined
47.84 + * @param mods modifier flags for the proposed member
47.85 + * @param lookupClass the class for which the access check is being made
47.86 + * @return true iff the the accessing class can access such a member
47.87 + */
47.88 + public static boolean isMemberAccessible(Class<?> refc, // symbolic ref class
47.89 + Class<?> defc, // actual def class
47.90 + int mods, // actual member mods
47.91 + Class<?> lookupClass,
47.92 + int allowedModes) {
47.93 + if (allowedModes == 0) return false;
47.94 + assert((allowedModes & PUBLIC) != 0 &&
47.95 + (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED)) == 0);
47.96 + // The symbolic reference class (refc) must always be fully verified.
47.97 + if (!isClassAccessible(refc, lookupClass, allowedModes)) {
47.98 + return false;
47.99 + }
47.100 + // Usually refc and defc are the same, but verify defc also in case they differ.
47.101 + if (defc == lookupClass &&
47.102 + (allowedModes & PRIVATE) != 0)
47.103 + return true; // easy check; all self-access is OK
47.104 + switch (mods & ALL_ACCESS_MODES) {
47.105 + case PUBLIC:
47.106 + return true; // already checked above
47.107 + case PROTECTED:
47.108 + if ((allowedModes & PROTECTED_OR_PACKAGE_ALLOWED) != 0 &&
47.109 + isSamePackage(defc, lookupClass))
47.110 + return true;
47.111 + if ((allowedModes & PROTECTED) == 0)
47.112 + return false;
47.113 + if ((mods & STATIC) != 0 &&
47.114 + !isRelatedClass(refc, lookupClass))
47.115 + return false;
47.116 + if ((allowedModes & PROTECTED) != 0 &&
47.117 + isSuperClass(defc, lookupClass))
47.118 + return true;
47.119 + return false;
47.120 + case PACKAGE_ONLY: // That is, zero. Unmarked member is package-only access.
47.121 + return ((allowedModes & PACKAGE_ALLOWED) != 0 &&
47.122 + isSamePackage(defc, lookupClass));
47.123 + case PRIVATE:
47.124 + // Loosened rules for privates follows access rules for inner classes.
47.125 + return (ALLOW_NESTMATE_ACCESS &&
47.126 + (allowedModes & PRIVATE) != 0 &&
47.127 + isSamePackageMember(defc, lookupClass));
47.128 + default:
47.129 + throw new IllegalArgumentException("bad modifiers: "+Modifier.toString(mods));
47.130 + }
47.131 + }
47.132 +
47.133 + static boolean isRelatedClass(Class<?> refc, Class<?> lookupClass) {
47.134 + return (refc == lookupClass ||
47.135 + refc.isAssignableFrom(lookupClass) ||
47.136 + lookupClass.isAssignableFrom(refc));
47.137 + }
47.138 +
47.139 + static boolean isSuperClass(Class<?> defc, Class<?> lookupClass) {
47.140 + return defc.isAssignableFrom(lookupClass);
47.141 + }
47.142 +
47.143 + static int getClassModifiers(Class<?> c) {
47.144 + // This would return the mask stored by javac for the source-level modifiers.
47.145 + // return c.getModifiers();
47.146 + // But what we need for JVM access checks are the actual bits from the class header.
47.147 + // ...But arrays and primitives are synthesized with their own odd flags:
47.148 + if (c.isArray() || c.isPrimitive())
47.149 + return c.getModifiers();
47.150 + return Reflection.getClassAccessFlags(c);
47.151 + }
47.152 +
47.153 + /**
47.154 + * Evaluate the JVM linkage rules for access to the given class on behalf of caller.
47.155 + * <h3>JVM Specification, 5.4.4 "Access Control"</h3>
47.156 + * A class or interface C is accessible to a class or interface D
47.157 + * if and only if either of the following conditions are true:<ul>
47.158 + * <li>C is public.
47.159 + * <li>C and D are members of the same runtime package.
47.160 + * </ul>
47.161 + * @param refc the symbolic reference class to which access is being checked (C)
47.162 + * @param lookupClass the class performing the lookup (D)
47.163 + */
47.164 + public static boolean isClassAccessible(Class<?> refc, Class<?> lookupClass,
47.165 + int allowedModes) {
47.166 + if (allowedModes == 0) return false;
47.167 + assert((allowedModes & PUBLIC) != 0 &&
47.168 + (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED)) == 0);
47.169 + int mods = getClassModifiers(refc);
47.170 + if (isPublic(mods))
47.171 + return true;
47.172 + if ((allowedModes & PACKAGE_ALLOWED) != 0 &&
47.173 + isSamePackage(lookupClass, refc))
47.174 + return true;
47.175 + return false;
47.176 + }
47.177 +
47.178 + /**
47.179 + * Decide if the given method type, attributed to a member or symbolic
47.180 + * reference of a given reference class, is really visible to that class.
47.181 + * @param type the supposed type of a member or symbolic reference of refc
47.182 + * @param refc the class attempting to make the reference
47.183 + */
47.184 + public static boolean isTypeVisible(Class<?> type, Class<?> refc) {
47.185 + if (type == refc) return true; // easy check
47.186 + while (type.isArray()) type = type.getComponentType();
47.187 + if (type.isPrimitive() || type == Object.class) return true;
47.188 + ClassLoader parent = type.getClassLoader();
47.189 + if (parent == null) return true;
47.190 + ClassLoader child = refc.getClassLoader();
47.191 + if (child == null) return false;
47.192 + if (parent == child || loadersAreRelated(parent, child, true))
47.193 + return true;
47.194 + // Do it the hard way: Look up the type name from the refc loader.
47.195 + try {
47.196 + Class<?> res = child.loadClass(type.getName());
47.197 + return (type == res);
47.198 + } catch (ClassNotFoundException ex) {
47.199 + return false;
47.200 + }
47.201 + }
47.202 +
47.203 + /**
47.204 + * Decide if the given method type, attributed to a member or symbolic
47.205 + * reference of a given reference class, is really visible to that class.
47.206 + * @param type the supposed type of a member or symbolic reference of refc
47.207 + * @param refc the class attempting to make the reference
47.208 + */
47.209 + public static boolean isTypeVisible(java.lang.invoke.MethodType type, Class<?> refc) {
47.210 + for (int n = -1, max = type.parameterCount(); n < max; n++) {
47.211 + Class<?> ptype = (n < 0 ? type.returnType() : type.parameterType(n));
47.212 + if (!isTypeVisible(ptype, refc))
47.213 + return false;
47.214 + }
47.215 + return true;
47.216 + }
47.217 +
47.218 + /**
47.219 + * Test if two classes have the same class loader and package qualifier.
47.220 + * @param class1 a class
47.221 + * @param class2 another class
47.222 + * @return whether they are in the same package
47.223 + */
47.224 + public static boolean isSamePackage(Class<?> class1, Class<?> class2) {
47.225 + assert(!class1.isArray() && !class2.isArray());
47.226 + if (class1 == class2)
47.227 + return true;
47.228 + if (class1.getClassLoader() != class2.getClassLoader())
47.229 + return false;
47.230 + String name1 = class1.getName(), name2 = class2.getName();
47.231 + int dot = name1.lastIndexOf('.');
47.232 + if (dot != name2.lastIndexOf('.'))
47.233 + return false;
47.234 + for (int i = 0; i < dot; i++) {
47.235 + if (name1.charAt(i) != name2.charAt(i))
47.236 + return false;
47.237 + }
47.238 + return true;
47.239 + }
47.240 +
47.241 + /** Return the package name for this class.
47.242 + */
47.243 + public static String getPackageName(Class<?> cls) {
47.244 + assert(!cls.isArray());
47.245 + String name = cls.getName();
47.246 + int dot = name.lastIndexOf('.');
47.247 + if (dot < 0) return "";
47.248 + return name.substring(0, dot);
47.249 + }
47.250 +
47.251 + /**
47.252 + * Test if two classes are defined as part of the same package member (top-level class).
47.253 + * If this is true, they can share private access with each other.
47.254 + * @param class1 a class
47.255 + * @param class2 another class
47.256 + * @return whether they are identical or nested together
47.257 + */
47.258 + public static boolean isSamePackageMember(Class<?> class1, Class<?> class2) {
47.259 + if (class1 == class2)
47.260 + return true;
47.261 + if (!isSamePackage(class1, class2))
47.262 + return false;
47.263 + if (getOutermostEnclosingClass(class1) != getOutermostEnclosingClass(class2))
47.264 + return false;
47.265 + return true;
47.266 + }
47.267 +
47.268 + private static Class<?> getOutermostEnclosingClass(Class<?> c) {
47.269 + Class<?> pkgmem = c;
47.270 + for (Class<?> enc = c; (enc = enc.getEnclosingClass()) != null; )
47.271 + pkgmem = enc;
47.272 + return pkgmem;
47.273 + }
47.274 +
47.275 + private static boolean loadersAreRelated(ClassLoader loader1, ClassLoader loader2,
47.276 + boolean loader1MustBeParent) {
47.277 + if (loader1 == loader2 || loader1 == null
47.278 + || (loader2 == null && !loader1MustBeParent)) {
47.279 + return true;
47.280 + }
47.281 + for (ClassLoader scan2 = loader2;
47.282 + scan2 != null; scan2 = scan2.getParent()) {
47.283 + if (scan2 == loader1) return true;
47.284 + }
47.285 + if (loader1MustBeParent) return false;
47.286 + // see if loader2 is a parent of loader1:
47.287 + for (ClassLoader scan1 = loader1;
47.288 + scan1 != null; scan1 = scan1.getParent()) {
47.289 + if (scan1 == loader2) return true;
47.290 + }
47.291 + return false;
47.292 + }
47.293 +
47.294 + /**
47.295 + * Is the class loader of parentClass identical to, or an ancestor of,
47.296 + * the class loader of childClass?
47.297 + * @param parentClass a class
47.298 + * @param childClass another class, which may be a descendent of the first class
47.299 + * @return whether parentClass precedes or equals childClass in class loader order
47.300 + */
47.301 + public static boolean classLoaderIsAncestor(Class<?> parentClass, Class<?> childClass) {
47.302 + return loadersAreRelated(parentClass.getClassLoader(), childClass.getClassLoader(), true);
47.303 + }
47.304 +}
48.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
48.2 +++ b/rt/emul/compact/src/main/java/sun/invoke/util/VerifyType.java Sat Aug 09 11:12:05 2014 +0200
48.3 @@ -0,0 +1,194 @@
48.4 +/*
48.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
48.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
48.7 + *
48.8 + * This code is free software; you can redistribute it and/or modify it
48.9 + * under the terms of the GNU General Public License version 2 only, as
48.10 + * published by the Free Software Foundation. Oracle designates this
48.11 + * particular file as subject to the "Classpath" exception as provided
48.12 + * by Oracle in the LICENSE file that accompanied this code.
48.13 + *
48.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
48.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
48.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
48.17 + * version 2 for more details (a copy is included in the LICENSE file that
48.18 + * accompanied this code).
48.19 + *
48.20 + * You should have received a copy of the GNU General Public License version
48.21 + * 2 along with this work; if not, write to the Free Software Foundation,
48.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
48.23 + *
48.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
48.25 + * or visit www.oracle.com if you need additional information or have any
48.26 + * questions.
48.27 + */
48.28 +
48.29 +package sun.invoke.util;
48.30 +
48.31 +import java.lang.invoke.MethodType;
48.32 +import sun.invoke.empty.Empty;
48.33 +
48.34 +/**
48.35 + * This class centralizes information about the JVM verifier
48.36 + * and its requirements about type correctness.
48.37 + * @author jrose
48.38 + */
48.39 +public class VerifyType {
48.40 +
48.41 + private VerifyType() { } // cannot instantiate
48.42 +
48.43 + /**
48.44 + * True if a value can be stacked as the source type and unstacked as the
48.45 + * destination type, without violating the JVM's type consistency.
48.46 + *
48.47 + * @param src the type of a stacked value
48.48 + * @param dst the type by which we'd like to treat it
48.49 + * @return whether the retyping can be done without motion or reformatting
48.50 + */
48.51 + public static boolean isNullConversion(Class<?> src, Class<?> dst) {
48.52 + if (src == dst) return true;
48.53 + // Verifier allows any interface to be treated as Object:
48.54 + if (dst.isInterface()) dst = Object.class;
48.55 + if (src.isInterface()) src = Object.class;
48.56 + if (src == dst) return true; // check again
48.57 + if (dst == void.class) return true; // drop any return value
48.58 + if (isNullType(src)) return !dst.isPrimitive();
48.59 + if (!src.isPrimitive()) return dst.isAssignableFrom(src);
48.60 + if (!dst.isPrimitive()) return false;
48.61 + // Verifier allows an int to carry byte, short, char, or even boolean:
48.62 + Wrapper sw = Wrapper.forPrimitiveType(src);
48.63 + if (dst == int.class) return sw.isSubwordOrInt();
48.64 + Wrapper dw = Wrapper.forPrimitiveType(dst);
48.65 + if (!sw.isSubwordOrInt()) return false;
48.66 + if (!dw.isSubwordOrInt()) return false;
48.67 + if (!dw.isSigned() && sw.isSigned()) return false;
48.68 + return dw.bitWidth() > sw.bitWidth();
48.69 + }
48.70 +
48.71 + /**
48.72 + * Specialization of isNullConversion to reference types.
48.73 + * @param src the type of a stacked value
48.74 + * @param dst the reference type by which we'd like to treat it
48.75 + * @return whether the retyping can be done without a cast
48.76 + */
48.77 + public static boolean isNullReferenceConversion(Class<?> src, Class<?> dst) {
48.78 + assert(!dst.isPrimitive());
48.79 + if (dst.isInterface()) return true; // verifier allows this
48.80 + if (isNullType(src)) return true;
48.81 + return dst.isAssignableFrom(src);
48.82 + }
48.83 +
48.84 + /**
48.85 + * Is the given type java.lang.Null or an equivalent null-only type?
48.86 + */
48.87 + public static boolean isNullType(Class<?> type) {
48.88 + if (type == null) return false;
48.89 + return type == NULL_CLASS
48.90 + // This one may also be used as a null type.
48.91 + // TO DO: Decide if we really want to legitimize it here.
48.92 + // Probably we do, unless java.lang.Null really makes it into Java 7
48.93 + //|| type == Void.class
48.94 + // Locally known null-only class:
48.95 + || type == Empty.class
48.96 + ;
48.97 + }
48.98 + private static final Class<?> NULL_CLASS;
48.99 + static {
48.100 + Class<?> nullClass = null;
48.101 + try {
48.102 + nullClass = Class.forName("java.lang.Null");
48.103 + } catch (ClassNotFoundException ex) {
48.104 + // OK, we'll cope
48.105 + }
48.106 + NULL_CLASS = nullClass;
48.107 + }
48.108 +
48.109 + /**
48.110 + * True if a method handle can receive a call under a slightly different
48.111 + * method type, without moving or reformatting any stack elements.
48.112 + *
48.113 + * @param call the type of call being made
48.114 + * @param recv the type of the method handle receiving the call
48.115 + * @return whether the retyping can be done without motion or reformatting
48.116 + */
48.117 + public static boolean isNullConversion(MethodType call, MethodType recv) {
48.118 + if (call == recv) return true;
48.119 + int len = call.parameterCount();
48.120 + if (len != recv.parameterCount()) return false;
48.121 + for (int i = 0; i < len; i++)
48.122 + if (!isNullConversion(call.parameterType(i), recv.parameterType(i)))
48.123 + return false;
48.124 + return isNullConversion(recv.returnType(), call.returnType());
48.125 + }
48.126 +
48.127 + /**
48.128 + * Determine if the JVM verifier allows a value of type call to be
48.129 + * passed to a formal parameter (or return variable) of type recv.
48.130 + * Returns 1 if the verifier allows the types to match without conversion.
48.131 + * Returns -1 if the types can be made to match by a JVM-supported adapter.
48.132 + * Cases supported are:
48.133 + * <ul><li>checkcast
48.134 + * </li><li>conversion between any two integral types (but not floats)
48.135 + * </li><li>unboxing from a wrapper to its corresponding primitive type
48.136 + * </li><li>conversion in either direction between float and double
48.137 + * </li></ul>
48.138 + * (Autoboxing is not supported here; it must be done via Java code.)
48.139 + * Returns 0 otherwise.
48.140 + */
48.141 + public static int canPassUnchecked(Class<?> src, Class<?> dst) {
48.142 + if (src == dst)
48.143 + return 1;
48.144 +
48.145 + if (dst.isPrimitive()) {
48.146 + if (dst == void.class)
48.147 + // Return anything to a caller expecting void.
48.148 + // This is a property of the implementation, which links
48.149 + // return values via a register rather than via a stack push.
48.150 + // This makes it possible to ignore cleanly.
48.151 + return 1;
48.152 + if (src == void.class)
48.153 + return 0; // void-to-something?
48.154 + if (!src.isPrimitive())
48.155 + // Cannot pass a reference to any primitive type (exc. void).
48.156 + return 0;
48.157 + Wrapper sw = Wrapper.forPrimitiveType(src);
48.158 + Wrapper dw = Wrapper.forPrimitiveType(dst);
48.159 + if (sw.isSubwordOrInt() && dw.isSubwordOrInt()) {
48.160 + if (sw.bitWidth() >= dw.bitWidth())
48.161 + return -1; // truncation may be required
48.162 + if (!dw.isSigned() && sw.isSigned())
48.163 + return -1; // sign elimination may be required
48.164 + return 1;
48.165 + }
48.166 + if (src == float.class || dst == float.class) {
48.167 + if (src == double.class || dst == double.class)
48.168 + return -1; // floating conversion may be required
48.169 + else
48.170 + return 0; // other primitive conversions NYI
48.171 + } else {
48.172 + // all fixed-point conversions are supported
48.173 + return 0;
48.174 + }
48.175 + } else if (src.isPrimitive()) {
48.176 + // Cannot pass a primitive to any reference type.
48.177 + // (Maybe allow null.class?)
48.178 + return 0;
48.179 + }
48.180 +
48.181 + // Handle reference types in the rest of the block:
48.182 +
48.183 + // The verifier treats interfaces exactly like Object.
48.184 + if (isNullReferenceConversion(src, dst))
48.185 + // pass any reference to object or an arb. interface
48.186 + return 1;
48.187 + // else it's a definite "maybe" (cast is required)
48.188 + return -1;
48.189 + }
48.190 +
48.191 + public static boolean isSpreadArgType(Class<?> spreadArg) {
48.192 + return spreadArg.isArray();
48.193 + }
48.194 + public static Class<?> spreadArgElementType(Class<?> spreadArg, int i) {
48.195 + return spreadArg.getComponentType();
48.196 + }
48.197 +}
49.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
49.2 +++ b/rt/emul/compact/src/main/java/sun/invoke/util/Wrapper.java Sat Aug 09 11:12:05 2014 +0200
49.3 @@ -0,0 +1,614 @@
49.4 +/*
49.5 + * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
49.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
49.7 + *
49.8 + * This code is free software; you can redistribute it and/or modify it
49.9 + * under the terms of the GNU General Public License version 2 only, as
49.10 + * published by the Free Software Foundation. Oracle designates this
49.11 + * particular file as subject to the "Classpath" exception as provided
49.12 + * by Oracle in the LICENSE file that accompanied this code.
49.13 + *
49.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
49.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
49.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
49.17 + * version 2 for more details (a copy is included in the LICENSE file that
49.18 + * accompanied this code).
49.19 + *
49.20 + * You should have received a copy of the GNU General Public License version
49.21 + * 2 along with this work; if not, write to the Free Software Foundation,
49.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
49.23 + *
49.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
49.25 + * or visit www.oracle.com if you need additional information or have any
49.26 + * questions.
49.27 + */
49.28 +
49.29 +package sun.invoke.util;
49.30 +
49.31 +public enum Wrapper {
49.32 + BOOLEAN(Boolean.class, boolean.class, 'Z', (Boolean)false, new boolean[0], Format.unsigned(1)),
49.33 + // These must be in the order defined for widening primitive conversions in JLS 5.1.2
49.34 + BYTE(Byte.class, byte.class, 'B', (Byte)(byte)0, new byte[0], Format.signed(8)),
49.35 + SHORT(Short.class, short.class, 'S', (Short)(short)0, new short[0], Format.signed(16)),
49.36 + CHAR(Character.class, char.class, 'C', (Character)(char)0, new char[0], Format.unsigned(16)),
49.37 + INT(Integer.class, int.class, 'I', (Integer)/*(int)*/0, new int[0], Format.signed(32)),
49.38 + LONG(Long.class, long.class, 'J', (Long)(long)0, new long[0], Format.signed(64)),
49.39 + FLOAT(Float.class, float.class, 'F', (Float)(float)0, new float[0], Format.floating(32)),
49.40 + DOUBLE(Double.class, double.class, 'D', (Double)(double)0, new double[0], Format.floating(64)),
49.41 + //NULL(Null.class, null.class, 'N', null, null, Format.other(1)),
49.42 + OBJECT(Object.class, Object.class, 'L', null, new Object[0], Format.other(1)),
49.43 + // VOID must be the last type, since it is "assignable" from any other type:
49.44 + VOID(Void.class, void.class, 'V', null, null, Format.other(0)),
49.45 + ;
49.46 +
49.47 + private final Class<?> wrapperType;
49.48 + private final Class<?> primitiveType;
49.49 + private final char basicTypeChar;
49.50 + private final Object zero;
49.51 + private final Object emptyArray;
49.52 + private final int format;
49.53 + private final String wrapperSimpleName;
49.54 + private final String primitiveSimpleName;
49.55 +
49.56 + private Wrapper(Class<?> wtype, Class<?> ptype, char tchar, Object zero, Object emptyArray, int format) {
49.57 + this.wrapperType = wtype;
49.58 + this.primitiveType = ptype;
49.59 + this.basicTypeChar = tchar;
49.60 + this.zero = zero;
49.61 + this.emptyArray = emptyArray;
49.62 + this.format = format;
49.63 + this.wrapperSimpleName = wtype.getSimpleName();
49.64 + this.primitiveSimpleName = ptype.getSimpleName();
49.65 + }
49.66 +
49.67 + /** For debugging, give the details of this wrapper. */
49.68 + public String detailString() {
49.69 + return wrapperSimpleName+
49.70 + java.util.Arrays.asList(wrapperType, primitiveType,
49.71 + basicTypeChar, zero,
49.72 + "0x"+Integer.toHexString(format));
49.73 + }
49.74 +
49.75 + private static abstract class Format {
49.76 + static final int SLOT_SHIFT = 0, SIZE_SHIFT = 2, KIND_SHIFT = 12;
49.77 + static final int
49.78 + SIGNED = (-1) << KIND_SHIFT,
49.79 + UNSIGNED = 0 << KIND_SHIFT,
49.80 + FLOATING = 1 << KIND_SHIFT;
49.81 + static final int
49.82 + SLOT_MASK = ((1<<(SIZE_SHIFT-SLOT_SHIFT))-1),
49.83 + SIZE_MASK = ((1<<(KIND_SHIFT-SIZE_SHIFT))-1);
49.84 + static int format(int kind, int size, int slots) {
49.85 + assert(((kind >> KIND_SHIFT) << KIND_SHIFT) == kind);
49.86 + assert((size & (size-1)) == 0); // power of two
49.87 + assert((kind == SIGNED) ? (size > 0) :
49.88 + (kind == UNSIGNED) ? (size > 0) :
49.89 + (kind == FLOATING) ? (size == 32 || size == 64) :
49.90 + false);
49.91 + assert((slots == 2) ? (size == 64) :
49.92 + (slots == 1) ? (size <= 32) :
49.93 + false);
49.94 + return kind | (size << SIZE_SHIFT) | (slots << SLOT_SHIFT);
49.95 + }
49.96 + static final int
49.97 + INT = SIGNED | (32 << SIZE_SHIFT) | (1 << SLOT_SHIFT),
49.98 + SHORT = SIGNED | (16 << SIZE_SHIFT) | (1 << SLOT_SHIFT),
49.99 + BOOLEAN = UNSIGNED | (1 << SIZE_SHIFT) | (1 << SLOT_SHIFT),
49.100 + CHAR = UNSIGNED | (16 << SIZE_SHIFT) | (1 << SLOT_SHIFT),
49.101 + FLOAT = FLOATING | (32 << SIZE_SHIFT) | (1 << SLOT_SHIFT),
49.102 + VOID = UNSIGNED | (0 << SIZE_SHIFT) | (0 << SLOT_SHIFT),
49.103 + NUM_MASK = (-1) << SIZE_SHIFT;
49.104 + static int signed(int size) { return format(SIGNED, size, (size > 32 ? 2 : 1)); }
49.105 + static int unsigned(int size) { return format(UNSIGNED, size, (size > 32 ? 2 : 1)); }
49.106 + static int floating(int size) { return format(FLOATING, size, (size > 32 ? 2 : 1)); }
49.107 + static int other(int slots) { return slots << SLOT_SHIFT; }
49.108 + }
49.109 +
49.110 + /// format queries:
49.111 +
49.112 + /** How many bits are in the wrapped value? Returns 0 for OBJECT or VOID. */
49.113 + public int bitWidth() { return (format >> Format.SIZE_SHIFT) & Format.SIZE_MASK; }
49.114 + /** How many JVM stack slots occupied by the wrapped value? Returns 0 for VOID. */
49.115 + public int stackSlots() { return (format >> Format.SLOT_SHIFT) & Format.SLOT_MASK; }
49.116 + /** Does the wrapped value occupy a single JVM stack slot? */
49.117 + public boolean isSingleWord() { return (format & (1 << Format.SLOT_SHIFT)) != 0; }
49.118 + /** Does the wrapped value occupy two JVM stack slots? */
49.119 + public boolean isDoubleWord() { return (format & (2 << Format.SLOT_SHIFT)) != 0; }
49.120 + /** Is the wrapped type numeric (not void or object)? */
49.121 + public boolean isNumeric() { return (format & Format.NUM_MASK) != 0; }
49.122 + /** Is the wrapped type a primitive other than float, double, or void? */
49.123 + public boolean isIntegral() { return isNumeric() && format < Format.FLOAT; }
49.124 + /** Is the wrapped type one of int, boolean, byte, char, or short? */
49.125 + public boolean isSubwordOrInt() { return isIntegral() && isSingleWord(); }
49.126 + /* Is the wrapped value a signed integral type (one of byte, short, int, or long)? */
49.127 + public boolean isSigned() { return format < Format.VOID; }
49.128 + /* Is the wrapped value an unsigned integral type (one of boolean or char)? */
49.129 + public boolean isUnsigned() { return format >= Format.BOOLEAN && format < Format.FLOAT; }
49.130 + /** Is the wrapped type either float or double? */
49.131 + public boolean isFloating() { return format >= Format.FLOAT; }
49.132 + /** Is the wrapped type either void or a reference? */
49.133 + public boolean isOther() { return (format & ~Format.SLOT_MASK) == 0; }
49.134 +
49.135 + /** Does the JLS 5.1.2 allow a variable of this wrapper's
49.136 + * primitive type to be assigned from a value of the given wrapper's primitive type?
49.137 + * Cases:
49.138 + * <ul>
49.139 + * <li>unboxing followed by widening primitive conversion
49.140 + * <li>any type converted to {@code void} (i.e., dropping a method call's value)
49.141 + * <li>boxing conversion followed by widening reference conversion to {@code Object}
49.142 + * </ul>
49.143 + * These are the cases allowed by MethodHandle.asType.
49.144 + */
49.145 + public boolean isConvertibleFrom(Wrapper source) {
49.146 + if (this == source) return true;
49.147 + if (this.compareTo(source) < 0) {
49.148 + // At best, this is a narrowing conversion.
49.149 + return false;
49.150 + }
49.151 + // All conversions are allowed in the enum order between floats and signed ints.
49.152 + // First detect non-signed non-float types (boolean, char, Object, void).
49.153 + boolean floatOrSigned = (((this.format & source.format) & Format.SIGNED) != 0);
49.154 + if (!floatOrSigned) {
49.155 + if (this.isOther()) return true;
49.156 + // can convert char to int or wider, but nothing else
49.157 + if (source.format == Format.CHAR) return true;
49.158 + // no other conversions are classified as widening
49.159 + return false;
49.160 + }
49.161 + // All signed and float conversions in the enum order are widening.
49.162 + assert(this.isFloating() || this.isSigned());
49.163 + assert(source.isFloating() || source.isSigned());
49.164 + return true;
49.165 + }
49.166 +
49.167 + static { assert(checkConvertibleFrom()); }
49.168 + private static boolean checkConvertibleFrom() {
49.169 + // Check the matrix for correct classification of widening conversions.
49.170 + for (Wrapper w : values()) {
49.171 + assert(w.isConvertibleFrom(w));
49.172 + assert(VOID.isConvertibleFrom(w));
49.173 + if (w != VOID) {
49.174 + assert(OBJECT.isConvertibleFrom(w));
49.175 + assert(!w.isConvertibleFrom(VOID));
49.176 + }
49.177 + // check relations with unsigned integral types:
49.178 + if (w != CHAR) {
49.179 + assert(!CHAR.isConvertibleFrom(w));
49.180 + if (!w.isConvertibleFrom(INT))
49.181 + assert(!w.isConvertibleFrom(CHAR));
49.182 + }
49.183 + if (w != BOOLEAN) {
49.184 + assert(!BOOLEAN.isConvertibleFrom(w));
49.185 + if (w != VOID && w != OBJECT)
49.186 + assert(!w.isConvertibleFrom(BOOLEAN));
49.187 + }
49.188 + // check relations with signed integral types:
49.189 + if (w.isSigned()) {
49.190 + for (Wrapper x : values()) {
49.191 + if (w == x) continue;
49.192 + if (x.isFloating())
49.193 + assert(!w.isConvertibleFrom(x));
49.194 + else if (x.isSigned()) {
49.195 + if (w.compareTo(x) < 0)
49.196 + assert(!w.isConvertibleFrom(x));
49.197 + else
49.198 + assert(w.isConvertibleFrom(x));
49.199 + }
49.200 + }
49.201 + }
49.202 + // check relations with floating types:
49.203 + if (w.isFloating()) {
49.204 + for (Wrapper x : values()) {
49.205 + if (w == x) continue;
49.206 + if (x.isSigned())
49.207 + assert(w.isConvertibleFrom(x));
49.208 + else if (x.isFloating()) {
49.209 + if (w.compareTo(x) < 0)
49.210 + assert(!w.isConvertibleFrom(x));
49.211 + else
49.212 + assert(w.isConvertibleFrom(x));
49.213 + }
49.214 + }
49.215 + }
49.216 + }
49.217 + return true; // i.e., assert(true)
49.218 + }
49.219 +
49.220 + /** Produce a zero value for the given wrapper type.
49.221 + * This will be a numeric zero for a number or character,
49.222 + * false for a boolean, and null for a reference or void.
49.223 + * The common thread is that this is what is contained
49.224 + * in a default-initialized variable of the given primitive
49.225 + * type. (For void, it is what a reflective method returns
49.226 + * instead of no value at all.)
49.227 + */
49.228 + public Object zero() { return zero; }
49.229 +
49.230 + /** Produce a zero value for the given wrapper type T.
49.231 + * The optional argument must a type compatible with this wrapper.
49.232 + * Equivalent to {@code this.cast(this.zero(), type)}.
49.233 + */
49.234 + public <T> T zero(Class<T> type) { return convert(zero, type); }
49.235 +
49.236 +// /** Produce a wrapper for the given wrapper or primitive type. */
49.237 +// public static Wrapper valueOf(Class<?> type) {
49.238 +// if (isPrimitiveType(type))
49.239 +// return forPrimitiveType(type);
49.240 +// else
49.241 +// return forWrapperType(type);
49.242 +// }
49.243 +
49.244 + /** Return the wrapper that wraps values of the given type.
49.245 + * The type may be {@code Object}, meaning the {@code OBJECT} wrapper.
49.246 + * Otherwise, the type must be a primitive.
49.247 + * @throws IllegalArgumentException for unexpected types
49.248 + */
49.249 + public static Wrapper forPrimitiveType(Class<?> type) {
49.250 + Wrapper w = findPrimitiveType(type);
49.251 + if (w != null) return w;
49.252 + if (type.isPrimitive())
49.253 + throw new InternalError(); // redo hash function
49.254 + throw newIllegalArgumentException("not primitive: "+type);
49.255 + }
49.256 +
49.257 + static Wrapper findPrimitiveType(Class<?> type) {
49.258 + Wrapper w = FROM_PRIM[hashPrim(type)];
49.259 + if (w != null && w.primitiveType == type) {
49.260 + return w;
49.261 + }
49.262 + return null;
49.263 + }
49.264 +
49.265 + /** Return the wrapper that wraps values into the given wrapper type.
49.266 + * If it is {@code Object}, return {@code OBJECT}.
49.267 + * Otherwise, it must be a wrapper type.
49.268 + * The type must not be a primitive type.
49.269 + * @throws IllegalArgumentException for unexpected types
49.270 + */
49.271 + public static Wrapper forWrapperType(Class<?> type) {
49.272 + Wrapper w = findWrapperType(type);
49.273 + if (w != null) return w;
49.274 + for (Wrapper x : values())
49.275 + if (x.wrapperType == type)
49.276 + throw new InternalError(); // redo hash function
49.277 + throw newIllegalArgumentException("not wrapper: "+type);
49.278 + }
49.279 +
49.280 + static Wrapper findWrapperType(Class<?> type) {
49.281 + Wrapper w = FROM_WRAP[hashWrap(type)];
49.282 + if (w != null && w.wrapperType == type) {
49.283 + return w;
49.284 + }
49.285 + return null;
49.286 + }
49.287 +
49.288 + /** Return the wrapper that corresponds to the given bytecode
49.289 + * signature character. Return {@code OBJECT} for the character 'L'.
49.290 + * @throws IllegalArgumentException for any non-signature character or {@code '['}.
49.291 + */
49.292 + public static Wrapper forBasicType(char type) {
49.293 + Wrapper w = FROM_CHAR[hashChar(type)];
49.294 + if (w != null && w.basicTypeChar == type) {
49.295 + return w;
49.296 + }
49.297 + for (Wrapper x : values())
49.298 + if (w.basicTypeChar == type)
49.299 + throw new InternalError(); // redo hash function
49.300 + throw newIllegalArgumentException("not basic type char: "+type);
49.301 + }
49.302 +
49.303 + /** Return the wrapper for the given type, if it is
49.304 + * a primitive type, else return {@code OBJECT}.
49.305 + */
49.306 + public static Wrapper forBasicType(Class<?> type) {
49.307 + if (type.isPrimitive())
49.308 + return forPrimitiveType(type);
49.309 + return OBJECT; // any reference, including wrappers or arrays
49.310 + }
49.311 +
49.312 + // Note on perfect hashes:
49.313 + // for signature chars c, do (c + (c >> 1)) % 16
49.314 + // for primitive type names n, do (n[0] + n[2]) % 16
49.315 + // The type name hash works for both primitive and wrapper names.
49.316 + // You can add "java/lang/Object" to the primitive names.
49.317 + // But you add the wrapper name Object, use (n[2] + (3*n[1])) % 16.
49.318 + private static final Wrapper[] FROM_PRIM = new Wrapper[16];
49.319 + private static final Wrapper[] FROM_WRAP = new Wrapper[16];
49.320 + private static final Wrapper[] FROM_CHAR = new Wrapper[16];
49.321 + private static int hashPrim(Class<?> x) {
49.322 + String xn = x.getName();
49.323 + if (xn.length() < 3) return 0;
49.324 + return (xn.charAt(0) + xn.charAt(2)) % 16;
49.325 + }
49.326 + private static int hashWrap(Class<?> x) {
49.327 + String xn = x.getName();
49.328 + final int offset = 10; assert(offset == "java.lang.".length());
49.329 + if (xn.length() < offset+3) return 0;
49.330 + return (3*xn.charAt(offset+1) + xn.charAt(offset+2)) % 16;
49.331 + }
49.332 + private static int hashChar(char x) {
49.333 + return (x + (x >> 1)) % 16;
49.334 + }
49.335 + static {
49.336 + for (Wrapper w : values()) {
49.337 + int pi = hashPrim(w.primitiveType);
49.338 + int wi = hashWrap(w.wrapperType);
49.339 + int ci = hashChar(w.basicTypeChar);
49.340 + assert(FROM_PRIM[pi] == null);
49.341 + assert(FROM_WRAP[wi] == null);
49.342 + assert(FROM_CHAR[ci] == null);
49.343 + FROM_PRIM[pi] = w;
49.344 + FROM_WRAP[wi] = w;
49.345 + FROM_CHAR[ci] = w;
49.346 + }
49.347 + //assert(jdk.sun.invoke.util.WrapperTest.test(false));
49.348 + }
49.349 +
49.350 + /** What is the primitive type wrapped by this wrapper? */
49.351 + public Class<?> primitiveType() { return primitiveType; }
49.352 +
49.353 + /** What is the wrapper type for this wrapper? */
49.354 + public Class<?> wrapperType() { return wrapperType; }
49.355 +
49.356 + /** What is the wrapper type for this wrapper?
49.357 + * Otherwise, the example type must be the wrapper type,
49.358 + * or the corresponding primitive type.
49.359 + * (For {@code OBJECT}, the example type can be any non-primitive,
49.360 + * and is normalized to {@code Object.class}.)
49.361 + * The resulting class type has the same type parameter.
49.362 + */
49.363 + public <T> Class<T> wrapperType(Class<T> exampleType) {
49.364 + if (exampleType == wrapperType) {
49.365 + return exampleType;
49.366 + } else if (exampleType == primitiveType ||
49.367 + wrapperType == Object.class ||
49.368 + exampleType.isInterface()) {
49.369 + return forceType(wrapperType, exampleType);
49.370 + }
49.371 + throw newClassCastException(exampleType, primitiveType);
49.372 + }
49.373 +
49.374 + private static ClassCastException newClassCastException(Class<?> actual, Class<?> expected) {
49.375 + return new ClassCastException(actual + " is not compatible with " + expected);
49.376 + }
49.377 +
49.378 + /** If {@code type} is a primitive type, return the corresponding
49.379 + * wrapper type, else return {@code type} unchanged.
49.380 + */
49.381 + public static <T> Class<T> asWrapperType(Class<T> type) {
49.382 + if (type.isPrimitive()) {
49.383 + return forPrimitiveType(type).wrapperType(type);
49.384 + }
49.385 + return type;
49.386 + }
49.387 +
49.388 + /** If {@code type} is a wrapper type, return the corresponding
49.389 + * primitive type, else return {@code type} unchanged.
49.390 + */
49.391 + public static <T> Class<T> asPrimitiveType(Class<T> type) {
49.392 + Wrapper w = findWrapperType(type);
49.393 + if (w != null) {
49.394 + return forceType(w.primitiveType(), type);
49.395 + }
49.396 + return type;
49.397 + }
49.398 +
49.399 + /** Query: Is the given type a wrapper, such as {@code Integer} or {@code Void}? */
49.400 + public static boolean isWrapperType(Class<?> type) {
49.401 + return findWrapperType(type) != null;
49.402 + }
49.403 +
49.404 + /** Query: Is the given type a primitive, such as {@code int} or {@code void}? */
49.405 + public static boolean isPrimitiveType(Class<?> type) {
49.406 + return type.isPrimitive();
49.407 + }
49.408 +
49.409 + /** What is the bytecode signature character for this type?
49.410 + * All non-primitives, including array types, report as 'L', the signature character for references.
49.411 + */
49.412 + public static char basicTypeChar(Class<?> type) {
49.413 + if (!type.isPrimitive())
49.414 + return 'L';
49.415 + else
49.416 + return forPrimitiveType(type).basicTypeChar();
49.417 + }
49.418 +
49.419 + /** What is the bytecode signature character for this wrapper's
49.420 + * primitive type?
49.421 + */
49.422 + public char basicTypeChar() { return basicTypeChar; }
49.423 +
49.424 + /** What is the simple name of the wrapper type?
49.425 + */
49.426 + public String wrapperSimpleName() { return wrapperSimpleName; }
49.427 +
49.428 + /** What is the simple name of the primitive type?
49.429 + */
49.430 + public String primitiveSimpleName() { return primitiveSimpleName; }
49.431 +
49.432 +// /** Wrap a value in the given type, which may be either a primitive or wrapper type.
49.433 +// * Performs standard primitive conversions, including truncation and float conversions.
49.434 +// */
49.435 +// public static <T> T wrap(Object x, Class<T> type) {
49.436 +// return Wrapper.valueOf(type).cast(x, type);
49.437 +// }
49.438 +
49.439 + /** Cast a wrapped value to the given type, which may be either a primitive or wrapper type.
49.440 + * The given target type must be this wrapper's primitive or wrapper type.
49.441 + * If this wrapper is OBJECT, the target type may also be an interface, perform no runtime check.
49.442 + * Performs standard primitive conversions, including truncation and float conversions.
49.443 + * The given type must be compatible with this wrapper. That is, it must either
49.444 + * be the wrapper type (or a subtype, in the case of {@code OBJECT}) or else
49.445 + * it must be the wrapper's primitive type.
49.446 + * Primitive conversions are only performed if the given type is itself a primitive.
49.447 + * @throws ClassCastException if the given type is not compatible with this wrapper
49.448 + */
49.449 + public <T> T cast(Object x, Class<T> type) {
49.450 + return convert(x, type, true);
49.451 + }
49.452 +
49.453 + /** Convert a wrapped value to the given type.
49.454 + * The given target type must be this wrapper's primitive or wrapper type.
49.455 + * This is equivalent to {@link #cast}, except that it refuses to perform
49.456 + * narrowing primitive conversions.
49.457 + */
49.458 + public <T> T convert(Object x, Class<T> type) {
49.459 + return convert(x, type, false);
49.460 + }
49.461 +
49.462 + private <T> T convert(Object x, Class<T> type, boolean isCast) {
49.463 + if (this == OBJECT) {
49.464 + // If the target wrapper is OBJECT, just do a reference cast.
49.465 + // If the target type is an interface, perform no runtime check.
49.466 + // (This loophole is safe, and is allowed by the JVM verifier.)
49.467 + // If the target type is a primitive, change it to a wrapper.
49.468 + assert(!type.isPrimitive());
49.469 + if (!type.isInterface())
49.470 + type.cast(x);
49.471 + @SuppressWarnings("unchecked")
49.472 + T result = (T) x; // unchecked warning is expected here
49.473 + return result;
49.474 + }
49.475 + Class<T> wtype = wrapperType(type);
49.476 + if (wtype.isInstance(x)) {
49.477 + return wtype.cast(x);
49.478 + }
49.479 + if (!isCast) {
49.480 + Class<?> sourceType = x.getClass(); // throw NPE if x is null
49.481 + Wrapper source = findWrapperType(sourceType);
49.482 + if (source == null || !this.isConvertibleFrom(source)) {
49.483 + throw newClassCastException(wtype, sourceType);
49.484 + }
49.485 + } else if (x == null) {
49.486 + @SuppressWarnings("unchecked")
49.487 + T z = (T) zero;
49.488 + return z;
49.489 + }
49.490 + @SuppressWarnings("unchecked")
49.491 + T result = (T) wrap(x); // unchecked warning is expected here
49.492 + assert (result == null ? Void.class : result.getClass()) == wtype;
49.493 + return result;
49.494 + }
49.495 +
49.496 + /** Cast a reference type to another reference type.
49.497 + * If the target type is an interface, perform no runtime check.
49.498 + * (This loophole is safe, and is allowed by the JVM verifier.)
49.499 + * If the target type is a primitive, change it to a wrapper.
49.500 + */
49.501 + static <T> Class<T> forceType(Class<?> type, Class<T> exampleType) {
49.502 + boolean z = (type == exampleType ||
49.503 + type.isPrimitive() && forPrimitiveType(type) == findWrapperType(exampleType) ||
49.504 + exampleType.isPrimitive() && forPrimitiveType(exampleType) == findWrapperType(type) ||
49.505 + type == Object.class && !exampleType.isPrimitive());
49.506 + if (!z)
49.507 + System.out.println(type+" <= "+exampleType);
49.508 + assert(type == exampleType ||
49.509 + type.isPrimitive() && forPrimitiveType(type) == findWrapperType(exampleType) ||
49.510 + exampleType.isPrimitive() && forPrimitiveType(exampleType) == findWrapperType(type) ||
49.511 + type == Object.class && !exampleType.isPrimitive());
49.512 + @SuppressWarnings("unchecked")
49.513 + Class<T> result = (Class<T>) type; // unchecked warning is expected here
49.514 + return result;
49.515 + }
49.516 +
49.517 + /** Wrap a value in this wrapper's type.
49.518 + * Performs standard primitive conversions, including truncation and float conversions.
49.519 + * Performs returns the unchanged reference for {@code OBJECT}.
49.520 + * Returns null for {@code VOID}.
49.521 + * Returns a zero value for a null input.
49.522 + * @throws ClassCastException if this wrapper is numeric and the operand
49.523 + * is not a number, character, boolean, or null
49.524 + */
49.525 + public Object wrap(Object x) {
49.526 + // do non-numeric wrappers first
49.527 + switch (basicTypeChar) {
49.528 + case 'L': return x;
49.529 + case 'V': return null;
49.530 + }
49.531 + Number xn = numberValue(x);
49.532 + switch (basicTypeChar) {
49.533 + case 'I': return Integer.valueOf(xn.intValue());
49.534 + case 'J': return Long.valueOf(xn.longValue());
49.535 + case 'F': return Float.valueOf(xn.floatValue());
49.536 + case 'D': return Double.valueOf(xn.doubleValue());
49.537 + case 'S': return Short.valueOf((short) xn.intValue());
49.538 + case 'B': return Byte.valueOf((byte) xn.intValue());
49.539 + case 'C': return Character.valueOf((char) xn.intValue());
49.540 + case 'Z': return Boolean.valueOf(boolValue(xn.byteValue()));
49.541 + }
49.542 + throw new InternalError("bad wrapper");
49.543 + }
49.544 +
49.545 + /** Wrap a value (an int or smaller value) in this wrapper's type.
49.546 + * Performs standard primitive conversions, including truncation and float conversions.
49.547 + * Produces an {@code Integer} for {@code OBJECT}, although the exact type
49.548 + * of the operand is not known.
49.549 + * Returns null for {@code VOID}.
49.550 + */
49.551 + public Object wrap(int x) {
49.552 + if (basicTypeChar == 'L') return (Integer)x;
49.553 + switch (basicTypeChar) {
49.554 + case 'L': throw newIllegalArgumentException("cannot wrap to object type");
49.555 + case 'V': return null;
49.556 + case 'I': return Integer.valueOf(x);
49.557 + case 'J': return Long.valueOf(x);
49.558 + case 'F': return Float.valueOf(x);
49.559 + case 'D': return Double.valueOf(x);
49.560 + case 'S': return Short.valueOf((short) x);
49.561 + case 'B': return Byte.valueOf((byte) x);
49.562 + case 'C': return Character.valueOf((char) x);
49.563 + case 'Z': return Boolean.valueOf(boolValue((byte) x));
49.564 + }
49.565 + throw new InternalError("bad wrapper");
49.566 + }
49.567 +
49.568 + private static Number numberValue(Object x) {
49.569 + if (x instanceof Number) return (Number)x;
49.570 + if (x instanceof Character) return (int)(Character)x;
49.571 + if (x instanceof Boolean) return (Boolean)x ? 1 : 0;
49.572 + // Remaining allowed case of void: Must be a null reference.
49.573 + return (Number)x;
49.574 + }
49.575 +
49.576 + // Parameter type of boolValue must be byte, because
49.577 + // MethodHandles.explicitCastArguments defines boolean
49.578 + // conversion as first converting to byte.
49.579 + private static boolean boolValue(byte bits) {
49.580 + bits &= 1; // simple 31-bit zero extension
49.581 + return (bits != 0);
49.582 + }
49.583 +
49.584 + private static RuntimeException newIllegalArgumentException(String message, Object x) {
49.585 + return newIllegalArgumentException(message + x);
49.586 + }
49.587 + private static RuntimeException newIllegalArgumentException(String message) {
49.588 + return new IllegalArgumentException(message);
49.589 + }
49.590 +
49.591 + // primitive array support
49.592 + public Object makeArray(int len) {
49.593 + return java.lang.reflect.Array.newInstance(primitiveType, len);
49.594 + }
49.595 + public Class<?> arrayType() {
49.596 + return emptyArray.getClass();
49.597 + }
49.598 + public void copyArrayUnboxing(Object[] values, int vpos, Object a, int apos, int length) {
49.599 + if (a.getClass() != arrayType())
49.600 + arrayType().cast(a); // throw NPE or CCE if bad type
49.601 + for (int i = 0; i < length; i++) {
49.602 + Object value = values[i+vpos];
49.603 + value = convert(value, primitiveType);
49.604 + java.lang.reflect.Array.set(a, i+apos, value);
49.605 + }
49.606 + }
49.607 + public void copyArrayBoxing(Object a, int apos, Object[] values, int vpos, int length) {
49.608 + if (a.getClass() != arrayType())
49.609 + arrayType().cast(a); // throw NPE or CCE if bad type
49.610 + for (int i = 0; i < length; i++) {
49.611 + Object value = java.lang.reflect.Array.get(a, i+apos);
49.612 + //Already done: value = convert(value, primitiveType);
49.613 + assert(value.getClass() == wrapperType);
49.614 + values[i+vpos] = value;
49.615 + }
49.616 + }
49.617 +}
50.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
50.2 +++ b/rt/emul/compact/src/main/java/sun/invoke/util/package-info.java Sat Aug 09 11:12:05 2014 +0200
50.3 @@ -0,0 +1,31 @@
50.4 +/*
50.5 + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
50.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
50.7 + *
50.8 + * This code is free software; you can redistribute it and/or modify it
50.9 + * under the terms of the GNU General Public License version 2 only, as
50.10 + * published by the Free Software Foundation. Oracle designates this
50.11 + * particular file as subject to the "Classpath" exception as provided
50.12 + * by Oracle in the LICENSE file that accompanied this code.
50.13 + *
50.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
50.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
50.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
50.17 + * version 2 for more details (a copy is included in the LICENSE file that
50.18 + * accompanied this code).
50.19 + *
50.20 + * You should have received a copy of the GNU General Public License version
50.21 + * 2 along with this work; if not, write to the Free Software Foundation,
50.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
50.23 + *
50.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
50.25 + * or visit www.oracle.com if you need additional information or have any
50.26 + * questions.
50.27 + */
50.28 +
50.29 +/**
50.30 + * Extra support for using JSR 292 RI, package java.lang.invoke.
50.31 + * @author jrose
50.32 + */
50.33 +
50.34 +package sun.invoke.util;