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() {