Add sources for API 35
Downloaded from https://dl.google.com/android/repository/source-35_r01.zip
using SdkManager in Studio
Test: None
Change-Id: I83f78aa820b66edfdc9f8594d17bc7b6cacccec1
diff --git a/android-35/java/lang/invoke/ArrayElementVarHandle.java b/android-35/java/lang/invoke/ArrayElementVarHandle.java
new file mode 100644
index 0000000..e315ba7
--- /dev/null
+++ b/android-35/java/lang/invoke/ArrayElementVarHandle.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.lang.invoke;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+/**
+ * A VarHandle to access array elements.
+ * @hide
+ */
+final class ArrayElementVarHandle extends VarHandle {
+ private ArrayElementVarHandle(Class<?> arrayClass) {
+ super(arrayClass.getComponentType(), arrayClass, false /* isFinal */,
+ arrayClass, int.class);
+ }
+
+ static ArrayElementVarHandle create(Class<?> arrayClass) {
+ return new ArrayElementVarHandle(arrayClass);
+ }
+}
diff --git a/android-35/java/lang/invoke/ByteArrayViewVarHandle.java b/android-35/java/lang/invoke/ByteArrayViewVarHandle.java
new file mode 100644
index 0000000..abdb1cb
--- /dev/null
+++ b/android-35/java/lang/invoke/ByteArrayViewVarHandle.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.lang.invoke;
+
+import java.nio.ByteOrder;
+
+/**
+ * A VarHandle to access byte array elements as an array of primitive types.
+ * @hide
+ */
+final class ByteArrayViewVarHandle extends VarHandle {
+ private boolean nativeByteOrder;
+
+ private ByteArrayViewVarHandle(Class<?> arrayClass, ByteOrder byteOrder) {
+ super(arrayClass.getComponentType(), byte[].class, false /* isFinal */,
+ byte[].class, int.class);
+ this.nativeByteOrder = byteOrder.equals(ByteOrder.nativeOrder());
+ }
+
+ static ByteArrayViewVarHandle create(Class<?> arrayClass, ByteOrder byteOrder) {
+ return new ByteArrayViewVarHandle(arrayClass, byteOrder);
+ }
+}
diff --git a/android-35/java/lang/invoke/ByteBufferViewVarHandle.java b/android-35/java/lang/invoke/ByteBufferViewVarHandle.java
new file mode 100644
index 0000000..75fcbab
--- /dev/null
+++ b/android-35/java/lang/invoke/ByteBufferViewVarHandle.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.lang.invoke;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * A VarHandle to access byte array elements as an array of primitive types.
+ * @hide
+ */
+final class ByteBufferViewVarHandle extends VarHandle {
+ private boolean nativeByteOrder;
+
+ private ByteBufferViewVarHandle(Class<?> arrayClass, ByteOrder byteOrder) {
+ super(arrayClass.getComponentType(), byte[].class, false /* isFinal */,
+ ByteBuffer.class, int.class);
+ this.nativeByteOrder = byteOrder.equals(ByteOrder.nativeOrder());
+ }
+
+ static ByteBufferViewVarHandle create(Class<?> arrayClass, ByteOrder byteOrder) {
+ return new ByteBufferViewVarHandle(arrayClass, byteOrder);
+ }
+}
diff --git a/android-35/java/lang/invoke/CallSite.java b/android-35/java/lang/invoke/CallSite.java
new file mode 100644
index 0000000..069b2fd
--- /dev/null
+++ b/android-35/java/lang/invoke/CallSite.java
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+// Android-changed: Not using Empty.
+//import sun.invoke.empty.Empty;
+import static java.lang.invoke.MethodHandleStatics.*;
+import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
+
+/**
+ * A {@code CallSite} is a holder for a variable {@link MethodHandle},
+ * which is called its {@code target}.
+ * An {@code invokedynamic} instruction linked to a {@code CallSite} delegates
+ * all calls to the site's current target.
+ * A {@code CallSite} may be associated with several {@code invokedynamic}
+ * instructions, or it may be "free floating", associated with none.
+ * In any case, it may be invoked through an associated method handle
+ * called its {@linkplain #dynamicInvoker dynamic invoker}.
+ * <p>
+ * {@code CallSite} is an abstract class which does not allow
+ * direct subclassing by users. It has three immediate,
+ * concrete subclasses that may be either instantiated or subclassed.
+ * <ul>
+ * <li>If a mutable target is not required, an {@code invokedynamic} instruction
+ * may be permanently bound by means of a {@linkplain ConstantCallSite constant call site}.
+ * <li>If a mutable target is required which has volatile variable semantics,
+ * because updates to the target must be immediately and reliably witnessed by other threads,
+ * a {@linkplain VolatileCallSite volatile call site} may be used.
+ * <li>Otherwise, if a mutable target is required,
+ * a {@linkplain MutableCallSite mutable call site} may be used.
+ * </ul>
+ * <p>
+ * A non-constant call site may be <em>relinked</em> by changing its target.
+ * The new target must have the same {@linkplain MethodHandle#type() type}
+ * as the previous target.
+ * Thus, though a call site can be relinked to a series of
+ * successive targets, it cannot change its type.
+ * <p>
+ * Here is a sample use of call sites and bootstrap methods which links every
+ * dynamic call site to print its arguments:
+<blockquote><pre>{@code
+static void test() throws Throwable {
+ // THE FOLLOWING LINE IS PSEUDOCODE FOR A JVM INSTRUCTION
+ InvokeDynamic[#bootstrapDynamic].baz("baz arg", 2, 3.14);
+}
+private static void printArgs(Object... args) {
+ System.out.println(java.util.Arrays.deepToString(args));
+}
+private static final MethodHandle printArgs;
+static {
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+ Class thisClass = lookup.lookupClass(); // (who am I?)
+ printArgs = lookup.findStatic(thisClass,
+ "printArgs", MethodType.methodType(void.class, Object[].class));
+}
+private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String name, MethodType type) {
+ // ignore caller and name, but match the type:
+ return new ConstantCallSite(printArgs.asType(type));
+}
+}</pre></blockquote>
+ * @author John Rose, JSR 292 EG
+ */
+abstract
+public class CallSite {
+ // Android-changed: not used.
+ // static { MethodHandleImpl.initStatics(); }
+
+ // The actual payload of this call site:
+ /*package-private*/
+ MethodHandle target; // Note: This field is known to the JVM. Do not change.
+
+ /**
+ * Make a blank call site object with the given method type.
+ * An initial target method is supplied which will throw
+ * an {@link IllegalStateException} if called.
+ * <p>
+ * Before this {@code CallSite} object is returned from a bootstrap method,
+ * it is usually provided with a more useful target method,
+ * via a call to {@link CallSite#setTarget(MethodHandle) setTarget}.
+ * @throws NullPointerException if the proposed type is null
+ */
+ /*package-private*/
+ CallSite(MethodType type) {
+ // Android-changed: No cache for these.
+ // Instead create uninitializedCallSite target here using method handle transformations
+ // to create a method handle that has the expected method type but throws an
+ // IllegalStateException.
+ // target = makeUninitializedCallSite(type);
+ this.target = MethodHandles.throwException(type.returnType(), IllegalStateException.class);
+ this.target = MethodHandles.insertArguments(
+ this.target, 0, new IllegalStateException("uninitialized call site"));
+ if (type.parameterCount() > 0) {
+ this.target = MethodHandles.dropArguments(this.target, 0, type.ptypes());
+ }
+
+ // Android-changed: Using initializer method for GET_TARGET instead of static initializer.
+ initializeGetTarget();
+ }
+
+ /**
+ * Make a call site object equipped with an initial target method handle.
+ * @param target the method handle which will be the initial target of the call site
+ * @throws NullPointerException if the proposed target is null
+ */
+ /*package-private*/
+ CallSite(MethodHandle target) {
+ target.type(); // null check
+ this.target = target;
+
+ // Android-changed: Using initializer method for GET_TARGET instead of static initializer.
+ initializeGetTarget();
+ }
+
+ /**
+ * Make a call site object equipped with an initial target method handle.
+ * @param targetType the desired type of the call site
+ * @param createTargetHook a hook which will bind the call site to the target method handle
+ * @throws WrongMethodTypeException if the hook cannot be invoked on the required arguments,
+ * or if the target returned by the hook is not of the given {@code targetType}
+ * @throws NullPointerException if the hook returns a null value
+ * @throws ClassCastException if the hook returns something other than a {@code MethodHandle}
+ * @throws Throwable anything else thrown by the hook function
+ */
+ /*package-private*/
+ CallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable {
+ this(targetType);
+ ConstantCallSite selfCCS = (ConstantCallSite) this;
+ MethodHandle boundTarget = (MethodHandle) createTargetHook.invokeWithArguments(selfCCS);
+ checkTargetChange(this.target, boundTarget);
+ this.target = boundTarget;
+
+ // Android-changed: Using initializer method for GET_TARGET instead of static initializer.
+ initializeGetTarget();
+ }
+
+ /**
+ * Returns the type of this call site's target.
+ * Although targets may change, any call site's type is permanent, and can never change to an unequal type.
+ * The {@code setTarget} method enforces this invariant by refusing any new target that does
+ * not have the previous target's type.
+ * @return the type of the current target, which is also the type of any future target
+ */
+ public MethodType type() {
+ // warning: do not call getTarget here, because CCS.getTarget can throw IllegalStateException
+ return target.type();
+ }
+
+ /**
+ * Returns the target method of the call site, according to the
+ * behavior defined by this call site's specific class.
+ * The immediate subclasses of {@code CallSite} document the
+ * class-specific behaviors of this method.
+ *
+ * @return the current linkage state of the call site, its target method handle
+ * @see ConstantCallSite
+ * @see VolatileCallSite
+ * @see #setTarget
+ * @see ConstantCallSite#getTarget
+ * @see MutableCallSite#getTarget
+ * @see VolatileCallSite#getTarget
+ */
+ public abstract MethodHandle getTarget();
+
+ /**
+ * Updates the target method of this call site, according to the
+ * behavior defined by this call site's specific class.
+ * The immediate subclasses of {@code CallSite} document the
+ * class-specific behaviors of this method.
+ * <p>
+ * The type of the new target must be {@linkplain MethodType#equals equal to}
+ * the type of the old target.
+ *
+ * @param newTarget the new target
+ * @throws NullPointerException if the proposed new target is null
+ * @throws WrongMethodTypeException if the proposed new target
+ * has a method type that differs from the previous target
+ * @see CallSite#getTarget
+ * @see ConstantCallSite#setTarget
+ * @see MutableCallSite#setTarget
+ * @see VolatileCallSite#setTarget
+ */
+ public abstract void setTarget(MethodHandle newTarget);
+
+ void checkTargetChange(MethodHandle oldTarget, MethodHandle newTarget) {
+ MethodType oldType = oldTarget.type();
+ MethodType newType = newTarget.type(); // null check!
+ if (!newType.equals(oldType))
+ throw wrongTargetType(newTarget, oldType);
+ }
+
+ private static WrongMethodTypeException wrongTargetType(MethodHandle target, MethodType type) {
+ return new WrongMethodTypeException(String.valueOf(target)+" should be of type "+type);
+ }
+
+ /**
+ * Produces a method handle equivalent to an invokedynamic instruction
+ * which has been linked to this call site.
+ * <p>
+ * This method is equivalent to the following code:
+ * <blockquote><pre>{@code
+ * MethodHandle getTarget, invoker, result;
+ * getTarget = MethodHandles.publicLookup().bind(this, "getTarget", MethodType.methodType(MethodHandle.class));
+ * invoker = MethodHandles.exactInvoker(this.type());
+ * result = MethodHandles.foldArguments(invoker, getTarget)
+ * }</pre></blockquote>
+ *
+ * @return a method handle which always invokes this call site's current target
+ */
+ public abstract MethodHandle dynamicInvoker();
+
+ /*non-public*/ MethodHandle makeDynamicInvoker() {
+ // Android-changed: Use bindTo() rather than bindArgumentL() (not implemented).
+ MethodHandle getTarget = GET_TARGET.bindTo(this);
+ MethodHandle invoker = MethodHandles.exactInvoker(this.type());
+ return MethodHandles.foldArguments(invoker, getTarget);
+ }
+
+ // Android-changed: no longer final. GET_TARGET assigned in initializeGetTarget().
+ private static MethodHandle GET_TARGET = null;
+
+ private void initializeGetTarget() {
+ // Android-changed: moved from static initializer for GET_TARGET.
+ // This avoids issues with running early. Called from constructors.
+ // CallSite creation is not performance critical.
+ synchronized (CallSite.class) {
+ if (GET_TARGET == null) {
+ try {
+ GET_TARGET = IMPL_LOOKUP.
+ findVirtual(CallSite.class, "getTarget",
+ MethodType.methodType(MethodHandle.class));
+ } catch (ReflectiveOperationException e) {
+ throw new InternalError(e);
+ }
+ }
+ }
+ }
+
+ // Android-changed: not used.
+ // /** This guy is rolled into the default target if a MethodType is supplied to the constructor. */
+ // /*package-private*/
+ // static Empty uninitializedCallSite() {
+ // throw new IllegalStateException("uninitialized call site");
+ // }
+
+ // unsafe stuff:
+ private static final long TARGET_OFFSET;
+ static {
+ try {
+ TARGET_OFFSET = UNSAFE.objectFieldOffset(CallSite.class.getDeclaredField("target"));
+ } catch (Exception ex) { throw new Error(ex); }
+ }
+
+ /*package-private*/
+ void setTargetNormal(MethodHandle newTarget) {
+ // Android-changed: Set value directly.
+ // MethodHandleNatives.setCallSiteTargetNormal(this, newTarget);
+ target = newTarget;
+ }
+ /*package-private*/
+ MethodHandle getTargetVolatile() {
+ return (MethodHandle) UNSAFE.getObjectVolatile(this, TARGET_OFFSET);
+ }
+ /*package-private*/
+ void setTargetVolatile(MethodHandle newTarget) {
+ // Android-changed: Set value directly.
+ // MethodHandleNatives.setCallSiteTargetVolatile(this, newTarget);
+ UNSAFE.putObjectVolatile(this, TARGET_OFFSET, newTarget);
+ }
+
+ // Android-changed: not used.
+ // this implements the upcall from the JVM, MethodHandleNatives.makeDynamicCallSite:
+ // static CallSite makeSite(MethodHandle bootstrapMethod,
+ // // Callee information:
+ // String name, MethodType type,
+ // // Extra arguments for BSM, if any:
+ // Object info,
+ // // Caller information:
+ // Class<?> callerClass) {
+ // MethodHandles.Lookup caller = IMPL_LOOKUP.in(callerClass);
+ // CallSite site;
+ // try {
+ // Object binding;
+ // info = maybeReBox(info);
+ // if (info == null) {
+ // binding = bootstrapMethod.invoke(caller, name, type);
+ // } else if (!info.getClass().isArray()) {
+ // binding = bootstrapMethod.invoke(caller, name, type, info);
+ // } else {
+ // Object[] argv = (Object[]) info;
+ // maybeReBoxElements(argv);
+ // switch (argv.length) {
+ // case 0:
+ // binding = bootstrapMethod.invoke(caller, name, type);
+ // break;
+ // case 1:
+ // binding = bootstrapMethod.invoke(caller, name, type,
+ // argv[0]);
+ // break;
+ // case 2:
+ // binding = bootstrapMethod.invoke(caller, name, type,
+ // argv[0], argv[1]);
+ // break;
+ // case 3:
+ // binding = bootstrapMethod.invoke(caller, name, type,
+ // argv[0], argv[1], argv[2]);
+ // break;
+ // case 4:
+ // binding = bootstrapMethod.invoke(caller, name, type,
+ // argv[0], argv[1], argv[2], argv[3]);
+ // break;
+ // case 5:
+ // binding = bootstrapMethod.invoke(caller, name, type,
+ // argv[0], argv[1], argv[2], argv[3], argv[4]);
+ // break;
+ // case 6:
+ // binding = bootstrapMethod.invoke(caller, name, type,
+ // argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
+ // break;
+ // default:
+ // final int NON_SPREAD_ARG_COUNT = 3; // (caller, name, type)
+ // if (NON_SPREAD_ARG_COUNT + argv.length > MethodType.MAX_MH_ARITY)
+ // throw new BootstrapMethodError("too many bootstrap method arguments");
+ // MethodType bsmType = bootstrapMethod.type();
+ // MethodType invocationType = MethodType.genericMethodType(NON_SPREAD_ARG_COUNT + argv.length);
+ // MethodHandle typedBSM = bootstrapMethod.asType(invocationType);
+ // MethodHandle spreader = invocationType.invokers().spreadInvoker(NON_SPREAD_ARG_COUNT);
+ // binding = spreader.invokeExact(typedBSM, (Object)caller, (Object)name, (Object)type, argv);
+ // }
+ // }
+ // //System.out.println("BSM for "+name+type+" => "+binding);
+ // if (binding instanceof CallSite) {
+ // site = (CallSite) binding;
+ // } else {
+ // throw new ClassCastException("bootstrap method failed to produce a CallSite");
+ // }
+ // if (!site.getTarget().type().equals(type))
+ // throw wrongTargetType(site.getTarget(), type);
+ // } catch (Throwable ex) {
+ // BootstrapMethodError bex;
+ // if (ex instanceof BootstrapMethodError)
+ // bex = (BootstrapMethodError) ex;
+ // else
+ // bex = new BootstrapMethodError("call site initialization exception", ex);
+ // throw bex;
+ // }
+ // return site;
+ // }
+
+ // private static Object maybeReBox(Object x) {
+ // if (x instanceof Integer) {
+ // int xi = (int) x;
+ // if (xi == (byte) xi)
+ // x = xi; // must rebox; see JLS 5.1.7
+ // }
+ // return x;
+ // }
+ // private static void maybeReBoxElements(Object[] xa) {
+ // for (int i = 0; i < xa.length; i++) {
+ // xa[i] = maybeReBox(xa[i]);
+ // }
+ // }
+}
diff --git a/android-35/java/lang/invoke/ConstantBootstraps.java b/android-35/java/lang/invoke/ConstantBootstraps.java
new file mode 100644
index 0000000..7e414b1
--- /dev/null
+++ b/android-35/java/lang/invoke/ConstantBootstraps.java
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.invoke;
+
+import sun.invoke.util.Wrapper;
+
+import static java.lang.invoke.MethodHandleNatives.mapLookupExceptionToError;
+import static java.util.Objects.requireNonNull;
+
+import java.lang.reflect.Modifier;
+
+/**
+ * Bootstrap methods for dynamically-computed constants.
+ *
+ * <p>The bootstrap methods in this class will throw a
+ * {@code NullPointerException} for any reference argument that is {@code null},
+ * unless the argument is specified to be unused or specified to accept a
+ * {@code null} value.
+ *
+ * @since 11
+ */
+public final class ConstantBootstraps {
+ /**
+ * Do not call.
+ */
+ private ConstantBootstraps() {throw new AssertionError();}
+
+ // implements the upcall from the JVM, MethodHandleNatives.linkDynamicConstant:
+ /*non-public*/
+ // BEGIN Android-removed: Remove unused implementation.
+ /*
+ static Object makeConstant(MethodHandle bootstrapMethod,
+ // Callee information:
+ String name, Class<?> type,
+ // Extra arguments for BSM, if any:
+ Object info,
+ // Caller information:
+ Class<?> callerClass) {
+ // Restrict bootstrap methods to those whose first parameter is Lookup
+ // The motivation here is, in the future, to possibly support BSMs
+ // that do not accept the meta-data of lookup/name/type, thereby
+ // allowing the co-opting of existing methods to be used as BSMs as
+ // long as the static arguments can be passed as method arguments
+ MethodType mt = bootstrapMethod.type();
+ if (mt.parameterCount() < 2 ||
+ !MethodHandles.Lookup.class.isAssignableFrom(mt.parameterType(0))) {
+ throw new BootstrapMethodError(
+ "Invalid bootstrap method declared for resolving a dynamic constant: " + bootstrapMethod);
+ }
+
+ // BSMI.invoke handles all type checking and exception translation.
+ // If type is not a reference type, the JVM is expecting a boxed
+ // version, and will manage unboxing on the other side.
+ return BootstrapMethodInvoker.invoke(
+ type, bootstrapMethod, name, type, info, callerClass);
+ }
+ */
+ // END Android-removed: Remove unused implementation.
+
+ /**
+ * Returns a {@code null} object reference for the reference type specified
+ * by {@code type}.
+ *
+ * @param lookup unused
+ * @param name unused
+ * @param type a reference type
+ * @return a {@code null} value
+ * @throws IllegalArgumentException if {@code type} is not a reference type
+ */
+ public static Object nullConstant(MethodHandles.Lookup lookup, String name, Class<?> type) {
+ if (requireNonNull(type).isPrimitive()) {
+ throw new IllegalArgumentException(String.format("not reference: %s", type));
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a {@link Class} mirror for the primitive type whose type
+ * descriptor is specified by {@code name}.
+ *
+ * @param lookup unused
+ * @param name the descriptor (JVMS 4.3) of the desired primitive type
+ * @param type the required result type (must be {@code Class.class})
+ * @return the {@link Class} mirror
+ * @throws IllegalArgumentException if the name is not a descriptor for a
+ * primitive type or the type is not {@code Class.class}
+ */
+ public static Class<?> primitiveClass(MethodHandles.Lookup lookup, String name, Class<?> type) {
+ requireNonNull(name);
+ requireNonNull(type);
+ if (type != Class.class) {
+ throw new IllegalArgumentException();
+ }
+ if (name.length() != 1) {
+ throw new IllegalArgumentException(String.format("not primitive: %s", name));
+ }
+
+ return Wrapper.forPrimitiveType(name.charAt(0)).primitiveType();
+ }
+
+ /**
+ * Returns an {@code enum} constant of the type specified by {@code type}
+ * with the name specified by {@code name}.
+ *
+ * @param lookup the lookup context describing the class performing the
+ * operation (normally stacked by the JVM)
+ * @param name the name of the constant to return, which must exactly match
+ * an enum constant in the specified type.
+ * @param type the {@code Class} object describing the enum type for which
+ * a constant is to be returned
+ * @param <E> The enum type for which a constant value is to be returned
+ * @return the enum constant of the specified enum type with the
+ * specified name
+ * @throws IllegalAccessError if the declaring class or the field is not
+ * accessible to the class performing the operation
+ * @throws IllegalArgumentException if the specified enum type has
+ * no constant with the specified name, or the specified
+ * class object does not represent an enum type
+ * @see Enum#valueOf(Class, String)
+ */
+ public static <E extends Enum<E>> E enumConstant(MethodHandles.Lookup lookup, String name, Class<E> type) {
+ requireNonNull(lookup);
+ requireNonNull(name);
+ requireNonNull(type);
+ validateClassAccess(lookup, type);
+
+ return Enum.valueOf(type, name);
+ }
+
+ /**
+ * Returns the value of a static final field.
+ *
+ * @param lookup the lookup context describing the class performing the
+ * operation (normally stacked by the JVM)
+ * @param name the name of the field
+ * @param type the type of the field
+ * @param declaringClass the class in which the field is declared
+ * @return the value of the field
+ * @throws IllegalAccessError if the declaring class or the field is not
+ * accessible to the class performing the operation
+ * @throws NoSuchFieldError if the specified field does not exist
+ * @throws IncompatibleClassChangeError if the specified field is not
+ * {@code final}
+ */
+ public static Object getStaticFinal(MethodHandles.Lookup lookup, String name, Class<?> type,
+ Class<?> declaringClass) {
+ requireNonNull(lookup);
+ requireNonNull(name);
+ requireNonNull(type);
+ requireNonNull(declaringClass);
+
+ MethodHandle mh;
+ try {
+ mh = lookup.findStaticGetter(declaringClass, name, type);
+ // Android-changed: Re-implement final modifier check with existing APIs.
+ // MemberName member = mh.internalMemberName();
+ // if (!member.isFinal()) {
+ MethodHandleInfo info = lookup.revealDirect(mh);
+ if (!Modifier.isFinal(info.getModifiers())) {
+ throw new IncompatibleClassChangeError("not a final field: " + name);
+ }
+ }
+ catch (ReflectiveOperationException ex) {
+ throw mapLookupExceptionToError(ex);
+ }
+
+ // Since mh is a handle to a static field only instances of
+ // VirtualMachineError are anticipated to be thrown, such as a
+ // StackOverflowError or an InternalError from the j.l.invoke code
+ try {
+ return mh.invoke();
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable e) {
+ throw new LinkageError("Unexpected throwable", e);
+ }
+ }
+
+ /**
+ * Returns the value of a static final field declared in the class which
+ * is the same as the field's type (or, for primitive-valued fields,
+ * declared in the wrapper class.) This is a simplified form of
+ * {@link #getStaticFinal(MethodHandles.Lookup, String, Class, Class)}
+ * for the case where a class declares distinguished constant instances of
+ * itself.
+ *
+ * @param lookup the lookup context describing the class performing the
+ * operation (normally stacked by the JVM)
+ * @param name the name of the field
+ * @param type the type of the field
+ * @return the value of the field
+ * @throws IllegalAccessError if the declaring class or the field is not
+ * accessible to the class performing the operation
+ * @throws NoSuchFieldError if the specified field does not exist
+ * @throws IncompatibleClassChangeError if the specified field is not
+ * {@code final}
+ * @see #getStaticFinal(MethodHandles.Lookup, String, Class, Class)
+ */
+ public static Object getStaticFinal(MethodHandles.Lookup lookup, String name, Class<?> type) {
+ requireNonNull(type);
+
+ Class<?> declaring = type.isPrimitive()
+ ? Wrapper.forPrimitiveType(type).wrapperType()
+ : type;
+ return getStaticFinal(lookup, name, type, declaring);
+ }
+
+
+ /**
+ * Returns the result of invoking a method handle with the provided
+ * arguments.
+ * <p>
+ * This method behaves as if the method handle to be invoked is the result
+ * of adapting the given method handle, via {@link MethodHandle#asType}, to
+ * adjust the return type to the desired type.
+ *
+ * @param lookup unused
+ * @param name unused
+ * @param type the desired type of the value to be returned, which must be
+ * compatible with the return type of the method handle
+ * @param handle the method handle to be invoked
+ * @param args the arguments to pass to the method handle, as if with
+ * {@link MethodHandle#invokeWithArguments}. Each argument may be
+ * {@code null}.
+ * @return the result of invoking the method handle
+ * @throws WrongMethodTypeException if the handle's method type cannot be
+ * adjusted to take the given number of arguments, or if the handle's return
+ * type cannot be adjusted to the desired type
+ * @throws ClassCastException if an argument or the result produced by
+ * invoking the handle cannot be converted by reference casting
+ * @throws Throwable anything thrown by the method handle invocation
+ */
+ public static Object invoke(MethodHandles.Lookup lookup, String name, Class<?> type,
+ MethodHandle handle, Object... args) throws Throwable {
+ requireNonNull(type);
+ requireNonNull(handle);
+ requireNonNull(args);
+
+ if (type != handle.type().returnType()) {
+ // Adjust the return type of the handle to be invoked while
+ // preserving variable arity if present
+ handle = handle.asType(handle.type().changeReturnType(type)).
+ withVarargs(handle.isVarargsCollector());
+ }
+
+ return handle.invokeWithArguments(args);
+ }
+
+ /**
+ * Finds a {@link VarHandle} for an instance field.
+ *
+ * @param lookup the lookup context describing the class performing the
+ * operation (normally stacked by the JVM)
+ * @param name the name of the field
+ * @param type the required result type (must be {@code Class<VarHandle>})
+ * @param declaringClass the class in which the field is declared
+ * @param fieldType the type of the field
+ * @return the {@link VarHandle}
+ * @throws IllegalAccessError if the declaring class or the field is not
+ * accessible to the class performing the operation
+ * @throws NoSuchFieldError if the specified field does not exist
+ * @throws IllegalArgumentException if the type is not {@code VarHandle}
+ */
+ public static VarHandle fieldVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type,
+ Class<?> declaringClass, Class<?> fieldType) {
+ requireNonNull(lookup);
+ requireNonNull(name);
+ requireNonNull(type);
+ requireNonNull(declaringClass);
+ requireNonNull(fieldType);
+ if (type != VarHandle.class) {
+ throw new IllegalArgumentException();
+ }
+
+ try {
+ return lookup.findVarHandle(declaringClass, name, fieldType);
+ }
+ catch (ReflectiveOperationException e) {
+ throw mapLookupExceptionToError(e);
+ }
+ }
+
+ /**
+ * Finds a {@link VarHandle} for a static field.
+ *
+ * @param lookup the lookup context describing the class performing the
+ * operation (normally stacked by the JVM)
+ * @param name the name of the field
+ * @param type the required result type (must be {@code Class<VarHandle>})
+ * @param declaringClass the class in which the field is declared
+ * @param fieldType the type of the field
+ * @return the {@link VarHandle}
+ * @throws IllegalAccessError if the declaring class or the field is not
+ * accessible to the class performing the operation
+ * @throws NoSuchFieldError if the specified field does not exist
+ * @throws IllegalArgumentException if the type is not {@code VarHandle}
+ */
+ public static VarHandle staticFieldVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type,
+ Class<?> declaringClass, Class<?> fieldType) {
+ requireNonNull(lookup);
+ requireNonNull(name);
+ requireNonNull(type);
+ requireNonNull(declaringClass);
+ requireNonNull(fieldType);
+ if (type != VarHandle.class) {
+ throw new IllegalArgumentException();
+ }
+
+ try {
+ return lookup.findStaticVarHandle(declaringClass, name, fieldType);
+ }
+ catch (ReflectiveOperationException e) {
+ throw mapLookupExceptionToError(e);
+ }
+ }
+
+ /**
+ * Finds a {@link VarHandle} for an array type.
+ *
+ * @param lookup the lookup context describing the class performing the
+ * operation (normally stacked by the JVM)
+ * @param name unused
+ * @param type the required result type (must be {@code Class<VarHandle>})
+ * @param arrayClass the type of the array
+ * @return the {@link VarHandle}
+ * @throws IllegalAccessError if the component type of the array is not
+ * accessible to the class performing the operation
+ * @throws IllegalArgumentException if the type is not {@code VarHandle}
+ */
+ public static VarHandle arrayVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type,
+ Class<?> arrayClass) {
+ requireNonNull(lookup);
+ requireNonNull(type);
+ requireNonNull(arrayClass);
+ if (type != VarHandle.class) {
+ throw new IllegalArgumentException();
+ }
+
+ return MethodHandles.arrayElementVarHandle(validateClassAccess(lookup, arrayClass));
+ }
+
+ /**
+ * Applies a conversion from a source type to a destination type.
+ * <p>
+ * Given a destination type {@code dstType} and an input
+ * value {@code value}, one of the following will happen:
+ * <ul>
+ * <li>If {@code dstType} is {@code void.class},
+ * a {@link ClassCastException} is thrown.
+ * <li>If {@code dstType} is {@code Object.class}, {@code value} is returned as is.
+ * </ul>
+ * <p>
+ * Otherwise one of the following conversions is applied to {@code value}:
+ * <ol>
+ * <li>If {@code dstType} is a reference type, a reference cast
+ * is applied to {@code value} as if by calling {@code dstType.cast(value)}.
+ * <li>If {@code dstType} is a primitive type, then, if the runtime type
+ * of {@code value} is a primitive wrapper type (such as {@link Integer}),
+ * a Java unboxing conversion is applied {@jls 5.1.8} followed by a
+ * Java casting conversion {@jls 5.5} converting either directly to
+ * {@code dstType}, or, if {@code dstType} is {@code boolean},
+ * to {@code int}, which is then converted to either {@code true}
+ * or {@code false} depending on whether the least-significant-bit
+ * is 1 or 0 respectively. If the runtime type of {@code value} is
+ * not a primitive wrapper type a {@link ClassCastException} is thrown.
+ * </ol>
+ * <p>
+ * The result is the same as when using the following code:
+ * <blockquote><pre>{@code
+ * MethodHandle id = MethodHandles.identity(dstType);
+ * MethodType mt = MethodType.methodType(dstType, Object.class);
+ * MethodHandle conv = MethodHandles.explicitCastArguments(id, mt);
+ * return conv.invoke(value);
+ * }</pre></blockquote>
+ *
+ * @param lookup unused
+ * @param name unused
+ * @param dstType the destination type of the conversion
+ * @param value the value to be converted
+ * @return the converted value
+ * @throws ClassCastException when {@code dstType} is {@code void},
+ * when a cast per (1) fails, or when {@code dstType} is a primitive type
+ * and the runtime type of {@code value} is not a primitive wrapper type
+ * (such as {@link Integer})
+ *
+ * @since 15
+ */
+ public static Object explicitCast(MethodHandles.Lookup lookup, String name, Class<?> dstType, Object value)
+ throws ClassCastException {
+ if (dstType == void.class)
+ throw new ClassCastException("Can not convert to void");
+ if (dstType == Object.class)
+ return value;
+
+ MethodHandle id = MethodHandles.identity(dstType);
+ MethodType mt = MethodType.methodType(dstType, Object.class);
+ MethodHandle conv = MethodHandles.explicitCastArguments(id, mt);
+ try {
+ return conv.invoke(value);
+ } catch (RuntimeException|Error e) {
+ throw e; // let specified CCE and other runtime exceptions/errors through
+ } catch (Throwable throwable) {
+ throw new InternalError(throwable); // Not specified, throw InternalError
+ }
+ }
+
+ private static <T> Class<T> validateClassAccess(MethodHandles.Lookup lookup, Class<T> type) {
+ try {
+ lookup.accessClass(type);
+ return type;
+ }
+ catch (ReflectiveOperationException ex) {
+ throw mapLookupExceptionToError(ex);
+ }
+ }
+}
diff --git a/android-35/java/lang/invoke/ConstantCallSite.java b/android-35/java/lang/invoke/ConstantCallSite.java
new file mode 100644
index 0000000..f7d87ba
--- /dev/null
+++ b/android-35/java/lang/invoke/ConstantCallSite.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+/**
+ * A {@code ConstantCallSite} is a {@link CallSite} whose target is permanent, and can never be changed.
+ * An {@code invokedynamic} instruction linked to a {@code ConstantCallSite} is permanently
+ * bound to the call site's target.
+ * @author John Rose, JSR 292 EG
+ * @since 1.7
+ */
+public class ConstantCallSite extends CallSite {
+ private final boolean isFrozen;
+
+ /**
+ * Creates a call site with a permanent target.
+ * @param target the target to be permanently associated with this call site
+ * @throws NullPointerException if the proposed target is null
+ */
+ public ConstantCallSite(MethodHandle target) {
+ super(target);
+ isFrozen = true;
+ }
+
+ /**
+ * Creates a call site with a permanent target, possibly bound to the call site itself.
+ * <p>
+ * During construction of the call site, the {@code createTargetHook} is invoked to
+ * produce the actual target, as if by a call of the form
+ * {@code (MethodHandle) createTargetHook.invoke(this)}.
+ * <p>
+ * Note that user code cannot perform such an action directly in a subclass constructor,
+ * since the target must be fixed before the {@code ConstantCallSite} constructor returns.
+ * <p>
+ * The hook is said to bind the call site to a target method handle,
+ * and a typical action would be {@code someTarget.bindTo(this)}.
+ * However, the hook is free to take any action whatever,
+ * including ignoring the call site and returning a constant target.
+ * <p>
+ * The result returned by the hook must be a method handle of exactly
+ * the same type as the call site.
+ * <p>
+ * While the hook is being called, the new {@code ConstantCallSite}
+ * object is in a partially constructed state.
+ * In this state,
+ * a call to {@code getTarget}, or any other attempt to use the target,
+ * will result in an {@code IllegalStateException}.
+ * It is legal at all times to obtain the call site's type using the {@code type} method.
+ *
+ * @param targetType the type of the method handle to be permanently associated with this call site
+ * @param createTargetHook a method handle to invoke (on the call site) to produce the call site's target
+ * @throws WrongMethodTypeException if the hook cannot be invoked on the required arguments,
+ * or if the target returned by the hook is not of the given {@code targetType}
+ * @throws NullPointerException if the hook returns a null value
+ * @throws ClassCastException if the hook returns something other than a {@code MethodHandle}
+ * @throws Throwable anything else thrown by the hook function
+ */
+ protected ConstantCallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable {
+ super(targetType, createTargetHook);
+ isFrozen = true;
+ }
+
+ /**
+ * Returns the target method of the call site, which behaves
+ * like a {@code final} field of the {@code ConstantCallSite}.
+ * That is, the target is always the original value passed
+ * to the constructor call which created this instance.
+ *
+ * @return the immutable linkage state of this call site, a constant method handle
+ * @throws IllegalStateException if the {@code ConstantCallSite} constructor has not completed
+ */
+ @Override public final MethodHandle getTarget() {
+ if (!isFrozen) throw new IllegalStateException();
+ return target;
+ }
+
+ /**
+ * Always throws an {@link UnsupportedOperationException}.
+ * This kind of call site cannot change its target.
+ * @param ignore a new target proposed for the call site, which is ignored
+ * @throws UnsupportedOperationException because this kind of call site cannot change its target
+ */
+ @Override public final void setTarget(MethodHandle ignore) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns this call site's permanent target.
+ * Since that target will never change, this is a correct implementation
+ * of {@link CallSite#dynamicInvoker CallSite.dynamicInvoker}.
+ * @return the immutable linkage state of this call site, a constant method handle
+ * @throws IllegalStateException if the {@code ConstantCallSite} constructor has not completed
+ */
+ @Override
+ public final MethodHandle dynamicInvoker() {
+ return getTarget();
+ }
+}
diff --git a/android-35/java/lang/invoke/FieldVarHandle.java b/android-35/java/lang/invoke/FieldVarHandle.java
new file mode 100644
index 0000000..beb056a
--- /dev/null
+++ b/android-35/java/lang/invoke/FieldVarHandle.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.lang.invoke;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+/**
+ * A VarHandle that's associated with an instance field.
+ * @hide
+ */
+class FieldVarHandle extends VarHandle {
+ private final long artField;
+
+ private FieldVarHandle(Field field, Class<?> coordinateType0) {
+ super(field.getType(), Modifier.isFinal(field.getModifiers()), coordinateType0);
+ artField = field.getArtField();
+ }
+
+ protected FieldVarHandle(Field field) {
+ super(field.getType(), Modifier.isFinal(field.getModifiers()));
+ artField = field.getArtField();
+ }
+
+ static FieldVarHandle create(Field field) {
+ assert !Modifier.isStatic(field.getModifiers());
+ return new FieldVarHandle(field, field.getDeclaringClass());
+ }
+}
diff --git a/android-35/java/lang/invoke/LambdaConversionException.java b/android-35/java/lang/invoke/LambdaConversionException.java
new file mode 100644
index 0000000..2dc8f22
--- /dev/null
+++ b/android-35/java/lang/invoke/LambdaConversionException.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+/**
+ * LambdaConversionException
+ *
+ * @since 1.8
+ */
+public class LambdaConversionException extends Exception {
+ private static final long serialVersionUID = 292L + 8L;
+
+ /**
+ * Constructs a {@code LambdaConversionException}.
+ */
+ public LambdaConversionException() {
+ }
+
+ /**
+ * Constructs a {@code LambdaConversionException} with a message.
+ * @param message the detail message
+ */
+ public LambdaConversionException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a {@code LambdaConversionException} with a message and cause.
+ * @param message the detail message
+ * @param cause the cause
+ */
+ public LambdaConversionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs a {@code LambdaConversionException} with a cause.
+ * @param cause the cause
+ */
+ public LambdaConversionException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Constructs a {@code LambdaConversionException} with a message,
+ * cause, and other settings.
+ * @param message the detail message
+ * @param cause the cause
+ * @param enableSuppression whether or not suppressed exceptions are enabled
+ * @param writableStackTrace whether or not the stack trace is writable
+ */
+ public LambdaConversionException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ }
+}
diff --git a/android-35/java/lang/invoke/LambdaMetafactory.java b/android-35/java/lang/invoke/LambdaMetafactory.java
new file mode 100644
index 0000000..e1ce46f
--- /dev/null
+++ b/android-35/java/lang/invoke/LambdaMetafactory.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+public class LambdaMetafactory {
+
+ public static final int FLAG_SERIALIZABLE = 1 << 0;
+
+ public static final int FLAG_MARKERS = 1 << 1;
+
+ public static final int FLAG_BRIDGES = 1 << 2;
+
+ public static CallSite metafactory(MethodHandles.Lookup caller,
+ String invokedName,
+ MethodType invokedType,
+ MethodType samMethodType,
+ MethodHandle implMethod,
+ MethodType instantiatedMethodType)
+ throws LambdaConversionException { return null; }
+
+ public static CallSite altMetafactory(MethodHandles.Lookup caller,
+ String invokedName,
+ MethodType invokedType,
+ Object... args)
+ throws LambdaConversionException { return null; }
+}
diff --git a/android-35/java/lang/invoke/MethodHandle.java b/android-35/java/lang/invoke/MethodHandle.java
new file mode 100644
index 0000000..b03b769
--- /dev/null
+++ b/android-35/java/lang/invoke/MethodHandle.java
@@ -0,0 +1,1769 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+import dalvik.system.EmulatedStackFrame;
+
+import static java.lang.invoke.MethodHandleStatics.*;
+
+/**
+ * A method handle is a typed, directly executable reference to an underlying method,
+ * constructor, field, or similar low-level operation, with optional
+ * transformations of arguments or return values.
+ * These transformations are quite general, and include such patterns as
+ * {@linkplain #asType conversion},
+ * {@linkplain #bindTo insertion},
+ * {@linkplain java.lang.invoke.MethodHandles#dropArguments deletion},
+ * and {@linkplain java.lang.invoke.MethodHandles#filterArguments substitution}.
+ *
+ * <h1>Method handle contents</h1>
+ * Method handles are dynamically and strongly typed according to their parameter and return types.
+ * They are not distinguished by the name or the defining class of their underlying methods.
+ * A method handle must be invoked using a symbolic type descriptor which matches
+ * the method handle's own {@linkplain #type type descriptor}.
+ * <p>
+ * Every method handle reports its type descriptor via the {@link #type type} accessor.
+ * This type descriptor is a {@link java.lang.invoke.MethodType MethodType} object,
+ * whose structure is a series of classes, one of which is
+ * the return type of the method (or {@code void.class} if none).
+ * <p>
+ * A method handle's type controls the types of invocations it accepts,
+ * and the kinds of transformations that apply to it.
+ * <p>
+ * A method handle contains a pair of special invoker methods
+ * called {@link #invokeExact invokeExact} and {@link #invoke invoke}.
+ * Both invoker methods provide direct access to the method handle's
+ * underlying method, constructor, field, or other operation,
+ * as modified by transformations of arguments and return values.
+ * Both invokers accept calls which exactly match the method handle's own type.
+ * The plain, inexact invoker also accepts a range of other call types.
+ * <p>
+ * Method handles are immutable and have no visible state.
+ * Of course, they can be bound to underlying methods or data which exhibit state.
+ * With respect to the Java Memory Model, any method handle will behave
+ * as if all of its (internal) fields are final variables. This means that any method
+ * handle made visible to the application will always be fully formed.
+ * This is true even if the method handle is published through a shared
+ * variable in a data race.
+ * <p>
+ * Method handles cannot be subclassed by the user.
+ * Implementations may (or may not) create internal subclasses of {@code MethodHandle}
+ * which may be visible via the {@link java.lang.Object#getClass Object.getClass}
+ * operation. The programmer should not draw conclusions about a method handle
+ * from its specific class, as the method handle class hierarchy (if any)
+ * may change from time to time or across implementations from different vendors.
+ *
+ * <h1>Method handle compilation</h1>
+ * A Java method call expression naming {@code invokeExact} or {@code invoke}
+ * can invoke a method handle from Java source code.
+ * From the viewpoint of source code, these methods can take any arguments
+ * and their result can be cast to any return type.
+ * Formally this is accomplished by giving the invoker methods
+ * {@code Object} return types and variable arity {@code Object} arguments,
+ * but they have an additional quality called <em>signature polymorphism</em>
+ * which connects this freedom of invocation directly to the JVM execution stack.
+ * <p>
+ * As is usual with virtual methods, source-level calls to {@code invokeExact}
+ * and {@code invoke} compile to an {@code invokevirtual} instruction.
+ * More unusually, the compiler must record the actual argument types,
+ * and may not perform method invocation conversions on the arguments.
+ * Instead, it must push them on the stack according to their own unconverted types.
+ * The method handle object itself is pushed on the stack before the arguments.
+ * The compiler then calls the method handle with a symbolic type descriptor which
+ * describes the argument and return types.
+ * <p>
+ * To issue a complete symbolic type descriptor, the compiler must also determine
+ * the return type. This is based on a cast on the method invocation expression,
+ * if there is one, or else {@code Object} if the invocation is an expression
+ * or else {@code void} if the invocation is a statement.
+ * The cast may be to a primitive type (but not {@code void}).
+ * <p>
+ * As a corner case, an uncasted {@code null} argument is given
+ * a symbolic type descriptor of {@code java.lang.Void}.
+ * The ambiguity with the type {@code Void} is harmless, since there are no references of type
+ * {@code Void} except the null reference.
+ *
+ * <h1>Method handle invocation</h1>
+ * The first time a {@code invokevirtual} instruction is executed
+ * it is linked, by symbolically resolving the names in the instruction
+ * and verifying that the method call is statically legal.
+ * This is true of calls to {@code invokeExact} and {@code invoke}.
+ * In this case, the symbolic type descriptor emitted by the compiler is checked for
+ * correct syntax and names it contains are resolved.
+ * Thus, an {@code invokevirtual} instruction which invokes
+ * a method handle will always link, as long
+ * as the symbolic type descriptor is syntactically well-formed
+ * and the types exist.
+ * <p>
+ * When the {@code invokevirtual} is executed after linking,
+ * the receiving method handle's type is first checked by the JVM
+ * to ensure that it matches the symbolic type descriptor.
+ * If the type match fails, it means that the method which the
+ * caller is invoking is not present on the individual
+ * method handle being invoked.
+ * <p>
+ * In the case of {@code invokeExact}, the type descriptor of the invocation
+ * (after resolving symbolic type names) must exactly match the method type
+ * of the receiving method handle.
+ * In the case of plain, inexact {@code invoke}, the resolved type descriptor
+ * must be a valid argument to the receiver's {@link #asType asType} method.
+ * Thus, plain {@code invoke} is more permissive than {@code invokeExact}.
+ * <p>
+ * After type matching, a call to {@code invokeExact} directly
+ * and immediately invoke the method handle's underlying method
+ * (or other behavior, as the case may be).
+ * <p>
+ * A call to plain {@code invoke} works the same as a call to
+ * {@code invokeExact}, if the symbolic type descriptor specified by the caller
+ * exactly matches the method handle's own type.
+ * If there is a type mismatch, {@code invoke} attempts
+ * to adjust the type of the receiving method handle,
+ * as if by a call to {@link #asType asType},
+ * to obtain an exactly invokable method handle {@code M2}.
+ * This allows a more powerful negotiation of method type
+ * between caller and callee.
+ * <p>
+ * (<em>Note:</em> The adjusted method handle {@code M2} is not directly observable,
+ * and implementations are therefore not required to materialize it.)
+ *
+ * <h1>Invocation checking</h1>
+ * In typical programs, method handle type matching will usually succeed.
+ * But if a match fails, the JVM will throw a {@link WrongMethodTypeException},
+ * either directly (in the case of {@code invokeExact}) or indirectly as if
+ * by a failed call to {@code asType} (in the case of {@code invoke}).
+ * <p>
+ * Thus, a method type mismatch which might show up as a linkage error
+ * in a statically typed program can show up as
+ * a dynamic {@code WrongMethodTypeException}
+ * in a program which uses method handles.
+ * <p>
+ * Because method types contain "live" {@code Class} objects,
+ * method type matching takes into account both types names and class loaders.
+ * Thus, even if a method handle {@code M} is created in one
+ * class loader {@code L1} and used in another {@code L2},
+ * method handle calls are type-safe, because the caller's symbolic type
+ * descriptor, as resolved in {@code L2},
+ * is matched against the original callee method's symbolic type descriptor,
+ * as resolved in {@code L1}.
+ * The resolution in {@code L1} happens when {@code M} is created
+ * and its type is assigned, while the resolution in {@code L2} happens
+ * when the {@code invokevirtual} instruction is linked.
+ * <p>
+ * Apart from the checking of type descriptors,
+ * a method handle's capability to call its underlying method is unrestricted.
+ * If a method handle is formed on a non-public method by a class
+ * that has access to that method, the resulting handle can be used
+ * in any place by any caller who receives a reference to it.
+ * <p>
+ * Unlike with the Core Reflection API, where access is checked every time
+ * a reflective method is invoked,
+ * method handle access checking is performed
+ * <a href="MethodHandles.Lookup.html#access">when the method handle is created</a>.
+ * In the case of {@code ldc} (see below), access checking is performed as part of linking
+ * the constant pool entry underlying the constant method handle.
+ * <p>
+ * Thus, handles to non-public methods, or to methods in non-public classes,
+ * should generally be kept secret.
+ * They should not be passed to untrusted code unless their use from
+ * the untrusted code would be harmless.
+ *
+ * <h1>Method handle creation</h1>
+ * Java code can create a method handle that directly accesses
+ * any method, constructor, or field that is accessible to that code.
+ * This is done via a reflective, capability-based API called
+ * {@link java.lang.invoke.MethodHandles.Lookup MethodHandles.Lookup}
+ * For example, a static method handle can be obtained
+ * from {@link java.lang.invoke.MethodHandles.Lookup#findStatic Lookup.findStatic}.
+ * There are also conversion methods from Core Reflection API objects,
+ * such as {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect}.
+ * <p>
+ * Like classes and strings, method handles that correspond to accessible
+ * fields, methods, and constructors can also be represented directly
+ * in a class file's constant pool as constants to be loaded by {@code ldc} bytecodes.
+ * A new type of constant pool entry, {@code CONSTANT_MethodHandle},
+ * refers directly to an associated {@code CONSTANT_Methodref},
+ * {@code CONSTANT_InterfaceMethodref}, or {@code CONSTANT_Fieldref}
+ * constant pool entry.
+ * (For full details on method handle constants,
+ * see sections 4.4.8 and 5.4.3.5 of the Java Virtual Machine Specification.)
+ * <p>
+ * Method handles produced by lookups or constant loads from methods or
+ * constructors with the variable arity modifier bit ({@code 0x0080})
+ * have a corresponding variable arity, as if they were defined with
+ * the help of {@link #asVarargsCollector asVarargsCollector}.
+ * <p>
+ * A method reference may refer either to a static or non-static method.
+ * In the non-static case, the method handle type includes an explicit
+ * receiver argument, prepended before any other arguments.
+ * In the method handle's type, the initial receiver argument is typed
+ * according to the class under which the method was initially requested.
+ * (E.g., if a non-static method handle is obtained via {@code ldc},
+ * the type of the receiver is the class named in the constant pool entry.)
+ * <p>
+ * Method handle constants are subject to the same link-time access checks
+ * their corresponding bytecode instructions, and the {@code ldc} instruction
+ * will throw corresponding linkage errors if the bytecode behaviors would
+ * throw such errors.
+ * <p>
+ * As a corollary of this, access to protected members is restricted
+ * to receivers only of the accessing class, or one of its subclasses,
+ * and the accessing class must in turn be a subclass (or package sibling)
+ * of the protected member's defining class.
+ * If a method reference refers to a protected non-static method or field
+ * of a class outside the current package, the receiver argument will
+ * be narrowed to the type of the accessing class.
+ * <p>
+ * When a method handle to a virtual method is invoked, the method is
+ * always looked up in the receiver (that is, the first argument).
+ * <p>
+ * A non-virtual method handle to a specific virtual method implementation
+ * can also be created. These do not perform virtual lookup based on
+ * receiver type. Such a method handle simulates the effect of
+ * an {@code invokespecial} instruction to the same method.
+ *
+ * <h1>Usage examples</h1>
+ * Here are some examples of usage:
+ * <blockquote><pre>{@code
+Object x, y; String s; int i;
+MethodType mt; MethodHandle mh;
+MethodHandles.Lookup lookup = MethodHandles.lookup();
+// mt is (char,char)String
+mt = MethodType.methodType(String.class, char.class, char.class);
+mh = lookup.findVirtual(String.class, "replace", mt);
+s = (String) mh.invokeExact("daddy",'d','n');
+// invokeExact(Ljava/lang/String;CC)Ljava/lang/String;
+assertEquals(s, "nanny");
+// weakly typed invocation (using MHs.invoke)
+s = (String) mh.invokeWithArguments("sappy", 'p', 'v');
+assertEquals(s, "savvy");
+// mt is (Object[])List
+mt = MethodType.methodType(java.util.List.class, Object[].class);
+mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
+assert(mh.isVarargsCollector());
+x = mh.invoke("one", "two");
+// invoke(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
+assertEquals(x, java.util.Arrays.asList("one","two"));
+// mt is (Object,Object,Object)Object
+mt = MethodType.genericMethodType(3);
+mh = mh.asType(mt);
+x = mh.invokeExact((Object)1, (Object)2, (Object)3);
+// invokeExact(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+assertEquals(x, java.util.Arrays.asList(1,2,3));
+// mt is ()int
+mt = MethodType.methodType(int.class);
+mh = lookup.findVirtual(java.util.List.class, "size", mt);
+i = (int) mh.invokeExact(java.util.Arrays.asList(1,2,3));
+// invokeExact(Ljava/util/List;)I
+assert(i == 3);
+mt = MethodType.methodType(void.class, String.class);
+mh = lookup.findVirtual(java.io.PrintStream.class, "println", mt);
+mh.invokeExact(System.out, "Hello, world.");
+// invokeExact(Ljava/io/PrintStream;Ljava/lang/String;)V
+ * }</pre></blockquote>
+ * Each of the above calls to {@code invokeExact} or plain {@code invoke}
+ * generates a single invokevirtual instruction with
+ * the symbolic type descriptor indicated in the following comment.
+ * In these examples, the helper method {@code assertEquals} is assumed to
+ * be a method which calls {@link java.util.Objects#equals(Object,Object) Objects.equals}
+ * on its arguments, and asserts that the result is true.
+ *
+ * <h1>Exceptions</h1>
+ * The methods {@code invokeExact} and {@code invoke} are declared
+ * to throw {@link java.lang.Throwable Throwable},
+ * which is to say that there is no static restriction on what a method handle
+ * can throw. Since the JVM does not distinguish between checked
+ * and unchecked exceptions (other than by their class, of course),
+ * there is no particular effect on bytecode shape from ascribing
+ * checked exceptions to method handle invocations. But in Java source
+ * code, methods which perform method handle calls must either explicitly
+ * throw {@code Throwable}, or else must catch all
+ * throwables locally, rethrowing only those which are legal in the context,
+ * and wrapping ones which are illegal.
+ *
+ * <h1><a name="sigpoly"></a>Signature polymorphism</h1>
+ * The unusual compilation and linkage behavior of
+ * {@code invokeExact} and plain {@code invoke}
+ * is referenced by the term <em>signature polymorphism</em>.
+ * As defined in the Java Language Specification,
+ * a signature polymorphic method is one which can operate with
+ * any of a wide range of call signatures and return types.
+ * <p>
+ * In source code, a call to a signature polymorphic method will
+ * compile, regardless of the requested symbolic type descriptor.
+ * As usual, the Java compiler emits an {@code invokevirtual}
+ * instruction with the given symbolic type descriptor against the named method.
+ * The unusual part is that the symbolic type descriptor is derived from
+ * the actual argument and return types, not from the method declaration.
+ * <p>
+ * When the JVM processes bytecode containing signature polymorphic calls,
+ * it will successfully link any such call, regardless of its symbolic type descriptor.
+ * (In order to retain type safety, the JVM will guard such calls with suitable
+ * dynamic type checks, as described elsewhere.)
+ * <p>
+ * Bytecode generators, including the compiler back end, are required to emit
+ * untransformed symbolic type descriptors for these methods.
+ * Tools which determine symbolic linkage are required to accept such
+ * untransformed descriptors, without reporting linkage errors.
+ *
+ * <h1>Interoperation between method handles and the Core Reflection API</h1>
+ * Using factory methods in the {@link java.lang.invoke.MethodHandles.Lookup Lookup} API,
+ * any class member represented by a Core Reflection API object
+ * can be converted to a behaviorally equivalent method handle.
+ * For example, a reflective {@link java.lang.reflect.Method Method} can
+ * be converted to a method handle using
+ * {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect}.
+ * The resulting method handles generally provide more direct and efficient
+ * access to the underlying class members.
+ * <p>
+ * As a special case,
+ * when the Core Reflection API is used to view the signature polymorphic
+ * methods {@code invokeExact} or plain {@code invoke} in this class,
+ * they appear as ordinary non-polymorphic methods.
+ * Their reflective appearance, as viewed by
+ * {@link java.lang.Class#getDeclaredMethod Class.getDeclaredMethod},
+ * is unaffected by their special status in this API.
+ * For example, {@link java.lang.reflect.Method#getModifiers Method.getModifiers}
+ * will report exactly those modifier bits required for any similarly
+ * declared method, including in this case {@code native} and {@code varargs} bits.
+ * <p>
+ * As with any reflected method, these methods (when reflected) may be
+ * invoked via {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}.
+ * However, such reflective calls do not result in method handle invocations.
+ * Such a call, if passed the required argument
+ * (a single one, of type {@code Object[]}), will ignore the argument and
+ * will throw an {@code UnsupportedOperationException}.
+ * <p>
+ * Since {@code invokevirtual} instructions can natively
+ * invoke method handles under any symbolic type descriptor, this reflective view conflicts
+ * with the normal presentation of these methods via bytecodes.
+ * Thus, these two native methods, when reflectively viewed by
+ * {@code Class.getDeclaredMethod}, may be regarded as placeholders only.
+ * <p>
+ * In order to obtain an invoker method for a particular type descriptor,
+ * use {@link java.lang.invoke.MethodHandles#exactInvoker MethodHandles.exactInvoker},
+ * or {@link java.lang.invoke.MethodHandles#invoker MethodHandles.invoker}.
+ * The {@link java.lang.invoke.MethodHandles.Lookup#findVirtual Lookup.findVirtual}
+ * API is also able to return a method handle
+ * to call {@code invokeExact} or plain {@code invoke},
+ * for any specified type descriptor .
+ *
+ * <h1>Interoperation between method handles and Java generics</h1>
+ * A method handle can be obtained on a method, constructor, or field
+ * which is declared with Java generic types.
+ * As with the Core Reflection API, the type of the method handle
+ * will constructed from the erasure of the source-level type.
+ * When a method handle is invoked, the types of its arguments
+ * or the return value cast type may be generic types or type instances.
+ * If this occurs, the compiler will replace those
+ * types by their erasures when it constructs the symbolic type descriptor
+ * for the {@code invokevirtual} instruction.
+ * <p>
+ * Method handles do not represent
+ * their function-like types in terms of Java parameterized (generic) types,
+ * because there are three mismatches between function-like types and parameterized
+ * Java types.
+ * <ul>
+ * <li>Method types range over all possible arities,
+ * from no arguments to up to the <a href="MethodHandle.html#maxarity">maximum number</a> of allowed arguments.
+ * Generics are not variadic, and so cannot represent this.</li>
+ * <li>Method types can specify arguments of primitive types,
+ * which Java generic types cannot range over.</li>
+ * <li>Higher order functions over method handles (combinators) are
+ * often generic across a wide range of function types, including
+ * those of multiple arities. It is impossible to represent such
+ * genericity with a Java type parameter.</li>
+ * </ul>
+ *
+ * <h1><a name="maxarity"></a>Arity limits</h1>
+ * The JVM imposes on all methods and constructors of any kind an absolute
+ * limit of 255 stacked arguments. This limit can appear more restrictive
+ * in certain cases:
+ * <ul>
+ * <li>A {@code long} or {@code double} argument counts (for purposes of arity limits) as two argument slots.
+ * <li>A non-static method consumes an extra argument for the object on which the method is called.
+ * <li>A constructor consumes an extra argument for the object which is being constructed.
+ * <li>Since a method handle’s {@code invoke} method (or other signature-polymorphic method) is non-virtual,
+ * it consumes an extra argument for the method handle itself, in addition to any non-virtual receiver object.
+ * </ul>
+ * These limits imply that certain method handles cannot be created, solely because of the JVM limit on stacked arguments.
+ * For example, if a static JVM method accepts exactly 255 arguments, a method handle cannot be created for it.
+ * Attempts to create method handles with impossible method types lead to an {@link IllegalArgumentException}.
+ * In particular, a method handle’s type must not have an arity of the exact maximum 255.
+ *
+ * @see MethodType
+ * @see MethodHandles
+ * @author John Rose, JSR 292 EG
+ */
+public abstract class MethodHandle {
+ // Android-removed: MethodHandleImpl.initStatics() unused on Android.
+ // static { MethodHandleImpl.initStatics(); }
+
+ /**
+ * Internal marker interface which distinguishes (to the Java compiler)
+ * those methods which are <a href="MethodHandle.html#sigpoly">signature polymorphic</a>.
+ *
+ * @hide
+ */
+ @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD})
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+ // Android-changed: Made public @hide as otherwise it breaks the stubs generation.
+ // @interface PolymorphicSignature { }
+ public @interface PolymorphicSignature { }
+
+ /**
+ * The type of this method handle, this corresponds to the exact type of the method
+ * being invoked.
+ */
+ private final MethodType type;
+
+ // Android-removed: LambdaForm is unused on Android.
+ // They will be substituted with appropriate implementation / delegate classes.
+ /*
+ /*private* final LambdaForm form;
+ // form is not private so that invokers can easily fetch it
+ */
+ /*private*/ MethodHandle asTypeCache;
+ // asTypeCache is not private so that invokers can easily fetch it
+ /*
+ // Android-removed: customizationCount is unused on Android.
+ /*non-public* byte customizationCount;
+ // customizationCount should be accessible from invokers
+ */
+
+ /**
+ * The spread invoker associated with this type with zero trailing arguments.
+ * This is used to speed up invokeWithArguments.
+ */
+ private MethodHandle cachedSpreadInvoker;
+
+ /**
+ * The INVOKE* constants and SGET/SPUT and IGET/IPUT constants specify the behaviour of this
+ * method handle with respect to the ArtField* or the ArtMethod* that it operates on. These
+ * behaviours are equivalent to the dex bytecode behaviour on the respective method_id or
+ * field_id in the equivalent instruction.
+ *
+ * INVOKE_TRANSFORM is a special type of handle which doesn't encode any dex bytecode behaviour,
+ * instead it transforms the list of input arguments or performs other higher order operations
+ * before (optionally) delegating to another method handle.
+ */
+
+ /** @hide */ public static final int INVOKE_VIRTUAL = 0;
+ /** @hide */ public static final int INVOKE_SUPER = 1;
+ /** @hide */ public static final int INVOKE_DIRECT = 2;
+ /** @hide */ public static final int INVOKE_STATIC = 3;
+ /** @hide */ public static final int INVOKE_INTERFACE = 4;
+ /** @hide */ public static final int INVOKE_TRANSFORM = 5;
+ /** @hide */ public static final int INVOKE_VAR_HANDLE = 6;
+ /** @hide */ public static final int INVOKE_VAR_HANDLE_EXACT = 7;
+ /** @hide */ public static final int IGET = 8;
+ /** @hide */ public static final int IPUT = 9;
+ /** @hide */ public static final int SGET = 10;
+ /** @hide */ public static final int SPUT = 11;
+
+ // The kind of this method handle (used by the runtime). This is one of the INVOKE_*
+ // constants or SGET/SPUT, IGET/IPUT.
+ /** @hide */ protected final int handleKind;
+
+ // The ArtMethod* or ArtField* associated with this method handle (used by the runtime).
+ /** @hide */ protected final long artFieldOrMethod;
+
+ /** @hide */
+ protected MethodHandle(long artFieldOrMethod, int handleKind, MethodType type) {
+ this.artFieldOrMethod = artFieldOrMethod;
+ this.handleKind = handleKind;
+ this.type = type;
+ }
+ // END Android-added: Android specific implementation.
+
+ /**
+ * Reports the type of this method handle.
+ * Every invocation of this method handle via {@code invokeExact} must exactly match this type.
+ * @return the method handle type
+ */
+ public MethodType type() {
+ return type;
+ }
+
+ // BEGIN Android-removed: LambdaForm unsupported on Android.
+ /*
+ /**
+ * Package-private constructor for the method handle implementation hierarchy.
+ * Method handle inheritance will be contained completely within
+ * the {@code java.lang.invoke} package.
+ *
+ // @param type type (permanently assigned) of the new method handle
+ /*non-public* MethodHandle(MethodType type, LambdaForm form) {
+ type.getClass(); // explicit NPE
+ form.getClass(); // explicit NPE
+ this.type = type;
+ this.form = form.uncustomize();
+
+ this.form.prepare(); // TO DO: Try to delay this step until just before invocation.
+ }
+ */
+ // END Android-removed: LambdaForm unsupported on Android.
+
+ /**
+ * Invokes the method handle, allowing any caller type descriptor, but requiring an exact type match.
+ * The symbolic type descriptor at the call site of {@code invokeExact} must
+ * exactly match this method handle's {@link #type type}.
+ * No conversions are allowed on arguments or return values.
+ * <p>
+ * When this method is observed via the Core Reflection API,
+ * it will appear as a single native method, taking an object array and returning an object.
+ * If this native method is invoked directly via
+ * {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}, via JNI,
+ * or indirectly via {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect},
+ * it will throw an {@code UnsupportedOperationException}.
+ * @param args the signature-polymorphic parameter list, statically represented using varargs
+ * @return the signature-polymorphic result, statically represented using {@code Object}
+ * @throws WrongMethodTypeException if the target's type is not identical with the caller's symbolic type descriptor
+ * @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call
+ */
+ public final native @PolymorphicSignature Object invokeExact(Object... args) throws Throwable;
+
+ /**
+ * Invokes the method handle, allowing any caller type descriptor,
+ * and optionally performing conversions on arguments and return values.
+ * <p>
+ * If the call site's symbolic type descriptor exactly matches this method handle's {@link #type type},
+ * the call proceeds as if by {@link #invokeExact invokeExact}.
+ * <p>
+ * Otherwise, the call proceeds as if this method handle were first
+ * adjusted by calling {@link #asType asType} to adjust this method handle
+ * to the required type, and then the call proceeds as if by
+ * {@link #invokeExact invokeExact} on the adjusted method handle.
+ * <p>
+ * There is no guarantee that the {@code asType} call is actually made.
+ * If the JVM can predict the results of making the call, it may perform
+ * adaptations directly on the caller's arguments,
+ * and call the target method handle according to its own exact type.
+ * <p>
+ * The resolved type descriptor at the call site of {@code invoke} must
+ * be a valid argument to the receivers {@code asType} method.
+ * In particular, the caller must specify the same argument arity
+ * as the callee's type,
+ * if the callee is not a {@linkplain #asVarargsCollector variable arity collector}.
+ * <p>
+ * When this method is observed via the Core Reflection API,
+ * it will appear as a single native method, taking an object array and returning an object.
+ * If this native method is invoked directly via
+ * {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}, via JNI,
+ * or indirectly via {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect},
+ * it will throw an {@code UnsupportedOperationException}.
+ * @param args the signature-polymorphic parameter list, statically represented using varargs
+ * @return the signature-polymorphic result, statically represented using {@code Object}
+ * @throws WrongMethodTypeException if the target's type cannot be adjusted to the caller's symbolic type descriptor
+ * @throws ClassCastException if the target's type can be adjusted to the caller, but a reference cast fails
+ * @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call
+ */
+ public final native @PolymorphicSignature Object invoke(Object... args) throws Throwable;
+
+ // BEGIN Android-removed: RI implementation unused on Android.
+ /*
+ /**
+ * Private method for trusted invocation of a method handle respecting simplified signatures.
+ * Type mismatches will not throw {@code WrongMethodTypeException}, but could crash the JVM.
+ * <p>
+ * The caller signature is restricted to the following basic types:
+ * Object, int, long, float, double, and void return.
+ * <p>
+ * The caller is responsible for maintaining type correctness by ensuring
+ * that the each outgoing argument value is a member of the range of the corresponding
+ * callee argument type.
+ * (The caller should therefore issue appropriate casts and integer narrowing
+ * operations on outgoing argument values.)
+ * The caller can assume that the incoming result value is part of the range
+ * of the callee's return type.
+ * @param args the signature-polymorphic parameter list, statically represented using varargs
+ * @return the signature-polymorphic result, statically represented using {@code Object}
+ *
+ /*non-public* final native @PolymorphicSignature Object invokeBasic(Object... args) throws Throwable;
+
+ /**
+ * Private method for trusted invocation of a MemberName of kind {@code REF_invokeVirtual}.
+ * The caller signature is restricted to basic types as with {@code invokeBasic}.
+ * The trailing (not leading) argument must be a MemberName.
+ * @param args the signature-polymorphic parameter list, statically represented using varargs
+ * @return the signature-polymorphic result, statically represented using {@code Object}
+ *
+ /*non-public* static native @PolymorphicSignature Object linkToVirtual(Object... args) throws Throwable;
+
+ /**
+ * Private method for trusted invocation of a MemberName of kind {@code REF_invokeStatic}.
+ * The caller signature is restricted to basic types as with {@code invokeBasic}.
+ * The trailing (not leading) argument must be a MemberName.
+ * @param args the signature-polymorphic parameter list, statically represented using varargs
+ * @return the signature-polymorphic result, statically represented using {@code Object}
+ *
+ /*non-public* static native @PolymorphicSignature Object linkToStatic(Object... args) throws Throwable;
+
+ /**
+ * Private method for trusted invocation of a MemberName of kind {@code REF_invokeSpecial}.
+ * The caller signature is restricted to basic types as with {@code invokeBasic}.
+ * The trailing (not leading) argument must be a MemberName.
+ * @param args the signature-polymorphic parameter list, statically represented using varargs
+ * @return the signature-polymorphic result, statically represented using {@code Object}
+ *
+ /*non-public* static native @PolymorphicSignature Object linkToSpecial(Object... args) throws Throwable;
+
+ /**
+ * Private method for trusted invocation of a MemberName of kind {@code REF_invokeInterface}.
+ * The caller signature is restricted to basic types as with {@code invokeBasic}.
+ * The trailing (not leading) argument must be a MemberName.
+ * @param args the signature-polymorphic parameter list, statically represented using varargs
+ * @return the signature-polymorphic result, statically represented using {@code Object}
+ *
+ /*non-public* static native @PolymorphicSignature Object linkToInterface(Object... args) throws Throwable;
+ */
+ // END Android-removed: RI implementation unused on Android.
+
+ /**
+ * Performs a variable arity invocation, passing the arguments in the given list
+ * to the method handle, as if via an inexact {@link #invoke invoke} from a call site
+ * which mentions only the type {@code Object}, and whose arity is the length
+ * of the argument list.
+ * <p>
+ * Specifically, execution proceeds as if by the following steps,
+ * although the methods are not guaranteed to be called if the JVM
+ * can predict their effects.
+ * <ul>
+ * <li>Determine the length of the argument array as {@code N}.
+ * For a null reference, {@code N=0}. </li>
+ * <li>Determine the general type {@code TN} of {@code N} arguments as
+ * as {@code TN=MethodType.genericMethodType(N)}.</li>
+ * <li>Force the original target method handle {@code MH0} to the
+ * required type, as {@code MH1 = MH0.asType(TN)}. </li>
+ * <li>Spread the array into {@code N} separate arguments {@code A0, ...}. </li>
+ * <li>Invoke the type-adjusted method handle on the unpacked arguments:
+ * MH1.invokeExact(A0, ...). </li>
+ * <li>Take the return value as an {@code Object} reference. </li>
+ * </ul>
+ * <p>
+ * Because of the action of the {@code asType} step, the following argument
+ * conversions are applied as necessary:
+ * <ul>
+ * <li>reference casting
+ * <li>unboxing
+ * <li>widening primitive conversions
+ * </ul>
+ * <p>
+ * The result returned by the call is boxed if it is a primitive,
+ * or forced to null if the return type is void.
+ * <p>
+ * This call is equivalent to the following code:
+ * <blockquote><pre>{@code
+ * MethodHandle invoker = MethodHandles.spreadInvoker(this.type(), 0);
+ * Object result = invoker.invokeExact(this, arguments);
+ * }</pre></blockquote>
+ * <p>
+ * Unlike the signature polymorphic methods {@code invokeExact} and {@code invoke},
+ * {@code invokeWithArguments} can be accessed normally via the Core Reflection API and JNI.
+ * It can therefore be used as a bridge between native or reflective code and method handles.
+ *
+ * @param arguments the arguments to pass to the target
+ * @return the result returned by the target
+ * @throws ClassCastException if an argument cannot be converted by reference casting
+ * @throws WrongMethodTypeException if the target's type cannot be adjusted to take the given number of {@code Object} arguments
+ * @throws Throwable anything thrown by the target method invocation
+ * @see MethodHandles#spreadInvoker
+ */
+ public Object invokeWithArguments(Object... arguments) throws Throwable {
+ MethodType invocationType = MethodType.genericMethodType(arguments == null ? 0 : arguments.length);
+ // BEGIN Android-changed: Android specific implementation.
+ // return invocationType.invokers().spreadInvoker(0).invokeExact(asType(invocationType), arguments);
+ MethodHandle invoker = cachedSpreadInvoker;
+ if (invoker == null || !invoker.type().equals(invocationType)) {
+ invoker = MethodHandles.spreadInvoker(invocationType, 0);
+ cachedSpreadInvoker = invoker;
+ }
+ return invoker.invoke(asType(invocationType), arguments);
+ // END Android-changed: Android specific implementation.
+ }
+
+ /**
+ * Performs a variable arity invocation, passing the arguments in the given array
+ * to the method handle, as if via an inexact {@link #invoke invoke} from a call site
+ * which mentions only the type {@code Object}, and whose arity is the length
+ * of the argument array.
+ * <p>
+ * This method is also equivalent to the following code:
+ * <blockquote><pre>{@code
+ * invokeWithArguments(arguments.toArray()
+ * }</pre></blockquote>
+ *
+ * @param arguments the arguments to pass to the target
+ * @return the result returned by the target
+ * @throws NullPointerException if {@code arguments} is a null reference
+ * @throws ClassCastException if an argument cannot be converted by reference casting
+ * @throws WrongMethodTypeException if the target's type cannot be adjusted to take the given number of {@code Object} arguments
+ * @throws Throwable anything thrown by the target method invocation
+ */
+ public Object invokeWithArguments(java.util.List<?> arguments) throws Throwable {
+ return invokeWithArguments(arguments.toArray());
+ }
+
+ /**
+ * Produces an adapter method handle which adapts the type of the
+ * current method handle to a new type.
+ * The resulting method handle is guaranteed to report a type
+ * which is equal to the desired new type.
+ * <p>
+ * If the original type and new type are equal, returns {@code this}.
+ * <p>
+ * The new method handle, when invoked, will perform the following
+ * steps:
+ * <ul>
+ * <li>Convert the incoming argument list to match the original
+ * method handle's argument list.
+ * <li>Invoke the original method handle on the converted argument list.
+ * <li>Convert any result returned by the original method handle
+ * to the return type of new method handle.
+ * </ul>
+ * <p>
+ * This method provides the crucial behavioral difference between
+ * {@link #invokeExact invokeExact} and plain, inexact {@link #invoke invoke}.
+ * The two methods
+ * perform the same steps when the caller's type descriptor exactly m atches
+ * the callee's, but when the types differ, plain {@link #invoke invoke}
+ * also calls {@code asType} (or some internal equivalent) in order
+ * to match up the caller's and callee's types.
+ * <p>
+ * If the current method is a variable arity method handle
+ * argument list conversion may involve the conversion and collection
+ * of several arguments into an array, as
+ * {@linkplain #asVarargsCollector described elsewhere}.
+ * In every other case, all conversions are applied <em>pairwise</em>,
+ * which means that each argument or return value is converted to
+ * exactly one argument or return value (or no return value).
+ * The applied conversions are defined by consulting the
+ * the corresponding component types of the old and new
+ * method handle types.
+ * <p>
+ * Let <em>T0</em> and <em>T1</em> be corresponding new and old parameter types,
+ * or old and new return types. Specifically, for some valid index {@code i}, let
+ * <em>T0</em>{@code =newType.parameterType(i)} and <em>T1</em>{@code =this.type().parameterType(i)}.
+ * Or else, going the other way for return values, let
+ * <em>T0</em>{@code =this.type().returnType()} and <em>T1</em>{@code =newType.returnType()}.
+ * If the types are the same, the new method handle makes no change
+ * to the corresponding argument or return value (if any).
+ * Otherwise, one of the following conversions is applied
+ * if possible:
+ * <ul>
+ * <li>If <em>T0</em> and <em>T1</em> are references, then a cast to <em>T1</em> is applied.
+ * (The types do not need to be related in any particular way.
+ * This is because a dynamic value of null can convert to any reference type.)
+ * <li>If <em>T0</em> and <em>T1</em> are primitives, then a Java method invocation
+ * conversion (JLS 5.3) is applied, if one exists.
+ * (Specifically, <em>T0</em> must convert to <em>T1</em> by a widening primitive conversion.)
+ * <li>If <em>T0</em> is a primitive and <em>T1</em> a reference,
+ * a Java casting conversion (JLS 5.5) is applied if one exists.
+ * (Specifically, the value is boxed from <em>T0</em> to its wrapper class,
+ * which is then widened as needed to <em>T1</em>.)
+ * <li>If <em>T0</em> is a reference and <em>T1</em> a primitive, an unboxing
+ * conversion will be applied at runtime, possibly followed
+ * by a Java method invocation conversion (JLS 5.3)
+ * on the primitive value. (These are the primitive widening conversions.)
+ * <em>T0</em> must be a wrapper class or a supertype of one.
+ * (In the case where <em>T0</em> is Object, these are the conversions
+ * allowed by {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}.)
+ * The unboxing conversion must have a possibility of success, which means that
+ * if <em>T0</em> is not itself a wrapper class, there must exist at least one
+ * wrapper class <em>TW</em> which is a subtype of <em>T0</em> and whose unboxed
+ * primitive value can be widened to <em>T1</em>.
+ * <li>If the return type <em>T1</em> is marked as void, any returned value is discarded
+ * <li>If the return type <em>T0</em> is void and <em>T1</em> a reference, a null value is introduced.
+ * <li>If the return type <em>T0</em> is void and <em>T1</em> a primitive,
+ * a zero value is introduced.
+ * </ul>
+ * (<em>Note:</em> Both <em>T0</em> and <em>T1</em> may be regarded as static types,
+ * because neither corresponds specifically to the <em>dynamic type</em> of any
+ * actual argument or return value.)
+ * <p>
+ * The method handle conversion cannot be made if any one of the required
+ * pairwise conversions cannot be made.
+ * <p>
+ * At runtime, the conversions applied to reference arguments
+ * or return values may require additional runtime checks which can fail.
+ * An unboxing operation may fail because the original reference is null,
+ * causing a {@link java.lang.NullPointerException NullPointerException}.
+ * An unboxing operation or a reference cast may also fail on a reference
+ * to an object of the wrong type,
+ * causing a {@link java.lang.ClassCastException ClassCastException}.
+ * Although an unboxing operation may accept several kinds of wrappers,
+ * if none are available, a {@code ClassCastException} will be thrown.
+ *
+ * @param newType the expected type of the new method handle
+ * @return a method handle which delegates to {@code this} after performing
+ * any necessary argument conversions, and arranges for any
+ * necessary return value conversions
+ * @throws NullPointerException if {@code newType} is a null reference
+ * @throws WrongMethodTypeException if the conversion cannot be made
+ * @see MethodHandles#explicitCastArguments
+ */
+ public MethodHandle asType(MethodType newType) {
+ // Fast path alternative to a heavyweight {@code asType} call.
+ // Return 'this' if the conversion will be a no-op.
+ // Android-changed: use equals() rather than = since MethodTypes are not interned.
+ if (newType.equals(type)) {
+ return this;
+ }
+ // Return 'this.asTypeCache' if the conversion is already memoized.
+ MethodHandle atc = asTypeCached(newType);
+ if (atc != null) {
+ return atc;
+ }
+ return asTypeUncached(newType);
+ }
+
+ private MethodHandle asTypeCached(MethodType newType) {
+ MethodHandle atc = asTypeCache;
+ // Android-changed: use equals() rather than = since MethodTypes are not interned.
+ if (atc != null && newType.equals(atc.type)) {
+ return atc;
+ }
+ return null;
+ }
+
+ /** Override this to change asType behavior. */
+ /*non-public*/ MethodHandle asTypeUncached(MethodType newType) {
+ if (!type.isConvertibleTo(newType))
+ throw new WrongMethodTypeException("cannot convert "+this+" to "+newType);
+ // BEGIN Android-changed: Android specific implementation.
+ // return asTypeCache = MethodHandleImpl.makePairwiseConvert(this, newType, true);
+ return asTypeCache = new Transformers.AsTypeAdapter(this, newType);
+ // END Android-changed: Android specific implementation.
+ }
+
+ /**
+ * Makes an <em>array-spreading</em> method handle, which accepts a trailing array argument
+ * and spreads its elements as positional arguments.
+ * The new method handle adapts, as its <i>target</i>,
+ * the current method handle. The type of the adapter will be
+ * the same as the type of the target, except that the final
+ * {@code arrayLength} parameters of the target's type are replaced
+ * by a single array parameter of type {@code arrayType}.
+ * <p>
+ * If the array element type differs from any of the corresponding
+ * argument types on the original target,
+ * the original target is adapted to take the array elements directly,
+ * as if by a call to {@link #asType asType}.
+ * <p>
+ * When called, the adapter replaces a trailing array argument
+ * by the array's elements, each as its own argument to the target.
+ * (The order of the arguments is preserved.)
+ * They are converted pairwise by casting and/or unboxing
+ * to the types of the trailing parameters of the target.
+ * Finally the target is called.
+ * What the target eventually returns is returned unchanged by the adapter.
+ * <p>
+ * Before calling the target, the adapter verifies that the array
+ * contains exactly enough elements to provide a correct argument count
+ * to the target method handle.
+ * (The array may also be null when zero elements are required.)
+ * <p>
+ * When the adapter is called, the length of the supplied {@code array}
+ * argument is queried as if by {@code array.length} or {@code arraylength}
+ * bytecode. If the adapter accepts a zero-length trailing array argument,
+ * the supplied {@code array} argument can either be a zero-length array or
+ * {@code null}; otherwise, the adapter will throw a {@code NullPointerException}
+ * if the array is {@code null} and throw an {@link IllegalArgumentException}
+ * if the array does not have the correct number of elements.
+ * <p>
+ * Here are some simple examples of array-spreading method handles:
+ * <blockquote><pre>{@code
+MethodHandle equals = publicLookup()
+ .findVirtual(String.class, "equals", methodType(boolean.class, Object.class));
+assert( (boolean) equals.invokeExact("me", (Object)"me"));
+assert(!(boolean) equals.invokeExact("me", (Object)"thee"));
+// spread both arguments from a 2-array:
+MethodHandle eq2 = equals.asSpreader(Object[].class, 2);
+assert( (boolean) eq2.invokeExact(new Object[]{ "me", "me" }));
+assert(!(boolean) eq2.invokeExact(new Object[]{ "me", "thee" }));
+// try to spread from anything but a 2-array:
+for (int n = 0; n <= 10; n++) {
+ Object[] badArityArgs = (n == 2 ? new Object[0] : new Object[n]);
+ try { assert((boolean) eq2.invokeExact(badArityArgs) && false); }
+ catch (IllegalArgumentException ex) { } // OK
+}
+// spread both arguments from a String array:
+MethodHandle eq2s = equals.asSpreader(String[].class, 2);
+assert( (boolean) eq2s.invokeExact(new String[]{ "me", "me" }));
+assert(!(boolean) eq2s.invokeExact(new String[]{ "me", "thee" }));
+// spread second arguments from a 1-array:
+MethodHandle eq1 = equals.asSpreader(Object[].class, 1);
+assert( (boolean) eq1.invokeExact("me", new Object[]{ "me" }));
+assert(!(boolean) eq1.invokeExact("me", new Object[]{ "thee" }));
+// spread no arguments from a 0-array or null:
+MethodHandle eq0 = equals.asSpreader(Object[].class, 0);
+assert( (boolean) eq0.invokeExact("me", (Object)"me", new Object[0]));
+assert(!(boolean) eq0.invokeExact("me", (Object)"thee", (Object[])null));
+// asSpreader and asCollector are approximate inverses:
+for (int n = 0; n <= 2; n++) {
+ for (Class<?> a : new Class<?>[]{Object[].class, String[].class, CharSequence[].class}) {
+ MethodHandle equals2 = equals.asSpreader(a, n).asCollector(a, n);
+ assert( (boolean) equals2.invokeWithArguments("me", "me"));
+ assert(!(boolean) equals2.invokeWithArguments("me", "thee"));
+ }
+}
+MethodHandle caToString = publicLookup()
+ .findStatic(Arrays.class, "toString", methodType(String.class, char[].class));
+assertEquals("[A, B, C]", (String) caToString.invokeExact("ABC".toCharArray()));
+MethodHandle caString3 = caToString.asCollector(char[].class, 3);
+assertEquals("[A, B, C]", (String) caString3.invokeExact('A', 'B', 'C'));
+MethodHandle caToString2 = caString3.asSpreader(char[].class, 2);
+assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray()));
+ * }</pre></blockquote>
+ * @param arrayType usually {@code Object[]}, the type of the array argument from which to extract the spread arguments
+ * @param arrayLength the number of arguments to spread from an incoming array argument
+ * @return a new method handle which spreads its final array argument,
+ * before calling the original method handle
+ * @throws NullPointerException if {@code arrayType} is a null reference
+ * @throws IllegalArgumentException if {@code arrayType} is not an array type,
+ * or if target does not have at least
+ * {@code arrayLength} parameter types,
+ * or if {@code arrayLength} is negative,
+ * or if the resulting method handle's type would have
+ * <a href="MethodHandle.html#maxarity">too many parameters</a>
+ * @throws WrongMethodTypeException if the implied {@code asType} call fails
+ * @see #asCollector
+ */
+ public MethodHandle asSpreader(Class<?> arrayType, int arrayLength) {
+ return asSpreader(type().parameterCount() - arrayLength, arrayType, arrayLength);
+ }
+
+ /**
+ * Makes an <em>array-spreading</em> method handle, which accepts an array argument at a given position and spreads
+ * its elements as positional arguments in place of the array. The new method handle adapts, as its <i>target</i>,
+ * the current method handle. The type of the adapter will be the same as the type of the target, except that the
+ * {@code arrayLength} parameters of the target's type, starting at the zero-based position {@code spreadArgPos},
+ * are replaced by a single array parameter of type {@code arrayType}.
+ * <p>
+ * This method behaves very much like {@link #asSpreader(Class, int)}, but accepts an additional {@code spreadArgPos}
+ * argument to indicate at which position in the parameter list the spreading should take place.
+ *
+ * @apiNote Example:
+ * <blockquote><pre>{@code
+ MethodHandle compare = LOOKUP.findStatic(Objects.class, "compare", methodType(int.class, Object.class, Object.class, Comparator.class));
+ MethodHandle compare2FromArray = compare.asSpreader(0, Object[].class, 2);
+ Object[] ints = new Object[]{3, 9, 7, 7};
+ Comparator<Integer> cmp = (a, b) -> a - b;
+ assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 0, 2), cmp) < 0);
+ assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 1, 3), cmp) > 0);
+ assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 2, 4), cmp) == 0);
+ * }</pre></blockquote>
+ * @param spreadArgPos the position (zero-based index) in the argument list at which spreading should start.
+ * @param arrayType usually {@code Object[]}, the type of the array argument from which to extract the spread arguments
+ * @param arrayLength the number of arguments to spread from an incoming array argument
+ * @return a new method handle which spreads an array argument at a given position,
+ * before calling the original method handle
+ * @throws NullPointerException if {@code arrayType} is a null reference
+ * @throws IllegalArgumentException if {@code arrayType} is not an array type,
+ * or if target does not have at least
+ * {@code arrayLength} parameter types,
+ * or if {@code arrayLength} is negative,
+ * or if {@code spreadArgPos} has an illegal value (negative, or together with arrayLength exceeding the
+ * number of arguments),
+ * or if the resulting method handle's type would have
+ * <a href="MethodHandle.html#maxarity">too many parameters</a>
+ * @throws WrongMethodTypeException if the implied {@code asType} call fails
+ *
+ * @see #asSpreader(Class, int)
+ * @since 9
+ */
+ public MethodHandle asSpreader(int spreadArgPos, Class<?> arrayType, int arrayLength) {
+ MethodType postSpreadType = asSpreaderChecks(arrayType, spreadArgPos, arrayLength);
+ // BEGIN Android-changed: Android specific implementation.
+ /*
+ MethodHandle afterSpread = this.asType(postSpreadType);
+ BoundMethodHandle mh = afterSpread.rebind();
+ LambdaForm lform = mh.editor().spreadArgumentsForm(1 + spreadArgPos, arrayType, arrayLength);
+ MethodType preSpreadType = postSpreadType.replaceParameterTypes(spreadArgPos, spreadArgPos + arrayLength, arrayType);
+ return mh.copyWith(preSpreadType, lform);
+ */
+ final int spreadEnd = spreadArgPos + arrayLength;
+ final MethodType adapterType =
+ postSpreadType.replaceParameterTypes(spreadArgPos, spreadEnd, arrayType);
+ return new Transformers.Spreader(
+ asType(postSpreadType), adapterType, spreadArgPos, arrayLength);
+ // END Android-changed: Android specific implementation.
+ }
+
+ /**
+ * See if {@code asSpreader} can be validly called with the given arguments.
+ * Return the type of the method handle call after spreading but before conversions.
+ */
+ private MethodType asSpreaderChecks(Class<?> arrayType, int pos, int arrayLength) {
+ spreadArrayChecks(arrayType, arrayLength);
+ int nargs = type().parameterCount();
+ if (nargs < arrayLength || arrayLength < 0)
+ throw newIllegalArgumentException("bad spread array length");
+ if (pos < 0 || pos + arrayLength > nargs) {
+ throw newIllegalArgumentException("bad spread position");
+ }
+ Class<?> arrayElement = arrayType.getComponentType();
+ MethodType mtype = type();
+ boolean match = true, fail = false;
+ for (int i = pos; i < pos + arrayLength; i++) {
+ Class<?> ptype = mtype.parameterType(i);
+ if (ptype != arrayElement) {
+ match = false;
+ if (!MethodType.canConvert(arrayElement, ptype)) {
+ fail = true;
+ break;
+ }
+ }
+ }
+ if (match) return mtype;
+ MethodType needType = mtype.asSpreaderType(arrayType, pos, arrayLength);
+ if (!fail) return needType;
+ // elicit an error:
+ this.asType(needType);
+ throw newInternalError("should not return");
+ }
+
+ private void spreadArrayChecks(Class<?> arrayType, int arrayLength) {
+ Class<?> arrayElement = arrayType.getComponentType();
+ if (arrayElement == null)
+ throw newIllegalArgumentException("not an array type", arrayType);
+ if ((arrayLength & 0x7F) != arrayLength) {
+ if ((arrayLength & 0xFF) != arrayLength)
+ throw newIllegalArgumentException("array length is not legal", arrayLength);
+ assert(arrayLength >= 128);
+ if (arrayElement == long.class ||
+ arrayElement == double.class)
+ throw newIllegalArgumentException("array length is not legal for long[] or double[]", arrayLength);
+ }
+ }
+
+ /**
+ * Adapts this method handle to be {@linkplain #asVarargsCollector variable arity}
+ * if the boolean flag is true, else {@linkplain #asFixedArity fixed arity}.
+ * If the method handle is already of the proper arity mode, it is returned
+ * unchanged.
+ * @apiNote
+ * <p>This method is sometimes useful when adapting a method handle that
+ * may be variable arity, to ensure that the resulting adapter is also
+ * variable arity if and only if the original handle was. For example,
+ * this code changes the first argument of a handle {@code mh} to {@code int} without
+ * disturbing its variable arity property:
+ * {@code mh.asType(mh.type().changeParameterType(0,int.class))
+ * .withVarargs(mh.isVarargsCollector())}
+ * <p>
+ * This call is approximately equivalent to the following code:
+ * <blockquote><pre>{@code
+ * if (makeVarargs == isVarargsCollector())
+ * return this;
+ * else if (makeVarargs)
+ * return asVarargsCollector(type().lastParameterType());
+ * else
+ * return return asFixedArity();
+ * }</pre></blockquote>
+ * @param makeVarargs true if the return method handle should have variable arity behavior
+ * @return a method handle of the same type, with possibly adjusted variable arity behavior
+ * @throws IllegalArgumentException if {@code makeVarargs} is true and
+ * this method handle does not have a trailing array parameter
+ * @since 9
+ * @see #asVarargsCollector
+ * @see #asFixedArity
+ */
+ public MethodHandle withVarargs(boolean makeVarargs) {
+ assert(!isVarargsCollector()); // subclass responsibility
+ if (makeVarargs) {
+ return asVarargsCollector(type().lastParameterType());
+ } else {
+ return this;
+ }
+ }
+
+ /**
+ * Makes an <em>array-collecting</em> method handle, which accepts a given number of trailing
+ * positional arguments and collects them into an array argument.
+ * The new method handle adapts, as its <i>target</i>,
+ * the current method handle. The type of the adapter will be
+ * the same as the type of the target, except that a single trailing
+ * parameter (usually of type {@code arrayType}) is replaced by
+ * {@code arrayLength} parameters whose type is element type of {@code arrayType}.
+ * <p>
+ * If the array type differs from the final argument type on the original target,
+ * the original target is adapted to take the array type directly,
+ * as if by a call to {@link #asType asType}.
+ * <p>
+ * When called, the adapter replaces its trailing {@code arrayLength}
+ * arguments by a single new array of type {@code arrayType}, whose elements
+ * comprise (in order) the replaced arguments.
+ * Finally the target is called.
+ * What the target eventually returns is returned unchanged by the adapter.
+ * <p>
+ * (The array may also be a shared constant when {@code arrayLength} is zero.)
+ * <p>
+ * (<em>Note:</em> The {@code arrayType} is often identical to the last
+ * parameter type of the original target.
+ * It is an explicit argument for symmetry with {@code asSpreader}, and also
+ * to allow the target to use a simple {@code Object} as its last parameter type.)
+ * <p>
+ * In order to create a collecting adapter which is not restricted to a particular
+ * number of collected arguments, use {@link #asVarargsCollector asVarargsCollector} instead.
+ * <p>
+ * Here are some examples of array-collecting method handles:
+ * <blockquote><pre>{@code
+MethodHandle deepToString = publicLookup()
+ .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
+assertEquals("[won]", (String) deepToString.invokeExact(new Object[]{"won"}));
+MethodHandle ts1 = deepToString.asCollector(Object[].class, 1);
+assertEquals(methodType(String.class, Object.class), ts1.type());
+//assertEquals("[won]", (String) ts1.invokeExact( new Object[]{"won"})); //FAIL
+assertEquals("[[won]]", (String) ts1.invokeExact((Object) new Object[]{"won"}));
+// arrayType can be a subtype of Object[]
+MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
+assertEquals(methodType(String.class, String.class, String.class), ts2.type());
+assertEquals("[two, too]", (String) ts2.invokeExact("two", "too"));
+MethodHandle ts0 = deepToString.asCollector(Object[].class, 0);
+assertEquals("[]", (String) ts0.invokeExact());
+// collectors can be nested, Lisp-style
+MethodHandle ts22 = deepToString.asCollector(Object[].class, 3).asCollector(String[].class, 2);
+assertEquals("[A, B, [C, D]]", ((String) ts22.invokeExact((Object)'A', (Object)"B", "C", "D")));
+// arrayType can be any primitive array type
+MethodHandle bytesToString = publicLookup()
+ .findStatic(Arrays.class, "toString", methodType(String.class, byte[].class))
+ .asCollector(byte[].class, 3);
+assertEquals("[1, 2, 3]", (String) bytesToString.invokeExact((byte)1, (byte)2, (byte)3));
+MethodHandle longsToString = publicLookup()
+ .findStatic(Arrays.class, "toString", methodType(String.class, long[].class))
+ .asCollector(long[].class, 1);
+assertEquals("[123]", (String) longsToString.invokeExact((long)123));
+ * }</pre></blockquote>
+ * @param arrayType often {@code Object[]}, the type of the array argument which will collect the arguments
+ * @param arrayLength the number of arguments to collect into a new array argument
+ * @return a new method handle which collects some trailing argument
+ * into an array, before calling the original method handle
+ * @throws NullPointerException if {@code arrayType} is a null reference
+ * @throws IllegalArgumentException if {@code arrayType} is not an array type
+ * or {@code arrayType} is not assignable to this method handle's trailing parameter type,
+ * or {@code arrayLength} is not a legal array size,
+ * or the resulting method handle's type would have
+ * <a href="MethodHandle.html#maxarity">too many parameters</a>
+ * @throws WrongMethodTypeException if the implied {@code asType} call fails
+ * @see #asSpreader
+ * @see #asVarargsCollector
+ */
+ public MethodHandle asCollector(Class<?> arrayType, int arrayLength) {
+ return asCollector(type().parameterCount() - 1, arrayType, arrayLength);
+ }
+
+ /**
+ * Makes an <em>array-collecting</em> method handle, which accepts a given number of positional arguments starting
+ * at a given position, and collects them into an array argument. The new method handle adapts, as its
+ * <i>target</i>, the current method handle. The type of the adapter will be the same as the type of the target,
+ * except that the parameter at the position indicated by {@code collectArgPos} (usually of type {@code arrayType})
+ * is replaced by {@code arrayLength} parameters whose type is element type of {@code arrayType}.
+ * <p>
+ * This method behaves very much like {@link #asCollector(Class, int)}, but differs in that its {@code
+ * collectArgPos} argument indicates at which position in the parameter list arguments should be collected. This
+ * index is zero-based.
+ *
+ * @apiNote Examples:
+ * <blockquote><pre>{@code
+ StringWriter swr = new StringWriter();
+ MethodHandle swWrite = LOOKUP.findVirtual(StringWriter.class, "write", methodType(void.class, char[].class, int.class, int.class)).bindTo(swr);
+ MethodHandle swWrite4 = swWrite.asCollector(0, char[].class, 4);
+ swWrite4.invoke('A', 'B', 'C', 'D', 1, 2);
+ assertEquals("BC", swr.toString());
+ swWrite4.invoke('P', 'Q', 'R', 'S', 0, 4);
+ assertEquals("BCPQRS", swr.toString());
+ swWrite4.invoke('W', 'X', 'Y', 'Z', 3, 1);
+ assertEquals("BCPQRSZ", swr.toString());
+ * }</pre></blockquote>
+ * <p>
+ * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+ * variable-arity method handle}, even if the original target method handle was.
+ * @param collectArgPos the zero-based position in the parameter list at which to start collecting.
+ * @param arrayType often {@code Object[]}, the type of the array argument which will collect the arguments
+ * @param arrayLength the number of arguments to collect into a new array argument
+ * @return a new method handle which collects some arguments
+ * into an array, before calling the original method handle
+ * @throws NullPointerException if {@code arrayType} is a null reference
+ * @throws IllegalArgumentException if {@code arrayType} is not an array type
+ * or {@code arrayType} is not assignable to this method handle's array parameter type,
+ * or {@code arrayLength} is not a legal array size,
+ * or {@code collectArgPos} has an illegal value (negative, or greater than the number of arguments),
+ * or the resulting method handle's type would have
+ * <a href="MethodHandle.html#maxarity">too many parameters</a>
+ * @throws WrongMethodTypeException if the implied {@code asType} call fails
+ *
+ * @see #asCollector(Class, int)
+ * @since 9
+ */
+ public MethodHandle asCollector(int collectArgPos, Class<?> arrayType, int arrayLength) {
+ asCollectorChecks(arrayType, collectArgPos, arrayLength);
+ // BEGIN Android-changed: Android specific implementation.
+ /*
+ BoundMethodHandle mh = rebind();
+ MethodType resultType = type().asCollectorType(arrayType, collectArgPos, arrayLength);
+ MethodHandle newArray = MethodHandleImpl.varargsArray(arrayType, arrayLength);
+ LambdaForm lform = mh.editor().collectArgumentArrayForm(1 + collectArgPos, newArray);
+ if (lform != null) {
+ return mh.copyWith(resultType, lform);
+ }
+ lform = mh.editor().collectArgumentsForm(1 + collectArgPos, newArray.type().basicType());
+ return mh.copyWithExtendL(resultType, lform, newArray);
+ */
+ return new Transformers.Collector(this, arrayType, collectArgPos, arrayLength);
+ // END Android-changed: Android specific implementation.
+ }
+
+ /**
+ * See if {@code asCollector} can be validly called with the given arguments.
+ * Return false if the last parameter is not an exact match to arrayType.
+ */
+ /*non-public*/ boolean asCollectorChecks(Class<?> arrayType, int pos, int arrayLength) {
+ spreadArrayChecks(arrayType, arrayLength);
+ int nargs = type().parameterCount();
+ if (pos < 0 || pos >= nargs) {
+ throw newIllegalArgumentException("bad collect position");
+ }
+ if (nargs != 0) {
+ Class<?> param = type().parameterType(pos);
+ if (param == arrayType) return true;
+ if (param.isAssignableFrom(arrayType)) return false;
+ }
+ throw newIllegalArgumentException("array type not assignable to argument", this, arrayType);
+ }
+
+ /**
+ * Makes a <em>variable arity</em> adapter which is able to accept
+ * any number of trailing positional arguments and collect them
+ * into an array argument.
+ * <p>
+ * The type and behavior of the adapter will be the same as
+ * the type and behavior of the target, except that certain
+ * {@code invoke} and {@code asType} requests can lead to
+ * trailing positional arguments being collected into target's
+ * trailing parameter.
+ * Also, the
+ * {@linkplain MethodType#lastParameterType last parameter type}
+ * of the adapter will be
+ * {@code arrayType}, even if the target has a different
+ * last parameter type.
+ * <p>
+ * This transformation may return {@code this} if the method handle is
+ * already of variable arity and its trailing parameter type
+ * is identical to {@code arrayType}.
+ * <p>
+ * When called with {@link #invokeExact invokeExact}, the adapter invokes
+ * the target with no argument changes.
+ * (<em>Note:</em> This behavior is different from a
+ * {@linkplain #asCollector fixed arity collector},
+ * since it accepts a whole array of indeterminate length,
+ * rather than a fixed number of arguments.)
+ * <p>
+ * When called with plain, inexact {@link #invoke invoke}, if the caller
+ * type is the same as the adapter, the adapter invokes the target as with
+ * {@code invokeExact}.
+ * (This is the normal behavior for {@code invoke} when types match.)
+ * <p>
+ * Otherwise, if the caller and adapter arity are the same, and the
+ * trailing parameter type of the caller is a reference type identical to
+ * or assignable to the trailing parameter type of the adapter,
+ * the arguments and return values are converted pairwise,
+ * as if by {@link #asType asType} on a fixed arity
+ * method handle.
+ * <p>
+ * Otherwise, the arities differ, or the adapter's trailing parameter
+ * type is not assignable from the corresponding caller type.
+ * In this case, the adapter replaces all trailing arguments from
+ * the original trailing argument position onward, by
+ * a new array of type {@code arrayType}, whose elements
+ * comprise (in order) the replaced arguments.
+ * <p>
+ * The caller type must provides as least enough arguments,
+ * and of the correct type, to satisfy the target's requirement for
+ * positional arguments before the trailing array argument.
+ * Thus, the caller must supply, at a minimum, {@code N-1} arguments,
+ * where {@code N} is the arity of the target.
+ * Also, there must exist conversions from the incoming arguments
+ * to the target's arguments.
+ * As with other uses of plain {@code invoke}, if these basic
+ * requirements are not fulfilled, a {@code WrongMethodTypeException}
+ * may be thrown.
+ * <p>
+ * In all cases, what the target eventually returns is returned unchanged by the adapter.
+ * <p>
+ * In the final case, it is exactly as if the target method handle were
+ * temporarily adapted with a {@linkplain #asCollector fixed arity collector}
+ * to the arity required by the caller type.
+ * (As with {@code asCollector}, if the array length is zero,
+ * a shared constant may be used instead of a new array.
+ * If the implied call to {@code asCollector} would throw
+ * an {@code IllegalArgumentException} or {@code WrongMethodTypeException},
+ * the call to the variable arity adapter must throw
+ * {@code WrongMethodTypeException}.)
+ * <p>
+ * The behavior of {@link #asType asType} is also specialized for
+ * variable arity adapters, to maintain the invariant that
+ * plain, inexact {@code invoke} is always equivalent to an {@code asType}
+ * call to adjust the target type, followed by {@code invokeExact}.
+ * Therefore, a variable arity adapter responds
+ * to an {@code asType} request by building a fixed arity collector,
+ * if and only if the adapter and requested type differ either
+ * in arity or trailing argument type.
+ * The resulting fixed arity collector has its type further adjusted
+ * (if necessary) to the requested type by pairwise conversion,
+ * as if by another application of {@code asType}.
+ * <p>
+ * When a method handle is obtained by executing an {@code ldc} instruction
+ * of a {@code CONSTANT_MethodHandle} constant, and the target method is marked
+ * as a variable arity method (with the modifier bit {@code 0x0080}),
+ * the method handle will accept multiple arities, as if the method handle
+ * constant were created by means of a call to {@code asVarargsCollector}.
+ * <p>
+ * In order to create a collecting adapter which collects a predetermined
+ * number of arguments, and whose type reflects this predetermined number,
+ * use {@link #asCollector asCollector} instead.
+ * <p>
+ * No method handle transformations produce new method handles with
+ * variable arity, unless they are documented as doing so.
+ * Therefore, besides {@code asVarargsCollector} and {@code withVarargs},
+ * all methods in {@code MethodHandle} and {@code MethodHandles}
+ * will return a method handle with fixed arity,
+ * except in the cases where they are specified to return their original
+ * operand (e.g., {@code asType} of the method handle's own type).
+ * <p>
+ * Calling {@code asVarargsCollector} on a method handle which is already
+ * of variable arity will produce a method handle with the same type and behavior.
+ * It may (or may not) return the original variable arity method handle.
+ * <p>
+ * Here is an example, of a list-making variable arity method handle:
+ * <blockquote><pre>{@code
+MethodHandle deepToString = publicLookup()
+ .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
+MethodHandle ts1 = deepToString.asVarargsCollector(Object[].class);
+assertEquals("[won]", (String) ts1.invokeExact( new Object[]{"won"}));
+assertEquals("[won]", (String) ts1.invoke( new Object[]{"won"}));
+assertEquals("[won]", (String) ts1.invoke( "won" ));
+assertEquals("[[won]]", (String) ts1.invoke((Object) new Object[]{"won"}));
+// findStatic of Arrays.asList(...) produces a variable arity method handle:
+MethodHandle asList = publicLookup()
+ .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class));
+assertEquals(methodType(List.class, Object[].class), asList.type());
+assert(asList.isVarargsCollector());
+assertEquals("[]", asList.invoke().toString());
+assertEquals("[1]", asList.invoke(1).toString());
+assertEquals("[two, too]", asList.invoke("two", "too").toString());
+String[] argv = { "three", "thee", "tee" };
+assertEquals("[three, thee, tee]", asList.invoke(argv).toString());
+assertEquals("[three, thee, tee]", asList.invoke((Object[])argv).toString());
+List ls = (List) asList.invoke((Object)argv);
+assertEquals(1, ls.size());
+assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0)));
+ * }</pre></blockquote>
+ * <p style="font-size:smaller;">
+ * <em>Discussion:</em>
+ * These rules are designed as a dynamically-typed variation
+ * of the Java rules for variable arity methods.
+ * In both cases, callers to a variable arity method or method handle
+ * can either pass zero or more positional arguments, or else pass
+ * pre-collected arrays of any length. Users should be aware of the
+ * special role of the final argument, and of the effect of a
+ * type match on that final argument, which determines whether
+ * or not a single trailing argument is interpreted as a whole
+ * array or a single element of an array to be collected.
+ * Note that the dynamic type of the trailing argument has no
+ * effect on this decision, only a comparison between the symbolic
+ * type descriptor of the call site and the type descriptor of the method handle.)
+ *
+ * @param arrayType often {@code Object[]}, the type of the array argument which will collect the arguments
+ * @return a new method handle which can collect any number of trailing arguments
+ * into an array, before calling the original method handle
+ * @throws NullPointerException if {@code arrayType} is a null reference
+ * @throws IllegalArgumentException if {@code arrayType} is not an array type
+ * or {@code arrayType} is not assignable to this method handle's trailing parameter type
+ * @see #asCollector
+ * @see #isVarargsCollector
+ * @see #withVarargs
+ * @see #asFixedArity
+ */
+ public MethodHandle asVarargsCollector(Class<?> arrayType) {
+ Objects.requireNonNull(arrayType);
+ boolean lastMatch = asCollectorChecks(arrayType, type().parameterCount() - 1, 0);
+ if (isVarargsCollector() && lastMatch)
+ return this;
+ // Android-changed: Android specific implementation.
+ // return MethodHandleImpl.makeVarargsCollector(this, arrayType);
+ return new Transformers.VarargsCollector(this);
+ }
+
+ /**
+ * Determines if this method handle
+ * supports {@linkplain #asVarargsCollector variable arity} calls.
+ * Such method handles arise from the following sources:
+ * <ul>
+ * <li>a call to {@linkplain #asVarargsCollector asVarargsCollector}
+ * <li>a call to a {@linkplain java.lang.invoke.MethodHandles.Lookup lookup method}
+ * which resolves to a variable arity Java method or constructor
+ * <li>an {@code ldc} instruction of a {@code CONSTANT_MethodHandle}
+ * which resolves to a variable arity Java method or constructor
+ * </ul>
+ * @return true if this method handle accepts more than one arity of plain, inexact {@code invoke} calls
+ * @see #asVarargsCollector
+ * @see #asFixedArity
+ */
+ public boolean isVarargsCollector() {
+ return false;
+ }
+
+ /**
+ * Makes a <em>fixed arity</em> method handle which is otherwise
+ * equivalent to the current method handle.
+ * <p>
+ * If the current method handle is not of
+ * {@linkplain #asVarargsCollector variable arity},
+ * the current method handle is returned.
+ * This is true even if the current method handle
+ * could not be a valid input to {@code asVarargsCollector}.
+ * <p>
+ * Otherwise, the resulting fixed-arity method handle has the same
+ * type and behavior of the current method handle,
+ * except that {@link #isVarargsCollector isVarargsCollector}
+ * will be false.
+ * The fixed-arity method handle may (or may not) be the
+ * a previous argument to {@code asVarargsCollector}.
+ * <p>
+ * Here is an example, of a list-making variable arity method handle:
+ * <blockquote><pre>{@code
+MethodHandle asListVar = publicLookup()
+ .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class))
+ .asVarargsCollector(Object[].class);
+MethodHandle asListFix = asListVar.asFixedArity();
+assertEquals("[1]", asListVar.invoke(1).toString());
+Exception caught = null;
+try { asListFix.invoke((Object)1); }
+catch (Exception ex) { caught = ex; }
+assert(caught instanceof ClassCastException);
+assertEquals("[two, too]", asListVar.invoke("two", "too").toString());
+try { asListFix.invoke("two", "too"); }
+catch (Exception ex) { caught = ex; }
+assert(caught instanceof WrongMethodTypeException);
+Object[] argv = { "three", "thee", "tee" };
+assertEquals("[three, thee, tee]", asListVar.invoke(argv).toString());
+assertEquals("[three, thee, tee]", asListFix.invoke(argv).toString());
+assertEquals(1, ((List) asListVar.invoke((Object)argv)).size());
+assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
+ * }</pre></blockquote>
+ *
+ * @return a new method handle which accepts only a fixed number of arguments
+ * @see #asVarargsCollector
+ * @see #isVarargsCollector
+ */
+ public MethodHandle asFixedArity() {
+ // BEGIN Android-changed: Android specific implementation.
+ // assert(!isVarargsCollector());
+ // return this;
+
+ MethodHandle mh = this;
+ if (mh.isVarargsCollector()) {
+ mh = ((Transformers.VarargsCollector) mh).asFixedArity();
+ }
+ assert(!mh.isVarargsCollector());
+ return mh;
+ // END Android-changed: Android specific implementation.
+ }
+
+ /**
+ * Binds a value {@code x} to the first argument of a method handle, without invoking it.
+ * The new method handle adapts, as its <i>target</i>,
+ * the current method handle by binding it to the given argument.
+ * The type of the bound handle will be
+ * the same as the type of the target, except that a single leading
+ * reference parameter will be omitted.
+ * <p>
+ * When called, the bound handle inserts the given value {@code x}
+ * as a new leading argument to the target. The other arguments are
+ * also passed unchanged.
+ * What the target eventually returns is returned unchanged by the bound handle.
+ * <p>
+ * The reference {@code x} must be convertible to the first parameter
+ * type of the target.
+ * <p>
+ * (<em>Note:</em> Because method handles are immutable, the target method handle
+ * retains its original type and behavior.)
+ * @param x the value to bind to the first argument of the target
+ * @return a new method handle which prepends the given value to the incoming
+ * argument list, before calling the original method handle
+ * @throws IllegalArgumentException if the target does not have a
+ * leading parameter type that is a reference type
+ * @throws ClassCastException if {@code x} cannot be converted
+ * to the leading parameter type of the target
+ * @see MethodHandles#insertArguments
+ */
+ public MethodHandle bindTo(Object x) {
+ x = type.leadingReferenceParameter().cast(x); // throw CCE if needed
+ // Android-changed: Android specific implementation.
+ // return bindArgumentL(0, x);
+ return new Transformers.BindTo(this, x);
+ }
+
+ /**
+ * Returns a string representation of the method handle,
+ * starting with the string {@code "MethodHandle"} and
+ * ending with the string representation of the method handle's type.
+ * In other words, this method returns a string equal to the value of:
+ * <blockquote><pre>{@code
+ * "MethodHandle" + type().toString()
+ * }</pre></blockquote>
+ * <p>
+ * (<em>Note:</em> Future releases of this API may add further information
+ * to the string representation.
+ * Therefore, the present syntax should not be parsed by applications.)
+ *
+ * @return a string representation of the method handle
+ */
+ @Override
+ public String toString() {
+ // Android-removed: Debugging support unused on Android.
+ // if (DEBUG_METHOD_HANDLE_NAMES) return "MethodHandle"+debugString();
+ return standardString();
+ }
+ String standardString() {
+ return "MethodHandle"+type;
+ }
+
+ // BEGIN Android-removed: Debugging support unused on Android.
+ /*
+ /** Return a string with a several lines describing the method handle structure.
+ * This string would be suitable for display in an IDE debugger.
+ *
+ String debugString() {
+ return type+" : "+internalForm()+internalProperties();
+ }
+ */
+ // END Android-removed: Debugging support unused on Android.
+
+ // BEGIN Android-added: Android specific implementation.
+ /** @hide */
+ public int getHandleKind() {
+ if (handleKind == INVOKE_VAR_HANDLE_EXACT || handleKind == INVOKE_VAR_HANDLE) {
+ // No need to expose Android implementation detail, avoids larger
+ // MethodHandleInfo changes in revealDirect() code path.
+ return INVOKE_VIRTUAL;
+ }
+ return handleKind;
+ }
+
+ /** @hide */
+ protected void transform(EmulatedStackFrame arguments) throws Throwable {
+ throw new AssertionError("MethodHandle.transform should never be called.");
+ }
+
+ /**
+ * Entry back into the runtime to dispatch a MethodHandle with a specific EmulatedStackFrame
+ * containing the arguments to provide.
+ * @param arguments the stack frame holding arguments for the invocation.
+ * @hide
+ */
+ /* package-private */ native void invokeExactWithFrame(EmulatedStackFrame arguments)
+ throws Throwable;
+
+ /**
+ * Creates a copy of this method handle, copying all relevant data.
+ *
+ * @hide
+ */
+ protected MethodHandle duplicate() {
+ try {
+ return (MethodHandle) this.clone();
+ } catch (CloneNotSupportedException cnse) {
+ throw new AssertionError("Subclass of Transformer is not cloneable");
+ }
+ }
+
+ /**
+ * This is the entry point for all transform calls, and dispatches to the protected
+ * transform method. This layer of indirection exists purely for convenience, because
+ * we can invoke-direct on a fixed ArtMethod for all transform variants.
+ *
+ * NOTE: If this extra layer of indirection proves to be a problem, we can get rid
+ * of this layer of indirection at the cost of some additional ugliness.
+ */
+ private void transformInternal(EmulatedStackFrame arguments) throws Throwable {
+ transform(arguments);
+ }
+ // END Android-added: Android specific implementation.
+
+ // BEGIN Android-removed: RI implementation unused on Android.
+ /*
+ //// Implementation methods.
+ //// Sub-classes can override these default implementations.
+ //// All these methods assume arguments are already validated.
+
+ // Other transforms to do: convert, explicitCast, permute, drop, filter, fold, GWT, catch
+
+ BoundMethodHandle bindArgumentL(int pos, Object value) {
+ return rebind().bindArgumentL(pos, value);
+ }
+
+ /*non-public*
+ MethodHandle setVarargs(MemberName member) throws IllegalAccessException {
+ if (!member.isVarargs()) return this;
+ Class<?> arrayType = type().lastParameterType();
+ if (arrayType.isArray()) {
+ return MethodHandleImpl.makeVarargsCollector(this, arrayType);
+ }
+ throw member.makeAccessException("cannot make variable arity", null);
+ }
+
+ /*non-public*
+ MethodHandle viewAsType(MethodType newType, boolean strict) {
+ // No actual conversions, just a new view of the same method.
+ // Note that this operation must not produce a DirectMethodHandle,
+ // because retyped DMHs, like any transformed MHs,
+ // cannot be cracked into MethodHandleInfo.
+ assert viewAsTypeChecks(newType, strict);
+ BoundMethodHandle mh = rebind();
+ assert(!((MethodHandle)mh instanceof DirectMethodHandle));
+ return mh.copyWith(newType, mh.form);
+ }
+
+ /*non-public*
+ boolean viewAsTypeChecks(MethodType newType, boolean strict) {
+ if (strict) {
+ assert(type().isViewableAs(newType, true))
+ : Arrays.asList(this, newType);
+ } else {
+ assert(type().basicType().isViewableAs(newType.basicType(), true))
+ : Arrays.asList(this, newType);
+ }
+ return true;
+ }
+
+ // Decoding
+
+ /*non-public*
+ LambdaForm internalForm() {
+ return form;
+ }
+
+ /*non-public*
+ MemberName internalMemberName() {
+ return null; // DMH returns DMH.member
+ }
+
+ /*non-public*
+ Class<?> internalCallerClass() {
+ return null; // caller-bound MH for @CallerSensitive method returns caller
+ }
+
+ /*non-public*
+ MethodHandleImpl.Intrinsic intrinsicName() {
+ // no special intrinsic meaning to most MHs
+ return MethodHandleImpl.Intrinsic.NONE;
+ }
+
+ /*non-public*
+ MethodHandle withInternalMemberName(MemberName member, boolean isInvokeSpecial) {
+ if (member != null) {
+ return MethodHandleImpl.makeWrappedMember(this, member, isInvokeSpecial);
+ } else if (internalMemberName() == null) {
+ // The required internaMemberName is null, and this MH (like most) doesn't have one.
+ return this;
+ } else {
+ // The following case is rare. Mask the internalMemberName by wrapping the MH in a BMH.
+ MethodHandle result = rebind();
+ assert (result.internalMemberName() == null);
+ return result;
+ }
+ }
+
+ /*non-public*
+ boolean isInvokeSpecial() {
+ return false; // DMH.Special returns true
+ }
+
+ /*non-public*
+ Object internalValues() {
+ return null;
+ }
+
+ /*non-public*
+ Object internalProperties() {
+ // Override to something to follow this.form, like "\n& FOO=bar"
+ return "";
+ }
+
+ //// Method handle implementation methods.
+ //// Sub-classes can override these default implementations.
+ //// All these methods assume arguments are already validated.
+
+ /*non-public*
+ abstract MethodHandle copyWith(MethodType mt, LambdaForm lf);
+
+ /** Require this method handle to be a BMH, or else replace it with a "wrapper" BMH.
+ * Many transforms are implemented only for BMHs.
+ * @return a behaviorally equivalent BMH
+ *
+ abstract BoundMethodHandle rebind();
+
+ /**
+ * Replace the old lambda form of this method handle with a new one.
+ * The new one must be functionally equivalent to the old one.
+ * Threads may continue running the old form indefinitely,
+ * but it is likely that the new one will be preferred for new executions.
+ * Use with discretion.
+ *
+ /*non-public*
+ void updateForm(LambdaForm newForm) {
+ assert(newForm.customized == null || newForm.customized == this);
+ if (form == newForm) return;
+ newForm.prepare(); // as in MethodHandle.<init>
+ UNSAFE.putObject(this, FORM_OFFSET, newForm);
+ UNSAFE.fullFence();
+ }
+
+ /** Craft a LambdaForm customized for this particular MethodHandle *
+ /*non-public*
+ void customize() {
+ if (form.customized == null) {
+ LambdaForm newForm = form.customize(this);
+ updateForm(newForm);
+ } else {
+ assert(form.customized == this);
+ }
+ }
+
+ private static final long FORM_OFFSET;
+ static {
+ try {
+ FORM_OFFSET = UNSAFE.objectFieldOffset(MethodHandle.class.getDeclaredField("form"));
+ } catch (ReflectiveOperationException ex) {
+ throw newInternalError(ex);
+ }
+ }
+ */
+ // END Android-removed: RI implementation unused on Android.
+}
diff --git a/android-35/java/lang/invoke/MethodHandleImpl.java b/android-35/java/lang/invoke/MethodHandleImpl.java
new file mode 100644
index 0000000..a72b07b
--- /dev/null
+++ b/android-35/java/lang/invoke/MethodHandleImpl.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. The Android Open Source
+ * Project designates this particular file as subject to the "Classpath"
+ * exception as provided by The Android Open Source Project in the LICENSE
+ * file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package java.lang.invoke;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+// Android-changed: Android specific implementation.
+// The whole class was implemented from scratch for the Android runtime based
+// on the specification of the MethodHandle class.
+// The code does not originate from upstream OpenJDK.
+/**
+ * A method handle that's directly associated with an ArtField or an ArtMethod and
+ * specifies no additional transformations.
+ *
+ * @hide
+ */
+public class MethodHandleImpl extends MethodHandle implements Cloneable {
+ private HandleInfo info;
+
+ MethodHandleImpl(long artFieldOrMethod, int handleKind, MethodType type) {
+ super(artFieldOrMethod, handleKind, type);
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+ MethodHandleInfo reveal() {
+ if (info == null) {
+ final Member member = getMemberInternal();
+ info = new HandleInfo(member, this);
+ }
+
+ return info;
+ }
+
+ /**
+ * Materialize a member from this method handle's ArtField or ArtMethod pointer.
+ */
+ public native Member getMemberInternal();
+
+ /**
+ * Implementation of {@code MethodHandleInfo} in terms of the handle being cracked
+ * and its corresponding {@code java.lang.reflect.Member}.
+ */
+ static class HandleInfo implements MethodHandleInfo {
+ private final Member member;
+ private final MethodHandle handle;
+
+ HandleInfo(Member member, MethodHandle handle) {
+ this.member = member;
+ this.handle = handle;
+ }
+
+ @Override
+ public int getReferenceKind() {
+ switch (handle.getHandleKind()) {
+ case INVOKE_VIRTUAL: {
+ if (member.getDeclaringClass().isInterface()) {
+ return REF_invokeInterface;
+ } else {
+ return REF_invokeVirtual;
+ }
+ }
+
+ case INVOKE_DIRECT: {
+ if (member instanceof Constructor) {
+ return REF_newInvokeSpecial;
+ } else {
+ return REF_invokeSpecial;
+ }
+ }
+
+ case INVOKE_SUPER:
+ return MethodHandleInfo.REF_invokeSpecial;
+ case INVOKE_STATIC:
+ return MethodHandleInfo.REF_invokeStatic;
+ case IGET:
+ return MethodHandleInfo.REF_getField;
+ case IPUT:
+ return MethodHandleInfo.REF_putField;
+ case SGET:
+ return MethodHandleInfo.REF_getStatic;
+ case SPUT:
+ return MethodHandleInfo.REF_putStatic;
+ default:
+ throw new AssertionError("Unexpected handle kind: " + handle.getHandleKind());
+ }
+ }
+
+ @Override
+ public Class<?> getDeclaringClass() {
+ return member.getDeclaringClass();
+ }
+
+ @Override
+ public String getName() {
+ if (member instanceof Constructor) {
+ return "<init>";
+ }
+
+ return member.getName();
+ }
+
+ @Override
+ public MethodType getMethodType() {
+ // The "nominal" type of a cracked method handle is the same as the type
+ // of the handle itself, except in the cases enumerated below.
+ MethodType handleType = handle.type();
+
+ boolean omitLeadingParam = false;
+
+ // For constructs, the return type is always void.class, and not the type of
+ // the object returned. We also need to omit the leading reference, which is
+ // nominally the type of the object being constructed.
+ if (member instanceof Constructor) {
+ handleType = handleType.changeReturnType(void.class);
+ omitLeadingParam = true;
+ }
+
+ // For instance field gets/puts and instance method gets/puts, we omit the
+ // leading reference parameter to |this|.
+ switch (handle.getHandleKind()) {
+ case IGET:
+ case IPUT:
+ case INVOKE_INTERFACE:
+ case INVOKE_DIRECT:
+ case INVOKE_VIRTUAL:
+ case INVOKE_SUPER:
+ omitLeadingParam = true;
+ }
+
+ return omitLeadingParam ? handleType.dropParameterTypes(0, 1) : handleType;
+ }
+
+ @Override
+ public <T extends Member> T reflectAs(Class<T> expected, MethodHandles.Lookup lookup) {
+ try {
+ final Class declaringClass = member.getDeclaringClass();
+ if (Modifier.isNative(getModifiers()) &&
+ (MethodHandle.class.isAssignableFrom(declaringClass)
+ || VarHandle.class.isAssignableFrom(declaringClass))) {
+ if (member instanceof Method) {
+ Method m = (Method) member;
+ if (m.isVarArgs()) {
+ // Signature-polymorphic methods should not be reflected as there
+ // is no support for invoking them via reflection.
+ //
+ // We've identified this method as signature-polymorphic due to
+ // its flags (var-args and native) and its class.
+ throw new IllegalArgumentException(
+ "Reflecting signature polymorphic method");
+ }
+ }
+ }
+ lookup.checkAccess(
+ declaringClass, declaringClass, member.getModifiers(), member.getName());
+ } catch (IllegalAccessException exception) {
+ throw new IllegalArgumentException("Unable to access member.", exception);
+ }
+
+ return (T) member;
+ }
+
+ @Override
+ public int getModifiers() {
+ return member.getModifiers();
+ }
+
+ @Override
+ public String toString() {
+ return MethodHandleInfo.toString(
+ getReferenceKind(), getDeclaringClass(), getName(), getMethodType());
+ }
+ }
+}
diff --git a/android-35/java/lang/invoke/MethodHandleInfo.java b/android-35/java/lang/invoke/MethodHandleInfo.java
new file mode 100644
index 0000000..356768d
--- /dev/null
+++ b/android-35/java/lang/invoke/MethodHandleInfo.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.lang.invoke.MethodHandleNatives.Constants;
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandleStatics.*;
+
+/**
+ * A symbolic reference obtained by cracking a direct method handle
+ * into its consitutent symbolic parts.
+ * To crack a direct method handle, call {@link Lookup#revealDirect Lookup.revealDirect}.
+ * <h1><a name="directmh"></a>Direct Method Handles</h1>
+ * A <em>direct method handle</em> represents a method, constructor, or field without
+ * any intervening argument bindings or other transformations.
+ * The method, constructor, or field referred to by a direct method handle is called
+ * its <em>underlying member</em>.
+ * Direct method handles may be obtained in any of these ways:
+ * <ul>
+ * <li>By executing an {@code ldc} instruction on a {@code CONSTANT_MethodHandle} constant.
+ * (See the Java Virtual Machine Specification, sections 4.4.8 and 5.4.3.)
+ * <li>By calling one of the <a href="MethodHandles.Lookup.html#lookups">Lookup Factory Methods</a>,
+ * such as {@link Lookup#findVirtual Lookup.findVirtual},
+ * to resolve a symbolic reference into a method handle.
+ * A symbolic reference consists of a class, name string, and type.
+ * <li>By calling the factory method {@link Lookup#unreflect Lookup.unreflect}
+ * or {@link Lookup#unreflectSpecial Lookup.unreflectSpecial}
+ * to convert a {@link Method} into a method handle.
+ * <li>By calling the factory method {@link Lookup#unreflectConstructor Lookup.unreflectConstructor}
+ * to convert a {@link Constructor} into a method handle.
+ * <li>By calling the factory method {@link Lookup#unreflectGetter Lookup.unreflectGetter}
+ * or {@link Lookup#unreflectSetter Lookup.unreflectSetter}
+ * to convert a {@link Field} into a method handle.
+ * </ul>
+ *
+ * <h1>Restrictions on Cracking</h1>
+ * Given a suitable {@code Lookup} object, it is possible to crack any direct method handle
+ * to recover a symbolic reference for the underlying method, constructor, or field.
+ * Cracking must be done via a {@code Lookup} object equivalent to that which created
+ * the target method handle, or which has enough access permissions to recreate
+ * an equivalent method handle.
+ * <p>
+ * If the underlying method is <a href="MethodHandles.Lookup.html#callsens">caller sensitive</a>,
+ * the direct method handle will have been "bound" to a particular caller class, the
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#lookupClass() lookup class}
+ * of the lookup object used to create it.
+ * Cracking this method handle with a different lookup class will fail
+ * even if the underlying method is public (like {@code Class.forName}).
+ * <p>
+ * The requirement of lookup object matching provides a "fast fail" behavior
+ * for programs which may otherwise trust erroneous revelation of a method
+ * handle with symbolic information (or caller binding) from an unexpected scope.
+ * Use {@link java.lang.invoke.MethodHandles#reflectAs} to override this limitation.
+ *
+ * <h1><a name="refkinds"></a>Reference kinds</h1>
+ * The <a href="MethodHandles.Lookup.html#lookups">Lookup Factory Methods</a>
+ * correspond to all major use cases for methods, constructors, and fields.
+ * These use cases may be distinguished using small integers as follows:
+ * <table border=1 cellpadding=5 summary="reference kinds">
+ * <tr><th>reference kind</th><th>descriptive name</th><th>scope</th><th>member</th><th>behavior</th></tr>
+ * <tr>
+ * <td>{@code 1}</td><td>{@code REF_getField}</td><td>{@code class}</td>
+ * <td>{@code FT f;}</td><td>{@code (T) this.f;}</td>
+ * </tr>
+ * <tr>
+ * <td>{@code 2}</td><td>{@code REF_getStatic}</td><td>{@code class} or {@code interface}</td>
+ * <td>{@code static}<br>{@code FT f;}</td><td>{@code (T) C.f;}</td>
+ * </tr>
+ * <tr>
+ * <td>{@code 3}</td><td>{@code REF_putField}</td><td>{@code class}</td>
+ * <td>{@code FT f;}</td><td>{@code this.f = x;}</td>
+ * </tr>
+ * <tr>
+ * <td>{@code 4}</td><td>{@code REF_putStatic}</td><td>{@code class}</td>
+ * <td>{@code static}<br>{@code FT f;}</td><td>{@code C.f = arg;}</td>
+ * </tr>
+ * <tr>
+ * <td>{@code 5}</td><td>{@code REF_invokeVirtual}</td><td>{@code class}</td>
+ * <td>{@code T m(A*);}</td><td>{@code (T) this.m(arg*);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@code 6}</td><td>{@code REF_invokeStatic}</td><td>{@code class} or {@code interface}</td>
+ * <td>{@code static}<br>{@code T m(A*);}</td><td>{@code (T) C.m(arg*);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@code 7}</td><td>{@code REF_invokeSpecial}</td><td>{@code class} or {@code interface}</td>
+ * <td>{@code T m(A*);}</td><td>{@code (T) super.m(arg*);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@code 8}</td><td>{@code REF_newInvokeSpecial}</td><td>{@code class}</td>
+ * <td>{@code C(A*);}</td><td>{@code new C(arg*);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@code 9}</td><td>{@code REF_invokeInterface}</td><td>{@code interface}</td>
+ * <td>{@code T m(A*);}</td><td>{@code (T) this.m(arg*);}</td>
+ * </tr>
+ * </table>
+ * @since 1.8
+ */
+public
+interface MethodHandleInfo {
+ /**
+ * A direct method handle reference kind,
+ * as defined in the <a href="MethodHandleInfo.html#refkinds">table above</a>.
+ */
+ public static final int
+ REF_getField = Constants.REF_getField,
+ REF_getStatic = Constants.REF_getStatic,
+ REF_putField = Constants.REF_putField,
+ REF_putStatic = Constants.REF_putStatic,
+ REF_invokeVirtual = Constants.REF_invokeVirtual,
+ REF_invokeStatic = Constants.REF_invokeStatic,
+ REF_invokeSpecial = Constants.REF_invokeSpecial,
+ REF_newInvokeSpecial = Constants.REF_newInvokeSpecial,
+ REF_invokeInterface = Constants.REF_invokeInterface;
+
+ /**
+ * Returns the reference kind of the cracked method handle, which in turn
+ * determines whether the method handle's underlying member was a constructor, method, or field.
+ * See the <a href="MethodHandleInfo.html#refkinds">table above</a> for definitions.
+ * @return the integer code for the kind of reference used to access the underlying member
+ */
+ public int getReferenceKind();
+
+ /**
+ * Returns the class in which the cracked method handle's underlying member was defined.
+ * @return the declaring class of the underlying member
+ */
+ public Class<?> getDeclaringClass();
+
+ /**
+ * Returns the name of the cracked method handle's underlying member.
+ * This is {@code "<init>"} if the underlying member was a constructor,
+ * else it is a simple method name or field name.
+ * @return the simple name of the underlying member
+ */
+ public String getName();
+
+ /**
+ * Returns the nominal type of the cracked symbolic reference, expressed as a method type.
+ * If the reference is to a constructor, the return type will be {@code void}.
+ * If it is to a non-static method, the method type will not mention the {@code this} parameter.
+ * If it is to a field and the requested access is to read the field,
+ * the method type will have no parameters and return the field type.
+ * If it is to a field and the requested access is to write the field,
+ * the method type will have one parameter of the field type and return {@code void}.
+ * <p>
+ * Note that original direct method handle may include a leading {@code this} parameter,
+ * or (in the case of a constructor) will replace the {@code void} return type
+ * with the constructed class.
+ * The nominal type does not include any {@code this} parameter,
+ * and (in the case of a constructor) will return {@code void}.
+ * @return the type of the underlying member, expressed as a method type
+ */
+ public MethodType getMethodType();
+
+ // Utility methods.
+ // NOTE: class/name/type and reference kind constitute a symbolic reference
+ // member and modifiers are an add-on, derived from Core Reflection (or the equivalent)
+
+ /**
+ * Reflects the underlying member as a method, constructor, or field object.
+ * If the underlying member is public, it is reflected as if by
+ * {@code getMethod}, {@code getConstructor}, or {@code getField}.
+ * Otherwise, it is reflected as if by
+ * {@code getDeclaredMethod}, {@code getDeclaredConstructor}, or {@code getDeclaredField}.
+ * The underlying member must be accessible to the given lookup object.
+ * @param <T> the desired type of the result, either {@link Member} or a subtype
+ * @param expected a class object representing the desired result type {@code T}
+ * @param lookup the lookup object that created this MethodHandleInfo, or one with equivalent access privileges
+ * @return a reference to the method, constructor, or field object
+ * @exception ClassCastException if the member is not of the expected type
+ * @exception NullPointerException if either argument is {@code null}
+ * @exception IllegalArgumentException if the underlying member is not accessible to the given lookup object
+ */
+ public <T extends Member> T reflectAs(Class<T> expected, Lookup lookup);
+
+ /**
+ * Returns the access modifiers of the underlying member.
+ * @return the Java language modifiers for underlying member,
+ * or -1 if the member cannot be accessed
+ * @see Modifier
+ * @see #reflectAs
+ */
+ public int getModifiers();
+
+ /**
+ * Determines if the underlying member was a variable arity method or constructor.
+ * Such members are represented by method handles that are varargs collectors.
+ * @implSpec
+ * This produces a result equivalent to:
+ * <pre>{@code
+ * getReferenceKind() >= REF_invokeVirtual && Modifier.isTransient(getModifiers())
+ * }</pre>
+ *
+ *
+ * @return {@code true} if and only if the underlying member was declared with variable arity.
+ */
+ // spelling derived from java.lang.reflect.Executable, not MethodHandle.isVarargsCollector
+ public default boolean isVarArgs() {
+ // fields are never varargs:
+ if (MethodHandleNatives.refKindIsField((byte) getReferenceKind()))
+ return false;
+ // not in the public API: Modifier.VARARGS
+ final int ACC_VARARGS = 0x00000080; // from JVMS 4.6 (Table 4.20)
+ assert(ACC_VARARGS == Modifier.TRANSIENT);
+ return Modifier.isTransient(getModifiers());
+ }
+
+ /**
+ * Returns the descriptive name of the given reference kind,
+ * as defined in the <a href="MethodHandleInfo.html#refkinds">table above</a>.
+ * The conventional prefix "REF_" is omitted.
+ * @param referenceKind an integer code for a kind of reference used to access a class member
+ * @return a mixed-case string such as {@code "getField"}
+ * @exception IllegalArgumentException if the argument is not a valid
+ * <a href="MethodHandleInfo.html#refkinds">reference kind number</a>
+ */
+ public static String referenceKindToString(int referenceKind) {
+ if (!MethodHandleNatives.refKindIsValid(referenceKind))
+ throw newIllegalArgumentException("invalid reference kind", referenceKind);
+ return MethodHandleNatives.refKindName((byte)referenceKind);
+ }
+
+ /**
+ * Returns a string representation for a {@code MethodHandleInfo},
+ * given the four parts of its symbolic reference.
+ * This is defined to be of the form {@code "RK C.N:MT"}, where {@code RK} is the
+ * {@linkplain #referenceKindToString reference kind string} for {@code kind},
+ * {@code C} is the {@linkplain java.lang.Class#getName name} of {@code defc}
+ * {@code N} is the {@code name}, and
+ * {@code MT} is the {@code type}.
+ * These four values may be obtained from the
+ * {@linkplain #getReferenceKind reference kind},
+ * {@linkplain #getDeclaringClass declaring class},
+ * {@linkplain #getName member name},
+ * and {@linkplain #getMethodType method type}
+ * of a {@code MethodHandleInfo} object.
+ *
+ * @implSpec
+ * This produces a result equivalent to:
+ * <pre>{@code
+ * String.format("%s %s.%s:%s", referenceKindToString(kind), defc.getName(), name, type)
+ * }</pre>
+ *
+ * @param kind the {@linkplain #getReferenceKind reference kind} part of the symbolic reference
+ * @param defc the {@linkplain #getDeclaringClass declaring class} part of the symbolic reference
+ * @param name the {@linkplain #getName member name} part of the symbolic reference
+ * @param type the {@linkplain #getMethodType method type} part of the symbolic reference
+ * @return a string of the form {@code "RK C.N:MT"}
+ * @exception IllegalArgumentException if the first argument is not a valid
+ * <a href="MethodHandleInfo.html#refkinds">reference kind number</a>
+ * @exception NullPointerException if any reference argument is {@code null}
+ */
+ public static String toString(int kind, Class<?> defc, String name, MethodType type) {
+ Objects.requireNonNull(name); Objects.requireNonNull(type);
+ return String.format("%s %s.%s:%s", referenceKindToString(kind), defc.getName(), name, type);
+ }
+
+ // BEGIN Android-added: refKind...() methods needed for API compatibility with 26.
+ // These methods were accidentally added into the public API in API level. They are now
+ // deprecated as a prelude to being removed from the public API.
+ /**
+ * @deprecated This internal method was accidentally added to API 26 and must not be used. No
+ * replacement is available but it is possible to replicate using information from
+ * the <a href="MethodHandleInfo.html#refkinds">table above</a>, e.g.
+ * {@code refKind >= 1 && refKind <= 9}. There are no guarantees that this logic
+ * will work if future versions extend the table.
+ */
+ @Deprecated
+ static boolean refKindIsValid(int refKind) {
+ return MethodHandleNatives.refKindIsValid(refKind);
+ }
+
+ /**
+ * @deprecated This internal method was accidentally added to API 26 and must not be used. No
+ * replacement is available but it is possible to replicate using information from
+ * the <a href="MethodHandleInfo.html#refkinds">table above</a>, e.g.
+ * {@code refKind >= 1 && refKind <= 4}. There are no guarantees that this logic
+ * will work if future versions extend the table.
+ */
+ @Deprecated
+ static boolean refKindIsField(int refKind) {
+ return MethodHandleNatives.refKindIsField((byte) refKind);
+ }
+
+ /**
+ * @deprecated This internal method was accidentally added to API 26 and must not be used. Use
+ * {@link MethodHandleInfo#referenceKindToString(int)} instead.
+ */
+ @Deprecated
+ static String refKindName(int refKind) {
+ return MethodHandleNatives.refKindName((byte) refKind);
+ }
+ // END Android-added: refKind...() methods needed for API compatibility with 26.
+}
diff --git a/android-35/java/lang/invoke/MethodHandleNatives.java b/android-35/java/lang/invoke/MethodHandleNatives.java
new file mode 100644
index 0000000..94e17bb
--- /dev/null
+++ b/android-35/java/lang/invoke/MethodHandleNatives.java
@@ -0,0 +1,580 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import static java.lang.invoke.MethodHandleNatives.Constants.*;
+
+/**
+ * The JVM interface for the method handles package is all here.
+ * This is an interface internal and private to an implementation of JSR 292.
+ * <em>This class is not part of the JSR 292 standard.</em>
+ * @author jrose
+ */
+class MethodHandleNatives {
+
+ // BEGIN Android-removed: Unused implementation code.
+ /*
+ private MethodHandleNatives() { } // static only
+
+ /// MemberName support
+
+ static native void init(MemberName self, Object ref);
+ static native void expand(MemberName self);
+ static native MemberName resolve(MemberName self, Class<?> caller) throws LinkageError, ClassNotFoundException;
+ static native int getMembers(Class<?> defc, String matchName, String matchSig,
+ int matchFlags, Class<?> caller, int skip, MemberName[] results);
+
+ /// Field layout queries parallel to sun.misc.Unsafe:
+ static native long objectFieldOffset(MemberName self); // e.g., returns vmindex
+ static native long staticFieldOffset(MemberName self); // e.g., returns vmindex
+ static native Object staticFieldBase(MemberName self); // e.g., returns clazz
+ static native Object getMemberVMInfo(MemberName self); // returns {vmindex,vmtarget}
+
+ /// MethodHandle support
+
+ /** Fetch MH-related JVM parameter.
+ * which=0 retrieves MethodHandlePushLimit
+ * which=1 retrieves stack slot push size (in address units)
+ *
+ static native int getConstant(int which);
+
+ static final boolean COUNT_GWT;
+
+ /// CallSite support
+
+ /** Tell the JVM that we need to change the target of a CallSite. *
+ static native void setCallSiteTargetNormal(CallSite site, MethodHandle target);
+ static native void setCallSiteTargetVolatile(CallSite site, MethodHandle target);
+
+ private static native void registerNatives();
+ static {
+ registerNatives();
+ COUNT_GWT = getConstant(Constants.GC_COUNT_GWT) != 0;
+
+ // The JVM calls MethodHandleNatives.<clinit>. Cascade the <clinit> calls as needed:
+ MethodHandleImpl.initStatics();
+ }
+ */
+ // END Android-removed: Unused implementation code.
+
+ // All compile-time constants go here.
+ // There is an opportunity to check them against the JVM's idea of them.
+ static class Constants {
+ Constants() { } // static only
+ // BEGIN Android-removed: Unused implementation code.
+ /*
+ // MethodHandleImpl
+ static final int // for getConstant
+ GC_COUNT_GWT = 4,
+ GC_LAMBDA_SUPPORT = 5;
+
+ // MemberName
+ // The JVM uses values of -2 and above for vtable indexes.
+ // Field values are simple positive offsets.
+ // Ref: src/share/vm/oops/methodOop.hpp
+ // This value is negative enough to avoid such numbers,
+ // but not too negative.
+ static final int
+ MN_IS_METHOD = 0x00010000, // method (not constructor)
+ MN_IS_CONSTRUCTOR = 0x00020000, // constructor
+ MN_IS_FIELD = 0x00040000, // field
+ MN_IS_TYPE = 0x00080000, // nested type
+ MN_CALLER_SENSITIVE = 0x00100000, // @CallerSensitive annotation detected
+ MN_REFERENCE_KIND_SHIFT = 24, // refKind
+ MN_REFERENCE_KIND_MASK = 0x0F000000 >> MN_REFERENCE_KIND_SHIFT,
+ // The SEARCH_* bits are not for MN.flags but for the matchFlags argument of MHN.getMembers:
+ MN_SEARCH_SUPERCLASSES = 0x00100000,
+ MN_SEARCH_INTERFACES = 0x00200000;
+
+ /**
+ * Basic types as encoded in the JVM. These code values are not
+ * intended for use outside this class. They are used as part of
+ * a private interface between the JVM and this class.
+ *
+ static final int
+ T_BOOLEAN = 4,
+ T_CHAR = 5,
+ T_FLOAT = 6,
+ T_DOUBLE = 7,
+ T_BYTE = 8,
+ T_SHORT = 9,
+ T_INT = 10,
+ T_LONG = 11,
+ T_OBJECT = 12,
+ //T_ARRAY = 13
+ T_VOID = 14,
+ //T_ADDRESS = 15
+ T_ILLEGAL = 99;
+
+ /**
+ * Constant pool entry types.
+ *
+ static final byte
+ CONSTANT_Utf8 = 1,
+ CONSTANT_Integer = 3,
+ CONSTANT_Float = 4,
+ CONSTANT_Long = 5,
+ CONSTANT_Double = 6,
+ CONSTANT_Class = 7,
+ CONSTANT_String = 8,
+ CONSTANT_Fieldref = 9,
+ CONSTANT_Methodref = 10,
+ CONSTANT_InterfaceMethodref = 11,
+ CONSTANT_NameAndType = 12,
+ CONSTANT_MethodHandle = 15, // JSR 292
+ CONSTANT_MethodType = 16, // JSR 292
+ CONSTANT_InvokeDynamic = 18,
+ CONSTANT_LIMIT = 19; // Limit to tags found in classfiles
+
+ /**
+ * Access modifier flags.
+ *
+ static final char
+ ACC_PUBLIC = 0x0001,
+ ACC_PRIVATE = 0x0002,
+ ACC_PROTECTED = 0x0004,
+ ACC_STATIC = 0x0008,
+ ACC_FINAL = 0x0010,
+ ACC_SYNCHRONIZED = 0x0020,
+ ACC_VOLATILE = 0x0040,
+ ACC_TRANSIENT = 0x0080,
+ ACC_NATIVE = 0x0100,
+ ACC_INTERFACE = 0x0200,
+ ACC_ABSTRACT = 0x0400,
+ ACC_STRICT = 0x0800,
+ ACC_SYNTHETIC = 0x1000,
+ ACC_ANNOTATION = 0x2000,
+ ACC_ENUM = 0x4000,
+ // aliases:
+ ACC_SUPER = ACC_SYNCHRONIZED,
+ ACC_BRIDGE = ACC_VOLATILE,
+ ACC_VARARGS = ACC_TRANSIENT;
+ */
+ // END Android-removed: Unused implementation code.
+
+ /**
+ * Constant pool reference-kind codes, as used by CONSTANT_MethodHandle CP entries.
+ */
+ static final byte
+ REF_NONE = 0, // null value
+ REF_getField = 1,
+ REF_getStatic = 2,
+ REF_putField = 3,
+ REF_putStatic = 4,
+ REF_invokeVirtual = 5,
+ REF_invokeStatic = 6,
+ REF_invokeSpecial = 7,
+ REF_newInvokeSpecial = 8,
+ REF_invokeInterface = 9,
+ REF_LIMIT = 10;
+ }
+
+ static boolean refKindIsValid(int refKind) {
+ return (refKind > REF_NONE && refKind < REF_LIMIT);
+ }
+ static boolean refKindIsField(byte refKind) {
+ assert(refKindIsValid(refKind));
+ return (refKind <= REF_putStatic);
+ }
+ // BEGIN Android-removed: Unused implementation code.
+ /*
+ static boolean refKindIsGetter(byte refKind) {
+ assert(refKindIsValid(refKind));
+ return (refKind <= REF_getStatic);
+ }
+ static boolean refKindIsSetter(byte refKind) {
+ return refKindIsField(refKind) && !refKindIsGetter(refKind);
+ }
+ static boolean refKindIsMethod(byte refKind) {
+ return !refKindIsField(refKind) && (refKind != REF_newInvokeSpecial);
+ }
+ static boolean refKindIsConstructor(byte refKind) {
+ return (refKind == REF_newInvokeSpecial);
+ }
+ static boolean refKindHasReceiver(byte refKind) {
+ assert(refKindIsValid(refKind));
+ return (refKind & 1) != 0;
+ }
+ static boolean refKindIsStatic(byte refKind) {
+ return !refKindHasReceiver(refKind) && (refKind != REF_newInvokeSpecial);
+ }
+ static boolean refKindDoesDispatch(byte refKind) {
+ assert(refKindIsValid(refKind));
+ return (refKind == REF_invokeVirtual ||
+ refKind == REF_invokeInterface);
+ }
+ static {
+ final int HR_MASK = ((1 << REF_getField) |
+ (1 << REF_putField) |
+ (1 << REF_invokeVirtual) |
+ (1 << REF_invokeSpecial) |
+ (1 << REF_invokeInterface)
+ );
+ for (byte refKind = REF_NONE+1; refKind < REF_LIMIT; refKind++) {
+ assert(refKindHasReceiver(refKind) == (((1<<refKind) & HR_MASK) != 0)) : refKind;
+ }
+ }
+ */
+ // END Android-removed: Unused implementation code.
+ static String refKindName(byte refKind) {
+ assert(refKindIsValid(refKind));
+ switch (refKind) {
+ case REF_getField: return "getField";
+ case REF_getStatic: return "getStatic";
+ case REF_putField: return "putField";
+ case REF_putStatic: return "putStatic";
+ case REF_invokeVirtual: return "invokeVirtual";
+ case REF_invokeStatic: return "invokeStatic";
+ case REF_invokeSpecial: return "invokeSpecial";
+ case REF_newInvokeSpecial: return "newInvokeSpecial";
+ case REF_invokeInterface: return "invokeInterface";
+ default: return "REF_???";
+ }
+ }
+ // BEGIN Android-removed: Unused implementation code.
+ /*
+ private static native int getNamedCon(int which, Object[] name);
+ static boolean verifyConstants() {
+ Object[] box = { null };
+ for (int i = 0; ; i++) {
+ box[0] = null;
+ int vmval = getNamedCon(i, box);
+ if (box[0] == null) break;
+ String name = (String) box[0];
+ try {
+ Field con = Constants.class.getDeclaredField(name);
+ int jval = con.getInt(null);
+ if (jval == vmval) continue;
+ String err = (name+": JVM has "+vmval+" while Java has "+jval);
+ if (name.equals("CONV_OP_LIMIT")) {
+ System.err.println("warning: "+err);
+ continue;
+ }
+ throw new InternalError(err);
+ } catch (NoSuchFieldException | IllegalAccessException ex) {
+ String err = (name+": JVM has "+vmval+" which Java does not define");
+ // ignore exotic ops the JVM cares about; we just wont issue them
+ //System.err.println("warning: "+err);
+ continue;
+ }
+ }
+ return true;
+ }
+ static {
+ assert(verifyConstants());
+ }
+
+ // Up-calls from the JVM.
+ // These must NOT be public.
+
+ /**
+ * The JVM is linking an invokedynamic instruction. Create a reified call site for it.
+ *
+ static MemberName linkCallSite(Object callerObj,
+ Object bootstrapMethodObj,
+ Object nameObj, Object typeObj,
+ Object staticArguments,
+ Object[] appendixResult) {
+ MethodHandle bootstrapMethod = (MethodHandle)bootstrapMethodObj;
+ Class<?> caller = (Class<?>)callerObj;
+ String name = nameObj.toString().intern();
+ MethodType type = (MethodType)typeObj;
+ if (!TRACE_METHOD_LINKAGE)
+ return linkCallSiteImpl(caller, bootstrapMethod, name, type,
+ staticArguments, appendixResult);
+ return linkCallSiteTracing(caller, bootstrapMethod, name, type,
+ staticArguments, appendixResult);
+ }
+ static MemberName linkCallSiteImpl(Class<?> caller,
+ MethodHandle bootstrapMethod,
+ String name, MethodType type,
+ Object staticArguments,
+ Object[] appendixResult) {
+ CallSite callSite = CallSite.makeSite(bootstrapMethod,
+ name,
+ type,
+ staticArguments,
+ caller);
+ if (callSite instanceof ConstantCallSite) {
+ appendixResult[0] = callSite.dynamicInvoker();
+ return Invokers.linkToTargetMethod(type);
+ } else {
+ appendixResult[0] = callSite;
+ return Invokers.linkToCallSiteMethod(type);
+ }
+ }
+ // Tracing logic:
+ static MemberName linkCallSiteTracing(Class<?> caller,
+ MethodHandle bootstrapMethod,
+ String name, MethodType type,
+ Object staticArguments,
+ Object[] appendixResult) {
+ Object bsmReference = bootstrapMethod.internalMemberName();
+ if (bsmReference == null) bsmReference = bootstrapMethod;
+ Object staticArglist = (staticArguments instanceof Object[] ?
+ java.util.Arrays.asList((Object[]) staticArguments) :
+ staticArguments);
+ System.out.println("linkCallSite "+caller.getName()+" "+
+ bsmReference+" "+
+ name+type+"/"+staticArglist);
+ try {
+ MemberName res = linkCallSiteImpl(caller, bootstrapMethod, name, type,
+ staticArguments, appendixResult);
+ System.out.println("linkCallSite => "+res+" + "+appendixResult[0]);
+ return res;
+ } catch (Throwable ex) {
+ System.out.println("linkCallSite => throw "+ex);
+ throw ex;
+ }
+ }
+
+ /**
+ * The JVM wants a pointer to a MethodType. Oblige it by finding or creating one.
+ *
+ static MethodType findMethodHandleType(Class<?> rtype, Class<?>[] ptypes) {
+ return MethodType.makeImpl(rtype, ptypes, true);
+ }
+
+ /**
+ * The JVM wants to link a call site that requires a dynamic type check.
+ * Name is a type-checking invoker, invokeExact or invoke.
+ * Return a JVM method (MemberName) to handle the invoking.
+ * The method assumes the following arguments on the stack:
+ * 0: the method handle being invoked
+ * 1-N: the arguments to the method handle invocation
+ * N+1: an optional, implicitly added argument (typically the given MethodType)
+ * <p>
+ * The nominal method at such a call site is an instance of
+ * a signature-polymorphic method (see @PolymorphicSignature).
+ * Such method instances are user-visible entities which are
+ * "split" from the generic placeholder method in {@code MethodHandle}.
+ * (Note that the placeholder method is not identical with any of
+ * its instances. If invoked reflectively, is guaranteed to throw an
+ * {@code UnsupportedOperationException}.)
+ * If the signature-polymorphic method instance is ever reified,
+ * it appears as a "copy" of the original placeholder
+ * (a native final member of {@code MethodHandle}) except
+ * that its type descriptor has shape required by the instance,
+ * and the method instance is <em>not</em> varargs.
+ * The method instance is also marked synthetic, since the
+ * method (by definition) does not appear in Java source code.
+ * <p>
+ * The JVM is allowed to reify this method as instance metadata.
+ * For example, {@code invokeBasic} is always reified.
+ * But the JVM may instead call {@code linkMethod}.
+ * If the result is an * ordered pair of a {@code (method, appendix)},
+ * the method gets all the arguments (0..N inclusive)
+ * plus the appendix (N+1), and uses the appendix to complete the call.
+ * In this way, one reusable method (called a "linker method")
+ * can perform the function of any number of polymorphic instance
+ * methods.
+ * <p>
+ * Linker methods are allowed to be weakly typed, with any or
+ * all references rewritten to {@code Object} and any primitives
+ * (except {@code long}/{@code float}/{@code double})
+ * rewritten to {@code int}.
+ * A linker method is trusted to return a strongly typed result,
+ * according to the specific method type descriptor of the
+ * signature-polymorphic instance it is emulating.
+ * This can involve (as necessary) a dynamic check using
+ * data extracted from the appendix argument.
+ * <p>
+ * The JVM does not inspect the appendix, other than to pass
+ * it verbatim to the linker method at every call.
+ * This means that the JDK runtime has wide latitude
+ * for choosing the shape of each linker method and its
+ * corresponding appendix.
+ * Linker methods should be generated from {@code LambdaForm}s
+ * so that they do not become visible on stack traces.
+ * <p>
+ * The {@code linkMethod} call is free to omit the appendix
+ * (returning null) and instead emulate the required function
+ * completely in the linker method.
+ * As a corner case, if N==255, no appendix is possible.
+ * In this case, the method returned must be custom-generated to
+ * to perform any needed type checking.
+ * <p>
+ * If the JVM does not reify a method at a call site, but instead
+ * calls {@code linkMethod}, the corresponding call represented
+ * in the bytecodes may mention a valid method which is not
+ * representable with a {@code MemberName}.
+ * Therefore, use cases for {@code linkMethod} tend to correspond to
+ * special cases in reflective code such as {@code findVirtual}
+ * or {@code revealDirect}.
+ *
+ static MemberName linkMethod(Class<?> callerClass, int refKind,
+ Class<?> defc, String name, Object type,
+ Object[] appendixResult) {
+ if (!TRACE_METHOD_LINKAGE)
+ return linkMethodImpl(callerClass, refKind, defc, name, type, appendixResult);
+ return linkMethodTracing(callerClass, refKind, defc, name, type, appendixResult);
+ }
+ static MemberName linkMethodImpl(Class<?> callerClass, int refKind,
+ Class<?> defc, String name, Object type,
+ Object[] appendixResult) {
+ try {
+ if (defc == MethodHandle.class && refKind == REF_invokeVirtual) {
+ return Invokers.methodHandleInvokeLinkerMethod(name, fixMethodType(callerClass, type), appendixResult);
+ }
+ } catch (Throwable ex) {
+ if (ex instanceof LinkageError)
+ throw (LinkageError) ex;
+ else
+ throw new LinkageError(ex.getMessage(), ex);
+ }
+ throw new LinkageError("no such method "+defc.getName()+"."+name+type);
+ }
+ private static MethodType fixMethodType(Class<?> callerClass, Object type) {
+ if (type instanceof MethodType)
+ return (MethodType) type;
+ else
+ return MethodType.fromMethodDescriptorString((String)type, callerClass.getClassLoader());
+ }
+ // Tracing logic:
+ static MemberName linkMethodTracing(Class<?> callerClass, int refKind,
+ Class<?> defc, String name, Object type,
+ Object[] appendixResult) {
+ System.out.println("linkMethod "+defc.getName()+"."+
+ name+type+"/"+Integer.toHexString(refKind));
+ try {
+ MemberName res = linkMethodImpl(callerClass, refKind, defc, name, type, appendixResult);
+ System.out.println("linkMethod => "+res+" + "+appendixResult[0]);
+ return res;
+ } catch (Throwable ex) {
+ System.out.println("linkMethod => throw "+ex);
+ throw ex;
+ }
+ }
+
+
+ /**
+ * The JVM is resolving a CONSTANT_MethodHandle CP entry. And it wants our help.
+ * It will make an up-call to this method. (Do not change the name or signature.)
+ * The type argument is a Class for field requests and a MethodType for non-fields.
+ * <p>
+ * Recent versions of the JVM may also pass a resolved MemberName for the type.
+ * In that case, the name is ignored and may be null.
+ *
+ static MethodHandle linkMethodHandleConstant(Class<?> callerClass, int refKind,
+ Class<?> defc, String name, Object type) {
+ try {
+ Lookup lookup = IMPL_LOOKUP.in(callerClass);
+ assert(refKindIsValid(refKind));
+ return lookup.linkMethodHandleConstant((byte) refKind, defc, name, type);
+ } catch (IllegalAccessException ex) {
+ Throwable cause = ex.getCause();
+ if (cause instanceof AbstractMethodError) {
+ throw (AbstractMethodError) cause;
+ } else {
+ Error err = new IllegalAccessError(ex.getMessage());
+ throw initCauseFrom(err, ex);
+ }
+ } catch (NoSuchMethodException ex) {
+ Error err = new NoSuchMethodError(ex.getMessage());
+ throw initCauseFrom(err, ex);
+ } catch (NoSuchFieldException ex) {
+ Error err = new NoSuchFieldError(ex.getMessage());
+ throw initCauseFrom(err, ex);
+ } catch (ReflectiveOperationException ex) {
+ Error err = new IncompatibleClassChangeError();
+ throw initCauseFrom(err, ex);
+ }
+ }
+ */
+ // END Android-removed: Unused implementation code.
+
+ // BEGIN Android-added: Add mapLookupExceptionToError(ex) from OpenJDK 17. http://b/270028670
+ /**
+ * Map a reflective exception to a linkage error.
+ */
+ static LinkageError mapLookupExceptionToError(ReflectiveOperationException ex) {
+ LinkageError err;
+ if (ex instanceof IllegalAccessException) {
+ Throwable cause = ex.getCause();
+ if (cause instanceof AbstractMethodError) {
+ return (AbstractMethodError) cause;
+ } else {
+ err = new IllegalAccessError(ex.getMessage());
+ }
+ } else if (ex instanceof NoSuchMethodException) {
+ err = new NoSuchMethodError(ex.getMessage());
+ } else if (ex instanceof NoSuchFieldException) {
+ err = new NoSuchFieldError(ex.getMessage());
+ } else {
+ err = new IncompatibleClassChangeError();
+ }
+ return initCauseFrom(err, ex);
+ }
+
+ /**
+ * Use best possible cause for err.initCause(), substituting the
+ * cause for err itself if the cause has the same (or better) type.
+ */
+ static <E extends Error> E initCauseFrom(E err, Exception ex) {
+ Throwable th = ex.getCause();
+ @SuppressWarnings("unchecked")
+ final Class<E> Eclass = (Class<E>) err.getClass();
+ if (Eclass.isInstance(th))
+ return Eclass.cast(th);
+ err.initCause(th == null ? ex : th);
+ return err;
+ }
+ // END Android-added: Add mapLookupExceptionToError(ex) from OpenJDK 17. http://b/270028670
+
+ // BEGIN Android-removed: Unused implementation code.
+ /**
+ * Is this method a caller-sensitive method?
+ * I.e., does it call Reflection.getCallerClass or a similer method
+ * to ask about the identity of its caller?
+ *
+ static boolean isCallerSensitive(MemberName mem) {
+ if (!mem.isInvocable()) return false; // fields are not caller sensitive
+
+ return mem.isCallerSensitive() || canBeCalledVirtual(mem);
+ }
+
+ static boolean canBeCalledVirtual(MemberName mem) {
+ assert(mem.isInvocable());
+ Class<?> defc = mem.getDeclaringClass();
+ switch (mem.getName()) {
+ case "checkMemberAccess":
+ return canBeCalledVirtual(mem, java.lang.SecurityManager.class);
+ case "getContextClassLoader":
+ return canBeCalledVirtual(mem, java.lang.Thread.class);
+ }
+ return false;
+ }
+
+ static boolean canBeCalledVirtual(MemberName symbolicRef, Class<?> definingClass) {
+ Class<?> symbolicRefClass = symbolicRef.getDeclaringClass();
+ if (symbolicRefClass == definingClass) return true;
+ if (symbolicRef.isStatic() || symbolicRef.isPrivate()) return false;
+ return (definingClass.isAssignableFrom(symbolicRefClass) || // Msym overrides Mdef
+ symbolicRefClass.isInterface()); // Mdef implements Msym
+ }
+ */
+ // END Android-removed: Unused implementation code.
+}
diff --git a/android-35/java/lang/invoke/MethodHandleStatics.java b/android-35/java/lang/invoke/MethodHandleStatics.java
new file mode 100644
index 0000000..90265cc
--- /dev/null
+++ b/android-35/java/lang/invoke/MethodHandleStatics.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import sun.misc.Unsafe;
+
+/**
+ * This class consists exclusively of static names internal to the
+ * method handle implementation.
+ * Usage: {@code import static java.lang.invoke.MethodHandleStatics.*}
+ * @author John Rose, JSR 292 EG
+ */
+/*non-public*/ class MethodHandleStatics {
+
+ private MethodHandleStatics() { } // do not instantiate
+
+ static final Unsafe UNSAFE = Unsafe.getUnsafe();
+
+ // Android-changed: Remove debugging related static fields.
+ // They are unused and have no equivalent on Android.
+ /*
+ static final boolean DEBUG_METHOD_HANDLE_NAMES;
+ static final boolean DUMP_CLASS_FILES;
+ static final boolean TRACE_INTERPRETER;
+ static final boolean TRACE_METHOD_LINKAGE;
+ static final int COMPILE_THRESHOLD;
+ static final int DONT_INLINE_THRESHOLD;
+ static final int PROFILE_LEVEL;
+ static final boolean PROFILE_GWT;
+ static final int CUSTOMIZE_THRESHOLD;
+
+ static {
+ final Object[] values = new Object[9];
+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ public Void run() {
+ values[0] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
+ values[1] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES");
+ values[2] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_INTERPRETER");
+ values[3] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE");
+ values[4] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", 0);
+ values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.DONT_INLINE_THRESHOLD", 30);
+ values[6] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0);
+ values[7] = Boolean.parseBoolean(System.getProperty("java.lang.invoke.MethodHandle.PROFILE_GWT", "true"));
+ values[8] = Integer.getInteger("java.lang.invoke.MethodHandle.CUSTOMIZE_THRESHOLD", 127);
+ return null;
+ }
+ });
+ DEBUG_METHOD_HANDLE_NAMES = (Boolean) values[0];
+ DUMP_CLASS_FILES = (Boolean) values[1];
+ TRACE_INTERPRETER = (Boolean) values[2];
+ TRACE_METHOD_LINKAGE = (Boolean) values[3];
+ COMPILE_THRESHOLD = (Integer) values[4];
+ DONT_INLINE_THRESHOLD = (Integer) values[5];
+ PROFILE_LEVEL = (Integer) values[6];
+ PROFILE_GWT = (Boolean) values[7];
+ CUSTOMIZE_THRESHOLD = (Integer) values[8];
+
+ if (CUSTOMIZE_THRESHOLD < -1 || CUSTOMIZE_THRESHOLD > 127) {
+ throw newInternalError("CUSTOMIZE_THRESHOLD should be in [-1...127] range");
+ }
+ }
+
+ /** Tell if any of the debugging switches are turned on.
+ * If this is the case, it is reasonable to perform extra checks or save extra information.
+ *
+ /*non-public* static boolean debugEnabled() {
+ return (DEBUG_METHOD_HANDLE_NAMES |
+ DUMP_CLASS_FILES |
+ TRACE_INTERPRETER |
+ TRACE_METHOD_LINKAGE);
+ }
+ */
+
+ // Android-removed: Methods operating on MethodHandles that are currently unused on Android.
+ /*
+ /*non-public* static String getNameString(MethodHandle target, MethodType type) {
+ if (type == null)
+ type = target.type();
+ MemberName name = null;
+ if (target != null)
+ name = target.internalMemberName();
+ if (name == null)
+ return "invoke" + type;
+ return name.getName() + type;
+ }
+
+ /*non-public* static String getNameString(MethodHandle target, MethodHandle typeHolder) {
+ return getNameString(target, typeHolder == null ? (MethodType) null : typeHolder.type());
+ }
+
+ /*non-public* static String getNameString(MethodHandle target) {
+ return getNameString(target, (MethodType) null);
+ }
+
+ /*non-public* static String addTypeString(Object obj, MethodHandle target) {
+ String str = String.valueOf(obj);
+ if (target == null) return str;
+ int paren = str.indexOf('(');
+ if (paren >= 0) str = str.substring(0, paren);
+ return str + target.type();
+ }
+ */
+
+ // handy shared exception makers (they simplify the common case code)
+ /*non-public*/ static InternalError newInternalError(String message) {
+ return new InternalError(message);
+ }
+ /*non-public*/ static InternalError newInternalError(String message, Throwable cause) {
+ return new InternalError(message, cause);
+ }
+ /*non-public*/ static InternalError newInternalError(Throwable cause) {
+ return new InternalError(cause);
+ }
+ /*non-public*/ static RuntimeException newIllegalStateException(String message) {
+ return new IllegalStateException(message);
+ }
+ /*non-public*/ static RuntimeException newIllegalStateException(String message, Object obj) {
+ return new IllegalStateException(message(message, obj));
+ }
+ /*non-public*/ static RuntimeException newIllegalArgumentException(String message) {
+ return new IllegalArgumentException(message);
+ }
+ /*non-public*/ static RuntimeException newIllegalArgumentException(String message, Object obj) {
+ return new IllegalArgumentException(message(message, obj));
+ }
+ /*non-public*/ static RuntimeException newIllegalArgumentException(String message, Object obj, Object obj2) {
+ return new IllegalArgumentException(message(message, obj, obj2));
+ }
+ /** Propagate unchecked exceptions and errors, but wrap anything checked and throw that instead. */
+ /*non-public*/ static Error uncaughtException(Throwable ex) {
+ if (ex instanceof Error) throw (Error) ex;
+ if (ex instanceof RuntimeException) throw (RuntimeException) ex;
+ throw newInternalError("uncaught exception", ex);
+ }
+ static Error NYI() {
+ throw new AssertionError("NYI");
+ }
+ private static String message(String message, Object obj) {
+ if (obj != null) message = message + ": " + obj;
+ return message;
+ }
+ private static String message(String message, Object obj, Object obj2) {
+ if (obj != null || obj2 != null) message = message + ": " + obj + ", " + obj2;
+ return message;
+ }
+}
diff --git a/android-35/java/lang/invoke/MethodHandles.java b/android-35/java/lang/invoke/MethodHandles.java
new file mode 100644
index 0000000..31756bf
--- /dev/null
+++ b/android-35/java/lang/invoke/MethodHandles.java
@@ -0,0 +1,5913 @@
+/*
+ * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import sun.invoke.util.VerifyAccess;
+import sun.invoke.util.Wrapper;
+import sun.reflect.Reflection;
+
+import java.lang.reflect.*;
+import java.nio.ByteOrder;
+import java.util.List;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static java.lang.invoke.MethodHandleStatics.*;
+import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException;
+import static java.lang.invoke.MethodType.methodType;
+
+/**
+ * This class consists exclusively of static methods that operate on or return
+ * method handles. They fall into several categories:
+ * <ul>
+ * <li>Lookup methods which help create method handles for methods and fields.
+ * <li>Combinator methods, which combine or transform pre-existing method handles into new ones.
+ * <li>Other factory methods to create method handles that emulate other common JVM operations or control flow patterns.
+ * </ul>
+ * <p>
+ * @author John Rose, JSR 292 EG
+ * @since 1.7
+ */
+public class MethodHandles {
+
+ private MethodHandles() { } // do not instantiate
+
+ // Android-changed: We do not use MemberName / MethodHandleImpl.
+ //
+ // private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
+ // static { MethodHandleImpl.initStatics(); }
+ // See IMPL_LOOKUP below.
+
+ //// Method handle creation from ordinary methods.
+
+ /**
+ * Returns a {@link Lookup lookup object} with
+ * full capabilities to emulate all supported bytecode behaviors of the caller.
+ * These capabilities include <a href="MethodHandles.Lookup.html#privacc">private access</a> to the caller.
+ * Factory methods on the lookup object can create
+ * <a href="MethodHandleInfo.html#directmh">direct method handles</a>
+ * for any member that the caller has access to via bytecodes,
+ * including protected and private fields and methods.
+ * This lookup object is a <em>capability</em> which may be delegated to trusted agents.
+ * Do not store it in place where untrusted code can access it.
+ * <p>
+ * This method is caller sensitive, which means that it may return different
+ * values to different callers.
+ * <p>
+ * For any given caller class {@code C}, the lookup object returned by this call
+ * has equivalent capabilities to any lookup object
+ * supplied by the JVM to the bootstrap method of an
+ * <a href="package-summary.html#indyinsn">invokedynamic instruction</a>
+ * executing in the same caller class {@code C}.
+ * @return a lookup object for the caller of this method, with private access
+ */
+ // Android-changed: Remove caller sensitive.
+ // @CallerSensitive
+ public static Lookup lookup() {
+ return new Lookup(Reflection.getCallerClass());
+ }
+
+ /**
+ * Returns a {@link Lookup lookup object} which is trusted minimally.
+ * It can only be used to create method handles to
+ * publicly accessible fields and methods.
+ * <p>
+ * As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class}
+ * of this lookup object will be {@link java.lang.Object}.
+ *
+ * <p style="font-size:smaller;">
+ * <em>Discussion:</em>
+ * The lookup class can be changed to any other class {@code C} using an expression of the form
+ * {@link Lookup#in publicLookup().in(C.class)}.
+ * Since all classes have equal access to public names,
+ * such a change would confer no new access rights.
+ * A public lookup object is always subject to
+ * <a href="MethodHandles.Lookup.html#secmgr">security manager checks</a>.
+ * Also, it cannot access
+ * <a href="MethodHandles.Lookup.html#callsens">caller sensitive methods</a>.
+ * @return a lookup object which is trusted minimally
+ */
+ public static Lookup publicLookup() {
+ return Lookup.PUBLIC_LOOKUP;
+ }
+
+ // Android-removed: Documentation related to the security manager and module checks
+ /**
+ * Returns a {@link Lookup lookup object} with full capabilities to emulate all
+ * supported bytecode behaviors, including <a href="MethodHandles.Lookup.html#privacc">
+ * private access</a>, on a target class.
+ * @param targetClass the target class
+ * @param lookup the caller lookup object
+ * @return a lookup object for the target class, with private access
+ * @throws IllegalArgumentException if {@code targetClass} is a primitive type or array class
+ * @throws NullPointerException if {@code targetClass} or {@code caller} is {@code null}
+ * @throws IllegalAccessException is not thrown on Android
+ * @since 9
+ */
+ public static Lookup privateLookupIn(Class<?> targetClass, Lookup lookup) throws IllegalAccessException {
+ // Android-removed: SecurityManager calls
+ // SecurityManager sm = System.getSecurityManager();
+ // if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
+ if (targetClass.isPrimitive())
+ throw new IllegalArgumentException(targetClass + " is a primitive class");
+ if (targetClass.isArray())
+ throw new IllegalArgumentException(targetClass + " is an array class");
+ // BEGIN Android-removed: There is no module information on Android
+ /**
+ * Module targetModule = targetClass.getModule();
+ * Module callerModule = lookup.lookupClass().getModule();
+ * if (!callerModule.canRead(targetModule))
+ * throw new IllegalAccessException(callerModule + " does not read " + targetModule);
+ * if (targetModule.isNamed()) {
+ * String pn = targetClass.getPackageName();
+ * assert pn.length() > 0 : "unnamed package cannot be in named module";
+ * if (!targetModule.isOpen(pn, callerModule))
+ * throw new IllegalAccessException(targetModule + " does not open " + pn + " to " + callerModule);
+ * }
+ * if ((lookup.lookupModes() & Lookup.MODULE) == 0)
+ * throw new IllegalAccessException("lookup does not have MODULE lookup mode");
+ * if (!callerModule.isNamed() && targetModule.isNamed()) {
+ * IllegalAccessLogger logger = IllegalAccessLogger.illegalAccessLogger();
+ * if (logger != null) {
+ * logger.logIfOpenedForIllegalAccess(lookup, targetClass);
+ * }
+ * }
+ */
+ // END Android-removed: There is no module information on Android
+ return new Lookup(targetClass);
+ }
+
+
+ /**
+ * Performs an unchecked "crack" of a
+ * <a href="MethodHandleInfo.html#directmh">direct method handle</a>.
+ * The result is as if the user had obtained a lookup object capable enough
+ * to crack the target method handle, called
+ * {@link java.lang.invoke.MethodHandles.Lookup#revealDirect Lookup.revealDirect}
+ * on the target to obtain its symbolic reference, and then called
+ * {@link java.lang.invoke.MethodHandleInfo#reflectAs MethodHandleInfo.reflectAs}
+ * to resolve the symbolic reference to a member.
+ * <p>
+ * If there is a security manager, its {@code checkPermission} method
+ * is called with a {@code ReflectPermission("suppressAccessChecks")} permission.
+ * @param <T> the desired type of the result, either {@link Member} or a subtype
+ * @param target a direct method handle to crack into symbolic reference components
+ * @param expected a class object representing the desired result type {@code T}
+ * @return a reference to the method, constructor, or field object
+ * @exception SecurityException if the caller is not privileged to call {@code setAccessible}
+ * @exception NullPointerException if either argument is {@code null}
+ * @exception IllegalArgumentException if the target is not a direct method handle
+ * @exception ClassCastException if the member is not of the expected type
+ * @since 1.8
+ */
+ public static <T extends Member> T
+ reflectAs(Class<T> expected, MethodHandle target) {
+ MethodHandleImpl directTarget = getMethodHandleImpl(target);
+ // Given that this is specified to be an "unchecked" crack, we can directly allocate
+ // a member from the underlying ArtField / Method and bypass all associated access checks.
+ return expected.cast(directTarget.getMemberInternal());
+ }
+
+ /**
+ * A <em>lookup object</em> is a factory for creating method handles,
+ * when the creation requires access checking.
+ * Method handles do not perform
+ * access checks when they are called, but rather when they are created.
+ * Therefore, method handle access
+ * restrictions must be enforced when a method handle is created.
+ * The caller class against which those restrictions are enforced
+ * is known as the {@linkplain #lookupClass lookup class}.
+ * <p>
+ * A lookup class which needs to create method handles will call
+ * {@link #lookup MethodHandles.lookup} to create a factory for itself.
+ * When the {@code Lookup} factory object is created, the identity of the lookup class is
+ * determined, and securely stored in the {@code Lookup} object.
+ * The lookup class (or its delegates) may then use factory methods
+ * on the {@code Lookup} object to create method handles for access-checked members.
+ * This includes all methods, constructors, and fields which are allowed to the lookup class,
+ * even private ones.
+ *
+ * <h1><a name="lookups"></a>Lookup Factory Methods</h1>
+ * The factory methods on a {@code Lookup} object correspond to all major
+ * use cases for methods, constructors, and fields.
+ * Each method handle created by a factory method is the functional
+ * equivalent of a particular <em>bytecode behavior</em>.
+ * (Bytecode behaviors are described in section 5.4.3.5 of the Java Virtual Machine Specification.)
+ * Here is a summary of the correspondence between these factory methods and
+ * the behavior the resulting method handles:
+ * <table border=1 cellpadding=5 summary="lookup method behaviors">
+ * <tr>
+ * <th><a name="equiv"></a>lookup expression</th>
+ * <th>member</th>
+ * <th>bytecode behavior</th>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#findGetter lookup.findGetter(C.class,"f",FT.class)}</td>
+ * <td>{@code FT f;}</td><td>{@code (T) this.f;}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#findStaticGetter lookup.findStaticGetter(C.class,"f",FT.class)}</td>
+ * <td>{@code static}<br>{@code FT f;}</td><td>{@code (T) C.f;}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#findSetter lookup.findSetter(C.class,"f",FT.class)}</td>
+ * <td>{@code FT f;}</td><td>{@code this.f = x;}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#findStaticSetter lookup.findStaticSetter(C.class,"f",FT.class)}</td>
+ * <td>{@code static}<br>{@code FT f;}</td><td>{@code C.f = arg;}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#findVirtual lookup.findVirtual(C.class,"m",MT)}</td>
+ * <td>{@code T m(A*);}</td><td>{@code (T) this.m(arg*);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#findStatic lookup.findStatic(C.class,"m",MT)}</td>
+ * <td>{@code static}<br>{@code T m(A*);}</td><td>{@code (T) C.m(arg*);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#findSpecial lookup.findSpecial(C.class,"m",MT,this.class)}</td>
+ * <td>{@code T m(A*);}</td><td>{@code (T) super.m(arg*);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#findConstructor lookup.findConstructor(C.class,MT)}</td>
+ * <td>{@code C(A*);}</td><td>{@code new C(arg*);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#unreflectGetter lookup.unreflectGetter(aField)}</td>
+ * <td>({@code static})?<br>{@code FT f;}</td><td>{@code (FT) aField.get(thisOrNull);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#unreflectSetter lookup.unreflectSetter(aField)}</td>
+ * <td>({@code static})?<br>{@code FT f;}</td><td>{@code aField.set(thisOrNull, arg);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)}</td>
+ * <td>({@code static})?<br>{@code T m(A*);}</td><td>{@code (T) aMethod.invoke(thisOrNull, arg*);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#unreflectConstructor lookup.unreflectConstructor(aConstructor)}</td>
+ * <td>{@code C(A*);}</td><td>{@code (C) aConstructor.newInstance(arg*);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)}</td>
+ * <td>({@code static})?<br>{@code T m(A*);}</td><td>{@code (T) aMethod.invoke(thisOrNull, arg*);}</td>
+ * </tr>
+ * </table>
+ *
+ * Here, the type {@code C} is the class or interface being searched for a member,
+ * documented as a parameter named {@code refc} in the lookup methods.
+ * The method type {@code MT} is composed from the return type {@code T}
+ * and the sequence of argument types {@code A*}.
+ * The constructor also has a sequence of argument types {@code A*} and
+ * is deemed to return the newly-created object of type {@code C}.
+ * Both {@code MT} and the field type {@code FT} are documented as a parameter named {@code type}.
+ * The formal parameter {@code this} stands for the self-reference of type {@code C};
+ * if it is present, it is always the leading argument to the method handle invocation.
+ * (In the case of some {@code protected} members, {@code this} may be
+ * restricted in type to the lookup class; see below.)
+ * The name {@code arg} stands for all the other method handle arguments.
+ * In the code examples for the Core Reflection API, the name {@code thisOrNull}
+ * stands for a null reference if the accessed method or field is static,
+ * and {@code this} otherwise.
+ * The names {@code aMethod}, {@code aField}, and {@code aConstructor} stand
+ * for reflective objects corresponding to the given members.
+ * <p>
+ * In cases where the given member is of variable arity (i.e., a method or constructor)
+ * the returned method handle will also be of {@linkplain MethodHandle#asVarargsCollector variable arity}.
+ * In all other cases, the returned method handle will be of fixed arity.
+ * <p style="font-size:smaller;">
+ * <em>Discussion:</em>
+ * The equivalence between looked-up method handles and underlying
+ * class members and bytecode behaviors
+ * can break down in a few ways:
+ * <ul style="font-size:smaller;">
+ * <li>If {@code C} is not symbolically accessible from the lookup class's loader,
+ * the lookup can still succeed, even when there is no equivalent
+ * Java expression or bytecoded constant.
+ * <li>Likewise, if {@code T} or {@code MT}
+ * is not symbolically accessible from the lookup class's loader,
+ * the lookup can still succeed.
+ * For example, lookups for {@code MethodHandle.invokeExact} and
+ * {@code MethodHandle.invoke} will always succeed, regardless of requested type.
+ * <li>If there is a security manager installed, it can forbid the lookup
+ * on various grounds (<a href="MethodHandles.Lookup.html#secmgr">see below</a>).
+ * By contrast, the {@code ldc} instruction on a {@code CONSTANT_MethodHandle}
+ * constant is not subject to security manager checks.
+ * <li>If the looked-up method has a
+ * <a href="MethodHandle.html#maxarity">very large arity</a>,
+ * the method handle creation may fail, due to the method handle
+ * type having too many parameters.
+ * </ul>
+ *
+ * <h1><a name="access"></a>Access checking</h1>
+ * Access checks are applied in the factory methods of {@code Lookup},
+ * when a method handle is created.
+ * This is a key difference from the Core Reflection API, since
+ * {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}
+ * performs access checking against every caller, on every call.
+ * <p>
+ * All access checks start from a {@code Lookup} object, which
+ * compares its recorded lookup class against all requests to
+ * create method handles.
+ * A single {@code Lookup} object can be used to create any number
+ * of access-checked method handles, all checked against a single
+ * lookup class.
+ * <p>
+ * A {@code Lookup} object can be shared with other trusted code,
+ * such as a metaobject protocol.
+ * A shared {@code Lookup} object delegates the capability
+ * to create method handles on private members of the lookup class.
+ * Even if privileged code uses the {@code Lookup} object,
+ * the access checking is confined to the privileges of the
+ * original lookup class.
+ * <p>
+ * A lookup can fail, because
+ * the containing class is not accessible to the lookup class, or
+ * because the desired class member is missing, or because the
+ * desired class member is not accessible to the lookup class, or
+ * because the lookup object is not trusted enough to access the member.
+ * In any of these cases, a {@code ReflectiveOperationException} will be
+ * thrown from the attempted lookup. The exact class will be one of
+ * the following:
+ * <ul>
+ * <li>NoSuchMethodException — if a method is requested but does not exist
+ * <li>NoSuchFieldException — if a field is requested but does not exist
+ * <li>IllegalAccessException — if the member exists but an access check fails
+ * </ul>
+ * <p>
+ * In general, the conditions under which a method handle may be
+ * looked up for a method {@code M} are no more restrictive than the conditions
+ * under which the lookup class could have compiled, verified, and resolved a call to {@code M}.
+ * Where the JVM would raise exceptions like {@code NoSuchMethodError},
+ * a method handle lookup will generally raise a corresponding
+ * checked exception, such as {@code NoSuchMethodException}.
+ * And the effect of invoking the method handle resulting from the lookup
+ * is <a href="MethodHandles.Lookup.html#equiv">exactly equivalent</a>
+ * to executing the compiled, verified, and resolved call to {@code M}.
+ * The same point is true of fields and constructors.
+ * <p style="font-size:smaller;">
+ * <em>Discussion:</em>
+ * Access checks only apply to named and reflected methods,
+ * constructors, and fields.
+ * Other method handle creation methods, such as
+ * {@link MethodHandle#asType MethodHandle.asType},
+ * do not require any access checks, and are used
+ * independently of any {@code Lookup} object.
+ * <p>
+ * If the desired member is {@code protected}, the usual JVM rules apply,
+ * including the requirement that the lookup class must be either be in the
+ * same package as the desired member, or must inherit that member.
+ * (See the Java Virtual Machine Specification, sections 4.9.2, 5.4.3.5, and 6.4.)
+ * In addition, if the desired member is a non-static field or method
+ * in a different package, the resulting method handle may only be applied
+ * to objects of the lookup class or one of its subclasses.
+ * This requirement is enforced by narrowing the type of the leading
+ * {@code this} parameter from {@code C}
+ * (which will necessarily be a superclass of the lookup class)
+ * to the lookup class itself.
+ * <p>
+ * The JVM imposes a similar requirement on {@code invokespecial} instruction,
+ * that the receiver argument must match both the resolved method <em>and</em>
+ * the current class. Again, this requirement is enforced by narrowing the
+ * type of the leading parameter to the resulting method handle.
+ * (See the Java Virtual Machine Specification, section 4.10.1.9.)
+ * <p>
+ * The JVM represents constructors and static initializer blocks as internal methods
+ * with special names ({@code "<init>"} and {@code "<clinit>"}).
+ * The internal syntax of invocation instructions allows them to refer to such internal
+ * methods as if they were normal methods, but the JVM bytecode verifier rejects them.
+ * A lookup of such an internal method will produce a {@code NoSuchMethodException}.
+ * <p>
+ * In some cases, access between nested classes is obtained by the Java compiler by creating
+ * an wrapper method to access a private method of another class
+ * in the same top-level declaration.
+ * For example, a nested class {@code C.D}
+ * can access private members within other related classes such as
+ * {@code C}, {@code C.D.E}, or {@code C.B},
+ * but the Java compiler may need to generate wrapper methods in
+ * those related classes. In such cases, a {@code Lookup} object on
+ * {@code C.E} would be unable to those private members.
+ * A workaround for this limitation is the {@link Lookup#in Lookup.in} method,
+ * which can transform a lookup on {@code C.E} into one on any of those other
+ * classes, without special elevation of privilege.
+ * <p>
+ * The accesses permitted to a given lookup object may be limited,
+ * according to its set of {@link #lookupModes lookupModes},
+ * to a subset of members normally accessible to the lookup class.
+ * For example, the {@link #publicLookup publicLookup}
+ * method produces a lookup object which is only allowed to access
+ * public members in public classes.
+ * The caller sensitive method {@link #lookup lookup}
+ * produces a lookup object with full capabilities relative to
+ * its caller class, to emulate all supported bytecode behaviors.
+ * Also, the {@link Lookup#in Lookup.in} method may produce a lookup object
+ * with fewer access modes than the original lookup object.
+ *
+ * <p style="font-size:smaller;">
+ * <a name="privacc"></a>
+ * <em>Discussion of private access:</em>
+ * We say that a lookup has <em>private access</em>
+ * if its {@linkplain #lookupModes lookup modes}
+ * include the possibility of accessing {@code private} members.
+ * As documented in the relevant methods elsewhere,
+ * only lookups with private access possess the following capabilities:
+ * <ul style="font-size:smaller;">
+ * <li>access private fields, methods, and constructors of the lookup class
+ * <li>create method handles which invoke <a href="MethodHandles.Lookup.html#callsens">caller sensitive</a> methods,
+ * such as {@code Class.forName}
+ * <li>create method handles which {@link Lookup#findSpecial emulate invokespecial} instructions
+ * <li>avoid <a href="MethodHandles.Lookup.html#secmgr">package access checks</a>
+ * for classes accessible to the lookup class
+ * <li>create {@link Lookup#in delegated lookup objects} which have private access to other classes
+ * within the same package member
+ * </ul>
+ * <p style="font-size:smaller;">
+ * Each of these permissions is a consequence of the fact that a lookup object
+ * with private access can be securely traced back to an originating class,
+ * whose <a href="MethodHandles.Lookup.html#equiv">bytecode behaviors</a> and Java language access permissions
+ * can be reliably determined and emulated by method handles.
+ *
+ * <h1><a name="secmgr"></a>Security manager interactions</h1>
+ * Although bytecode instructions can only refer to classes in
+ * a related class loader, this API can search for methods in any
+ * class, as long as a reference to its {@code Class} object is
+ * available. Such cross-loader references are also possible with the
+ * Core Reflection API, and are impossible to bytecode instructions
+ * such as {@code invokestatic} or {@code getfield}.
+ * There is a {@linkplain java.lang.SecurityManager security manager API}
+ * to allow applications to check such cross-loader references.
+ * These checks apply to both the {@code MethodHandles.Lookup} API
+ * and the Core Reflection API
+ * (as found on {@link java.lang.Class Class}).
+ * <p>
+ * If a security manager is present, member lookups are subject to
+ * additional checks.
+ * From one to three calls are made to the security manager.
+ * Any of these calls can refuse access by throwing a
+ * {@link java.lang.SecurityException SecurityException}.
+ * Define {@code smgr} as the security manager,
+ * {@code lookc} as the lookup class of the current lookup object,
+ * {@code refc} as the containing class in which the member
+ * is being sought, and {@code defc} as the class in which the
+ * member is actually defined.
+ * The value {@code lookc} is defined as <em>not present</em>
+ * if the current lookup object does not have
+ * <a href="MethodHandles.Lookup.html#privacc">private access</a>.
+ * The calls are made according to the following rules:
+ * <ul>
+ * <li><b>Step 1:</b>
+ * If {@code lookc} is not present, or if its class loader is not
+ * the same as or an ancestor of the class loader of {@code refc},
+ * then {@link SecurityManager#checkPackageAccess
+ * smgr.checkPackageAccess(refcPkg)} is called,
+ * where {@code refcPkg} is the package of {@code refc}.
+ * <li><b>Step 2:</b>
+ * If the retrieved member is not public and
+ * {@code lookc} is not present, then
+ * {@link SecurityManager#checkPermission smgr.checkPermission}
+ * with {@code RuntimePermission("accessDeclaredMembers")} is called.
+ * <li><b>Step 3:</b>
+ * If the retrieved member is not public,
+ * and if {@code lookc} is not present,
+ * and if {@code defc} and {@code refc} are different,
+ * then {@link SecurityManager#checkPackageAccess
+ * smgr.checkPackageAccess(defcPkg)} is called,
+ * where {@code defcPkg} is the package of {@code defc}.
+ * </ul>
+ * Security checks are performed after other access checks have passed.
+ * Therefore, the above rules presuppose a member that is public,
+ * or else that is being accessed from a lookup class that has
+ * rights to access the member.
+ *
+ * <h1><a name="callsens"></a>Caller sensitive methods</h1>
+ * A small number of Java methods have a special property called caller sensitivity.
+ * A <em>caller-sensitive</em> method can behave differently depending on the
+ * identity of its immediate caller.
+ * <p>
+ * If a method handle for a caller-sensitive method is requested,
+ * the general rules for <a href="MethodHandles.Lookup.html#equiv">bytecode behaviors</a> apply,
+ * but they take account of the lookup class in a special way.
+ * The resulting method handle behaves as if it were called
+ * from an instruction contained in the lookup class,
+ * so that the caller-sensitive method detects the lookup class.
+ * (By contrast, the invoker of the method handle is disregarded.)
+ * Thus, in the case of caller-sensitive methods,
+ * different lookup classes may give rise to
+ * differently behaving method handles.
+ * <p>
+ * In cases where the lookup object is
+ * {@link #publicLookup publicLookup()},
+ * or some other lookup object without
+ * <a href="MethodHandles.Lookup.html#privacc">private access</a>,
+ * the lookup class is disregarded.
+ * In such cases, no caller-sensitive method handle can be created,
+ * access is forbidden, and the lookup fails with an
+ * {@code IllegalAccessException}.
+ * <p style="font-size:smaller;">
+ * <em>Discussion:</em>
+ * For example, the caller-sensitive method
+ * {@link java.lang.Class#forName(String) Class.forName(x)}
+ * can return varying classes or throw varying exceptions,
+ * depending on the class loader of the class that calls it.
+ * A public lookup of {@code Class.forName} will fail, because
+ * there is no reasonable way to determine its bytecode behavior.
+ * <p style="font-size:smaller;">
+ * If an application caches method handles for broad sharing,
+ * it should use {@code publicLookup()} to create them.
+ * If there is a lookup of {@code Class.forName}, it will fail,
+ * and the application must take appropriate action in that case.
+ * It may be that a later lookup, perhaps during the invocation of a
+ * bootstrap method, can incorporate the specific identity
+ * of the caller, making the method accessible.
+ * <p style="font-size:smaller;">
+ * The function {@code MethodHandles.lookup} is caller sensitive
+ * so that there can be a secure foundation for lookups.
+ * Nearly all other methods in the JSR 292 API rely on lookup
+ * objects to check access requests.
+ */
+ // Android-changed: Change link targets from MethodHandles#[public]Lookup to
+ // #[public]Lookup to work around complaints from javadoc.
+ public static final
+ class Lookup {
+ /** The class on behalf of whom the lookup is being performed. */
+ /* @NonNull */ private final Class<?> lookupClass;
+
+ /** The allowed sorts of members which may be looked up (PUBLIC, etc.). */
+ private final int allowedModes;
+
+ /** A single-bit mask representing {@code public} access,
+ * which may contribute to the result of {@link #lookupModes lookupModes}.
+ * The value, {@code 0x01}, happens to be the same as the value of the
+ * {@code public} {@linkplain java.lang.reflect.Modifier#PUBLIC modifier bit}.
+ */
+ public static final int PUBLIC = Modifier.PUBLIC;
+
+ /** A single-bit mask representing {@code private} access,
+ * which may contribute to the result of {@link #lookupModes lookupModes}.
+ * The value, {@code 0x02}, happens to be the same as the value of the
+ * {@code private} {@linkplain java.lang.reflect.Modifier#PRIVATE modifier bit}.
+ */
+ public static final int PRIVATE = Modifier.PRIVATE;
+
+ /** A single-bit mask representing {@code protected} access,
+ * which may contribute to the result of {@link #lookupModes lookupModes}.
+ * The value, {@code 0x04}, happens to be the same as the value of the
+ * {@code protected} {@linkplain java.lang.reflect.Modifier#PROTECTED modifier bit}.
+ */
+ public static final int PROTECTED = Modifier.PROTECTED;
+
+ /** A single-bit mask representing {@code package} access (default access),
+ * which may contribute to the result of {@link #lookupModes lookupModes}.
+ * The value is {@code 0x08}, which does not correspond meaningfully to
+ * any particular {@linkplain java.lang.reflect.Modifier modifier bit}.
+ */
+ public static final int PACKAGE = Modifier.STATIC;
+
+ private static final int ALL_MODES = (PUBLIC | PRIVATE | PROTECTED | PACKAGE);
+
+ // Android-note: Android has no notion of a trusted lookup. If required, such lookups
+ // are performed by the runtime. As a result, we always use lookupClass, which will always
+ // be non-null in our implementation.
+ //
+ // private static final int TRUSTED = -1;
+
+ private static int fixmods(int mods) {
+ mods &= (ALL_MODES - PACKAGE);
+ return (mods != 0) ? mods : PACKAGE;
+ }
+
+ /** Tells which class is performing the lookup. It is this class against
+ * which checks are performed for visibility and access permissions.
+ * <p>
+ * The class implies a maximum level of access permission,
+ * but the permissions may be additionally limited by the bitmask
+ * {@link #lookupModes lookupModes}, which controls whether non-public members
+ * can be accessed.
+ * @return the lookup class, on behalf of which this lookup object finds members
+ */
+ public Class<?> lookupClass() {
+ return lookupClass;
+ }
+
+ /** Tells which access-protection classes of members this lookup object can produce.
+ * The result is a bit-mask of the bits
+ * {@linkplain #PUBLIC PUBLIC (0x01)},
+ * {@linkplain #PRIVATE PRIVATE (0x02)},
+ * {@linkplain #PROTECTED PROTECTED (0x04)},
+ * and {@linkplain #PACKAGE PACKAGE (0x08)}.
+ * <p>
+ * A freshly-created lookup object
+ * on the {@linkplain java.lang.invoke.MethodHandles#lookup() caller's class}
+ * has all possible bits set, since the caller class can access all its own members.
+ * A lookup object on a new lookup class
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#in created from a previous lookup object}
+ * may have some mode bits set to zero.
+ * The purpose of this is to restrict access via the new lookup object,
+ * so that it can access only names which can be reached by the original
+ * lookup object, and also by the new lookup class.
+ * @return the lookup modes, which limit the kinds of access performed by this lookup object
+ */
+ public int lookupModes() {
+ return allowedModes & ALL_MODES;
+ }
+
+ /** Embody the current class (the lookupClass) as a lookup class
+ * for method handle creation.
+ * Must be called by from a method in this package,
+ * which in turn is called by a method not in this package.
+ */
+ Lookup(Class<?> lookupClass) {
+ this(lookupClass, ALL_MODES);
+ // make sure we haven't accidentally picked up a privileged class:
+ checkUnprivilegedlookupClass(lookupClass, ALL_MODES);
+ }
+
+ private Lookup(Class<?> lookupClass, int allowedModes) {
+ this.lookupClass = lookupClass;
+ this.allowedModes = allowedModes;
+ }
+
+ /**
+ * Creates a lookup on the specified new lookup class.
+ * The resulting object will report the specified
+ * class as its own {@link #lookupClass lookupClass}.
+ * <p>
+ * However, the resulting {@code Lookup} object is guaranteed
+ * to have no more access capabilities than the original.
+ * In particular, access capabilities can be lost as follows:<ul>
+ * <li>If the new lookup class differs from the old one,
+ * protected members will not be accessible by virtue of inheritance.
+ * (Protected members may continue to be accessible because of package sharing.)
+ * <li>If the new lookup class is in a different package
+ * than the old one, protected and default (package) members will not be accessible.
+ * <li>If the new lookup class is not within the same package member
+ * as the old one, private members will not be accessible.
+ * <li>If the new lookup class is not accessible to the old lookup class,
+ * then no members, not even public members, will be accessible.
+ * (In all other cases, public members will continue to be accessible.)
+ * </ul>
+ *
+ * @param requestedLookupClass the desired lookup class for the new lookup object
+ * @return a lookup object which reports the desired lookup class
+ * @throws NullPointerException if the argument is null
+ */
+ public Lookup in(Class<?> requestedLookupClass) {
+ requestedLookupClass.getClass(); // null check
+ // Android-changed: There's no notion of a trusted lookup.
+ // if (allowedModes == TRUSTED) // IMPL_LOOKUP can make any lookup at all
+ // return new Lookup(requestedLookupClass, ALL_MODES);
+
+ if (requestedLookupClass == this.lookupClass)
+ return this; // keep same capabilities
+ int newModes = (allowedModes & (ALL_MODES & ~PROTECTED));
+ if ((newModes & PACKAGE) != 0
+ && !VerifyAccess.isSamePackage(this.lookupClass, requestedLookupClass)) {
+ newModes &= ~(PACKAGE|PRIVATE);
+ }
+ // Allow nestmate lookups to be created without special privilege:
+ if ((newModes & PRIVATE) != 0
+ && !VerifyAccess.isSamePackageMember(this.lookupClass, requestedLookupClass)) {
+ newModes &= ~PRIVATE;
+ }
+ if ((newModes & PUBLIC) != 0
+ && !VerifyAccess.isClassAccessible(requestedLookupClass, this.lookupClass, allowedModes)) {
+ // The requested class it not accessible from the lookup class.
+ // No permissions.
+ newModes = 0;
+ }
+ checkUnprivilegedlookupClass(requestedLookupClass, newModes);
+ return new Lookup(requestedLookupClass, newModes);
+ }
+
+ // Make sure outer class is initialized first.
+ //
+ // Android-changed: Removed unnecessary reference to IMPL_NAMES.
+ // static { IMPL_NAMES.getClass(); }
+
+ /** Version of lookup which is trusted minimally.
+ * It can only be used to create method handles to
+ * publicly accessible members.
+ */
+ static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, PUBLIC);
+
+ /** Package-private version of lookup which is trusted. */
+ static final Lookup IMPL_LOOKUP = new Lookup(Object.class, ALL_MODES);
+
+ private static void checkUnprivilegedlookupClass(Class<?> lookupClass, int allowedModes) {
+ String name = lookupClass.getName();
+ if (name.startsWith("java.lang.invoke."))
+ throw newIllegalArgumentException("illegal lookupClass: "+lookupClass);
+
+ // For caller-sensitive MethodHandles.lookup()
+ // disallow lookup more restricted packages
+ //
+ // Android-changed: The bootstrap classloader isn't null.
+ if (allowedModes == ALL_MODES &&
+ lookupClass.getClassLoader() == Object.class.getClassLoader()) {
+ if ((name.startsWith("java.")
+ && !name.startsWith("java.io.ObjectStreamClass")
+ && !name.startsWith("java.util.concurrent.")
+ && !name.equals("java.lang.Daemons$FinalizerWatchdogDaemon")
+ && !name.equals("java.lang.runtime.ObjectMethods")
+ && !name.equals("java.lang.Thread")
+ && !name.equals("java.util.HashMap")) ||
+ (name.startsWith("sun.")
+ && !name.startsWith("sun.invoke.")
+ && !name.equals("sun.reflect.ReflectionFactory"))) {
+ throw newIllegalArgumentException("illegal lookupClass: " + lookupClass);
+ }
+ }
+ }
+
+ /**
+ * Displays the name of the class from which lookups are to be made.
+ * (The name is the one reported by {@link java.lang.Class#getName() Class.getName}.)
+ * If there are restrictions on the access permitted to this lookup,
+ * this is indicated by adding a suffix to the class name, consisting
+ * of a slash and a keyword. The keyword represents the strongest
+ * allowed access, and is chosen as follows:
+ * <ul>
+ * <li>If no access is allowed, the suffix is "/noaccess".
+ * <li>If only public access is allowed, the suffix is "/public".
+ * <li>If only public and package access are allowed, the suffix is "/package".
+ * <li>If only public, package, and private access are allowed, the suffix is "/private".
+ * </ul>
+ * If none of the above cases apply, it is the case that full
+ * access (public, package, private, and protected) is allowed.
+ * In this case, no suffix is added.
+ * This is true only of an object obtained originally from
+ * {@link java.lang.invoke.MethodHandles#lookup MethodHandles.lookup}.
+ * Objects created by {@link java.lang.invoke.MethodHandles.Lookup#in Lookup.in}
+ * always have restricted access, and will display a suffix.
+ * <p>
+ * (It may seem strange that protected access should be
+ * stronger than private access. Viewed independently from
+ * package access, protected access is the first to be lost,
+ * because it requires a direct subclass relationship between
+ * caller and callee.)
+ * @see #in
+ */
+ @Override
+ public String toString() {
+ String cname = lookupClass.getName();
+ switch (allowedModes) {
+ case 0: // no privileges
+ return cname + "/noaccess";
+ case PUBLIC:
+ return cname + "/public";
+ case PUBLIC|PACKAGE:
+ return cname + "/package";
+ case ALL_MODES & ~PROTECTED:
+ return cname + "/private";
+ case ALL_MODES:
+ return cname;
+ // Android-changed: No support for TRUSTED callers.
+ // case TRUSTED:
+ // return "/trusted"; // internal only; not exported
+ default: // Should not happen, but it's a bitfield...
+ cname = cname + "/" + Integer.toHexString(allowedModes);
+ assert(false) : cname;
+ return cname;
+ }
+ }
+
+ /**
+ * Produces a method handle for a static method.
+ * The type of the method handle will be that of the method.
+ * (Since static methods do not take receivers, there is no
+ * additional receiver argument inserted into the method handle type,
+ * as there would be with {@link #findVirtual findVirtual} or {@link #findSpecial findSpecial}.)
+ * The method and all its argument types must be accessible to the lookup object.
+ * <p>
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the method's variable arity modifier bit ({@code 0x0080}) is set.
+ * <p>
+ * If the returned method handle is invoked, the method's class will
+ * be initialized, if it has not already been initialized.
+ * <p><b>Example:</b>
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle MH_asList = publicLookup().findStatic(Arrays.class,
+ "asList", methodType(List.class, Object[].class));
+assertEquals("[x, y]", MH_asList.invoke("x", "y").toString());
+ * }</pre></blockquote>
+ * @param refc the class from which the method is accessed
+ * @param name the name of the method
+ * @param type the type of the method
+ * @return the desired method handle
+ * @throws NoSuchMethodException if the method does not exist
+ * @throws IllegalAccessException if access checking fails,
+ * or if the method is not {@code static},
+ * or if the method's variable arity modifier bit
+ * is set and {@code asVarargsCollector} fails
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if any argument is null
+ */
+ public
+ MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
+ Method method = refc.getDeclaredMethod(name, type.ptypes());
+ final int modifiers = method.getModifiers();
+ if (!Modifier.isStatic(modifiers)) {
+ throw new IllegalAccessException("Method" + method + " is not static");
+ }
+ checkReturnType(method, type);
+ checkAccess(refc, method.getDeclaringClass(), modifiers, method.getName());
+ return createMethodHandle(method, MethodHandle.INVOKE_STATIC, type);
+ }
+
+ private MethodHandle findVirtualForMH(String name, MethodType type) {
+ // these names require special lookups because of the implicit MethodType argument
+ if ("invoke".equals(name))
+ return invoker(type);
+ if ("invokeExact".equals(name))
+ return exactInvoker(type);
+ return null;
+ }
+
+ private MethodHandle findVirtualForVH(String name, MethodType type) {
+ VarHandle.AccessMode accessMode;
+ try {
+ accessMode = VarHandle.AccessMode.valueFromMethodName(name);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ return varHandleInvoker(accessMode, type);
+ }
+
+ private static MethodHandle createMethodHandle(Method method, int handleKind,
+ MethodType methodType) {
+ MethodHandle mh = new MethodHandleImpl(method.getArtMethod(), handleKind, methodType);
+ if (method.isVarArgs()) {
+ return new Transformers.VarargsCollector(mh);
+ } else {
+ return mh;
+ }
+ }
+
+ /**
+ * Produces a method handle for a virtual method.
+ * The type of the method handle will be that of the method,
+ * with the receiver type (usually {@code refc}) prepended.
+ * The method and all its argument types must be accessible to the lookup object.
+ * <p>
+ * When called, the handle will treat the first argument as a receiver
+ * and dispatch on the receiver's type to determine which method
+ * implementation to enter.
+ * (The dispatching action is identical with that performed by an
+ * {@code invokevirtual} or {@code invokeinterface} instruction.)
+ * <p>
+ * The first argument will be of type {@code refc} if the lookup
+ * class has full privileges to access the member. Otherwise
+ * the member must be {@code protected} and the first argument
+ * will be restricted in type to the lookup class.
+ * <p>
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the method's variable arity modifier bit ({@code 0x0080}) is set.
+ * <p>
+ * Because of the general <a href="MethodHandles.Lookup.html#equiv">equivalence</a> between {@code invokevirtual}
+ * instructions and method handles produced by {@code findVirtual},
+ * if the class is {@code MethodHandle} and the name string is
+ * {@code invokeExact} or {@code invoke}, the resulting
+ * method handle is equivalent to one produced by
+ * {@link java.lang.invoke.MethodHandles#exactInvoker MethodHandles.exactInvoker} or
+ * {@link java.lang.invoke.MethodHandles#invoker MethodHandles.invoker}
+ * with the same {@code type} argument.
+ *
+ * <b>Example:</b>
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle MH_concat = publicLookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+MethodHandle MH_hashCode = publicLookup().findVirtual(Object.class,
+ "hashCode", methodType(int.class));
+MethodHandle MH_hashCode_String = publicLookup().findVirtual(String.class,
+ "hashCode", methodType(int.class));
+assertEquals("xy", (String) MH_concat.invokeExact("x", "y"));
+assertEquals("xy".hashCode(), (int) MH_hashCode.invokeExact((Object)"xy"));
+assertEquals("xy".hashCode(), (int) MH_hashCode_String.invokeExact("xy"));
+// interface method:
+MethodHandle MH_subSequence = publicLookup().findVirtual(CharSequence.class,
+ "subSequence", methodType(CharSequence.class, int.class, int.class));
+assertEquals("def", MH_subSequence.invoke("abcdefghi", 3, 6).toString());
+// constructor "internal method" must be accessed differently:
+MethodType MT_newString = methodType(void.class); //()V for new String()
+try { assertEquals("impossible", lookup()
+ .findVirtual(String.class, "<init>", MT_newString));
+ } catch (NoSuchMethodException ex) { } // OK
+MethodHandle MH_newString = publicLookup()
+ .findConstructor(String.class, MT_newString);
+assertEquals("", (String) MH_newString.invokeExact());
+ * }</pre></blockquote>
+ *
+ * @param refc the class or interface from which the method is accessed
+ * @param name the name of the method
+ * @param type the type of the method, with the receiver argument omitted
+ * @return the desired method handle
+ * @throws NoSuchMethodException if the method does not exist
+ * @throws IllegalAccessException if access checking fails,
+ * or if the method is {@code static}
+ * or if the method's variable arity modifier bit
+ * is set and {@code asVarargsCollector} fails
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if any argument is null
+ */
+ public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
+ // Special case : when we're looking up a virtual method on the MethodHandles class
+ // itself, we can return one of our specialized invokers.
+ if (refc == MethodHandle.class) {
+ MethodHandle mh = findVirtualForMH(name, type);
+ if (mh != null) {
+ return mh;
+ }
+ } else if (refc == VarHandle.class) {
+ // Returns an non-exact invoker.
+ MethodHandle mh = findVirtualForVH(name, type);
+ if (mh != null) {
+ return mh;
+ }
+ }
+
+ Method method = refc.getInstanceMethod(name, type.ptypes());
+ if (method == null) {
+ // This is pretty ugly and a consequence of the MethodHandles API. We have to throw
+ // an IAE and not an NSME if the method exists but is static (even though the RI's
+ // IAE has a message that says "no such method"). We confine the ugliness and
+ // slowness to the failure case, and allow getInstanceMethod to remain fairly
+ // general.
+ try {
+ Method m = refc.getDeclaredMethod(name, type.ptypes());
+ if (Modifier.isStatic(m.getModifiers())) {
+ throw new IllegalAccessException("Method" + m + " is static");
+ }
+ } catch (NoSuchMethodException ignored) {
+ }
+
+ throw new NoSuchMethodException(name + " " + Arrays.toString(type.ptypes()));
+ }
+ checkReturnType(method, type);
+
+ // We have a valid method, perform access checks.
+ checkAccess(refc, method.getDeclaringClass(), method.getModifiers(), method.getName());
+
+ // Insert the leading reference parameter.
+ MethodType handleType = type.insertParameterTypes(0, refc);
+ return createMethodHandle(method, MethodHandle.INVOKE_VIRTUAL, handleType);
+ }
+
+ /**
+ * Produces a method handle which creates an object and initializes it, using
+ * the constructor of the specified type.
+ * The parameter types of the method handle will be those of the constructor,
+ * while the return type will be a reference to the constructor's class.
+ * The constructor and all its argument types must be accessible to the lookup object.
+ * <p>
+ * The requested type must have a return type of {@code void}.
+ * (This is consistent with the JVM's treatment of constructor type descriptors.)
+ * <p>
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the constructor's variable arity modifier bit ({@code 0x0080}) is set.
+ * <p>
+ * If the returned method handle is invoked, the constructor's class will
+ * be initialized, if it has not already been initialized.
+ * <p><b>Example:</b>
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle MH_newArrayList = publicLookup().findConstructor(
+ ArrayList.class, methodType(void.class, Collection.class));
+Collection orig = Arrays.asList("x", "y");
+Collection copy = (ArrayList) MH_newArrayList.invokeExact(orig);
+assert(orig != copy);
+assertEquals(orig, copy);
+// a variable-arity constructor:
+MethodHandle MH_newProcessBuilder = publicLookup().findConstructor(
+ ProcessBuilder.class, methodType(void.class, String[].class));
+ProcessBuilder pb = (ProcessBuilder)
+ MH_newProcessBuilder.invoke("x", "y", "z");
+assertEquals("[x, y, z]", pb.command().toString());
+ * }</pre></blockquote>
+ * @param refc the class or interface from which the method is accessed
+ * @param type the type of the method, with the receiver argument omitted, and a void return type
+ * @return the desired method handle
+ * @throws NoSuchMethodException if the constructor does not exist
+ * @throws IllegalAccessException if access checking fails
+ * or if the method's variable arity modifier bit
+ * is set and {@code asVarargsCollector} fails
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if any argument is null
+ */
+ public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
+ if (refc.isArray()) {
+ throw new NoSuchMethodException("no constructor for array class: " + refc.getName());
+ }
+ // The queried |type| is (PT1,PT2,..)V
+ Constructor constructor = refc.getDeclaredConstructor(type.ptypes());
+ if (constructor == null) {
+ throw new NoSuchMethodException(
+ "No constructor for " + constructor.getDeclaringClass() + " matching " + type);
+ }
+ checkAccess(refc, constructor.getDeclaringClass(), constructor.getModifiers(),
+ constructor.getName());
+
+ return createMethodHandleForConstructor(constructor);
+ }
+
+ // BEGIN Android-added: Add findClass(String) from OpenJDK 17. http://b/270028670
+ // TODO: Unhide this method.
+ /**
+ * Looks up a class by name from the lookup context defined by this {@code Lookup} object,
+ * <a href="MethodHandles.Lookup.html#equiv">as if resolved</a> by an {@code ldc} instruction.
+ * Such a resolution, as specified in JVMS 5.4.3.1 section, attempts to locate and load the class,
+ * and then determines whether the class is accessible to this lookup object.
+ * <p>
+ * The lookup context here is determined by the {@linkplain #lookupClass() lookup class},
+ * its class loader, and the {@linkplain #lookupModes() lookup modes}.
+ *
+ * @param targetName the fully qualified name of the class to be looked up.
+ * @return the requested class.
+ * @throws SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws LinkageError if the linkage fails
+ * @throws ClassNotFoundException if the class cannot be loaded by the lookup class' loader.
+ * @throws IllegalAccessException if the class is not accessible, using the allowed access
+ * modes.
+ * @throws NullPointerException if {@code targetName} is null
+ * @since 9
+ * @jvms 5.4.3.1 Class and Interface Resolution
+ * @hide
+ */
+ public Class<?> findClass(String targetName) throws ClassNotFoundException, IllegalAccessException {
+ Class<?> targetClass = Class.forName(targetName, false, lookupClass.getClassLoader());
+ return accessClass(targetClass);
+ }
+ // END Android-added: Add findClass(String) from OpenJDK 17. http://b/270028670
+
+ private MethodHandle createMethodHandleForConstructor(Constructor constructor) {
+ Class<?> refc = constructor.getDeclaringClass();
+ MethodType constructorType =
+ MethodType.methodType(refc, constructor.getParameterTypes());
+ MethodHandle mh;
+ if (refc == String.class) {
+ // String constructors have optimized StringFactory methods
+ // that matches returned type. These factory methods combine the
+ // memory allocation and initialization calls for String objects.
+ mh = new MethodHandleImpl(constructor.getArtMethod(), MethodHandle.INVOKE_DIRECT,
+ constructorType);
+ } else {
+ // Constructors for all other classes use a Construct transformer to perform
+ // their memory allocation and call to <init>.
+ MethodType initType = initMethodType(constructorType);
+ MethodHandle initHandle = new MethodHandleImpl(
+ constructor.getArtMethod(), MethodHandle.INVOKE_DIRECT, initType);
+ mh = new Transformers.Construct(initHandle, constructorType);
+ }
+
+ if (constructor.isVarArgs()) {
+ mh = new Transformers.VarargsCollector(mh);
+ }
+ return mh;
+ }
+
+ private static MethodType initMethodType(MethodType constructorType) {
+ // Returns a MethodType appropriate for class <init>
+ // methods. Constructor MethodTypes have the form
+ // (PT1,PT2,...)C and class <init> MethodTypes have the
+ // form (C,PT1,PT2,...)V.
+ assert constructorType.rtype() != void.class;
+
+ // Insert constructorType C as the first parameter type in
+ // the MethodType for <init>.
+ Class<?> [] initPtypes = new Class<?> [constructorType.ptypes().length + 1];
+ initPtypes[0] = constructorType.rtype();
+ System.arraycopy(constructorType.ptypes(), 0, initPtypes, 1,
+ constructorType.ptypes().length);
+
+ // Set the return type for the <init> MethodType to be void.
+ return MethodType.methodType(void.class, initPtypes);
+ }
+
+ // BEGIN Android-added: Add accessClass(Class) from OpenJDK 17. http://b/270028670
+ /*
+ * Returns IllegalAccessException due to access violation to the given targetClass.
+ *
+ * This method is called by {@link Lookup#accessClass} and {@link Lookup#ensureInitialized}
+ * which verifies access to a class rather a member.
+ */
+ private IllegalAccessException makeAccessException(Class<?> targetClass) {
+ String message = "access violation: "+ targetClass;
+ if (this == MethodHandles.publicLookup()) {
+ message += ", from public Lookup";
+ } else {
+ // Android-changed: Remove unsupported module name.
+ // Module m = lookupClass().getModule();
+ // message += ", from " + lookupClass() + " (" + m + ")";
+ message += ", from " + lookupClass();
+ // Android-removed: Remove prevLookupClass until supported by Lookup in OpenJDK 17.
+ // if (prevLookupClass != null) {
+ // message += ", previous lookup " +
+ // prevLookupClass.getName() + " (" + prevLookupClass.getModule() + ")";
+ // }
+ }
+ return new IllegalAccessException(message);
+ }
+
+ // TODO: Unhide this method.
+ /**
+ * Determines if a class can be accessed from the lookup context defined by
+ * this {@code Lookup} object. The static initializer of the class is not run.
+ * If {@code targetClass} is an array class, {@code targetClass} is accessible
+ * if the element type of the array class is accessible. Otherwise,
+ * {@code targetClass} is determined as accessible as follows.
+ *
+ * <p>
+ * If {@code targetClass} is in the same module as the lookup class,
+ * the lookup class is {@code LC} in module {@code M1} and
+ * the previous lookup class is in module {@code M0} or
+ * {@code null} if not present,
+ * {@code targetClass} is accessible if and only if one of the following is true:
+ * <ul>
+ * <li>If this lookup has {@link #PRIVATE} access, {@code targetClass} is
+ * {@code LC} or other class in the same nest of {@code LC}.</li>
+ * <li>If this lookup has {@link #PACKAGE} access, {@code targetClass} is
+ * in the same runtime package of {@code LC}.</li>
+ * <li>If this lookup has {@link #MODULE} access, {@code targetClass} is
+ * a public type in {@code M1}.</li>
+ * <li>If this lookup has {@link #PUBLIC} access, {@code targetClass} is
+ * a public type in a package exported by {@code M1} to at least {@code M0}
+ * if the previous lookup class is present; otherwise, {@code targetClass}
+ * is a public type in a package exported by {@code M1} unconditionally.</li>
+ * </ul>
+ *
+ * <p>
+ * Otherwise, if this lookup has {@link #UNCONDITIONAL} access, this lookup
+ * can access public types in all modules when the type is in a package
+ * that is exported unconditionally.
+ * <p>
+ * Otherwise, {@code targetClass} is in a different module from {@code lookupClass},
+ * and if this lookup does not have {@code PUBLIC} access, {@code lookupClass}
+ * is inaccessible.
+ * <p>
+ * Otherwise, if this lookup has no {@linkplain #previousLookupClass() previous lookup class},
+ * {@code M1} is the module containing {@code lookupClass} and
+ * {@code M2} is the module containing {@code targetClass},
+ * then {@code targetClass} is accessible if and only if
+ * <ul>
+ * <li>{@code M1} reads {@code M2}, and
+ * <li>{@code targetClass} is public and in a package exported by
+ * {@code M2} at least to {@code M1}.
+ * </ul>
+ * <p>
+ * Otherwise, if this lookup has a {@linkplain #previousLookupClass() previous lookup class},
+ * {@code M1} and {@code M2} are as before, and {@code M0} is the module
+ * containing the previous lookup class, then {@code targetClass} is accessible
+ * if and only if one of the following is true:
+ * <ul>
+ * <li>{@code targetClass} is in {@code M0} and {@code M1}
+ * {@linkplain Module#reads reads} {@code M0} and the type is
+ * in a package that is exported to at least {@code M1}.
+ * <li>{@code targetClass} is in {@code M1} and {@code M0}
+ * {@linkplain Module#reads reads} {@code M1} and the type is
+ * in a package that is exported to at least {@code M0}.
+ * <li>{@code targetClass} is in a third module {@code M2} and both {@code M0}
+ * and {@code M1} reads {@code M2} and the type is in a package
+ * that is exported to at least both {@code M0} and {@code M2}.
+ * </ul>
+ * <p>
+ * Otherwise, {@code targetClass} is not accessible.
+ *
+ * @param targetClass the class to be access-checked
+ * @return the class that has been access-checked
+ * @throws IllegalAccessException if the class is not accessible from the lookup class
+ * and previous lookup class, if present, using the allowed access modes.
+ * @throws SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if {@code targetClass} is {@code null}
+ * @since 9
+ * @see <a href="#cross-module-lookup">Cross-module lookups</a>
+ * @hide
+ */
+ public Class<?> accessClass(Class<?> targetClass) throws IllegalAccessException {
+ if (!isClassAccessible(targetClass)) {
+ throw makeAccessException(targetClass);
+ }
+ // Android-removed: SecurityManager is unnecessary on Android.
+ // checkSecurityManager(targetClass);
+ return targetClass;
+ }
+
+ boolean isClassAccessible(Class<?> refc) {
+ Objects.requireNonNull(refc);
+ Class<?> caller = lookupClassOrNull();
+ Class<?> type = refc;
+ while (type.isArray()) {
+ type = type.getComponentType();
+ }
+ // Android-removed: Remove prevLookupClass until supported by Lookup in OpenJDK 17.
+ // return caller == null || VerifyAccess.isClassAccessible(type, caller, prevLookupClass, allowedModes);
+ return caller == null || VerifyAccess.isClassAccessible(type, caller, allowedModes);
+ }
+
+ // This is just for calling out to MethodHandleImpl.
+ private Class<?> lookupClassOrNull() {
+ // Android-changed: Android always returns lookupClass and has no concept of TRUSTED.
+ // return (allowedModes == TRUSTED) ? null : lookupClass;
+ return lookupClass;
+ }
+ // END Android-added: Add accessClass(Class) from OpenJDK 17. http://b/270028670
+
+ /**
+ * Produces an early-bound method handle for a virtual method.
+ * It will bypass checks for overriding methods on the receiver,
+ * <a href="MethodHandles.Lookup.html#equiv">as if called</a> from an {@code invokespecial}
+ * instruction from within the explicitly specified {@code specialCaller}.
+ * The type of the method handle will be that of the method,
+ * with a suitably restricted receiver type prepended.
+ * (The receiver type will be {@code specialCaller} or a subtype.)
+ * The method and all its argument types must be accessible
+ * to the lookup object.
+ * <p>
+ * Before method resolution,
+ * if the explicitly specified caller class is not identical with the
+ * lookup class, or if this lookup object does not have
+ * <a href="MethodHandles.Lookup.html#privacc">private access</a>
+ * privileges, the access fails.
+ * <p>
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the method's variable arity modifier bit ({@code 0x0080}) is set.
+ * <p style="font-size:smaller;">
+ * <em>(Note: JVM internal methods named {@code "<init>"} are not visible to this API,
+ * even though the {@code invokespecial} instruction can refer to them
+ * in special circumstances. Use {@link #findConstructor findConstructor}
+ * to access instance initialization methods in a safe manner.)</em>
+ * <p><b>Example:</b>
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+static class Listie extends ArrayList {
+ public String toString() { return "[wee Listie]"; }
+ static Lookup lookup() { return MethodHandles.lookup(); }
+}
+...
+// no access to constructor via invokeSpecial:
+MethodHandle MH_newListie = Listie.lookup()
+ .findConstructor(Listie.class, methodType(void.class));
+Listie l = (Listie) MH_newListie.invokeExact();
+try { assertEquals("impossible", Listie.lookup().findSpecial(
+ Listie.class, "<init>", methodType(void.class), Listie.class));
+ } catch (NoSuchMethodException ex) { } // OK
+// access to super and self methods via invokeSpecial:
+MethodHandle MH_super = Listie.lookup().findSpecial(
+ ArrayList.class, "toString" , methodType(String.class), Listie.class);
+MethodHandle MH_this = Listie.lookup().findSpecial(
+ Listie.class, "toString" , methodType(String.class), Listie.class);
+MethodHandle MH_duper = Listie.lookup().findSpecial(
+ Object.class, "toString" , methodType(String.class), Listie.class);
+assertEquals("[]", (String) MH_super.invokeExact(l));
+assertEquals(""+l, (String) MH_this.invokeExact(l));
+assertEquals("[]", (String) MH_duper.invokeExact(l)); // ArrayList method
+try { assertEquals("inaccessible", Listie.lookup().findSpecial(
+ String.class, "toString", methodType(String.class), Listie.class));
+ } catch (IllegalAccessException ex) { } // OK
+Listie subl = new Listie() { public String toString() { return "[subclass]"; } };
+assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
+ * }</pre></blockquote>
+ *
+ * @param refc the class or interface from which the method is accessed
+ * @param name the name of the method (which must not be "<init>")
+ * @param type the type of the method, with the receiver argument omitted
+ * @param specialCaller the proposed calling class to perform the {@code invokespecial}
+ * @return the desired method handle
+ * @throws NoSuchMethodException if the method does not exist
+ * @throws IllegalAccessException if access checking fails
+ * or if the method's variable arity modifier bit
+ * is set and {@code asVarargsCollector} fails
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if any argument is null
+ */
+ public MethodHandle findSpecial(Class<?> refc, String name, MethodType type,
+ Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException {
+ if (specialCaller == null) {
+ throw new NullPointerException("specialCaller == null");
+ }
+
+ if (type == null) {
+ throw new NullPointerException("type == null");
+ }
+
+ if (name == null) {
+ throw new NullPointerException("name == null");
+ }
+
+ if (refc == null) {
+ throw new NullPointerException("ref == null");
+ }
+
+ // Make sure that the special caller is identical to the lookup class or that we have
+ // private access.
+ // Android-changed: Also allow access to any interface methods.
+ checkSpecialCaller(specialCaller, refc);
+
+ // Even though constructors are invoked using a "special" invoke, handles to them can't
+ // be created using findSpecial. Callers must use findConstructor instead. Similarly,
+ // there is no path for calling static class initializers.
+ if (name.startsWith("<")) {
+ throw new NoSuchMethodException(name + " is not a valid method name.");
+ }
+
+ Method method = refc.getDeclaredMethod(name, type.ptypes());
+ checkReturnType(method, type);
+ return findSpecial(method, type, refc, specialCaller);
+ }
+
+ private MethodHandle findSpecial(Method method, MethodType type,
+ Class<?> refc, Class<?> specialCaller)
+ throws IllegalAccessException {
+ if (Modifier.isStatic(method.getModifiers())) {
+ throw new IllegalAccessException("expected a non-static method:" + method);
+ }
+
+ if (Modifier.isPrivate(method.getModifiers())) {
+ // Since this is a private method, we'll need to also make sure that the
+ // lookup class is the same as the refering class. We've already checked that
+ // the specialCaller is the same as the special lookup class, both of these must
+ // be the same as the declaring class(*) in order to access the private method.
+ //
+ // (*) Well, this isn't true for nested classes but OpenJDK doesn't support those
+ // either.
+ if (refc != lookupClass()) {
+ throw new IllegalAccessException("no private access for invokespecial : "
+ + refc + ", from" + this);
+ }
+
+ // This is a private method, so there's nothing special to do.
+ MethodType handleType = type.insertParameterTypes(0, refc);
+ return createMethodHandle(method, MethodHandle.INVOKE_DIRECT, handleType);
+ }
+
+ // This is a public, protected or package-private method, which means we're expecting
+ // invoke-super semantics. We'll have to restrict the receiver type appropriately on the
+ // handle once we check that there really is a "super" relationship between them.
+ if (!method.getDeclaringClass().isAssignableFrom(specialCaller)) {
+ throw new IllegalAccessException(refc + "is not assignable from " + specialCaller);
+ }
+
+ // Note that we restrict the receiver to "specialCaller" instances.
+ MethodType handleType = type.insertParameterTypes(0, specialCaller);
+ return createMethodHandle(method, MethodHandle.INVOKE_SUPER, handleType);
+ }
+
+ /**
+ * Produces a method handle giving read access to a non-static field.
+ * The type of the method handle will have a return type of the field's
+ * value type.
+ * The method handle's single argument will be the instance containing
+ * the field.
+ * Access checking is performed immediately on behalf of the lookup class.
+ * @param refc the class or interface from which the method is accessed
+ * @param name the field's name
+ * @param type the field's type
+ * @return a method handle which can load values from the field
+ * @throws NoSuchFieldException if the field does not exist
+ * @throws IllegalAccessException if access checking fails, or if the field is {@code static}
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if any argument is null
+ */
+ public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
+ return findAccessor(refc, name, type, MethodHandle.IGET);
+ }
+
+ private MethodHandle findAccessor(Class<?> refc, String name, Class<?> type, int kind)
+ throws NoSuchFieldException, IllegalAccessException {
+ final Field field = findFieldOfType(refc, name, type);
+ return findAccessor(field, refc, type, kind, true /* performAccessChecks */);
+ }
+
+ private MethodHandle findAccessor(Field field, Class<?> refc, Class<?> type, int kind,
+ boolean performAccessChecks)
+ throws IllegalAccessException {
+ final boolean isSetterKind = kind == MethodHandle.IPUT || kind == MethodHandle.SPUT;
+ final boolean isStaticKind = kind == MethodHandle.SGET || kind == MethodHandle.SPUT;
+ commonFieldChecks(field, refc, type, isStaticKind, performAccessChecks);
+ if (performAccessChecks) {
+ final int modifiers = field.getModifiers();
+ if (isSetterKind && Modifier.isFinal(modifiers)) {
+ throw new IllegalAccessException("Field " + field + " is final");
+ }
+ }
+
+ final MethodType methodType;
+ switch (kind) {
+ case MethodHandle.SGET:
+ methodType = MethodType.methodType(type);
+ break;
+ case MethodHandle.SPUT:
+ methodType = MethodType.methodType(void.class, type);
+ break;
+ case MethodHandle.IGET:
+ methodType = MethodType.methodType(type, refc);
+ break;
+ case MethodHandle.IPUT:
+ methodType = MethodType.methodType(void.class, refc, type);
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid kind " + kind);
+ }
+ return new MethodHandleImpl(field.getArtField(), kind, methodType);
+ }
+
+ /**
+ * Produces a method handle giving write access to a non-static field.
+ * The type of the method handle will have a void return type.
+ * The method handle will take two arguments, the instance containing
+ * the field, and the value to be stored.
+ * The second argument will be of the field's value type.
+ * Access checking is performed immediately on behalf of the lookup class.
+ * @param refc the class or interface from which the method is accessed
+ * @param name the field's name
+ * @param type the field's type
+ * @return a method handle which can store values into the field
+ * @throws NoSuchFieldException if the field does not exist
+ * @throws IllegalAccessException if access checking fails, or if the field is {@code static}
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if any argument is null
+ */
+ public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
+ return findAccessor(refc, name, type, MethodHandle.IPUT);
+ }
+
+ // BEGIN Android-changed: OpenJDK 9+181 VarHandle API factory method.
+ /**
+ * Produces a VarHandle giving access to a non-static field {@code name}
+ * of type {@code type} declared in a class of type {@code recv}.
+ * The VarHandle's variable type is {@code type} and it has one
+ * coordinate type, {@code recv}.
+ * <p>
+ * Access checking is performed immediately on behalf of the lookup
+ * class.
+ * <p>
+ * Certain access modes of the returned VarHandle are unsupported under
+ * the following conditions:
+ * <ul>
+ * <li>if the field is declared {@code final}, then the write, atomic
+ * update, numeric atomic update, and bitwise atomic update access
+ * modes are unsupported.
+ * <li>if the field type is anything other than {@code byte},
+ * {@code short}, {@code char}, {@code int}, {@code long},
+ * {@code float}, or {@code double} then numeric atomic update
+ * access modes are unsupported.
+ * <li>if the field type is anything other than {@code boolean},
+ * {@code byte}, {@code short}, {@code char}, {@code int} or
+ * {@code long} then bitwise atomic update access modes are
+ * unsupported.
+ * </ul>
+ * <p>
+ * If the field is declared {@code volatile} then the returned VarHandle
+ * will override access to the field (effectively ignore the
+ * {@code volatile} declaration) in accordance to its specified
+ * access modes.
+ * <p>
+ * If the field type is {@code float} or {@code double} then numeric
+ * and atomic update access modes compare values using their bitwise
+ * representation (see {@link Float#floatToRawIntBits} and
+ * {@link Double#doubleToRawLongBits}, respectively).
+ * @apiNote
+ * Bitwise comparison of {@code float} values or {@code double} values,
+ * as performed by the numeric and atomic update access modes, differ
+ * from the primitive {@code ==} operator and the {@link Float#equals}
+ * and {@link Double#equals} methods, specifically with respect to
+ * comparing NaN values or comparing {@code -0.0} with {@code +0.0}.
+ * Care should be taken when performing a compare and set or a compare
+ * and exchange operation with such values since the operation may
+ * unexpectedly fail.
+ * There are many possible NaN values that are considered to be
+ * {@code NaN} in Java, although no IEEE 754 floating-point operation
+ * provided by Java can distinguish between them. Operation failure can
+ * occur if the expected or witness value is a NaN value and it is
+ * transformed (perhaps in a platform specific manner) into another NaN
+ * value, and thus has a different bitwise representation (see
+ * {@link Float#intBitsToFloat} or {@link Double#longBitsToDouble} for more
+ * details).
+ * The values {@code -0.0} and {@code +0.0} have different bitwise
+ * representations but are considered equal when using the primitive
+ * {@code ==} operator. Operation failure can occur if, for example, a
+ * numeric algorithm computes an expected value to be say {@code -0.0}
+ * and previously computed the witness value to be say {@code +0.0}.
+ * @param recv the receiver class, of type {@code R}, that declares the
+ * non-static field
+ * @param name the field's name
+ * @param type the field's type, of type {@code T}
+ * @return a VarHandle giving access to non-static fields.
+ * @throws NoSuchFieldException if the field does not exist
+ * @throws IllegalAccessException if access checking fails, or if the field is {@code static}
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if any argument is null
+ * @since 9
+ */
+ public VarHandle findVarHandle(Class<?> recv, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
+ final Field field = findFieldOfType(recv, name, type);
+ final boolean isStatic = false;
+ final boolean performAccessChecks = true;
+ commonFieldChecks(field, recv, type, isStatic, performAccessChecks);
+ return FieldVarHandle.create(field);
+ }
+ // END Android-changed: OpenJDK 9+181 VarHandle API factory method.
+
+ // BEGIN Android-added: Common field resolution and access check methods.
+ private Field findFieldOfType(final Class<?> refc, String name, Class<?> type)
+ throws NoSuchFieldException {
+ Field field = null;
+
+ // Search refc and super classes for the field.
+ for (Class<?> cls = refc; cls != null; cls = cls.getSuperclass()) {
+ try {
+ field = cls.getDeclaredField(name);
+ break;
+ } catch (NoSuchFieldException e) {
+ }
+ }
+
+ if (field == null) {
+ // Force failure citing refc.
+ field = refc.getDeclaredField(name);
+ }
+
+ final Class<?> fieldType = field.getType();
+ if (fieldType != type) {
+ throw new NoSuchFieldException(name);
+ }
+ return field;
+ }
+
+ private void commonFieldChecks(Field field, Class<?> refc, Class<?> type,
+ boolean isStatic, boolean performAccessChecks)
+ throws IllegalAccessException {
+ final int modifiers = field.getModifiers();
+ if (performAccessChecks) {
+ checkAccess(refc, field.getDeclaringClass(), modifiers, field.getName());
+ }
+ if (Modifier.isStatic(modifiers) != isStatic) {
+ String reason = "Field " + field + " is " +
+ (isStatic ? "not " : "") + "static";
+ throw new IllegalAccessException(reason);
+ }
+ }
+ // END Android-added: Common field resolution and access check methods.
+
+ /**
+ * Produces a method handle giving read access to a static field.
+ * The type of the method handle will have a return type of the field's
+ * value type.
+ * The method handle will take no arguments.
+ * Access checking is performed immediately on behalf of the lookup class.
+ * <p>
+ * If the returned method handle is invoked, the field's class will
+ * be initialized, if it has not already been initialized.
+ * @param refc the class or interface from which the method is accessed
+ * @param name the field's name
+ * @param type the field's type
+ * @return a method handle which can load values from the field
+ * @throws NoSuchFieldException if the field does not exist
+ * @throws IllegalAccessException if access checking fails, or if the field is not {@code static}
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if any argument is null
+ */
+ public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
+ return findAccessor(refc, name, type, MethodHandle.SGET);
+ }
+
+ /**
+ * Produces a method handle giving write access to a static field.
+ * The type of the method handle will have a void return type.
+ * The method handle will take a single
+ * argument, of the field's value type, the value to be stored.
+ * Access checking is performed immediately on behalf of the lookup class.
+ * <p>
+ * If the returned method handle is invoked, the field's class will
+ * be initialized, if it has not already been initialized.
+ * @param refc the class or interface from which the method is accessed
+ * @param name the field's name
+ * @param type the field's type
+ * @return a method handle which can store values into the field
+ * @throws NoSuchFieldException if the field does not exist
+ * @throws IllegalAccessException if access checking fails, or if the field is not {@code static}
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if any argument is null
+ */
+ public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
+ return findAccessor(refc, name, type, MethodHandle.SPUT);
+ }
+
+ // BEGIN Android-changed: OpenJDK 9+181 VarHandle API factory method.
+ /**
+ * Produces a VarHandle giving access to a static field {@code name} of
+ * type {@code type} declared in a class of type {@code decl}.
+ * The VarHandle's variable type is {@code type} and it has no
+ * coordinate types.
+ * <p>
+ * Access checking is performed immediately on behalf of the lookup
+ * class.
+ * <p>
+ * If the returned VarHandle is operated on, the declaring class will be
+ * initialized, if it has not already been initialized.
+ * <p>
+ * Certain access modes of the returned VarHandle are unsupported under
+ * the following conditions:
+ * <ul>
+ * <li>if the field is declared {@code final}, then the write, atomic
+ * update, numeric atomic update, and bitwise atomic update access
+ * modes are unsupported.
+ * <li>if the field type is anything other than {@code byte},
+ * {@code short}, {@code char}, {@code int}, {@code long},
+ * {@code float}, or {@code double}, then numeric atomic update
+ * access modes are unsupported.
+ * <li>if the field type is anything other than {@code boolean},
+ * {@code byte}, {@code short}, {@code char}, {@code int} or
+ * {@code long} then bitwise atomic update access modes are
+ * unsupported.
+ * </ul>
+ * <p>
+ * If the field is declared {@code volatile} then the returned VarHandle
+ * will override access to the field (effectively ignore the
+ * {@code volatile} declaration) in accordance to its specified
+ * access modes.
+ * <p>
+ * If the field type is {@code float} or {@code double} then numeric
+ * and atomic update access modes compare values using their bitwise
+ * representation (see {@link Float#floatToRawIntBits} and
+ * {@link Double#doubleToRawLongBits}, respectively).
+ * @apiNote
+ * Bitwise comparison of {@code float} values or {@code double} values,
+ * as performed by the numeric and atomic update access modes, differ
+ * from the primitive {@code ==} operator and the {@link Float#equals}
+ * and {@link Double#equals} methods, specifically with respect to
+ * comparing NaN values or comparing {@code -0.0} with {@code +0.0}.
+ * Care should be taken when performing a compare and set or a compare
+ * and exchange operation with such values since the operation may
+ * unexpectedly fail.
+ * There are many possible NaN values that are considered to be
+ * {@code NaN} in Java, although no IEEE 754 floating-point operation
+ * provided by Java can distinguish between them. Operation failure can
+ * occur if the expected or witness value is a NaN value and it is
+ * transformed (perhaps in a platform specific manner) into another NaN
+ * value, and thus has a different bitwise representation (see
+ * {@link Float#intBitsToFloat} or {@link Double#longBitsToDouble} for more
+ * details).
+ * The values {@code -0.0} and {@code +0.0} have different bitwise
+ * representations but are considered equal when using the primitive
+ * {@code ==} operator. Operation failure can occur if, for example, a
+ * numeric algorithm computes an expected value to be say {@code -0.0}
+ * and previously computed the witness value to be say {@code +0.0}.
+ * @param decl the class that declares the static field
+ * @param name the field's name
+ * @param type the field's type, of type {@code T}
+ * @return a VarHandle giving access to a static field
+ * @throws NoSuchFieldException if the field does not exist
+ * @throws IllegalAccessException if access checking fails, or if the field is not {@code static}
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if any argument is null
+ * @since 9
+ */
+ public VarHandle findStaticVarHandle(Class<?> decl, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
+ final Field field = findFieldOfType(decl, name, type);
+ final boolean isStatic = true;
+ final boolean performAccessChecks = true;
+ commonFieldChecks(field, decl, type, isStatic, performAccessChecks);
+ return StaticFieldVarHandle.create(field);
+ }
+ // END Android-changed: OpenJDK 9+181 VarHandle API factory method.
+
+ /**
+ * Produces an early-bound method handle for a non-static method.
+ * The receiver must have a supertype {@code defc} in which a method
+ * of the given name and type is accessible to the lookup class.
+ * The method and all its argument types must be accessible to the lookup object.
+ * The type of the method handle will be that of the method,
+ * without any insertion of an additional receiver parameter.
+ * The given receiver will be bound into the method handle,
+ * so that every call to the method handle will invoke the
+ * requested method on the given receiver.
+ * <p>
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the method's variable arity modifier bit ({@code 0x0080}) is set
+ * <em>and</em> the trailing array argument is not the only argument.
+ * (If the trailing array argument is the only argument,
+ * the given receiver value will be bound to it.)
+ * <p>
+ * This is equivalent to the following code:
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle mh0 = lookup().findVirtual(defc, name, type);
+MethodHandle mh1 = mh0.bindTo(receiver);
+MethodType mt1 = mh1.type();
+if (mh0.isVarargsCollector())
+ mh1 = mh1.asVarargsCollector(mt1.parameterType(mt1.parameterCount()-1));
+return mh1;
+ * }</pre></blockquote>
+ * where {@code defc} is either {@code receiver.getClass()} or a super
+ * type of that class, in which the requested method is accessible
+ * to the lookup class.
+ * (Note that {@code bindTo} does not preserve variable arity.)
+ * @param receiver the object from which the method is accessed
+ * @param name the name of the method
+ * @param type the type of the method, with the receiver argument omitted
+ * @return the desired method handle
+ * @throws NoSuchMethodException if the method does not exist
+ * @throws IllegalAccessException if access checking fails
+ * or if the method's variable arity modifier bit
+ * is set and {@code asVarargsCollector} fails
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if any argument is null
+ * @see MethodHandle#bindTo
+ * @see #findVirtual
+ */
+ public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
+ MethodHandle handle = findVirtual(receiver.getClass(), name, type);
+ MethodHandle adapter = handle.bindTo(receiver);
+ MethodType adapterType = adapter.type();
+ if (handle.isVarargsCollector()) {
+ adapter = adapter.asVarargsCollector(
+ adapterType.parameterType(adapterType.parameterCount() - 1));
+ }
+
+ return adapter;
+ }
+
+ /**
+ * Makes a <a href="MethodHandleInfo.html#directmh">direct method handle</a>
+ * to <i>m</i>, if the lookup class has permission.
+ * If <i>m</i> is non-static, the receiver argument is treated as an initial argument.
+ * If <i>m</i> is virtual, overriding is respected on every call.
+ * Unlike the Core Reflection API, exceptions are <em>not</em> wrapped.
+ * The type of the method handle will be that of the method,
+ * with the receiver type prepended (but only if it is non-static).
+ * If the method's {@code accessible} flag is not set,
+ * access checking is performed immediately on behalf of the lookup class.
+ * If <i>m</i> is not public, do not share the resulting handle with untrusted parties.
+ * <p>
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the method's variable arity modifier bit ({@code 0x0080}) is set.
+ * <p>
+ * If <i>m</i> is static, and
+ * if the returned method handle is invoked, the method's class will
+ * be initialized, if it has not already been initialized.
+ * @param m the reflected method
+ * @return a method handle which can invoke the reflected method
+ * @throws IllegalAccessException if access checking fails
+ * or if the method's variable arity modifier bit
+ * is set and {@code asVarargsCollector} fails
+ * @throws NullPointerException if the argument is null
+ */
+ public MethodHandle unreflect(Method m) throws IllegalAccessException {
+ if (m == null) {
+ throw new NullPointerException("m == null");
+ }
+
+ MethodType methodType = MethodType.methodType(m.getReturnType(),
+ m.getParameterTypes());
+
+ // We should only perform access checks if setAccessible hasn't been called yet.
+ if (!m.isAccessible()) {
+ checkAccess(m.getDeclaringClass(), m.getDeclaringClass(), m.getModifiers(),
+ m.getName());
+ }
+
+ if (Modifier.isStatic(m.getModifiers())) {
+ return createMethodHandle(m, MethodHandle.INVOKE_STATIC, methodType);
+ } else {
+ methodType = methodType.insertParameterTypes(0, m.getDeclaringClass());
+ return createMethodHandle(m, MethodHandle.INVOKE_VIRTUAL, methodType);
+ }
+ }
+
+ /**
+ * Produces a method handle for a reflected method.
+ * It will bypass checks for overriding methods on the receiver,
+ * <a href="MethodHandles.Lookup.html#equiv">as if called</a> from an {@code invokespecial}
+ * instruction from within the explicitly specified {@code specialCaller}.
+ * The type of the method handle will be that of the method,
+ * with a suitably restricted receiver type prepended.
+ * (The receiver type will be {@code specialCaller} or a subtype.)
+ * If the method's {@code accessible} flag is not set,
+ * access checking is performed immediately on behalf of the lookup class,
+ * as if {@code invokespecial} instruction were being linked.
+ * <p>
+ * Before method resolution,
+ * if the explicitly specified caller class is not identical with the
+ * lookup class, or if this lookup object does not have
+ * <a href="MethodHandles.Lookup.html#privacc">private access</a>
+ * privileges, the access fails.
+ * <p>
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the method's variable arity modifier bit ({@code 0x0080}) is set.
+ * @param m the reflected method
+ * @param specialCaller the class nominally calling the method
+ * @return a method handle which can invoke the reflected method
+ * @throws IllegalAccessException if access checking fails
+ * or if the method's variable arity modifier bit
+ * is set and {@code asVarargsCollector} fails
+ * @throws NullPointerException if any argument is null
+ */
+ public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException {
+ if (m == null) {
+ throw new NullPointerException("m == null");
+ }
+
+ if (specialCaller == null) {
+ throw new NullPointerException("specialCaller == null");
+ }
+
+ if (!m.isAccessible()) {
+ // Android-changed: Match Java language 9 behavior where unreflectSpecial continues
+ // to require exact caller lookupClass match.
+ checkSpecialCaller(specialCaller, null);
+ }
+
+ final MethodType methodType = MethodType.methodType(m.getReturnType(),
+ m.getParameterTypes());
+ return findSpecial(m, methodType, m.getDeclaringClass() /* refc */, specialCaller);
+ }
+
+ /**
+ * Produces a method handle for a reflected constructor.
+ * The type of the method handle will be that of the constructor,
+ * with the return type changed to the declaring class.
+ * The method handle will perform a {@code newInstance} operation,
+ * creating a new instance of the constructor's class on the
+ * arguments passed to the method handle.
+ * <p>
+ * If the constructor's {@code accessible} flag is not set,
+ * access checking is performed immediately on behalf of the lookup class.
+ * <p>
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the constructor's variable arity modifier bit ({@code 0x0080}) is set.
+ * <p>
+ * If the returned method handle is invoked, the constructor's class will
+ * be initialized, if it has not already been initialized.
+ * @param c the reflected constructor
+ * @return a method handle which can invoke the reflected constructor
+ * @throws IllegalAccessException if access checking fails
+ * or if the method's variable arity modifier bit
+ * is set and {@code asVarargsCollector} fails
+ * @throws NullPointerException if the argument is null
+ */
+ public MethodHandle unreflectConstructor(Constructor<?> c) throws IllegalAccessException {
+ if (c == null) {
+ throw new NullPointerException("c == null");
+ }
+
+ if (!c.isAccessible()) {
+ checkAccess(c.getDeclaringClass(), c.getDeclaringClass(), c.getModifiers(),
+ c.getName());
+ }
+
+ return createMethodHandleForConstructor(c);
+ }
+
+ /**
+ * Produces a method handle giving read access to a reflected field.
+ * The type of the method handle will have a return type of the field's
+ * value type.
+ * If the field is static, the method handle will take no arguments.
+ * Otherwise, its single argument will be the instance containing
+ * the field.
+ * If the field's {@code accessible} flag is not set,
+ * access checking is performed immediately on behalf of the lookup class.
+ * <p>
+ * If the field is static, and
+ * if the returned method handle is invoked, the field's class will
+ * be initialized, if it has not already been initialized.
+ * @param f the reflected field
+ * @return a method handle which can load values from the reflected field
+ * @throws IllegalAccessException if access checking fails
+ * @throws NullPointerException if the argument is null
+ */
+ public MethodHandle unreflectGetter(Field f) throws IllegalAccessException {
+ return findAccessor(f, f.getDeclaringClass(), f.getType(),
+ Modifier.isStatic(f.getModifiers()) ? MethodHandle.SGET : MethodHandle.IGET,
+ !f.isAccessible() /* performAccessChecks */);
+ }
+
+ /**
+ * Produces a method handle giving write access to a reflected field.
+ * The type of the method handle will have a void return type.
+ * If the field is static, the method handle will take a single
+ * argument, of the field's value type, the value to be stored.
+ * Otherwise, the two arguments will be the instance containing
+ * the field, and the value to be stored.
+ * If the field's {@code accessible} flag is not set,
+ * access checking is performed immediately on behalf of the lookup class.
+ * <p>
+ * If the field is static, and
+ * if the returned method handle is invoked, the field's class will
+ * be initialized, if it has not already been initialized.
+ * @param f the reflected field
+ * @return a method handle which can store values into the reflected field
+ * @throws IllegalAccessException if access checking fails
+ * @throws NullPointerException if the argument is null
+ */
+ public MethodHandle unreflectSetter(Field f) throws IllegalAccessException {
+ return findAccessor(f, f.getDeclaringClass(), f.getType(),
+ Modifier.isStatic(f.getModifiers()) ? MethodHandle.SPUT : MethodHandle.IPUT,
+ !f.isAccessible() /* performAccessChecks */);
+ }
+
+ // BEGIN Android-changed: OpenJDK 9+181 VarHandle API factory method.
+ /**
+ * Produces a VarHandle giving access to a reflected field {@code f}
+ * of type {@code T} declared in a class of type {@code R}.
+ * The VarHandle's variable type is {@code T}.
+ * If the field is non-static the VarHandle has one coordinate type,
+ * {@code R}. Otherwise, the field is static, and the VarHandle has no
+ * coordinate types.
+ * <p>
+ * Access checking is performed immediately on behalf of the lookup
+ * class, regardless of the value of the field's {@code accessible}
+ * flag.
+ * <p>
+ * If the field is static, and if the returned VarHandle is operated
+ * on, the field's declaring class will be initialized, if it has not
+ * already been initialized.
+ * <p>
+ * Certain access modes of the returned VarHandle are unsupported under
+ * the following conditions:
+ * <ul>
+ * <li>if the field is declared {@code final}, then the write, atomic
+ * update, numeric atomic update, and bitwise atomic update access
+ * modes are unsupported.
+ * <li>if the field type is anything other than {@code byte},
+ * {@code short}, {@code char}, {@code int}, {@code long},
+ * {@code float}, or {@code double} then numeric atomic update
+ * access modes are unsupported.
+ * <li>if the field type is anything other than {@code boolean},
+ * {@code byte}, {@code short}, {@code char}, {@code int} or
+ * {@code long} then bitwise atomic update access modes are
+ * unsupported.
+ * </ul>
+ * <p>
+ * If the field is declared {@code volatile} then the returned VarHandle
+ * will override access to the field (effectively ignore the
+ * {@code volatile} declaration) in accordance to its specified
+ * access modes.
+ * <p>
+ * If the field type is {@code float} or {@code double} then numeric
+ * and atomic update access modes compare values using their bitwise
+ * representation (see {@link Float#floatToRawIntBits} and
+ * {@link Double#doubleToRawLongBits}, respectively).
+ * @apiNote
+ * Bitwise comparison of {@code float} values or {@code double} values,
+ * as performed by the numeric and atomic update access modes, differ
+ * from the primitive {@code ==} operator and the {@link Float#equals}
+ * and {@link Double#equals} methods, specifically with respect to
+ * comparing NaN values or comparing {@code -0.0} with {@code +0.0}.
+ * Care should be taken when performing a compare and set or a compare
+ * and exchange operation with such values since the operation may
+ * unexpectedly fail.
+ * There are many possible NaN values that are considered to be
+ * {@code NaN} in Java, although no IEEE 754 floating-point operation
+ * provided by Java can distinguish between them. Operation failure can
+ * occur if the expected or witness value is a NaN value and it is
+ * transformed (perhaps in a platform specific manner) into another NaN
+ * value, and thus has a different bitwise representation (see
+ * {@link Float#intBitsToFloat} or {@link Double#longBitsToDouble} for more
+ * details).
+ * The values {@code -0.0} and {@code +0.0} have different bitwise
+ * representations but are considered equal when using the primitive
+ * {@code ==} operator. Operation failure can occur if, for example, a
+ * numeric algorithm computes an expected value to be say {@code -0.0}
+ * and previously computed the witness value to be say {@code +0.0}.
+ * @param f the reflected field, with a field of type {@code T}, and
+ * a declaring class of type {@code R}
+ * @return a VarHandle giving access to non-static fields or a static
+ * field
+ * @throws IllegalAccessException if access checking fails
+ * @throws NullPointerException if the argument is null
+ * @since 9
+ */
+ public VarHandle unreflectVarHandle(Field f) throws IllegalAccessException {
+ final boolean isStatic = Modifier.isStatic(f.getModifiers());
+ final boolean performAccessChecks = true;
+ commonFieldChecks(f, f.getDeclaringClass(), f.getType(), isStatic, performAccessChecks);
+ return isStatic ? StaticFieldVarHandle.create(f) : FieldVarHandle.create(f);
+ }
+ // END Android-changed: OpenJDK 9+181 VarHandle API factory method.
+
+ /**
+ * Cracks a <a href="MethodHandleInfo.html#directmh">direct method handle</a>
+ * created by this lookup object or a similar one.
+ * Security and access checks are performed to ensure that this lookup object
+ * is capable of reproducing the target method handle.
+ * This means that the cracking may fail if target is a direct method handle
+ * but was created by an unrelated lookup object.
+ * This can happen if the method handle is <a href="MethodHandles.Lookup.html#callsens">caller sensitive</a>
+ * and was created by a lookup object for a different class.
+ * @param target a direct method handle to crack into symbolic reference components
+ * @return a symbolic reference which can be used to reconstruct this method handle from this lookup object
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws IllegalArgumentException if the target is not a direct method handle or if access checking fails
+ * @exception NullPointerException if the target is {@code null}
+ * @see MethodHandleInfo
+ * @since 1.8
+ */
+ public MethodHandleInfo revealDirect(MethodHandle target) {
+ MethodHandleImpl directTarget = getMethodHandleImpl(target);
+ MethodHandleInfo info = directTarget.reveal();
+
+ try {
+ checkAccess(lookupClass(), info.getDeclaringClass(), info.getModifiers(),
+ info.getName());
+ } catch (IllegalAccessException exception) {
+ throw new IllegalArgumentException("Unable to access memeber.", exception);
+ }
+
+ return info;
+ }
+
+ private boolean hasPrivateAccess() {
+ return (allowedModes & PRIVATE) != 0;
+ }
+
+ /** Check public/protected/private bits on the symbolic reference class and its member. */
+ void checkAccess(Class<?> refc, Class<?> defc, int mods, String methName)
+ throws IllegalAccessException {
+ int allowedModes = this.allowedModes;
+
+ if (Modifier.isProtected(mods) &&
+ defc == Object.class &&
+ "clone".equals(methName) &&
+ refc.isArray()) {
+ // The JVM does this hack also.
+ // (See ClassVerifier::verify_invoke_instructions
+ // and LinkResolver::check_method_accessability.)
+ // Because the JVM does not allow separate methods on array types,
+ // there is no separate method for int[].clone.
+ // All arrays simply inherit Object.clone.
+ // But for access checking logic, we make Object.clone
+ // (normally protected) appear to be public.
+ // Later on, when the DirectMethodHandle is created,
+ // its leading argument will be restricted to the
+ // requested array type.
+ // N.B. The return type is not adjusted, because
+ // that is *not* the bytecode behavior.
+ mods ^= Modifier.PROTECTED | Modifier.PUBLIC;
+ }
+
+ if (Modifier.isProtected(mods) && Modifier.isConstructor(mods)) {
+ // cannot "new" a protected ctor in a different package
+ mods ^= Modifier.PROTECTED;
+ }
+
+ if (Modifier.isPublic(mods) && Modifier.isPublic(refc.getModifiers()) && allowedModes != 0)
+ return; // common case
+ int requestedModes = fixmods(mods); // adjust 0 => PACKAGE
+ if ((requestedModes & allowedModes) != 0) {
+ if (VerifyAccess.isMemberAccessible(refc, defc, mods, lookupClass(), allowedModes))
+ return;
+ } else {
+ // Protected members can also be checked as if they were package-private.
+ if ((requestedModes & PROTECTED) != 0 && (allowedModes & PACKAGE) != 0
+ && VerifyAccess.isSamePackage(defc, lookupClass()))
+ return;
+ }
+
+ throwMakeAccessException(accessFailedMessage(refc, defc, mods), this);
+ }
+
+ String accessFailedMessage(Class<?> refc, Class<?> defc, int mods) {
+ // check the class first:
+ boolean classOK = (Modifier.isPublic(defc.getModifiers()) &&
+ (defc == refc ||
+ Modifier.isPublic(refc.getModifiers())));
+ if (!classOK && (allowedModes & PACKAGE) != 0) {
+ classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), ALL_MODES) &&
+ (defc == refc ||
+ VerifyAccess.isClassAccessible(refc, lookupClass(), ALL_MODES)));
+ }
+ if (!classOK)
+ return "class is not public";
+ if (Modifier.isPublic(mods))
+ return "access to public member failed"; // (how?)
+ if (Modifier.isPrivate(mods))
+ return "member is private";
+ if (Modifier.isProtected(mods))
+ return "member is protected";
+ return "member is private to package";
+ }
+
+ // Android-changed: checkSpecialCaller assumes that ALLOW_NESTMATE_ACCESS = false,
+ // as in upstream OpenJDK.
+ //
+ // private static final boolean ALLOW_NESTMATE_ACCESS = false;
+
+ // Android-changed: Match java language 9 behavior allowing special access if the reflected
+ // class (called 'refc', the class from which the method is being accessed) is an interface
+ // and is implemented by the caller.
+ private void checkSpecialCaller(Class<?> specialCaller, Class<?> refc) throws IllegalAccessException {
+ // Android-changed: No support for TRUSTED lookups. Also construct the
+ // IllegalAccessException by hand because the upstream code implicitly assumes
+ // that the lookupClass == specialCaller.
+ //
+ // if (allowedModes == TRUSTED) return;
+ boolean isInterfaceLookup = (refc != null &&
+ refc.isInterface() &&
+ refc.isAssignableFrom(specialCaller));
+ if (!hasPrivateAccess() || (specialCaller != lookupClass() && !isInterfaceLookup)) {
+ throw new IllegalAccessException("no private access for invokespecial : "
+ + specialCaller + ", from" + this);
+ }
+ }
+
+ private void throwMakeAccessException(String message, Object from) throws
+ IllegalAccessException{
+ message = message + ": "+ toString();
+ if (from != null) message += ", from " + from;
+ throw new IllegalAccessException(message);
+ }
+
+ private void checkReturnType(Method method, MethodType methodType)
+ throws NoSuchMethodException {
+ if (method.getReturnType() != methodType.rtype()) {
+ throw new NoSuchMethodException(method.getName() + methodType);
+ }
+ }
+ }
+
+ /**
+ * "Cracks" {@code target} to reveal the underlying {@code MethodHandleImpl}.
+ */
+ private static MethodHandleImpl getMethodHandleImpl(MethodHandle target) {
+ // Special case : We implement handles to constructors as transformers,
+ // so we must extract the underlying handle from the transformer.
+ if (target instanceof Transformers.Construct) {
+ target = ((Transformers.Construct) target).getConstructorHandle();
+ }
+
+ // Special case: Var-args methods are also implemented as Transformers,
+ // so we should get the underlying handle in that case as well.
+ if (target instanceof Transformers.VarargsCollector) {
+ target = target.asFixedArity();
+ }
+
+ if (target instanceof MethodHandleImpl) {
+ return (MethodHandleImpl) target;
+ }
+
+ throw new IllegalArgumentException(target + " is not a direct handle");
+ }
+
+ // Android-removed: unsupported @jvms tag in doc-comment.
+ /**
+ * Produces a method handle constructing arrays of a desired type,
+ * as if by the {@code anewarray} bytecode.
+ * The return type of the method handle will be the array type.
+ * The type of its sole argument will be {@code int}, which specifies the size of the array.
+ *
+ * <p> If the returned method handle is invoked with a negative
+ * array size, a {@code NegativeArraySizeException} will be thrown.
+ *
+ * @param arrayClass an array type
+ * @return a method handle which can create arrays of the given type
+ * @throws NullPointerException if the argument is {@code null}
+ * @throws IllegalArgumentException if {@code arrayClass} is not an array type
+ * @see java.lang.reflect.Array#newInstance(Class, int)
+ * @since 9
+ */
+ public static
+ MethodHandle arrayConstructor(Class<?> arrayClass) throws IllegalArgumentException {
+ if (!arrayClass.isArray()) {
+ throw newIllegalArgumentException("not an array class: " + arrayClass.getName());
+ }
+ // Android-changed: transformer based implementation.
+ // MethodHandle ani = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_Array_newInstance).
+ // bindTo(arrayClass.getComponentType());
+ // return ani.asType(ani.type().changeReturnType(arrayClass))
+ return new Transformers.ArrayConstructor(arrayClass);
+ }
+
+ // Android-removed: unsupported @jvms tag in doc-comment.
+ /**
+ * Produces a method handle returning the length of an array,
+ * as if by the {@code arraylength} bytecode.
+ * The type of the method handle will have {@code int} as return type,
+ * and its sole argument will be the array type.
+ *
+ * <p> If the returned method handle is invoked with a {@code null}
+ * array reference, a {@code NullPointerException} will be thrown.
+ *
+ * @param arrayClass an array type
+ * @return a method handle which can retrieve the length of an array of the given array type
+ * @throws NullPointerException if the argument is {@code null}
+ * @throws IllegalArgumentException if arrayClass is not an array type
+ * @since 9
+ */
+ public static
+ MethodHandle arrayLength(Class<?> arrayClass) throws IllegalArgumentException {
+ // Android-changed: transformer based implementation.
+ // return MethodHandleImpl.makeArrayElementAccessor(arrayClass, MethodHandleImpl.ArrayAccess.LENGTH);
+ if (!arrayClass.isArray()) {
+ throw newIllegalArgumentException("not an array class: " + arrayClass.getName());
+ }
+ return new Transformers.ArrayLength(arrayClass);
+ }
+
+ // BEGIN Android-added: method to check if a class is an array.
+ private static void checkClassIsArray(Class<?> c) {
+ if (!c.isArray()) {
+ throw new IllegalArgumentException("Not an array type: " + c);
+ }
+ }
+
+ private static void checkTypeIsViewable(Class<?> componentType) {
+ if (componentType == short.class ||
+ componentType == char.class ||
+ componentType == int.class ||
+ componentType == long.class ||
+ componentType == float.class ||
+ componentType == double.class) {
+ return;
+ }
+ throw new UnsupportedOperationException("Component type not supported: " + componentType);
+ }
+ // END Android-added: method to check if a class is an array.
+
+ /**
+ * Produces a method handle giving read access to elements of an array.
+ * The type of the method handle will have a return type of the array's
+ * element type. Its first argument will be the array type,
+ * and the second will be {@code int}.
+ * @param arrayClass an array type
+ * @return a method handle which can load values from the given array type
+ * @throws NullPointerException if the argument is null
+ * @throws IllegalArgumentException if arrayClass is not an array type
+ */
+ public static
+ MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentException {
+ checkClassIsArray(arrayClass);
+ final Class<?> componentType = arrayClass.getComponentType();
+ if (componentType.isPrimitive()) {
+ try {
+ return Lookup.PUBLIC_LOOKUP.findStatic(MethodHandles.class,
+ "arrayElementGetter",
+ MethodType.methodType(componentType, arrayClass, int.class));
+ } catch (NoSuchMethodException | IllegalAccessException exception) {
+ throw new AssertionError(exception);
+ }
+ }
+
+ return new Transformers.ReferenceArrayElementGetter(arrayClass);
+ }
+
+ /** @hide */ public static byte arrayElementGetter(byte[] array, int i) { return array[i]; }
+ /** @hide */ public static boolean arrayElementGetter(boolean[] array, int i) { return array[i]; }
+ /** @hide */ public static char arrayElementGetter(char[] array, int i) { return array[i]; }
+ /** @hide */ public static short arrayElementGetter(short[] array, int i) { return array[i]; }
+ /** @hide */ public static int arrayElementGetter(int[] array, int i) { return array[i]; }
+ /** @hide */ public static long arrayElementGetter(long[] array, int i) { return array[i]; }
+ /** @hide */ public static float arrayElementGetter(float[] array, int i) { return array[i]; }
+ /** @hide */ public static double arrayElementGetter(double[] array, int i) { return array[i]; }
+
+ /**
+ * Produces a method handle giving write access to elements of an array.
+ * The type of the method handle will have a void return type.
+ * Its last argument will be the array's element type.
+ * The first and second arguments will be the array type and int.
+ * @param arrayClass the class of an array
+ * @return a method handle which can store values into the array type
+ * @throws NullPointerException if the argument is null
+ * @throws IllegalArgumentException if arrayClass is not an array type
+ */
+ public static
+ MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException {
+ checkClassIsArray(arrayClass);
+ final Class<?> componentType = arrayClass.getComponentType();
+ if (componentType.isPrimitive()) {
+ try {
+ return Lookup.PUBLIC_LOOKUP.findStatic(MethodHandles.class,
+ "arrayElementSetter",
+ MethodType.methodType(void.class, arrayClass, int.class, componentType));
+ } catch (NoSuchMethodException | IllegalAccessException exception) {
+ throw new AssertionError(exception);
+ }
+ }
+
+ return new Transformers.ReferenceArrayElementSetter(arrayClass);
+ }
+
+ /** @hide */
+ public static void arrayElementSetter(byte[] array, int i, byte val) { array[i] = val; }
+ /** @hide */
+ public static void arrayElementSetter(boolean[] array, int i, boolean val) { array[i] = val; }
+ /** @hide */
+ public static void arrayElementSetter(char[] array, int i, char val) { array[i] = val; }
+ /** @hide */
+ public static void arrayElementSetter(short[] array, int i, short val) { array[i] = val; }
+ /** @hide */
+ public static void arrayElementSetter(int[] array, int i, int val) { array[i] = val; }
+ /** @hide */
+ public static void arrayElementSetter(long[] array, int i, long val) { array[i] = val; }
+ /** @hide */
+ public static void arrayElementSetter(float[] array, int i, float val) { array[i] = val; }
+ /** @hide */
+ public static void arrayElementSetter(double[] array, int i, double val) { array[i] = val; }
+
+ // BEGIN Android-changed: OpenJDK 9+181 VarHandle API factory methods.
+ /**
+ * Produces a VarHandle giving access to elements of an array of type
+ * {@code arrayClass}. The VarHandle's variable type is the component type
+ * of {@code arrayClass} and the list of coordinate types is
+ * {@code (arrayClass, int)}, where the {@code int} coordinate type
+ * corresponds to an argument that is an index into an array.
+ * <p>
+ * Certain access modes of the returned VarHandle are unsupported under
+ * the following conditions:
+ * <ul>
+ * <li>if the component type is anything other than {@code byte},
+ * {@code short}, {@code char}, {@code int}, {@code long},
+ * {@code float}, or {@code double} then numeric atomic update access
+ * modes are unsupported.
+ * <li>if the field type is anything other than {@code boolean},
+ * {@code byte}, {@code short}, {@code char}, {@code int} or
+ * {@code long} then bitwise atomic update access modes are
+ * unsupported.
+ * </ul>
+ * <p>
+ * If the component type is {@code float} or {@code double} then numeric
+ * and atomic update access modes compare values using their bitwise
+ * representation (see {@link Float#floatToRawIntBits} and
+ * {@link Double#doubleToRawLongBits}, respectively).
+ * @apiNote
+ * Bitwise comparison of {@code float} values or {@code double} values,
+ * as performed by the numeric and atomic update access modes, differ
+ * from the primitive {@code ==} operator and the {@link Float#equals}
+ * and {@link Double#equals} methods, specifically with respect to
+ * comparing NaN values or comparing {@code -0.0} with {@code +0.0}.
+ * Care should be taken when performing a compare and set or a compare
+ * and exchange operation with such values since the operation may
+ * unexpectedly fail.
+ * There are many possible NaN values that are considered to be
+ * {@code NaN} in Java, although no IEEE 754 floating-point operation
+ * provided by Java can distinguish between them. Operation failure can
+ * occur if the expected or witness value is a NaN value and it is
+ * transformed (perhaps in a platform specific manner) into another NaN
+ * value, and thus has a different bitwise representation (see
+ * {@link Float#intBitsToFloat} or {@link Double#longBitsToDouble} for more
+ * details).
+ * The values {@code -0.0} and {@code +0.0} have different bitwise
+ * representations but are considered equal when using the primitive
+ * {@code ==} operator. Operation failure can occur if, for example, a
+ * numeric algorithm computes an expected value to be say {@code -0.0}
+ * and previously computed the witness value to be say {@code +0.0}.
+ * @param arrayClass the class of an array, of type {@code T[]}
+ * @return a VarHandle giving access to elements of an array
+ * @throws NullPointerException if the arrayClass is null
+ * @throws IllegalArgumentException if arrayClass is not an array type
+ * @since 9
+ */
+ public static
+ VarHandle arrayElementVarHandle(Class<?> arrayClass) throws IllegalArgumentException {
+ checkClassIsArray(arrayClass);
+ return ArrayElementVarHandle.create(arrayClass);
+ }
+
+ /**
+ * Produces a VarHandle giving access to elements of a {@code byte[]} array
+ * viewed as if it were a different primitive array type, such as
+ * {@code int[]} or {@code long[]}.
+ * The VarHandle's variable type is the component type of
+ * {@code viewArrayClass} and the list of coordinate types is
+ * {@code (byte[], int)}, where the {@code int} coordinate type
+ * corresponds to an argument that is an index into a {@code byte[]} array.
+ * The returned VarHandle accesses bytes at an index in a {@code byte[]}
+ * array, composing bytes to or from a value of the component type of
+ * {@code viewArrayClass} according to the given endianness.
+ * <p>
+ * The supported component types (variables types) are {@code short},
+ * {@code char}, {@code int}, {@code long}, {@code float} and
+ * {@code double}.
+ * <p>
+ * Access of bytes at a given index will result in an
+ * {@code IndexOutOfBoundsException} if the index is less than {@code 0}
+ * or greater than the {@code byte[]} array length minus the size (in bytes)
+ * of {@code T}.
+ * <p>
+ * Access of bytes at an index may be aligned or misaligned for {@code T},
+ * with respect to the underlying memory address, {@code A} say, associated
+ * with the array and index.
+ * If access is misaligned then access for anything other than the
+ * {@code get} and {@code set} access modes will result in an
+ * {@code IllegalStateException}. In such cases atomic access is only
+ * guaranteed with respect to the largest power of two that divides the GCD
+ * of {@code A} and the size (in bytes) of {@code T}.
+ * If access is aligned then following access modes are supported and are
+ * guaranteed to support atomic access:
+ * <ul>
+ * <li>read write access modes for all {@code T}, with the exception of
+ * access modes {@code get} and {@code set} for {@code long} and
+ * {@code double} on 32-bit platforms.
+ * <li>atomic update access modes for {@code int}, {@code long},
+ * {@code float} or {@code double}.
+ * (Future major platform releases of the JDK may support additional
+ * types for certain currently unsupported access modes.)
+ * <li>numeric atomic update access modes for {@code int} and {@code long}.
+ * (Future major platform releases of the JDK may support additional
+ * numeric types for certain currently unsupported access modes.)
+ * <li>bitwise atomic update access modes for {@code int} and {@code long}.
+ * (Future major platform releases of the JDK may support additional
+ * numeric types for certain currently unsupported access modes.)
+ * </ul>
+ * <p>
+ * Misaligned access, and therefore atomicity guarantees, may be determined
+ * for {@code byte[]} arrays without operating on a specific array. Given
+ * an {@code index}, {@code T} and it's corresponding boxed type,
+ * {@code T_BOX}, misalignment may be determined as follows:
+ * <pre>{@code
+ * int sizeOfT = T_BOX.BYTES; // size in bytes of T
+ * int misalignedAtZeroIndex = ByteBuffer.wrap(new byte[0]).
+ * alignmentOffset(0, sizeOfT);
+ * int misalignedAtIndex = (misalignedAtZeroIndex + index) % sizeOfT;
+ * boolean isMisaligned = misalignedAtIndex != 0;
+ * }</pre>
+ * <p>
+ * If the variable type is {@code float} or {@code double} then atomic
+ * update access modes compare values using their bitwise representation
+ * (see {@link Float#floatToRawIntBits} and
+ * {@link Double#doubleToRawLongBits}, respectively).
+ * @param viewArrayClass the view array class, with a component type of
+ * type {@code T}
+ * @param byteOrder the endianness of the view array elements, as
+ * stored in the underlying {@code byte} array
+ * @return a VarHandle giving access to elements of a {@code byte[]} array
+ * viewed as if elements corresponding to the components type of the view
+ * array class
+ * @throws NullPointerException if viewArrayClass or byteOrder is null
+ * @throws IllegalArgumentException if viewArrayClass is not an array type
+ * @throws UnsupportedOperationException if the component type of
+ * viewArrayClass is not supported as a variable type
+ * @since 9
+ */
+ public static
+ VarHandle byteArrayViewVarHandle(Class<?> viewArrayClass,
+ ByteOrder byteOrder) throws IllegalArgumentException {
+ checkClassIsArray(viewArrayClass);
+ checkTypeIsViewable(viewArrayClass.getComponentType());
+ return ByteArrayViewVarHandle.create(viewArrayClass, byteOrder);
+ }
+
+ /**
+ * Produces a VarHandle giving access to elements of a {@code ByteBuffer}
+ * viewed as if it were an array of elements of a different primitive
+ * component type to that of {@code byte}, such as {@code int[]} or
+ * {@code long[]}.
+ * The VarHandle's variable type is the component type of
+ * {@code viewArrayClass} and the list of coordinate types is
+ * {@code (ByteBuffer, int)}, where the {@code int} coordinate type
+ * corresponds to an argument that is an index into a {@code byte[]} array.
+ * The returned VarHandle accesses bytes at an index in a
+ * {@code ByteBuffer}, composing bytes to or from a value of the component
+ * type of {@code viewArrayClass} according to the given endianness.
+ * <p>
+ * The supported component types (variables types) are {@code short},
+ * {@code char}, {@code int}, {@code long}, {@code float} and
+ * {@code double}.
+ * <p>
+ * Access will result in a {@code ReadOnlyBufferException} for anything
+ * other than the read access modes if the {@code ByteBuffer} is read-only.
+ * <p>
+ * Access of bytes at a given index will result in an
+ * {@code IndexOutOfBoundsException} if the index is less than {@code 0}
+ * or greater than the {@code ByteBuffer} limit minus the size (in bytes) of
+ * {@code T}.
+ * <p>
+ * Access of bytes at an index may be aligned or misaligned for {@code T},
+ * with respect to the underlying memory address, {@code A} say, associated
+ * with the {@code ByteBuffer} and index.
+ * If access is misaligned then access for anything other than the
+ * {@code get} and {@code set} access modes will result in an
+ * {@code IllegalStateException}. In such cases atomic access is only
+ * guaranteed with respect to the largest power of two that divides the GCD
+ * of {@code A} and the size (in bytes) of {@code T}.
+ * If access is aligned then following access modes are supported and are
+ * guaranteed to support atomic access:
+ * <ul>
+ * <li>read write access modes for all {@code T}, with the exception of
+ * access modes {@code get} and {@code set} for {@code long} and
+ * {@code double} on 32-bit platforms.
+ * <li>atomic update access modes for {@code int}, {@code long},
+ * {@code float} or {@code double}.
+ * (Future major platform releases of the JDK may support additional
+ * types for certain currently unsupported access modes.)
+ * <li>numeric atomic update access modes for {@code int} and {@code long}.
+ * (Future major platform releases of the JDK may support additional
+ * numeric types for certain currently unsupported access modes.)
+ * <li>bitwise atomic update access modes for {@code int} and {@code long}.
+ * (Future major platform releases of the JDK may support additional
+ * numeric types for certain currently unsupported access modes.)
+ * </ul>
+ * <p>
+ * Misaligned access, and therefore atomicity guarantees, may be determined
+ * for a {@code ByteBuffer}, {@code bb} (direct or otherwise), an
+ * {@code index}, {@code T} and it's corresponding boxed type,
+ * {@code T_BOX}, as follows:
+ * <pre>{@code
+ * int sizeOfT = T_BOX.BYTES; // size in bytes of T
+ * ByteBuffer bb = ...
+ * int misalignedAtIndex = bb.alignmentOffset(index, sizeOfT);
+ * boolean isMisaligned = misalignedAtIndex != 0;
+ * }</pre>
+ * <p>
+ * If the variable type is {@code float} or {@code double} then atomic
+ * update access modes compare values using their bitwise representation
+ * (see {@link Float#floatToRawIntBits} and
+ * {@link Double#doubleToRawLongBits}, respectively).
+ * @param viewArrayClass the view array class, with a component type of
+ * type {@code T}
+ * @param byteOrder the endianness of the view array elements, as
+ * stored in the underlying {@code ByteBuffer} (Note this overrides the
+ * endianness of a {@code ByteBuffer})
+ * @return a VarHandle giving access to elements of a {@code ByteBuffer}
+ * viewed as if elements corresponding to the components type of the view
+ * array class
+ * @throws NullPointerException if viewArrayClass or byteOrder is null
+ * @throws IllegalArgumentException if viewArrayClass is not an array type
+ * @throws UnsupportedOperationException if the component type of
+ * viewArrayClass is not supported as a variable type
+ * @since 9
+ */
+ public static
+ VarHandle byteBufferViewVarHandle(Class<?> viewArrayClass,
+ ByteOrder byteOrder) throws IllegalArgumentException {
+ checkClassIsArray(viewArrayClass);
+ checkTypeIsViewable(viewArrayClass.getComponentType());
+ return ByteBufferViewVarHandle.create(viewArrayClass, byteOrder);
+ }
+ // END Android-changed: OpenJDK 9+181 VarHandle API factory methods.
+
+ /// method handle invocation (reflective style)
+
+ /**
+ * Produces a method handle which will invoke any method handle of the
+ * given {@code type}, with a given number of trailing arguments replaced by
+ * a single trailing {@code Object[]} array.
+ * The resulting invoker will be a method handle with the following
+ * arguments:
+ * <ul>
+ * <li>a single {@code MethodHandle} target
+ * <li>zero or more leading values (counted by {@code leadingArgCount})
+ * <li>an {@code Object[]} array containing trailing arguments
+ * </ul>
+ * <p>
+ * The invoker will invoke its target like a call to {@link MethodHandle#invoke invoke} with
+ * the indicated {@code type}.
+ * That is, if the target is exactly of the given {@code type}, it will behave
+ * like {@code invokeExact}; otherwise it behave as if {@link MethodHandle#asType asType}
+ * is used to convert the target to the required {@code type}.
+ * <p>
+ * The type of the returned invoker will not be the given {@code type}, but rather
+ * will have all parameters except the first {@code leadingArgCount}
+ * replaced by a single array of type {@code Object[]}, which will be
+ * the final parameter.
+ * <p>
+ * Before invoking its target, the invoker will spread the final array, apply
+ * reference casts as necessary, and unbox and widen primitive arguments.
+ * If, when the invoker is called, the supplied array argument does
+ * not have the correct number of elements, the invoker will throw
+ * an {@link IllegalArgumentException} instead of invoking the target.
+ * <p>
+ * This method is equivalent to the following code (though it may be more efficient):
+ * <blockquote><pre>{@code
+MethodHandle invoker = MethodHandles.invoker(type);
+int spreadArgCount = type.parameterCount() - leadingArgCount;
+invoker = invoker.asSpreader(Object[].class, spreadArgCount);
+return invoker;
+ * }</pre></blockquote>
+ * This method throws no reflective or security exceptions.
+ * @param type the desired target type
+ * @param leadingArgCount number of fixed arguments, to be passed unchanged to the target
+ * @return a method handle suitable for invoking any method handle of the given type
+ * @throws NullPointerException if {@code type} is null
+ * @throws IllegalArgumentException if {@code leadingArgCount} is not in
+ * the range from 0 to {@code type.parameterCount()} inclusive,
+ * or if the resulting method handle's type would have
+ * <a href="MethodHandle.html#maxarity">too many parameters</a>
+ */
+ static public
+ MethodHandle spreadInvoker(MethodType type, int leadingArgCount) {
+ if (leadingArgCount < 0 || leadingArgCount > type.parameterCount())
+ throw newIllegalArgumentException("bad argument count", leadingArgCount);
+
+ MethodHandle invoker = MethodHandles.invoker(type);
+ int spreadArgCount = type.parameterCount() - leadingArgCount;
+ invoker = invoker.asSpreader(Object[].class, spreadArgCount);
+ return invoker;
+ }
+
+ /**
+ * Produces a special <em>invoker method handle</em> which can be used to
+ * invoke any method handle of the given type, as if by {@link MethodHandle#invokeExact invokeExact}.
+ * The resulting invoker will have a type which is
+ * exactly equal to the desired type, except that it will accept
+ * an additional leading argument of type {@code MethodHandle}.
+ * <p>
+ * This method is equivalent to the following code (though it may be more efficient):
+ * {@code publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)}
+ *
+ * <p style="font-size:smaller;">
+ * <em>Discussion:</em>
+ * Invoker method handles can be useful when working with variable method handles
+ * of unknown types.
+ * For example, to emulate an {@code invokeExact} call to a variable method
+ * handle {@code M}, extract its type {@code T},
+ * look up the invoker method {@code X} for {@code T},
+ * and call the invoker method, as {@code X.invoke(T, A...)}.
+ * (It would not work to call {@code X.invokeExact}, since the type {@code T}
+ * is unknown.)
+ * If spreading, collecting, or other argument transformations are required,
+ * they can be applied once to the invoker {@code X} and reused on many {@code M}
+ * method handle values, as long as they are compatible with the type of {@code X}.
+ * <p style="font-size:smaller;">
+ * <em>(Note: The invoker method is not available via the Core Reflection API.
+ * An attempt to call {@linkplain java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}
+ * on the declared {@code invokeExact} or {@code invoke} method will raise an
+ * {@link java.lang.UnsupportedOperationException UnsupportedOperationException}.)</em>
+ * <p>
+ * This method throws no reflective or security exceptions.
+ * @param type the desired target type
+ * @return a method handle suitable for invoking any method handle of the given type
+ * @throws IllegalArgumentException if the resulting method handle's type would have
+ * <a href="MethodHandle.html#maxarity">too many parameters</a>
+ */
+ static public
+ MethodHandle exactInvoker(MethodType type) {
+ return new Transformers.Invoker(type, true /* isExactInvoker */);
+ }
+
+ /**
+ * Produces a special <em>invoker method handle</em> which can be used to
+ * invoke any method handle compatible with the given type, as if by {@link MethodHandle#invoke invoke}.
+ * The resulting invoker will have a type which is
+ * exactly equal to the desired type, except that it will accept
+ * an additional leading argument of type {@code MethodHandle}.
+ * <p>
+ * Before invoking its target, if the target differs from the expected type,
+ * the invoker will apply reference casts as
+ * necessary and box, unbox, or widen primitive values, as if by {@link MethodHandle#asType asType}.
+ * Similarly, the return value will be converted as necessary.
+ * If the target is a {@linkplain MethodHandle#asVarargsCollector variable arity method handle},
+ * the required arity conversion will be made, again as if by {@link MethodHandle#asType asType}.
+ * <p>
+ * This method is equivalent to the following code (though it may be more efficient):
+ * {@code publicLookup().findVirtual(MethodHandle.class, "invoke", type)}
+ * <p style="font-size:smaller;">
+ * <em>Discussion:</em>
+ * A {@linkplain MethodType#genericMethodType general method type} is one which
+ * mentions only {@code Object} arguments and return values.
+ * An invoker for such a type is capable of calling any method handle
+ * of the same arity as the general type.
+ * <p style="font-size:smaller;">
+ * <em>(Note: The invoker method is not available via the Core Reflection API.
+ * An attempt to call {@linkplain java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}
+ * on the declared {@code invokeExact} or {@code invoke} method will raise an
+ * {@link java.lang.UnsupportedOperationException UnsupportedOperationException}.)</em>
+ * <p>
+ * This method throws no reflective or security exceptions.
+ * @param type the desired target type
+ * @return a method handle suitable for invoking any method handle convertible to the given type
+ * @throws IllegalArgumentException if the resulting method handle's type would have
+ * <a href="MethodHandle.html#maxarity">too many parameters</a>
+ */
+ static public
+ MethodHandle invoker(MethodType type) {
+ return new Transformers.Invoker(type, false /* isExactInvoker */);
+ }
+
+ // BEGIN Android-added: resolver for VarHandle accessor methods.
+ static private MethodHandle methodHandleForVarHandleAccessor(VarHandle.AccessMode accessMode,
+ MethodType type,
+ boolean isExactInvoker) {
+ Class<?> refc = VarHandle.class;
+ Method method;
+ try {
+ method = refc.getDeclaredMethod(accessMode.methodName(), Object[].class);
+ } catch (NoSuchMethodException e) {
+ throw new InternalError("No method for AccessMode " + accessMode, e);
+ }
+ MethodType methodType = type.insertParameterTypes(0, VarHandle.class);
+ int kind = isExactInvoker ? MethodHandle.INVOKE_VAR_HANDLE_EXACT
+ : MethodHandle.INVOKE_VAR_HANDLE;
+ return new MethodHandleImpl(method.getArtMethod(), kind, methodType);
+ }
+ // END Android-added: resolver for VarHandle accessor methods.
+
+ /**
+ * Produces a special <em>invoker method handle</em> which can be used to
+ * invoke a signature-polymorphic access mode method on any VarHandle whose
+ * associated access mode type is compatible with the given type.
+ * The resulting invoker will have a type which is exactly equal to the
+ * desired given type, except that it will accept an additional leading
+ * argument of type {@code VarHandle}.
+ *
+ * @param accessMode the VarHandle access mode
+ * @param type the desired target type
+ * @return a method handle suitable for invoking an access mode method of
+ * any VarHandle whose access mode type is of the given type.
+ * @since 9
+ */
+ static public
+ MethodHandle varHandleExactInvoker(VarHandle.AccessMode accessMode, MethodType type) {
+ return methodHandleForVarHandleAccessor(accessMode, type, true /* isExactInvoker */);
+ }
+
+ /**
+ * Produces a special <em>invoker method handle</em> which can be used to
+ * invoke a signature-polymorphic access mode method on any VarHandle whose
+ * associated access mode type is compatible with the given type.
+ * The resulting invoker will have a type which is exactly equal to the
+ * desired given type, except that it will accept an additional leading
+ * argument of type {@code VarHandle}.
+ * <p>
+ * Before invoking its target, if the access mode type differs from the
+ * desired given type, the invoker will apply reference casts as necessary
+ * and box, unbox, or widen primitive values, as if by
+ * {@link MethodHandle#asType asType}. Similarly, the return value will be
+ * converted as necessary.
+ * <p>
+ * This method is equivalent to the following code (though it may be more
+ * efficient): {@code publicLookup().findVirtual(VarHandle.class, accessMode.name(), type)}
+ *
+ * @param accessMode the VarHandle access mode
+ * @param type the desired target type
+ * @return a method handle suitable for invoking an access mode method of
+ * any VarHandle whose access mode type is convertible to the given
+ * type.
+ * @since 9
+ */
+ static public
+ MethodHandle varHandleInvoker(VarHandle.AccessMode accessMode, MethodType type) {
+ return methodHandleForVarHandleAccessor(accessMode, type, false /* isExactInvoker */);
+ }
+
+ // Android-changed: Basic invokers are not supported.
+ //
+ // static /*non-public*/
+ // MethodHandle basicInvoker(MethodType type) {
+ // return type.invokers().basicInvoker();
+ // }
+
+ /// method handle modification (creation from other method handles)
+
+ /**
+ * Produces a method handle which adapts the type of the
+ * given method handle to a new type by pairwise argument and return type conversion.
+ * The original type and new type must have the same number of arguments.
+ * The resulting method handle is guaranteed to report a type
+ * which is equal to the desired new type.
+ * <p>
+ * If the original type and new type are equal, returns target.
+ * <p>
+ * The same conversions are allowed as for {@link MethodHandle#asType MethodHandle.asType},
+ * and some additional conversions are also applied if those conversions fail.
+ * Given types <em>T0</em>, <em>T1</em>, one of the following conversions is applied
+ * if possible, before or instead of any conversions done by {@code asType}:
+ * <ul>
+ * <li>If <em>T0</em> and <em>T1</em> are references, and <em>T1</em> is an interface type,
+ * then the value of type <em>T0</em> is passed as a <em>T1</em> without a cast.
+ * (This treatment of interfaces follows the usage of the bytecode verifier.)
+ * <li>If <em>T0</em> is boolean and <em>T1</em> is another primitive,
+ * the boolean is converted to a byte value, 1 for true, 0 for false.
+ * (This treatment follows the usage of the bytecode verifier.)
+ * <li>If <em>T1</em> is boolean and <em>T0</em> is another primitive,
+ * <em>T0</em> is converted to byte via Java casting conversion (JLS 5.5),
+ * and the low order bit of the result is tested, as if by {@code (x & 1) != 0}.
+ * <li>If <em>T0</em> and <em>T1</em> are primitives other than boolean,
+ * then a Java casting conversion (JLS 5.5) is applied.
+ * (Specifically, <em>T0</em> will convert to <em>T1</em> by
+ * widening and/or narrowing.)
+ * <li>If <em>T0</em> is a reference and <em>T1</em> a primitive, an unboxing
+ * conversion will be applied at runtime, possibly followed
+ * by a Java casting conversion (JLS 5.5) on the primitive value,
+ * possibly followed by a conversion from byte to boolean by testing
+ * the low-order bit.
+ * <li>If <em>T0</em> is a reference and <em>T1</em> a primitive,
+ * and if the reference is null at runtime, a zero value is introduced.
+ * </ul>
+ * @param target the method handle to invoke after arguments are retyped
+ * @param newType the expected type of the new method handle
+ * @return a method handle which delegates to the target after performing
+ * any necessary argument conversions, and arranges for any
+ * necessary return value conversions
+ * @throws NullPointerException if either argument is null
+ * @throws WrongMethodTypeException if the conversion cannot be made
+ * @see MethodHandle#asType
+ */
+ public static
+ MethodHandle explicitCastArguments(MethodHandle target, MethodType newType) {
+ explicitCastArgumentsChecks(target, newType);
+ // use the asTypeCache when possible:
+ MethodType oldType = target.type();
+ if (oldType == newType) return target;
+ if (oldType.explicitCastEquivalentToAsType(newType)) {
+ if (Transformers.Transformer.class.isAssignableFrom(target.getClass())) {
+ // The StackFrameReader and StackFrameWriter used to perform transforms on
+ // EmulatedStackFrames (in Transformers.java) do not how to perform asType()
+ // conversions, but we know here that an explicit cast transform is the same as
+ // having called asType() on the method handle.
+ return new Transformers.ExplicitCastArguments(target.asFixedArity(), newType);
+ } else {
+ // Runtime will perform asType() conversion during invocation.
+ return target.asFixedArity().asType(newType);
+ }
+ }
+ return new Transformers.ExplicitCastArguments(target, newType);
+ }
+
+ private static void explicitCastArgumentsChecks(MethodHandle target, MethodType newType) {
+ if (target.type().parameterCount() != newType.parameterCount()) {
+ throw new WrongMethodTypeException("cannot explicitly cast " + target +
+ " to " + newType);
+ }
+ }
+
+ /**
+ * Produces a method handle which adapts the calling sequence of the
+ * given method handle to a new type, by reordering the arguments.
+ * The resulting method handle is guaranteed to report a type
+ * which is equal to the desired new type.
+ * <p>
+ * The given array controls the reordering.
+ * Call {@code #I} the number of incoming parameters (the value
+ * {@code newType.parameterCount()}, and call {@code #O} the number
+ * of outgoing parameters (the value {@code target.type().parameterCount()}).
+ * Then the length of the reordering array must be {@code #O},
+ * and each element must be a non-negative number less than {@code #I}.
+ * For every {@code N} less than {@code #O}, the {@code N}-th
+ * outgoing argument will be taken from the {@code I}-th incoming
+ * argument, where {@code I} is {@code reorder[N]}.
+ * <p>
+ * No argument or return value conversions are applied.
+ * The type of each incoming argument, as determined by {@code newType},
+ * must be identical to the type of the corresponding outgoing parameter
+ * or parameters in the target method handle.
+ * The return type of {@code newType} must be identical to the return
+ * type of the original target.
+ * <p>
+ * The reordering array need not specify an actual permutation.
+ * An incoming argument will be duplicated if its index appears
+ * more than once in the array, and an incoming argument will be dropped
+ * if its index does not appear in the array.
+ * As in the case of {@link #dropArguments(MethodHandle,int,List) dropArguments},
+ * incoming arguments which are not mentioned in the reordering array
+ * are may be any type, as determined only by {@code newType}.
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodType intfn1 = methodType(int.class, int.class);
+MethodType intfn2 = methodType(int.class, int.class, int.class);
+MethodHandle sub = ... (int x, int y) -> (x-y) ...;
+assert(sub.type().equals(intfn2));
+MethodHandle sub1 = permuteArguments(sub, intfn2, 0, 1);
+MethodHandle rsub = permuteArguments(sub, intfn2, 1, 0);
+assert((int)rsub.invokeExact(1, 100) == 99);
+MethodHandle add = ... (int x, int y) -> (x+y) ...;
+assert(add.type().equals(intfn2));
+MethodHandle twice = permuteArguments(add, intfn1, 0, 0);
+assert(twice.type().equals(intfn1));
+assert((int)twice.invokeExact(21) == 42);
+ * }</pre></blockquote>
+ * @param target the method handle to invoke after arguments are reordered
+ * @param newType the expected type of the new method handle
+ * @param reorder an index array which controls the reordering
+ * @return a method handle which delegates to the target after it
+ * drops unused arguments and moves and/or duplicates the other arguments
+ * @throws NullPointerException if any argument is null
+ * @throws IllegalArgumentException if the index array length is not equal to
+ * the arity of the target, or if any index array element
+ * not a valid index for a parameter of {@code newType},
+ * or if two corresponding parameter types in
+ * {@code target.type()} and {@code newType} are not identical,
+ */
+ public static
+ MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder) {
+ reorder = reorder.clone(); // get a private copy
+ MethodType oldType = target.type();
+ permuteArgumentChecks(reorder, newType, oldType);
+
+ return new Transformers.PermuteArguments(newType, target, reorder);
+ }
+
+ // Android-changed: findFirstDupOrDrop is unused and removed.
+ // private static int findFirstDupOrDrop(int[] reorder, int newArity);
+
+ private static boolean permuteArgumentChecks(int[] reorder, MethodType newType, MethodType oldType) {
+ if (newType.returnType() != oldType.returnType())
+ throw newIllegalArgumentException("return types do not match",
+ oldType, newType);
+ if (reorder.length == oldType.parameterCount()) {
+ int limit = newType.parameterCount();
+ boolean bad = false;
+ for (int j = 0; j < reorder.length; j++) {
+ int i = reorder[j];
+ if (i < 0 || i >= limit) {
+ bad = true; break;
+ }
+ Class<?> src = newType.parameterType(i);
+ Class<?> dst = oldType.parameterType(j);
+ if (src != dst)
+ throw newIllegalArgumentException("parameter types do not match after reorder",
+ oldType, newType);
+ }
+ if (!bad) return true;
+ }
+ throw newIllegalArgumentException("bad reorder array: "+Arrays.toString(reorder));
+ }
+
+ /**
+ * Produces a method handle of the requested return type which returns the given
+ * constant value every time it is invoked.
+ * <p>
+ * Before the method handle is returned, the passed-in value is converted to the requested type.
+ * If the requested type is primitive, widening primitive conversions are attempted,
+ * else reference conversions are attempted.
+ * <p>The returned method handle is equivalent to {@code identity(type).bindTo(value)}.
+ * @param type the return type of the desired method handle
+ * @param value the value to return
+ * @return a method handle of the given return type and no arguments, which always returns the given value
+ * @throws NullPointerException if the {@code type} argument is null
+ * @throws ClassCastException if the value cannot be converted to the required return type
+ * @throws IllegalArgumentException if the given type is {@code void.class}
+ */
+ public static
+ MethodHandle constant(Class<?> type, Object value) {
+ if (type.isPrimitive()) {
+ if (type == void.class)
+ throw newIllegalArgumentException("void type");
+ Wrapper w = Wrapper.forPrimitiveType(type);
+ value = w.convert(value, type);
+ if (w.zero().equals(value))
+ return zero(w, type);
+ return insertArguments(identity(type), 0, value);
+ } else {
+ if (value == null)
+ return zero(Wrapper.OBJECT, type);
+ return identity(type).bindTo(value);
+ }
+ }
+
+ /**
+ * Produces a method handle which returns its sole argument when invoked.
+ * @param type the type of the sole parameter and return value of the desired method handle
+ * @return a unary method handle which accepts and returns the given type
+ * @throws NullPointerException if the argument is null
+ * @throws IllegalArgumentException if the given type is {@code void.class}
+ */
+ public static
+ MethodHandle identity(Class<?> type) {
+ // Android-added: explicit non-null check.
+ Objects.requireNonNull(type);
+ Wrapper btw = (type.isPrimitive() ? Wrapper.forPrimitiveType(type) : Wrapper.OBJECT);
+ int pos = btw.ordinal();
+ MethodHandle ident = IDENTITY_MHS[pos];
+ if (ident == null) {
+ ident = setCachedMethodHandle(IDENTITY_MHS, pos, makeIdentity(btw.primitiveType()));
+ }
+ if (ident.type().returnType() == type)
+ return ident;
+ // something like identity(Foo.class); do not bother to intern these
+ assert (btw == Wrapper.OBJECT);
+ return makeIdentity(type);
+ }
+
+ /**
+ * Produces a constant method handle of the requested return type which
+ * returns the default value for that type every time it is invoked.
+ * The resulting constant method handle will have no side effects.
+ * <p>The returned method handle is equivalent to {@code empty(methodType(type))}.
+ * It is also equivalent to {@code explicitCastArguments(constant(Object.class, null), methodType(type))},
+ * since {@code explicitCastArguments} converts {@code null} to default values.
+ * @param type the expected return type of the desired method handle
+ * @return a constant method handle that takes no arguments
+ * and returns the default value of the given type (or void, if the type is void)
+ * @throws NullPointerException if the argument is null
+ * @see MethodHandles#constant
+ * @see MethodHandles#empty
+ * @see MethodHandles#explicitCastArguments
+ * @since 9
+ */
+ public static MethodHandle zero(Class<?> type) {
+ Objects.requireNonNull(type);
+ return type.isPrimitive() ? zero(Wrapper.forPrimitiveType(type), type) : zero(Wrapper.OBJECT, type);
+ }
+
+ private static MethodHandle identityOrVoid(Class<?> type) {
+ return type == void.class ? zero(type) : identity(type);
+ }
+
+ /**
+ * Produces a method handle of the requested type which ignores any arguments, does nothing,
+ * and returns a suitable default depending on the return type.
+ * That is, it returns a zero primitive value, a {@code null}, or {@code void}.
+ * <p>The returned method handle is equivalent to
+ * {@code dropArguments(zero(type.returnType()), 0, type.parameterList())}.
+ *
+ * @apiNote Given a predicate and target, a useful "if-then" construct can be produced as
+ * {@code guardWithTest(pred, target, empty(target.type())}.
+ * @param type the type of the desired method handle
+ * @return a constant method handle of the given type, which returns a default value of the given return type
+ * @throws NullPointerException if the argument is null
+ * @see MethodHandles#zero
+ * @see MethodHandles#constant
+ * @since 9
+ */
+ public static MethodHandle empty(MethodType type) {
+ Objects.requireNonNull(type);
+ return dropArguments(zero(type.returnType()), 0, type.parameterList());
+ }
+
+ private static final MethodHandle[] IDENTITY_MHS = new MethodHandle[Wrapper.COUNT];
+ private static MethodHandle makeIdentity(Class<?> ptype) {
+ // Android-changed: Android implementation using identity() functions and transformers.
+ // MethodType mtype = methodType(ptype, ptype);
+ // LambdaForm lform = LambdaForm.identityForm(BasicType.basicType(ptype));
+ // return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.IDENTITY);
+ if (ptype.isPrimitive()) {
+ try {
+ final MethodType mt = methodType(ptype, ptype);
+ return Lookup.PUBLIC_LOOKUP.findStatic(MethodHandles.class, "identity", mt);
+ } catch (NoSuchMethodException | IllegalAccessException e) {
+ throw new AssertionError(e);
+ }
+ } else {
+ return new Transformers.ReferenceIdentity(ptype);
+ }
+ }
+
+ // Android-added: helper methods for identity().
+ /** @hide */ public static byte identity(byte val) { return val; }
+ /** @hide */ public static boolean identity(boolean val) { return val; }
+ /** @hide */ public static char identity(char val) { return val; }
+ /** @hide */ public static short identity(short val) { return val; }
+ /** @hide */ public static int identity(int val) { return val; }
+ /** @hide */ public static long identity(long val) { return val; }
+ /** @hide */ public static float identity(float val) { return val; }
+ /** @hide */ public static double identity(double val) { return val; }
+
+ private static MethodHandle zero(Wrapper btw, Class<?> rtype) {
+ int pos = btw.ordinal();
+ MethodHandle zero = ZERO_MHS[pos];
+ if (zero == null) {
+ zero = setCachedMethodHandle(ZERO_MHS, pos, makeZero(btw.primitiveType()));
+ }
+ if (zero.type().returnType() == rtype)
+ return zero;
+ assert(btw == Wrapper.OBJECT);
+ return makeZero(rtype);
+ }
+ private static final MethodHandle[] ZERO_MHS = new MethodHandle[Wrapper.COUNT];
+ private static MethodHandle makeZero(Class<?> rtype) {
+ // Android-changed: use Android specific implementation.
+ // MethodType mtype = methodType(rtype);
+ // LambdaForm lform = LambdaForm.zeroForm(BasicType.basicType(rtype));
+ // return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.ZERO);
+ return new Transformers.ZeroValue(rtype);
+ }
+
+ private static synchronized MethodHandle setCachedMethodHandle(MethodHandle[] cache, int pos, MethodHandle value) {
+ // Simulate a CAS, to avoid racy duplication of results.
+ MethodHandle prev = cache[pos];
+ if (prev != null) return prev;
+ return cache[pos] = value;
+ }
+
+ /**
+ * Provides a target method handle with one or more <em>bound arguments</em>
+ * in advance of the method handle's invocation.
+ * The formal parameters to the target corresponding to the bound
+ * arguments are called <em>bound parameters</em>.
+ * Returns a new method handle which saves away the bound arguments.
+ * When it is invoked, it receives arguments for any non-bound parameters,
+ * binds the saved arguments to their corresponding parameters,
+ * and calls the original target.
+ * <p>
+ * The type of the new method handle will drop the types for the bound
+ * parameters from the original target type, since the new method handle
+ * will no longer require those arguments to be supplied by its callers.
+ * <p>
+ * Each given argument object must match the corresponding bound parameter type.
+ * If a bound parameter type is a primitive, the argument object
+ * must be a wrapper, and will be unboxed to produce the primitive value.
+ * <p>
+ * The {@code pos} argument selects which parameters are to be bound.
+ * It may range between zero and <i>N-L</i> (inclusively),
+ * where <i>N</i> is the arity of the target method handle
+ * and <i>L</i> is the length of the values array.
+ * @param target the method handle to invoke after the argument is inserted
+ * @param pos where to insert the argument (zero for the first)
+ * @param values the series of arguments to insert
+ * @return a method handle which inserts an additional argument,
+ * before calling the original method handle
+ * @throws NullPointerException if the target or the {@code values} array is null
+ * @see MethodHandle#bindTo
+ */
+ public static
+ MethodHandle insertArguments(MethodHandle target, int pos, Object... values) {
+ int insCount = values.length;
+ Class<?>[] ptypes = insertArgumentsChecks(target, insCount, pos);
+ if (insCount == 0) {
+ return target;
+ }
+
+ // Throw ClassCastExceptions early if we can't cast any of the provided values
+ // to the required type.
+ for (int i = 0; i < insCount; i++) {
+ final Class<?> ptype = ptypes[pos + i];
+ if (!ptype.isPrimitive()) {
+ ptypes[pos + i].cast(values[i]);
+ } else {
+ // Will throw a ClassCastException if something terrible happens.
+ values[i] = Wrapper.forPrimitiveType(ptype).convert(values[i], ptype);
+ }
+ }
+
+ return new Transformers.InsertArguments(target, pos, values);
+ }
+
+ // Android-changed: insertArgumentPrimitive is unused.
+ //
+ // private static BoundMethodHandle insertArgumentPrimitive(BoundMethodHandle result, int pos,
+ // Class<?> ptype, Object value) {
+ // Wrapper w = Wrapper.forPrimitiveType(ptype);
+ // // perform unboxing and/or primitive conversion
+ // value = w.convert(value, ptype);
+ // switch (w) {
+ // case INT: return result.bindArgumentI(pos, (int)value);
+ // case LONG: return result.bindArgumentJ(pos, (long)value);
+ // case FLOAT: return result.bindArgumentF(pos, (float)value);
+ // case DOUBLE: return result.bindArgumentD(pos, (double)value);
+ // default: return result.bindArgumentI(pos, ValueConversions.widenSubword(value));
+ // }
+ // }
+
+ private static Class<?>[] insertArgumentsChecks(MethodHandle target, int insCount, int pos) throws RuntimeException {
+ MethodType oldType = target.type();
+ int outargs = oldType.parameterCount();
+ int inargs = outargs - insCount;
+ if (inargs < 0)
+ throw newIllegalArgumentException("too many values to insert");
+ if (pos < 0 || pos > inargs)
+ throw newIllegalArgumentException("no argument type to append");
+ return oldType.ptypes();
+ }
+
+ // Android-changed: inclusive language preference for 'placeholder'.
+ /**
+ * Produces a method handle which will discard some placeholder arguments
+ * before calling some other specified <i>target</i> method handle.
+ * The type of the new method handle will be the same as the target's type,
+ * except it will also include the placeholder argument types,
+ * at some given position.
+ * <p>
+ * The {@code pos} argument may range between zero and <i>N</i>,
+ * where <i>N</i> is the arity of the target.
+ * If {@code pos} is zero, the placeholder arguments will precede
+ * the target's real arguments; if {@code pos} is <i>N</i>
+ * they will come after.
+ * <p>
+ * <b>Example:</b>
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle cat = lookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+assertEquals("xy", (String) cat.invokeExact("x", "y"));
+MethodType bigType = cat.type().insertParameterTypes(0, int.class, String.class);
+MethodHandle d0 = dropArguments(cat, 0, bigType.parameterList().subList(0,2));
+assertEquals(bigType, d0.type());
+assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
+ * }</pre></blockquote>
+ * <p>
+ * This method is also equivalent to the following code:
+ * <blockquote><pre>
+ * {@link #dropArguments(MethodHandle,int,Class...) dropArguments}{@code (target, pos, valueTypes.toArray(new Class[0]))}
+ * </pre></blockquote>
+ * @param target the method handle to invoke after the arguments are dropped
+ * @param valueTypes the type(s) of the argument(s) to drop
+ * @param pos position of first argument to drop (zero for the leftmost)
+ * @return a method handle which drops arguments of the given types,
+ * before calling the original method handle
+ * @throws NullPointerException if the target is null,
+ * or if the {@code valueTypes} list or any of its elements is null
+ * @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class},
+ * or if {@code pos} is negative or greater than the arity of the target,
+ * or if the new method handle's type would have too many parameters
+ */
+ public static
+ MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes) {
+ return dropArguments0(target, pos, copyTypes(valueTypes.toArray()));
+ }
+
+ private static List<Class<?>> copyTypes(Object[] array) {
+ return Arrays.asList(Arrays.copyOf(array, array.length, Class[].class));
+ }
+
+ private static
+ MethodHandle dropArguments0(MethodHandle target, int pos, List<Class<?>> valueTypes) {
+ MethodType oldType = target.type(); // get NPE
+ int dropped = dropArgumentChecks(oldType, pos, valueTypes);
+ MethodType newType = oldType.insertParameterTypes(pos, valueTypes);
+ if (dropped == 0) return target;
+ // Android-changed: transformer implementation.
+ // BoundMethodHandle result = target.rebind();
+ // LambdaForm lform = result.form;
+ // int insertFormArg = 1 + pos;
+ // for (Class<?> ptype : valueTypes) {
+ // lform = lform.editor().addArgumentForm(insertFormArg++, BasicType.basicType(ptype));
+ // }
+ // result = result.copyWith(newType, lform);
+ // return result;
+ return new Transformers.DropArguments(newType, target, pos, dropped);
+ }
+
+ private static int dropArgumentChecks(MethodType oldType, int pos, List<Class<?>> valueTypes) {
+ int dropped = valueTypes.size();
+ MethodType.checkSlotCount(dropped);
+ int outargs = oldType.parameterCount();
+ int inargs = outargs + dropped;
+ if (pos < 0 || pos > outargs)
+ throw newIllegalArgumentException("no argument type to remove"
+ + Arrays.asList(oldType, pos, valueTypes, inargs, outargs)
+ );
+ return dropped;
+ }
+
+ // Android-changed: inclusive language preference for 'placeholder'.
+ /**
+ * Produces a method handle which will discard some placeholder arguments
+ * before calling some other specified <i>target</i> method handle.
+ * The type of the new method handle will be the same as the target's type,
+ * except it will also include the placeholder argument types,
+ * at some given position.
+ * <p>
+ * The {@code pos} argument may range between zero and <i>N</i>,
+ * where <i>N</i> is the arity of the target.
+ * If {@code pos} is zero, the placeholder arguments will precede
+ * the target's real arguments; if {@code pos} is <i>N</i>
+ * they will come after.
+ * @apiNote
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle cat = lookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+assertEquals("xy", (String) cat.invokeExact("x", "y"));
+MethodHandle d0 = dropArguments(cat, 0, String.class);
+assertEquals("yz", (String) d0.invokeExact("x", "y", "z"));
+MethodHandle d1 = dropArguments(cat, 1, String.class);
+assertEquals("xz", (String) d1.invokeExact("x", "y", "z"));
+MethodHandle d2 = dropArguments(cat, 2, String.class);
+assertEquals("xy", (String) d2.invokeExact("x", "y", "z"));
+MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
+assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
+ * }</pre></blockquote>
+ * <p>
+ * This method is also equivalent to the following code:
+ * <blockquote><pre>
+ * {@link #dropArguments(MethodHandle,int,List) dropArguments}{@code (target, pos, Arrays.asList(valueTypes))}
+ * </pre></blockquote>
+ * @param target the method handle to invoke after the arguments are dropped
+ * @param valueTypes the type(s) of the argument(s) to drop
+ * @param pos position of first argument to drop (zero for the leftmost)
+ * @return a method handle which drops arguments of the given types,
+ * before calling the original method handle
+ * @throws NullPointerException if the target is null,
+ * or if the {@code valueTypes} array or any of its elements is null
+ * @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class},
+ * or if {@code pos} is negative or greater than the arity of the target,
+ * or if the new method handle's type would have
+ * <a href="MethodHandle.html#maxarity">too many parameters</a>
+ */
+ public static
+ MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes) {
+ return dropArguments0(target, pos, copyTypes(valueTypes));
+ }
+
+ // private version which allows caller some freedom with error handling
+ private static MethodHandle dropArgumentsToMatch(MethodHandle target, int skip, List<Class<?>> newTypes, int pos,
+ boolean nullOnFailure) {
+ newTypes = copyTypes(newTypes.toArray());
+ List<Class<?>> oldTypes = target.type().parameterList();
+ int match = oldTypes.size();
+ if (skip != 0) {
+ if (skip < 0 || skip > match) {
+ throw newIllegalArgumentException("illegal skip", skip, target);
+ }
+ oldTypes = oldTypes.subList(skip, match);
+ match -= skip;
+ }
+ List<Class<?>> addTypes = newTypes;
+ int add = addTypes.size();
+ if (pos != 0) {
+ if (pos < 0 || pos > add) {
+ throw newIllegalArgumentException("illegal pos", pos, newTypes);
+ }
+ addTypes = addTypes.subList(pos, add);
+ add -= pos;
+ assert(addTypes.size() == add);
+ }
+ // Do not add types which already match the existing arguments.
+ if (match > add || !oldTypes.equals(addTypes.subList(0, match))) {
+ if (nullOnFailure) {
+ return null;
+ }
+ throw newIllegalArgumentException("argument lists do not match", oldTypes, newTypes);
+ }
+ addTypes = addTypes.subList(match, add);
+ add -= match;
+ assert(addTypes.size() == add);
+ // newTypes: ( P*[pos], M*[match], A*[add] )
+ // target: ( S*[skip], M*[match] )
+ MethodHandle adapter = target;
+ if (add > 0) {
+ adapter = dropArguments0(adapter, skip+ match, addTypes);
+ }
+ // adapter: (S*[skip], M*[match], A*[add] )
+ if (pos > 0) {
+ adapter = dropArguments0(adapter, skip, newTypes.subList(0, pos));
+ }
+ // adapter: (S*[skip], P*[pos], M*[match], A*[add] )
+ return adapter;
+ }
+
+ // Android-changed: inclusive language preference for 'placeholder'.
+ /**
+ * Adapts a target method handle to match the given parameter type list. If necessary, adds placeholder arguments. Some
+ * leading parameters can be skipped before matching begins. The remaining types in the {@code target}'s parameter
+ * type list must be a sub-list of the {@code newTypes} type list at the starting position {@code pos}. The
+ * resulting handle will have the target handle's parameter type list, with any non-matching parameter types (before
+ * or after the matching sub-list) inserted in corresponding positions of the target's original parameters, as if by
+ * {@link #dropArguments(MethodHandle, int, Class[])}.
+ * <p>
+ * The resulting handle will have the same return type as the target handle.
+ * <p>
+ * In more formal terms, assume these two type lists:<ul>
+ * <li>The target handle has the parameter type list {@code S..., M...}, with as many types in {@code S} as
+ * indicated by {@code skip}. The {@code M} types are those that are supposed to match part of the given type list,
+ * {@code newTypes}.
+ * <li>The {@code newTypes} list contains types {@code P..., M..., A...}, with as many types in {@code P} as
+ * indicated by {@code pos}. The {@code M} types are precisely those that the {@code M} types in the target handle's
+ * parameter type list are supposed to match. The types in {@code A} are additional types found after the matching
+ * sub-list.
+ * </ul>
+ * Given these assumptions, the result of an invocation of {@code dropArgumentsToMatch} will have the parameter type
+ * list {@code S..., P..., M..., A...}, with the {@code P} and {@code A} types inserted as if by
+ * {@link #dropArguments(MethodHandle, int, Class[])}.
+ *
+ * @apiNote
+ * Two method handles whose argument lists are "effectively identical" (i.e., identical in a common prefix) may be
+ * mutually converted to a common type by two calls to {@code dropArgumentsToMatch}, as follows:
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+...
+MethodHandle h0 = constant(boolean.class, true);
+MethodHandle h1 = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class));
+MethodType bigType = h1.type().insertParameterTypes(1, String.class, int.class);
+MethodHandle h2 = dropArguments(h1, 0, bigType.parameterList());
+if (h1.type().parameterCount() < h2.type().parameterCount())
+ h1 = dropArgumentsToMatch(h1, 0, h2.type().parameterList(), 0); // lengthen h1
+else
+ h2 = dropArgumentsToMatch(h2, 0, h1.type().parameterList(), 0); // lengthen h2
+MethodHandle h3 = guardWithTest(h0, h1, h2);
+assertEquals("xy", h3.invoke("x", "y", 1, "a", "b", "c"));
+ * }</pre></blockquote>
+ * @param target the method handle to adapt
+ * @param skip number of targets parameters to disregard (they will be unchanged)
+ * @param newTypes the list of types to match {@code target}'s parameter type list to
+ * @param pos place in {@code newTypes} where the non-skipped target parameters must occur
+ * @return a possibly adapted method handle
+ * @throws NullPointerException if either argument is null
+ * @throws IllegalArgumentException if any element of {@code newTypes} is {@code void.class},
+ * or if {@code skip} is negative or greater than the arity of the target,
+ * or if {@code pos} is negative or greater than the newTypes list size,
+ * or if {@code newTypes} does not contain the {@code target}'s non-skipped parameter types at position
+ * {@code pos}.
+ * @since 9
+ */
+ public static
+ MethodHandle dropArgumentsToMatch(MethodHandle target, int skip, List<Class<?>> newTypes, int pos) {
+ Objects.requireNonNull(target);
+ Objects.requireNonNull(newTypes);
+ return dropArgumentsToMatch(target, skip, newTypes, pos, false);
+ }
+
+ /**
+ * Drop the return value of the target handle (if any).
+ * The returned method handle will have a {@code void} return type.
+ *
+ * @param target the method handle to adapt
+ * @return a possibly adapted method handle
+ * @throws NullPointerException if {@code target} is null
+ * @since 16
+ */
+ public static MethodHandle dropReturn(MethodHandle target) {
+ Objects.requireNonNull(target);
+ MethodType oldType = target.type();
+ Class<?> oldReturnType = oldType.returnType();
+ if (oldReturnType == void.class)
+ return target;
+
+ MethodType newType = oldType.changeReturnType(void.class);
+ // Android-changed: no support for BoundMethodHandle or LambdaForm.
+ // BoundMethodHandle result = target.rebind();
+ // LambdaForm lform = result.editor().filterReturnForm(V_TYPE, true);
+ // result = result.copyWith(newType, lform);
+ // return result;
+ return target.asType(newType);
+ }
+
+ /**
+ * Adapts a target method handle by pre-processing
+ * one or more of its arguments, each with its own unary filter function,
+ * and then calling the target with each pre-processed argument
+ * replaced by the result of its corresponding filter function.
+ * <p>
+ * The pre-processing is performed by one or more method handles,
+ * specified in the elements of the {@code filters} array.
+ * The first element of the filter array corresponds to the {@code pos}
+ * argument of the target, and so on in sequence.
+ * The filter functions are invoked in left to right order.
+ * <p>
+ * Null arguments in the array are treated as identity functions,
+ * and the corresponding arguments left unchanged.
+ * (If there are no non-null elements in the array, the original target is returned.)
+ * Each filter is applied to the corresponding argument of the adapter.
+ * <p>
+ * If a filter {@code F} applies to the {@code N}th argument of
+ * the target, then {@code F} must be a method handle which
+ * takes exactly one argument. The type of {@code F}'s sole argument
+ * replaces the corresponding argument type of the target
+ * in the resulting adapted method handle.
+ * The return type of {@code F} must be identical to the corresponding
+ * parameter type of the target.
+ * <p>
+ * It is an error if there are elements of {@code filters}
+ * (null or not)
+ * which do not correspond to argument positions in the target.
+ * <p><b>Example:</b>
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle cat = lookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+MethodHandle upcase = lookup().findVirtual(String.class,
+ "toUpperCase", methodType(String.class));
+assertEquals("xy", (String) cat.invokeExact("x", "y"));
+MethodHandle f0 = filterArguments(cat, 0, upcase);
+assertEquals("Xy", (String) f0.invokeExact("x", "y")); // Xy
+MethodHandle f1 = filterArguments(cat, 1, upcase);
+assertEquals("xY", (String) f1.invokeExact("x", "y")); // xY
+MethodHandle f2 = filterArguments(cat, 0, upcase, upcase);
+assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
+ * }</pre></blockquote>
+ * <p>Here is pseudocode for the resulting adapter. In the code, {@code T}
+ * denotes the return type of both the {@code target} and resulting adapter.
+ * {@code P}/{@code p} and {@code B}/{@code b} represent the types and values
+ * of the parameters and arguments that precede and follow the filter position
+ * {@code pos}, respectively. {@code A[i]}/{@code a[i]} stand for the types and
+ * values of the filtered parameters and arguments; they also represent the
+ * return types of the {@code filter[i]} handles. The latter accept arguments
+ * {@code v[i]} of type {@code V[i]}, which also appear in the signature of
+ * the resulting adapter.
+ * <blockquote><pre>{@code
+ * T target(P... p, A[i]... a[i], B... b);
+ * A[i] filter[i](V[i]);
+ * T adapter(P... p, V[i]... v[i], B... b) {
+ * return target(p..., filter[i](v[i])..., b...);
+ * }
+ * }</pre></blockquote>
+ * <p>
+ * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+ * variable-arity method handle}, even if the original target method handle was.
+ *
+ * @param target the method handle to invoke after arguments are filtered
+ * @param pos the position of the first argument to filter
+ * @param filters method handles to call initially on filtered arguments
+ * @return method handle which incorporates the specified argument filtering logic
+ * @throws NullPointerException if the target is null
+ * or if the {@code filters} array is null
+ * @throws IllegalArgumentException if a non-null element of {@code filters}
+ * does not match a corresponding argument type of target as described above,
+ * or if the {@code pos+filters.length} is greater than {@code target.type().parameterCount()},
+ * or if the resulting method handle's type would have
+ * <a href="MethodHandle.html#maxarity">too many parameters</a>
+ */
+ public static
+ MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) {
+ filterArgumentsCheckArity(target, pos, filters);
+ MethodHandle adapter = target;
+ // Android-changed: transformer implementation.
+ // process filters in reverse order so that the invocation of
+ // the resulting adapter will invoke the filters in left-to-right order
+ // for (int i = filters.length - 1; i >= 0; --i) {
+ // MethodHandle filter = filters[i];
+ // if (filter == null) continue; // ignore null elements of filters
+ // adapter = filterArgument(adapter, pos + i, filter);
+ // }
+ // return adapter;
+ boolean hasNonNullFilter = false;
+ for (int i = 0; i < filters.length; ++i) {
+ MethodHandle filter = filters[i];
+ if (filter != null) {
+ hasNonNullFilter = true;
+ filterArgumentChecks(target, i + pos, filter);
+ }
+ }
+ if (!hasNonNullFilter) {
+ return target;
+ }
+ return new Transformers.FilterArguments(target, pos, filters);
+ }
+
+ /*non-public*/ static
+ MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) {
+ filterArgumentChecks(target, pos, filter);
+ // Android-changed: use Transformer implementation.
+ // MethodType targetType = target.type();
+ // MethodType filterType = filter.type();
+ // BoundMethodHandle result = target.rebind();
+ // Class<?> newParamType = filterType.parameterType(0);
+ // LambdaForm lform = result.editor().filterArgumentForm(1 + pos, BasicType.basicType(newParamType));
+ // MethodType newType = targetType.changeParameterType(pos, newParamType);
+ // result = result.copyWithExtendL(newType, lform, filter);
+ // return result;
+ return new Transformers.FilterArguments(target, pos, filter);
+ }
+
+ private static void filterArgumentsCheckArity(MethodHandle target, int pos, MethodHandle[] filters) {
+ MethodType targetType = target.type();
+ int maxPos = targetType.parameterCount();
+ if (pos + filters.length > maxPos)
+ throw newIllegalArgumentException("too many filters");
+ }
+
+ private static void filterArgumentChecks(MethodHandle target, int pos, MethodHandle filter) throws RuntimeException {
+ MethodType targetType = target.type();
+ MethodType filterType = filter.type();
+ if (filterType.parameterCount() != 1
+ || filterType.returnType() != targetType.parameterType(pos))
+ throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
+ }
+
+ /**
+ * Adapts a target method handle by pre-processing
+ * a sub-sequence of its arguments with a filter (another method handle).
+ * The pre-processed arguments are replaced by the result (if any) of the
+ * filter function.
+ * The target is then called on the modified (usually shortened) argument list.
+ * <p>
+ * If the filter returns a value, the target must accept that value as
+ * its argument in position {@code pos}, preceded and/or followed by
+ * any arguments not passed to the filter.
+ * If the filter returns void, the target must accept all arguments
+ * not passed to the filter.
+ * No arguments are reordered, and a result returned from the filter
+ * replaces (in order) the whole subsequence of arguments originally
+ * passed to the adapter.
+ * <p>
+ * The argument types (if any) of the filter
+ * replace zero or one argument types of the target, at position {@code pos},
+ * in the resulting adapted method handle.
+ * The return type of the filter (if any) must be identical to the
+ * argument type of the target at position {@code pos}, and that target argument
+ * is supplied by the return value of the filter.
+ * <p>
+ * In all cases, {@code pos} must be greater than or equal to zero, and
+ * {@code pos} must also be less than or equal to the target's arity.
+ * <p><b>Example:</b>
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle deepToString = publicLookup()
+ .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
+
+MethodHandle ts1 = deepToString.asCollector(String[].class, 1);
+assertEquals("[strange]", (String) ts1.invokeExact("strange"));
+
+MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
+assertEquals("[up, down]", (String) ts2.invokeExact("up", "down"));
+
+MethodHandle ts3 = deepToString.asCollector(String[].class, 3);
+MethodHandle ts3_ts2 = collectArguments(ts3, 1, ts2);
+assertEquals("[top, [up, down], strange]",
+ (String) ts3_ts2.invokeExact("top", "up", "down", "strange"));
+
+MethodHandle ts3_ts2_ts1 = collectArguments(ts3_ts2, 3, ts1);
+assertEquals("[top, [up, down], [strange]]",
+ (String) ts3_ts2_ts1.invokeExact("top", "up", "down", "strange"));
+
+MethodHandle ts3_ts2_ts3 = collectArguments(ts3_ts2, 1, ts3);
+assertEquals("[top, [[up, down, strange], charm], bottom]",
+ (String) ts3_ts2_ts3.invokeExact("top", "up", "down", "strange", "charm", "bottom"));
+ * }</pre></blockquote>
+ * <p> Here is pseudocode for the resulting adapter:
+ * <blockquote><pre>{@code
+ * T target(A...,V,C...);
+ * V filter(B...);
+ * T adapter(A... a,B... b,C... c) {
+ * V v = filter(b...);
+ * return target(a...,v,c...);
+ * }
+ * // and if the filter has no arguments:
+ * T target2(A...,V,C...);
+ * V filter2();
+ * T adapter2(A... a,C... c) {
+ * V v = filter2();
+ * return target2(a...,v,c...);
+ * }
+ * // and if the filter has a void return:
+ * T target3(A...,C...);
+ * void filter3(B...);
+ * void adapter3(A... a,B... b,C... c) {
+ * filter3(b...);
+ * return target3(a...,c...);
+ * }
+ * }</pre></blockquote>
+ * <p>
+ * A collection adapter {@code collectArguments(mh, 0, coll)} is equivalent to
+ * one which first "folds" the affected arguments, and then drops them, in separate
+ * steps as follows:
+ * <blockquote><pre>{@code
+ * mh = MethodHandles.dropArguments(mh, 1, coll.type().parameterList()); //step 2
+ * mh = MethodHandles.foldArguments(mh, coll); //step 1
+ * }</pre></blockquote>
+ * If the target method handle consumes no arguments besides than the result
+ * (if any) of the filter {@code coll}, then {@code collectArguments(mh, 0, coll)}
+ * is equivalent to {@code filterReturnValue(coll, mh)}.
+ * If the filter method handle {@code coll} consumes one argument and produces
+ * a non-void result, then {@code collectArguments(mh, N, coll)}
+ * is equivalent to {@code filterArguments(mh, N, coll)}.
+ * Other equivalences are possible but would require argument permutation.
+ *
+ * @param target the method handle to invoke after filtering the subsequence of arguments
+ * @param pos the position of the first adapter argument to pass to the filter,
+ * and/or the target argument which receives the result of the filter
+ * @param filter method handle to call on the subsequence of arguments
+ * @return method handle which incorporates the specified argument subsequence filtering logic
+ * @throws NullPointerException if either argument is null
+ * @throws IllegalArgumentException if the return type of {@code filter}
+ * is non-void and is not the same as the {@code pos} argument of the target,
+ * or if {@code pos} is not between 0 and the target's arity, inclusive,
+ * or if the resulting method handle's type would have
+ * <a href="MethodHandle.html#maxarity">too many parameters</a>
+ * @see MethodHandles#foldArguments
+ * @see MethodHandles#filterArguments
+ * @see MethodHandles#filterReturnValue
+ */
+ public static
+ MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter) {
+ MethodType newType = collectArgumentsChecks(target, pos, filter);
+ return new Transformers.CollectArguments(target, filter, pos, newType);
+ }
+
+ private static MethodType collectArgumentsChecks(MethodHandle target, int pos, MethodHandle filter) throws RuntimeException {
+ MethodType targetType = target.type();
+ MethodType filterType = filter.type();
+ Class<?> rtype = filterType.returnType();
+ List<Class<?>> filterArgs = filterType.parameterList();
+ if (rtype == void.class) {
+ return targetType.insertParameterTypes(pos, filterArgs);
+ }
+ if (rtype != targetType.parameterType(pos)) {
+ throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
+ }
+ return targetType.dropParameterTypes(pos, pos+1).insertParameterTypes(pos, filterArgs);
+ }
+
+ /**
+ * Adapts a target method handle by post-processing
+ * its return value (if any) with a filter (another method handle).
+ * The result of the filter is returned from the adapter.
+ * <p>
+ * If the target returns a value, the filter must accept that value as
+ * its only argument.
+ * If the target returns void, the filter must accept no arguments.
+ * <p>
+ * The return type of the filter
+ * replaces the return type of the target
+ * in the resulting adapted method handle.
+ * The argument type of the filter (if any) must be identical to the
+ * return type of the target.
+ * <p><b>Example:</b>
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle cat = lookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+MethodHandle length = lookup().findVirtual(String.class,
+ "length", methodType(int.class));
+System.out.println((String) cat.invokeExact("x", "y")); // xy
+MethodHandle f0 = filterReturnValue(cat, length);
+System.out.println((int) f0.invokeExact("x", "y")); // 2
+ * }</pre></blockquote>
+ * <p>Here is pseudocode for the resulting adapter. In the code,
+ * {@code T}/{@code t} represent the result type and value of the
+ * {@code target}; {@code V}, the result type of the {@code filter}; and
+ * {@code A}/{@code a}, the types and values of the parameters and arguments
+ * of the {@code target} as well as the resulting adapter.
+ * <blockquote><pre>{@code
+ * T target(A...);
+ * V filter(T);
+ * V adapter(A... a) {
+ * T t = target(a...);
+ * return filter(t);
+ * }
+ * // and if the target has a void return:
+ * void target2(A...);
+ * V filter2();
+ * V adapter2(A... a) {
+ * target2(a...);
+ * return filter2();
+ * }
+ * // and if the filter has a void return:
+ * T target3(A...);
+ * void filter3(V);
+ * void adapter3(A... a) {
+ * T t = target3(a...);
+ * filter3(t);
+ * }
+ * }</pre></blockquote>
+ * <p>
+ * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+ * variable-arity method handle}, even if the original target method handle was.
+ * @param target the method handle to invoke before filtering the return value
+ * @param filter method handle to call on the return value
+ * @return method handle which incorporates the specified return value filtering logic
+ * @throws NullPointerException if either argument is null
+ * @throws IllegalArgumentException if the argument list of {@code filter}
+ * does not match the return type of target as described above
+ */
+ public static
+ MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) {
+ MethodType targetType = target.type();
+ MethodType filterType = filter.type();
+ filterReturnValueChecks(targetType, filterType);
+ // Android-changed: use a transformer.
+ // BoundMethodHandle result = target.rebind();
+ // BasicType rtype = BasicType.basicType(filterType.returnType());
+ // LambdaForm lform = result.editor().filterReturnForm(rtype, false);
+ // MethodType newType = targetType.changeReturnType(filterType.returnType());
+ // result = result.copyWithExtendL(newType, lform, filter);
+ // return result;
+ return new Transformers.FilterReturnValue(target, filter);
+ }
+
+ private static void filterReturnValueChecks(MethodType targetType, MethodType filterType) throws RuntimeException {
+ Class<?> rtype = targetType.returnType();
+ int filterValues = filterType.parameterCount();
+ if (filterValues == 0
+ ? (rtype != void.class)
+ : (rtype != filterType.parameterType(0) || filterValues != 1))
+ throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
+ }
+
+ /**
+ * Adapts a target method handle by pre-processing
+ * some of its arguments, and then calling the target with
+ * the result of the pre-processing, inserted into the original
+ * sequence of arguments.
+ * <p>
+ * The pre-processing is performed by {@code combiner}, a second method handle.
+ * Of the arguments passed to the adapter, the first {@code N} arguments
+ * are copied to the combiner, which is then called.
+ * (Here, {@code N} is defined as the parameter count of the combiner.)
+ * After this, control passes to the target, with any result
+ * from the combiner inserted before the original {@code N} incoming
+ * arguments.
+ * <p>
+ * If the combiner returns a value, the first parameter type of the target
+ * must be identical with the return type of the combiner, and the next
+ * {@code N} parameter types of the target must exactly match the parameters
+ * of the combiner.
+ * <p>
+ * If the combiner has a void return, no result will be inserted,
+ * and the first {@code N} parameter types of the target
+ * must exactly match the parameters of the combiner.
+ * <p>
+ * The resulting adapter is the same type as the target, except that the
+ * first parameter type is dropped,
+ * if it corresponds to the result of the combiner.
+ * <p>
+ * (Note that {@link #dropArguments(MethodHandle,int,List) dropArguments} can be used to remove any arguments
+ * that either the combiner or the target does not wish to receive.
+ * If some of the incoming arguments are destined only for the combiner,
+ * consider using {@link MethodHandle#asCollector asCollector} instead, since those
+ * arguments will not need to be live on the stack on entry to the
+ * target.)
+ * <p><b>Example:</b>
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class,
+ "println", methodType(void.class, String.class))
+ .bindTo(System.out);
+MethodHandle cat = lookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+assertEquals("boojum", (String) cat.invokeExact("boo", "jum"));
+MethodHandle catTrace = foldArguments(cat, trace);
+// also prints "boo":
+assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
+ * }</pre></blockquote>
+ * <p>Here is pseudocode for the resulting adapter. In the code, {@code T}
+ * represents the result type of the {@code target} and resulting adapter.
+ * {@code V}/{@code v} represent the type and value of the parameter and argument
+ * of {@code target} that precedes the folding position; {@code V} also is
+ * the result type of the {@code combiner}. {@code A}/{@code a} denote the
+ * types and values of the {@code N} parameters and arguments at the folding
+ * position. {@code B}/{@code b} represent the types and values of the
+ * {@code target} parameters and arguments that follow the folded parameters
+ * and arguments.
+ * <blockquote><pre>{@code
+ * // there are N arguments in A...
+ * T target(V, A[N]..., B...);
+ * V combiner(A...);
+ * T adapter(A... a, B... b) {
+ * V v = combiner(a...);
+ * return target(v, a..., b...);
+ * }
+ * // and if the combiner has a void return:
+ * T target2(A[N]..., B...);
+ * void combiner2(A...);
+ * T adapter2(A... a, B... b) {
+ * combiner2(a...);
+ * return target2(a..., b...);
+ * }
+ * }</pre></blockquote>
+ * <p>
+ * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+ * variable-arity method handle}, even if the original target method handle was.
+ * @param target the method handle to invoke after arguments are combined
+ * @param combiner method handle to call initially on the incoming arguments
+ * @return method handle which incorporates the specified argument folding logic
+ * @throws NullPointerException if either argument is null
+ * @throws IllegalArgumentException if {@code combiner}'s return type
+ * is non-void and not the same as the first argument type of
+ * the target, or if the initial {@code N} argument types
+ * of the target
+ * (skipping one matching the {@code combiner}'s return type)
+ * are not identical with the argument types of {@code combiner}
+ */
+ public static
+ MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) {
+ return foldArguments(target, 0, combiner);
+ }
+
+ /**
+ * Adapts a target method handle by pre-processing some of its arguments, starting at a given position, and then
+ * calling the target with the result of the pre-processing, inserted into the original sequence of arguments just
+ * before the folded arguments.
+ * <p>
+ * This method is closely related to {@link #foldArguments(MethodHandle, MethodHandle)}, but allows to control the
+ * position in the parameter list at which folding takes place. The argument controlling this, {@code pos}, is a
+ * zero-based index. The aforementioned method {@link #foldArguments(MethodHandle, MethodHandle)} assumes position
+ * 0.
+ *
+ * @apiNote Example:
+ * <blockquote><pre>{@code
+ import static java.lang.invoke.MethodHandles.*;
+ import static java.lang.invoke.MethodType.*;
+ ...
+ MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class,
+ "println", methodType(void.class, String.class))
+ .bindTo(System.out);
+ MethodHandle cat = lookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+ assertEquals("boojum", (String) cat.invokeExact("boo", "jum"));
+ MethodHandle catTrace = foldArguments(cat, 1, trace);
+ // also prints "jum":
+ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
+ * }</pre></blockquote>
+ * <p>Here is pseudocode for the resulting adapter. In the code, {@code T}
+ * represents the result type of the {@code target} and resulting adapter.
+ * {@code V}/{@code v} represent the type and value of the parameter and argument
+ * of {@code target} that precedes the folding position; {@code V} also is
+ * the result type of the {@code combiner}. {@code A}/{@code a} denote the
+ * types and values of the {@code N} parameters and arguments at the folding
+ * position. {@code Z}/{@code z} and {@code B}/{@code b} represent the types
+ * and values of the {@code target} parameters and arguments that precede and
+ * follow the folded parameters and arguments starting at {@code pos},
+ * respectively.
+ * <blockquote><pre>{@code
+ * // there are N arguments in A...
+ * T target(Z..., V, A[N]..., B...);
+ * V combiner(A...);
+ * T adapter(Z... z, A... a, B... b) {
+ * V v = combiner(a...);
+ * return target(z..., v, a..., b...);
+ * }
+ * // and if the combiner has a void return:
+ * T target2(Z..., A[N]..., B...);
+ * void combiner2(A...);
+ * T adapter2(Z... z, A... a, B... b) {
+ * combiner2(a...);
+ * return target2(z..., a..., b...);
+ * }
+ * }</pre></blockquote>
+ * <p>
+ * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+ * variable-arity method handle}, even if the original target method handle was.
+ *
+ * @param target the method handle to invoke after arguments are combined
+ * @param pos the position at which to start folding and at which to insert the folding result; if this is {@code
+ * 0}, the effect is the same as for {@link #foldArguments(MethodHandle, MethodHandle)}.
+ * @param combiner method handle to call initially on the incoming arguments
+ * @return method handle which incorporates the specified argument folding logic
+ * @throws NullPointerException if either argument is null
+ * @throws IllegalArgumentException if either of the following two conditions holds:
+ * (1) {@code combiner}'s return type is non-{@code void} and not the same as the argument type at position
+ * {@code pos} of the target signature;
+ * (2) the {@code N} argument types at position {@code pos} of the target signature (skipping one matching
+ * the {@code combiner}'s return type) are not identical with the argument types of {@code combiner}.
+ *
+ * @see #foldArguments(MethodHandle, MethodHandle)
+ * @since 9
+ */
+ public static
+ MethodHandle foldArguments(MethodHandle target, int pos, MethodHandle combiner) {
+ MethodType targetType = target.type();
+ MethodType combinerType = combiner.type();
+ Class<?> rtype = foldArgumentChecks(pos, targetType, combinerType);
+ // Android-changed: // Android-changed: transformer implementation.
+ // BoundMethodHandle result = target.rebind();
+ // boolean dropResult = rtype == void.class;
+ // LambdaForm lform = result.editor().foldArgumentsForm(1 + pos, dropResult, combinerType.basicType());
+ // MethodType newType = targetType;
+ // if (!dropResult) {
+ // newType = newType.dropParameterTypes(pos, pos + 1);
+ // }
+ // result = result.copyWithExtendL(newType, lform, combiner);
+ // return result;
+
+ return new Transformers.FoldArguments(target, pos, combiner);
+ }
+
+ private static Class<?> foldArgumentChecks(int foldPos, MethodType targetType, MethodType combinerType) {
+ int foldArgs = combinerType.parameterCount();
+ Class<?> rtype = combinerType.returnType();
+ int foldVals = rtype == void.class ? 0 : 1;
+ int afterInsertPos = foldPos + foldVals;
+ boolean ok = (targetType.parameterCount() >= afterInsertPos + foldArgs);
+ if (ok) {
+ for (int i = 0; i < foldArgs; i++) {
+ if (combinerType.parameterType(i) != targetType.parameterType(i + afterInsertPos)) {
+ ok = false;
+ break;
+ }
+ }
+ }
+ if (ok && foldVals != 0 && combinerType.returnType() != targetType.parameterType(foldPos))
+ ok = false;
+ if (!ok)
+ throw misMatchedTypes("target and combiner types", targetType, combinerType);
+ return rtype;
+ }
+
+ /**
+ * Makes a method handle which adapts a target method handle,
+ * by guarding it with a test, a boolean-valued method handle.
+ * If the guard fails, a fallback handle is called instead.
+ * All three method handles must have the same corresponding
+ * argument and return types, except that the return type
+ * of the test must be boolean, and the test is allowed
+ * to have fewer arguments than the other two method handles.
+ * <p> Here is pseudocode for the resulting adapter:
+ * <blockquote><pre>{@code
+ * boolean test(A...);
+ * T target(A...,B...);
+ * T fallback(A...,B...);
+ * T adapter(A... a,B... b) {
+ * if (test(a...))
+ * return target(a..., b...);
+ * else
+ * return fallback(a..., b...);
+ * }
+ * }</pre></blockquote>
+ * Note that the test arguments ({@code a...} in the pseudocode) cannot
+ * be modified by execution of the test, and so are passed unchanged
+ * from the caller to the target or fallback as appropriate.
+ * @param test method handle used for test, must return boolean
+ * @param target method handle to call if test passes
+ * @param fallback method handle to call if test fails
+ * @return method handle which incorporates the specified if/then/else logic
+ * @throws NullPointerException if any argument is null
+ * @throws IllegalArgumentException if {@code test} does not return boolean,
+ * or if all three method types do not match (with the return
+ * type of {@code test} changed to match that of the target).
+ */
+ public static
+ MethodHandle guardWithTest(MethodHandle test,
+ MethodHandle target,
+ MethodHandle fallback) {
+ MethodType gtype = test.type();
+ MethodType ttype = target.type();
+ MethodType ftype = fallback.type();
+ if (!ttype.equals(ftype))
+ throw misMatchedTypes("target and fallback types", ttype, ftype);
+ if (gtype.returnType() != boolean.class)
+ throw newIllegalArgumentException("guard type is not a predicate "+gtype);
+ List<Class<?>> targs = ttype.parameterList();
+ List<Class<?>> gargs = gtype.parameterList();
+ if (!targs.equals(gargs)) {
+ int gpc = gargs.size(), tpc = targs.size();
+ if (gpc >= tpc || !targs.subList(0, gpc).equals(gargs))
+ throw misMatchedTypes("target and test types", ttype, gtype);
+ test = dropArguments(test, gpc, targs.subList(gpc, tpc));
+ gtype = test.type();
+ }
+
+ return new Transformers.GuardWithTest(test, target, fallback);
+ }
+
+ static <T> RuntimeException misMatchedTypes(String what, T t1, T t2) {
+ return newIllegalArgumentException(what + " must match: " + t1 + " != " + t2);
+ }
+
+ /**
+ * Makes a method handle which adapts a target method handle,
+ * by running it inside an exception handler.
+ * If the target returns normally, the adapter returns that value.
+ * If an exception matching the specified type is thrown, the fallback
+ * handle is called instead on the exception, plus the original arguments.
+ * <p>
+ * The target and handler must have the same corresponding
+ * argument and return types, except that handler may omit trailing arguments
+ * (similarly to the predicate in {@link #guardWithTest guardWithTest}).
+ * Also, the handler must have an extra leading parameter of {@code exType} or a supertype.
+ * <p>
+ * Here is pseudocode for the resulting adapter. In the code, {@code T}
+ * represents the return type of the {@code target} and {@code handler},
+ * and correspondingly that of the resulting adapter; {@code A}/{@code a},
+ * the types and values of arguments to the resulting handle consumed by
+ * {@code handler}; and {@code B}/{@code b}, those of arguments to the
+ * resulting handle discarded by {@code handler}.
+ * <blockquote><pre>{@code
+ * T target(A..., B...);
+ * T handler(ExType, A...);
+ * T adapter(A... a, B... b) {
+ * try {
+ * return target(a..., b...);
+ * } catch (ExType ex) {
+ * return handler(ex, a...);
+ * }
+ * }
+ * }</pre></blockquote>
+ * Note that the saved arguments ({@code a...} in the pseudocode) cannot
+ * be modified by execution of the target, and so are passed unchanged
+ * from the caller to the handler, if the handler is invoked.
+ * <p>
+ * The target and handler must return the same type, even if the handler
+ * always throws. (This might happen, for instance, because the handler
+ * is simulating a {@code finally} clause).
+ * To create such a throwing handler, compose the handler creation logic
+ * with {@link #throwException throwException},
+ * in order to create a method handle of the correct return type.
+ * @param target method handle to call
+ * @param exType the type of exception which the handler will catch
+ * @param handler method handle to call if a matching exception is thrown
+ * @return method handle which incorporates the specified try/catch logic
+ * @throws NullPointerException if any argument is null
+ * @throws IllegalArgumentException if {@code handler} does not accept
+ * the given exception type, or if the method handle types do
+ * not match in their return types and their
+ * corresponding parameters
+ * @see MethodHandles#tryFinally(MethodHandle, MethodHandle)
+ */
+ public static
+ MethodHandle catchException(MethodHandle target,
+ Class<? extends Throwable> exType,
+ MethodHandle handler) {
+ MethodType ttype = target.type();
+ MethodType htype = handler.type();
+ if (!Throwable.class.isAssignableFrom(exType))
+ throw new ClassCastException(exType.getName());
+ if (htype.parameterCount() < 1 ||
+ !htype.parameterType(0).isAssignableFrom(exType))
+ throw newIllegalArgumentException("handler does not accept exception type "+exType);
+ if (htype.returnType() != ttype.returnType())
+ throw misMatchedTypes("target and handler return types", ttype, htype);
+ handler = dropArgumentsToMatch(handler, 1, ttype.parameterList(), 0, true);
+ if (handler == null) {
+ throw misMatchedTypes("target and handler types", ttype, htype);
+ }
+ // Android-changed: use Transformer implementation.
+ // return MethodHandleImpl.makeGuardWithCatch(target, exType, handler);
+ return new Transformers.CatchException(target, handler, exType);
+ }
+
+ /**
+ * Produces a method handle which will throw exceptions of the given {@code exType}.
+ * The method handle will accept a single argument of {@code exType},
+ * and immediately throw it as an exception.
+ * The method type will nominally specify a return of {@code returnType}.
+ * The return type may be anything convenient: It doesn't matter to the
+ * method handle's behavior, since it will never return normally.
+ * @param returnType the return type of the desired method handle
+ * @param exType the parameter type of the desired method handle
+ * @return method handle which can throw the given exceptions
+ * @throws NullPointerException if either argument is null
+ */
+ public static
+ MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType) {
+ if (!Throwable.class.isAssignableFrom(exType))
+ throw new ClassCastException(exType.getName());
+ // Android-changed: use Transformer implementation.
+ // return MethodHandleImpl.throwException(methodType(returnType, exType));
+ return new Transformers.AlwaysThrow(returnType, exType);
+ }
+
+ /**
+ * Constructs a method handle representing a loop with several loop variables that are updated and checked upon each
+ * iteration. Upon termination of the loop due to one of the predicates, a corresponding finalizer is run and
+ * delivers the loop's result, which is the return value of the resulting handle.
+ * <p>
+ * Intuitively, every loop is formed by one or more "clauses", each specifying a local <em>iteration variable</em> and/or a loop
+ * exit. Each iteration of the loop executes each clause in order. A clause can optionally update its iteration
+ * variable; it can also optionally perform a test and conditional loop exit. In order to express this logic in
+ * terms of method handles, each clause will specify up to four independent actions:<ul>
+ * <li><em>init:</em> Before the loop executes, the initialization of an iteration variable {@code v} of type {@code V}.
+ * <li><em>step:</em> When a clause executes, an update step for the iteration variable {@code v}.
+ * <li><em>pred:</em> When a clause executes, a predicate execution to test for loop exit.
+ * <li><em>fini:</em> If a clause causes a loop exit, a finalizer execution to compute the loop's return value.
+ * </ul>
+ * The full sequence of all iteration variable types, in clause order, will be notated as {@code (V...)}.
+ * The values themselves will be {@code (v...)}. When we speak of "parameter lists", we will usually
+ * be referring to types, but in some contexts (describing execution) the lists will be of actual values.
+ * <p>
+ * Some of these clause parts may be omitted according to certain rules, and useful default behavior is provided in
+ * this case. See below for a detailed description.
+ * <p>
+ * <em>Parameters optional everywhere:</em>
+ * Each clause function is allowed but not required to accept a parameter for each iteration variable {@code v}.
+ * As an exception, the init functions cannot take any {@code v} parameters,
+ * because those values are not yet computed when the init functions are executed.
+ * Any clause function may neglect to take any trailing subsequence of parameters it is entitled to take.
+ * In fact, any clause function may take no arguments at all.
+ * <p>
+ * <em>Loop parameters:</em>
+ * A clause function may take all the iteration variable values it is entitled to, in which case
+ * it may also take more trailing parameters. Such extra values are called <em>loop parameters</em>,
+ * with their types and values notated as {@code (A...)} and {@code (a...)}.
+ * These become the parameters of the resulting loop handle, to be supplied whenever the loop is executed.
+ * (Since init functions do not accept iteration variables {@code v}, any parameter to an
+ * init function is automatically a loop parameter {@code a}.)
+ * As with iteration variables, clause functions are allowed but not required to accept loop parameters.
+ * These loop parameters act as loop-invariant values visible across the whole loop.
+ * <p>
+ * <em>Parameters visible everywhere:</em>
+ * Each non-init clause function is permitted to observe the entire loop state, because it can be passed the full
+ * list {@code (v... a...)} of current iteration variable values and incoming loop parameters.
+ * The init functions can observe initial pre-loop state, in the form {@code (a...)}.
+ * Most clause functions will not need all of this information, but they will be formally connected to it
+ * as if by {@link #dropArguments}.
+ * <a id="astar"></a>
+ * More specifically, we shall use the notation {@code (V*)} to express an arbitrary prefix of a full
+ * sequence {@code (V...)} (and likewise for {@code (v*)}, {@code (A*)}, {@code (a*)}).
+ * In that notation, the general form of an init function parameter list
+ * is {@code (A*)}, and the general form of a non-init function parameter list is {@code (V*)} or {@code (V... A*)}.
+ * <p>
+ * <em>Checking clause structure:</em>
+ * Given a set of clauses, there is a number of checks and adjustments performed to connect all the parts of the
+ * loop. They are spelled out in detail in the steps below. In these steps, every occurrence of the word "must"
+ * corresponds to a place where {@link IllegalArgumentException} will be thrown if the required constraint is not
+ * met by the inputs to the loop combinator.
+ * <p>
+ * <em>Effectively identical sequences:</em>
+ * <a id="effid"></a>
+ * A parameter list {@code A} is defined to be <em>effectively identical</em> to another parameter list {@code B}
+ * if {@code A} and {@code B} are identical, or if {@code A} is shorter and is identical with a proper prefix of {@code B}.
+ * When speaking of an unordered set of parameter lists, we say they the set is "effectively identical"
+ * as a whole if the set contains a longest list, and all members of the set are effectively identical to
+ * that longest list.
+ * For example, any set of type sequences of the form {@code (V*)} is effectively identical,
+ * and the same is true if more sequences of the form {@code (V... A*)} are added.
+ * <p>
+ * <em>Step 0: Determine clause structure.</em><ol type="a">
+ * <li>The clause array (of type {@code MethodHandle[][]}) must be non-{@code null} and contain at least one element.
+ * <li>The clause array may not contain {@code null}s or sub-arrays longer than four elements.
+ * <li>Clauses shorter than four elements are treated as if they were padded by {@code null} elements to length
+ * four. Padding takes place by appending elements to the array.
+ * <li>Clauses with all {@code null}s are disregarded.
+ * <li>Each clause is treated as a four-tuple of functions, called "init", "step", "pred", and "fini".
+ * </ol>
+ * <p>
+ * <em>Step 1A: Determine iteration variable types {@code (V...)}.</em><ol type="a">
+ * <li>The iteration variable type for each clause is determined using the clause's init and step return types.
+ * <li>If both functions are omitted, there is no iteration variable for the corresponding clause ({@code void} is
+ * used as the type to indicate that). If one of them is omitted, the other's return type defines the clause's
+ * iteration variable type. If both are given, the common return type (they must be identical) defines the clause's
+ * iteration variable type.
+ * <li>Form the list of return types (in clause order), omitting all occurrences of {@code void}.
+ * <li>This list of types is called the "iteration variable types" ({@code (V...)}).
+ * </ol>
+ * <p>
+ * <em>Step 1B: Determine loop parameters {@code (A...)}.</em><ul>
+ * <li>Examine and collect init function parameter lists (which are of the form {@code (A*)}).
+ * <li>Examine and collect the suffixes of the step, pred, and fini parameter lists, after removing the iteration variable types.
+ * (They must have the form {@code (V... A*)}; collect the {@code (A*)} parts only.)
+ * <li>Do not collect suffixes from step, pred, and fini parameter lists that do not begin with all the iteration variable types.
+ * (These types will be checked in step 2, along with all the clause function types.)
+ * <li>Omitted clause functions are ignored. (Equivalently, they are deemed to have empty parameter lists.)
+ * <li>All of the collected parameter lists must be effectively identical.
+ * <li>The longest parameter list (which is necessarily unique) is called the "external parameter list" ({@code (A...)}).
+ * <li>If there is no such parameter list, the external parameter list is taken to be the empty sequence.
+ * <li>The combined list consisting of iteration variable types followed by the external parameter types is called
+ * the "internal parameter list".
+ * </ul>
+ * <p>
+ * <em>Step 1C: Determine loop return type.</em><ol type="a">
+ * <li>Examine fini function return types, disregarding omitted fini functions.
+ * <li>If there are no fini functions, the loop return type is {@code void}.
+ * <li>Otherwise, the common return type {@code R} of the fini functions (their return types must be identical) defines the loop return
+ * type.
+ * </ol>
+ * <p>
+ * <em>Step 1D: Check other types.</em><ol type="a">
+ * <li>There must be at least one non-omitted pred function.
+ * <li>Every non-omitted pred function must have a {@code boolean} return type.
+ * </ol>
+ * <p>
+ * <em>Step 2: Determine parameter lists.</em><ol type="a">
+ * <li>The parameter list for the resulting loop handle will be the external parameter list {@code (A...)}.
+ * <li>The parameter list for init functions will be adjusted to the external parameter list.
+ * (Note that their parameter lists are already effectively identical to this list.)
+ * <li>The parameter list for every non-omitted, non-init (step, pred, and fini) function must be
+ * effectively identical to the internal parameter list {@code (V... A...)}.
+ * </ol>
+ * <p>
+ * <em>Step 3: Fill in omitted functions.</em><ol type="a">
+ * <li>If an init function is omitted, use a {@linkplain #empty default value} for the clause's iteration variable
+ * type.
+ * <li>If a step function is omitted, use an {@linkplain #identity identity function} of the clause's iteration
+ * variable type; insert dropped argument parameters before the identity function parameter for the non-{@code void}
+ * iteration variables of preceding clauses. (This will turn the loop variable into a local loop invariant.)
+ * <li>If a pred function is omitted, use a constant {@code true} function. (This will keep the loop going, as far
+ * as this clause is concerned. Note that in such cases the corresponding fini function is unreachable.)
+ * <li>If a fini function is omitted, use a {@linkplain #empty default value} for the
+ * loop return type.
+ * </ol>
+ * <p>
+ * <em>Step 4: Fill in missing parameter types.</em><ol type="a">
+ * <li>At this point, every init function parameter list is effectively identical to the external parameter list {@code (A...)},
+ * but some lists may be shorter. For every init function with a short parameter list, pad out the end of the list.
+ * <li>At this point, every non-init function parameter list is effectively identical to the internal parameter
+ * list {@code (V... A...)}, but some lists may be shorter. For every non-init function with a short parameter list,
+ * pad out the end of the list.
+ * <li>Argument lists are padded out by {@linkplain #dropArgumentsToMatch(MethodHandle, int, List, int) dropping unused trailing arguments}.
+ * </ol>
+ * <p>
+ * <em>Final observations.</em><ol type="a">
+ * <li>After these steps, all clauses have been adjusted by supplying omitted functions and arguments.
+ * <li>All init functions have a common parameter type list {@code (A...)}, which the final loop handle will also have.
+ * <li>All fini functions have a common return type {@code R}, which the final loop handle will also have.
+ * <li>All non-init functions have a common parameter type list {@code (V... A...)}, of
+ * (non-{@code void}) iteration variables {@code V} followed by loop parameters.
+ * <li>Each pair of init and step functions agrees in their return type {@code V}.
+ * <li>Each non-init function will be able to observe the current values {@code (v...)} of all iteration variables.
+ * <li>Every function will be able to observe the incoming values {@code (a...)} of all loop parameters.
+ * </ol>
+ * <p>
+ * <em>Example.</em> As a consequence of step 1A above, the {@code loop} combinator has the following property:
+ * <ul>
+ * <li>Given {@code N} clauses {@code Cn = {null, Sn, Pn}} with {@code n = 1..N}.
+ * <li>Suppose predicate handles {@code Pn} are either {@code null} or have no parameters.
+ * (Only one {@code Pn} has to be non-{@code null}.)
+ * <li>Suppose step handles {@code Sn} have signatures {@code (B1..BX)Rn}, for some constant {@code X>=N}.
+ * <li>Suppose {@code Q} is the count of non-void types {@code Rn}, and {@code (V1...VQ)} is the sequence of those types.
+ * <li>It must be that {@code Vn == Bn} for {@code n = 1..min(X,Q)}.
+ * <li>The parameter types {@code Vn} will be interpreted as loop-local state elements {@code (V...)}.
+ * <li>Any remaining types {@code BQ+1..BX} (if {@code Q<X}) will determine
+ * the resulting loop handle's parameter types {@code (A...)}.
+ * </ul>
+ * In this example, the loop handle parameters {@code (A...)} were derived from the step functions,
+ * which is natural if most of the loop computation happens in the steps. For some loops,
+ * the burden of computation might be heaviest in the pred functions, and so the pred functions
+ * might need to accept the loop parameter values. For loops with complex exit logic, the fini
+ * functions might need to accept loop parameters, and likewise for loops with complex entry logic,
+ * where the init functions will need the extra parameters. For such reasons, the rules for
+ * determining these parameters are as symmetric as possible, across all clause parts.
+ * In general, the loop parameters function as common invariant values across the whole
+ * loop, while the iteration variables function as common variant values, or (if there is
+ * no step function) as internal loop invariant temporaries.
+ * <p>
+ * <em>Loop execution.</em><ol type="a">
+ * <li>When the loop is called, the loop input values are saved in locals, to be passed to
+ * every clause function. These locals are loop invariant.
+ * <li>Each init function is executed in clause order (passing the external arguments {@code (a...)})
+ * and the non-{@code void} values are saved (as the iteration variables {@code (v...)}) into locals.
+ * These locals will be loop varying (unless their steps behave as identity functions, as noted above).
+ * <li>All function executions (except init functions) will be passed the internal parameter list, consisting of
+ * the non-{@code void} iteration values {@code (v...)} (in clause order) and then the loop inputs {@code (a...)}
+ * (in argument order).
+ * <li>The step and pred functions are then executed, in clause order (step before pred), until a pred function
+ * returns {@code false}.
+ * <li>The non-{@code void} result from a step function call is used to update the corresponding value in the
+ * sequence {@code (v...)} of loop variables.
+ * The updated value is immediately visible to all subsequent function calls.
+ * <li>If a pred function returns {@code false}, the corresponding fini function is called, and the resulting value
+ * (of type {@code R}) is returned from the loop as a whole.
+ * <li>If all the pred functions always return true, no fini function is ever invoked, and the loop cannot exit
+ * except by throwing an exception.
+ * </ol>
+ * <p>
+ * <em>Usage tips.</em>
+ * <ul>
+ * <li>Although each step function will receive the current values of <em>all</em> the loop variables,
+ * sometimes a step function only needs to observe the current value of its own variable.
+ * In that case, the step function may need to explicitly {@linkplain #dropArguments drop all preceding loop variables}.
+ * This will require mentioning their types, in an expression like {@code dropArguments(step, 0, V0.class, ...)}.
+ * <li>Loop variables are not required to vary; they can be loop invariant. A clause can create
+ * a loop invariant by a suitable init function with no step, pred, or fini function. This may be
+ * useful to "wire" an incoming loop argument into the step or pred function of an adjacent loop variable.
+ * <li>If some of the clause functions are virtual methods on an instance, the instance
+ * itself can be conveniently placed in an initial invariant loop "variable", using an initial clause
+ * like {@code new MethodHandle[]{identity(ObjType.class)}}. In that case, the instance reference
+ * will be the first iteration variable value, and it will be easy to use virtual
+ * methods as clause parts, since all of them will take a leading instance reference matching that value.
+ * </ul>
+ * <p>
+ * Here is pseudocode for the resulting loop handle. As above, {@code V} and {@code v} represent the types
+ * and values of loop variables; {@code A} and {@code a} represent arguments passed to the whole loop;
+ * and {@code R} is the common result type of all finalizers as well as of the resulting loop.
+ * <blockquote><pre>{@code
+ * V... init...(A...);
+ * boolean pred...(V..., A...);
+ * V... step...(V..., A...);
+ * R fini...(V..., A...);
+ * R loop(A... a) {
+ * V... v... = init...(a...);
+ * for (;;) {
+ * for ((v, p, s, f) in (v..., pred..., step..., fini...)) {
+ * v = s(v..., a...);
+ * if (!p(v..., a...)) {
+ * return f(v..., a...);
+ * }
+ * }
+ * }
+ * }
+ * }</pre></blockquote>
+ * Note that the parameter type lists {@code (V...)} and {@code (A...)} have been expanded
+ * to their full length, even though individual clause functions may neglect to take them all.
+ * As noted above, missing parameters are filled in as if by {@link #dropArgumentsToMatch(MethodHandle, int, List, int)}.
+ *
+ * @apiNote Example:
+ * <blockquote><pre>{@code
+ * // iterative implementation of the factorial function as a loop handle
+ * static int one(int k) { return 1; }
+ * static int inc(int i, int acc, int k) { return i + 1; }
+ * static int mult(int i, int acc, int k) { return i * acc; }
+ * static boolean pred(int i, int acc, int k) { return i < k; }
+ * static int fin(int i, int acc, int k) { return acc; }
+ * // assume MH_one, MH_inc, MH_mult, MH_pred, and MH_fin are handles to the above methods
+ * // null initializer for counter, should initialize to 0
+ * MethodHandle[] counterClause = new MethodHandle[]{null, MH_inc};
+ * MethodHandle[] accumulatorClause = new MethodHandle[]{MH_one, MH_mult, MH_pred, MH_fin};
+ * MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause);
+ * assertEquals(120, loop.invoke(5));
+ * }</pre></blockquote>
+ * The same example, dropping arguments and using combinators:
+ * <blockquote><pre>{@code
+ * // simplified implementation of the factorial function as a loop handle
+ * static int inc(int i) { return i + 1; } // drop acc, k
+ * static int mult(int i, int acc) { return i * acc; } //drop k
+ * static boolean cmp(int i, int k) { return i < k; }
+ * // assume MH_inc, MH_mult, and MH_cmp are handles to the above methods
+ * // null initializer for counter, should initialize to 0
+ * MethodHandle MH_one = MethodHandles.constant(int.class, 1);
+ * MethodHandle MH_pred = MethodHandles.dropArguments(MH_cmp, 1, int.class); // drop acc
+ * MethodHandle MH_fin = MethodHandles.dropArguments(MethodHandles.identity(int.class), 0, int.class); // drop i
+ * MethodHandle[] counterClause = new MethodHandle[]{null, MH_inc};
+ * MethodHandle[] accumulatorClause = new MethodHandle[]{MH_one, MH_mult, MH_pred, MH_fin};
+ * MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause);
+ * assertEquals(720, loop.invoke(6));
+ * }</pre></blockquote>
+ * A similar example, using a helper object to hold a loop parameter:
+ * <blockquote><pre>{@code
+ * // instance-based implementation of the factorial function as a loop handle
+ * static class FacLoop {
+ * final int k;
+ * FacLoop(int k) { this.k = k; }
+ * int inc(int i) { return i + 1; }
+ * int mult(int i, int acc) { return i * acc; }
+ * boolean pred(int i) { return i < k; }
+ * int fin(int i, int acc) { return acc; }
+ * }
+ * // assume MH_FacLoop is a handle to the constructor
+ * // assume MH_inc, MH_mult, MH_pred, and MH_fin are handles to the above methods
+ * // null initializer for counter, should initialize to 0
+ * MethodHandle MH_one = MethodHandles.constant(int.class, 1);
+ * MethodHandle[] instanceClause = new MethodHandle[]{MH_FacLoop};
+ * MethodHandle[] counterClause = new MethodHandle[]{null, MH_inc};
+ * MethodHandle[] accumulatorClause = new MethodHandle[]{MH_one, MH_mult, MH_pred, MH_fin};
+ * MethodHandle loop = MethodHandles.loop(instanceClause, counterClause, accumulatorClause);
+ * assertEquals(5040, loop.invoke(7));
+ * }</pre></blockquote>
+ *
+ * @param clauses an array of arrays (4-tuples) of {@link MethodHandle}s adhering to the rules described above.
+ *
+ * @return a method handle embodying the looping behavior as defined by the arguments.
+ *
+ * @throws IllegalArgumentException in case any of the constraints described above is violated.
+ *
+ * @see MethodHandles#whileLoop(MethodHandle, MethodHandle, MethodHandle)
+ * @see MethodHandles#doWhileLoop(MethodHandle, MethodHandle, MethodHandle)
+ * @see MethodHandles#countedLoop(MethodHandle, MethodHandle, MethodHandle)
+ * @see MethodHandles#iteratedLoop(MethodHandle, MethodHandle, MethodHandle)
+ * @since 9
+ */
+ public static MethodHandle loop(MethodHandle[]... clauses) {
+ // Step 0: determine clause structure.
+ loopChecks0(clauses);
+
+ List<MethodHandle> init = new ArrayList<>();
+ List<MethodHandle> step = new ArrayList<>();
+ List<MethodHandle> pred = new ArrayList<>();
+ List<MethodHandle> fini = new ArrayList<>();
+
+ Stream.of(clauses).filter(c -> Stream.of(c).anyMatch(Objects::nonNull)).forEach(clause -> {
+ init.add(clause[0]); // all clauses have at least length 1
+ step.add(clause.length <= 1 ? null : clause[1]);
+ pred.add(clause.length <= 2 ? null : clause[2]);
+ fini.add(clause.length <= 3 ? null : clause[3]);
+ });
+
+ assert Stream.of(init, step, pred, fini).map(List::size).distinct().count() == 1;
+ final int nclauses = init.size();
+
+ // Step 1A: determine iteration variables (V...).
+ final List<Class<?>> iterationVariableTypes = new ArrayList<>();
+ for (int i = 0; i < nclauses; ++i) {
+ MethodHandle in = init.get(i);
+ MethodHandle st = step.get(i);
+ if (in == null && st == null) {
+ iterationVariableTypes.add(void.class);
+ } else if (in != null && st != null) {
+ loopChecks1a(i, in, st);
+ iterationVariableTypes.add(in.type().returnType());
+ } else {
+ iterationVariableTypes.add(in == null ? st.type().returnType() : in.type().returnType());
+ }
+ }
+ final List<Class<?>> commonPrefix = iterationVariableTypes.stream().filter(t -> t != void.class).
+ collect(Collectors.toList());
+
+ // Step 1B: determine loop parameters (A...).
+ final List<Class<?>> commonSuffix = buildCommonSuffix(init, step, pred, fini, commonPrefix.size());
+ loopChecks1b(init, commonSuffix);
+
+ // Step 1C: determine loop return type.
+ // Step 1D: check other types.
+ // local variable required here; see JDK-8223553
+ Stream<Class<?>> cstream = fini.stream().filter(Objects::nonNull).map(MethodHandle::type)
+ .map(MethodType::returnType);
+ final Class<?> loopReturnType = cstream.findFirst().orElse(void.class);
+ loopChecks1cd(pred, fini, loopReturnType);
+
+ // Step 2: determine parameter lists.
+ final List<Class<?>> commonParameterSequence = new ArrayList<>(commonPrefix);
+ commonParameterSequence.addAll(commonSuffix);
+ loopChecks2(step, pred, fini, commonParameterSequence);
+
+ // Step 3: fill in omitted functions.
+ for (int i = 0; i < nclauses; ++i) {
+ Class<?> t = iterationVariableTypes.get(i);
+ if (init.get(i) == null) {
+ init.set(i, empty(methodType(t, commonSuffix)));
+ }
+ if (step.get(i) == null) {
+ step.set(i, dropArgumentsToMatch(identityOrVoid(t), 0, commonParameterSequence, i));
+ }
+ if (pred.get(i) == null) {
+ pred.set(i, dropArguments0(constant(boolean.class, true), 0, commonParameterSequence));
+ }
+ if (fini.get(i) == null) {
+ fini.set(i, empty(methodType(t, commonParameterSequence)));
+ }
+ }
+
+ // Step 4: fill in missing parameter types.
+ // Also convert all handles to fixed-arity handles.
+ List<MethodHandle> finit = fixArities(fillParameterTypes(init, commonSuffix));
+ List<MethodHandle> fstep = fixArities(fillParameterTypes(step, commonParameterSequence));
+ List<MethodHandle> fpred = fixArities(fillParameterTypes(pred, commonParameterSequence));
+ List<MethodHandle> ffini = fixArities(fillParameterTypes(fini, commonParameterSequence));
+
+ assert finit.stream().map(MethodHandle::type).map(MethodType::parameterList).
+ allMatch(pl -> pl.equals(commonSuffix));
+ assert Stream.of(fstep, fpred, ffini).flatMap(List::stream).map(MethodHandle::type).map(MethodType::parameterList).
+ allMatch(pl -> pl.equals(commonParameterSequence));
+
+ // Android-changed: transformer implementation.
+ // return MethodHandleImpl.makeLoop(loopReturnType, commonSuffix, finit, fstep, fpred, ffini);
+ return new Transformers.Loop(loopReturnType,
+ commonSuffix,
+ finit.toArray(MethodHandle[]::new),
+ fstep.toArray(MethodHandle[]::new),
+ fpred.toArray(MethodHandle[]::new),
+ ffini.toArray(MethodHandle[]::new));
+ }
+
+ private static void loopChecks0(MethodHandle[][] clauses) {
+ if (clauses == null || clauses.length == 0) {
+ throw newIllegalArgumentException("null or no clauses passed");
+ }
+ if (Stream.of(clauses).anyMatch(Objects::isNull)) {
+ throw newIllegalArgumentException("null clauses are not allowed");
+ }
+ if (Stream.of(clauses).anyMatch(c -> c.length > 4)) {
+ throw newIllegalArgumentException("All loop clauses must be represented as MethodHandle arrays with at most 4 elements.");
+ }
+ }
+
+ private static void loopChecks1a(int i, MethodHandle in, MethodHandle st) {
+ if (in.type().returnType() != st.type().returnType()) {
+ throw misMatchedTypes("clause " + i + ": init and step return types", in.type().returnType(),
+ st.type().returnType());
+ }
+ }
+
+ private static List<Class<?>> longestParameterList(Stream<MethodHandle> mhs, int skipSize) {
+ final List<Class<?>> empty = List.of();
+ final List<Class<?>> longest = mhs.filter(Objects::nonNull).
+ // take only those that can contribute to a common suffix because they are longer than the prefix
+ map(MethodHandle::type).
+ filter(t -> t.parameterCount() > skipSize).
+ map(MethodType::parameterList).
+ reduce((p, q) -> p.size() >= q.size() ? p : q).orElse(empty);
+ return longest.size() == 0 ? empty : longest.subList(skipSize, longest.size());
+ }
+
+ private static List<Class<?>> longestParameterList(List<List<Class<?>>> lists) {
+ final List<Class<?>> empty = List.of();
+ return lists.stream().reduce((p, q) -> p.size() >= q.size() ? p : q).orElse(empty);
+ }
+
+ private static List<Class<?>> buildCommonSuffix(List<MethodHandle> init, List<MethodHandle> step, List<MethodHandle> pred, List<MethodHandle> fini, int cpSize) {
+ final List<Class<?>> longest1 = longestParameterList(Stream.of(step, pred, fini).flatMap(List::stream), cpSize);
+ final List<Class<?>> longest2 = longestParameterList(init.stream(), 0);
+ return longestParameterList(Arrays.asList(longest1, longest2));
+ }
+
+ private static void loopChecks1b(List<MethodHandle> init, List<Class<?>> commonSuffix) {
+ if (init.stream().filter(Objects::nonNull).map(MethodHandle::type).
+ anyMatch(t -> !t.effectivelyIdenticalParameters(0, commonSuffix))) {
+ throw newIllegalArgumentException("found non-effectively identical init parameter type lists: " + init +
+ " (common suffix: " + commonSuffix + ")");
+ }
+ }
+
+ private static void loopChecks1cd(List<MethodHandle> pred, List<MethodHandle> fini, Class<?> loopReturnType) {
+ if (fini.stream().filter(Objects::nonNull).map(MethodHandle::type).map(MethodType::returnType).
+ anyMatch(t -> t != loopReturnType)) {
+ throw newIllegalArgumentException("found non-identical finalizer return types: " + fini + " (return type: " +
+ loopReturnType + ")");
+ }
+
+ if (!pred.stream().filter(Objects::nonNull).findFirst().isPresent()) {
+ throw newIllegalArgumentException("no predicate found", pred);
+ }
+ if (pred.stream().filter(Objects::nonNull).map(MethodHandle::type).map(MethodType::returnType).
+ anyMatch(t -> t != boolean.class)) {
+ throw newIllegalArgumentException("predicates must have boolean return type", pred);
+ }
+ }
+
+ private static void loopChecks2(List<MethodHandle> step, List<MethodHandle> pred, List<MethodHandle> fini, List<Class<?>> commonParameterSequence) {
+ if (Stream.of(step, pred, fini).flatMap(List::stream).filter(Objects::nonNull).map(MethodHandle::type).
+ anyMatch(t -> !t.effectivelyIdenticalParameters(0, commonParameterSequence))) {
+ throw newIllegalArgumentException("found non-effectively identical parameter type lists:\nstep: " + step +
+ "\npred: " + pred + "\nfini: " + fini + " (common parameter sequence: " + commonParameterSequence + ")");
+ }
+ }
+
+ private static List<MethodHandle> fillParameterTypes(List<MethodHandle> hs, final List<Class<?>> targetParams) {
+ return hs.stream().map(h -> {
+ int pc = h.type().parameterCount();
+ int tpsize = targetParams.size();
+ return pc < tpsize ? dropArguments0(h, pc, targetParams.subList(pc, tpsize)) : h;
+ }).collect(Collectors.toList());
+ }
+
+ private static List<MethodHandle> fixArities(List<MethodHandle> hs) {
+ return hs.stream().map(MethodHandle::asFixedArity).collect(Collectors.toList());
+ }
+
+ /**
+ * Constructs a {@code while} loop from an initializer, a body, and a predicate.
+ * This is a convenience wrapper for the {@linkplain #loop(MethodHandle[][]) generic loop combinator}.
+ * <p>
+ * The {@code pred} handle describes the loop condition; and {@code body}, its body. The loop resulting from this
+ * method will, in each iteration, first evaluate the predicate and then execute its body (if the predicate
+ * evaluates to {@code true}).
+ * The loop will terminate once the predicate evaluates to {@code false} (the body will not be executed in this case).
+ * <p>
+ * The {@code init} handle describes the initial value of an additional optional loop-local variable.
+ * In each iteration, this loop-local variable, if present, will be passed to the {@code body}
+ * and updated with the value returned from its invocation. The result of loop execution will be
+ * the final value of the additional loop-local variable (if present).
+ * <p>
+ * The following rules hold for these argument handles:<ul>
+ * <li>The {@code body} handle must not be {@code null}; its type must be of the form
+ * {@code (V A...)V}, where {@code V} is non-{@code void}, or else {@code (A...)void}.
+ * (In the {@code void} case, we assign the type {@code void} to the name {@code V},
+ * and we will write {@code (V A...)V} with the understanding that a {@code void} type {@code V}
+ * is quietly dropped from the parameter list, leaving {@code (A...)V}.)
+ * <li>The parameter list {@code (V A...)} of the body is called the <em>internal parameter list</em>.
+ * It will constrain the parameter lists of the other loop parts.
+ * <li>If the iteration variable type {@code V} is dropped from the internal parameter list, the resulting shorter
+ * list {@code (A...)} is called the <em>external parameter list</em>.
+ * <li>The body return type {@code V}, if non-{@code void}, determines the type of an
+ * additional state variable of the loop.
+ * The body must both accept and return a value of this type {@code V}.
+ * <li>If {@code init} is non-{@code null}, it must have return type {@code V}.
+ * Its parameter list (of some <a href="MethodHandles.html#astar">form {@code (A*)}</a>) must be
+ * <a href="MethodHandles.html#effid">effectively identical</a>
+ * to the external parameter list {@code (A...)}.
+ * <li>If {@code init} is {@code null}, the loop variable will be initialized to its
+ * {@linkplain #empty default value}.
+ * <li>The {@code pred} handle must not be {@code null}. It must have {@code boolean} as its return type.
+ * Its parameter list (either empty or of the form {@code (V A*)}) must be
+ * effectively identical to the internal parameter list.
+ * </ul>
+ * <p>
+ * The resulting loop handle's result type and parameter signature are determined as follows:<ul>
+ * <li>The loop handle's result type is the result type {@code V} of the body.
+ * <li>The loop handle's parameter types are the types {@code (A...)},
+ * from the external parameter list.
+ * </ul>
+ * <p>
+ * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the type / value of
+ * the sole loop variable as well as the result type of the loop; and {@code A}/{@code a}, that of the argument
+ * passed to the loop.
+ * <blockquote><pre>{@code
+ * V init(A...);
+ * boolean pred(V, A...);
+ * V body(V, A...);
+ * V whileLoop(A... a...) {
+ * V v = init(a...);
+ * while (pred(v, a...)) {
+ * v = body(v, a...);
+ * }
+ * return v;
+ * }
+ * }</pre></blockquote>
+ *
+ * @apiNote Example:
+ * <blockquote><pre>{@code
+ * // implement the zip function for lists as a loop handle
+ * static List<String> initZip(Iterator<String> a, Iterator<String> b) { return new ArrayList<>(); }
+ * static boolean zipPred(List<String> zip, Iterator<String> a, Iterator<String> b) { return a.hasNext() && b.hasNext(); }
+ * static List<String> zipStep(List<String> zip, Iterator<String> a, Iterator<String> b) {
+ * zip.add(a.next());
+ * zip.add(b.next());
+ * return zip;
+ * }
+ * // assume MH_initZip, MH_zipPred, and MH_zipStep are handles to the above methods
+ * MethodHandle loop = MethodHandles.whileLoop(MH_initZip, MH_zipPred, MH_zipStep);
+ * List<String> a = Arrays.asList("a", "b", "c", "d");
+ * List<String> b = Arrays.asList("e", "f", "g", "h");
+ * List<String> zipped = Arrays.asList("a", "e", "b", "f", "c", "g", "d", "h");
+ * assertEquals(zipped, (List<String>) loop.invoke(a.iterator(), b.iterator()));
+ * }</pre></blockquote>
+ *
+ *
+ * @apiNote The implementation of this method can be expressed as follows:
+ * <blockquote><pre>{@code
+ * MethodHandle whileLoop(MethodHandle init, MethodHandle pred, MethodHandle body) {
+ * MethodHandle fini = (body.type().returnType() == void.class
+ * ? null : identity(body.type().returnType()));
+ * MethodHandle[]
+ * checkExit = { null, null, pred, fini },
+ * varBody = { init, body };
+ * return loop(checkExit, varBody);
+ * }
+ * }</pre></blockquote>
+ *
+ * @param init optional initializer, providing the initial value of the loop variable.
+ * May be {@code null}, implying a default initial value. See above for other constraints.
+ * @param pred condition for the loop, which may not be {@code null}. Its result type must be {@code boolean}. See
+ * above for other constraints.
+ * @param body body of the loop, which may not be {@code null}. It controls the loop parameters and result type.
+ * See above for other constraints.
+ *
+ * @return a method handle implementing the {@code while} loop as described by the arguments.
+ * @throws IllegalArgumentException if the rules for the arguments are violated.
+ * @throws NullPointerException if {@code pred} or {@code body} are {@code null}.
+ *
+ * @see #loop(MethodHandle[][])
+ * @see #doWhileLoop(MethodHandle, MethodHandle, MethodHandle)
+ * @since 9
+ */
+ public static MethodHandle whileLoop(MethodHandle init, MethodHandle pred, MethodHandle body) {
+ whileLoopChecks(init, pred, body);
+ MethodHandle fini = identityOrVoid(body.type().returnType());
+ MethodHandle[] checkExit = { null, null, pred, fini };
+ MethodHandle[] varBody = { init, body };
+ return loop(checkExit, varBody);
+ }
+
+ /**
+ * Constructs a {@code do-while} loop from an initializer, a body, and a predicate.
+ * This is a convenience wrapper for the {@linkplain #loop(MethodHandle[][]) generic loop combinator}.
+ * <p>
+ * The {@code pred} handle describes the loop condition; and {@code body}, its body. The loop resulting from this
+ * method will, in each iteration, first execute its body and then evaluate the predicate.
+ * The loop will terminate once the predicate evaluates to {@code false} after an execution of the body.
+ * <p>
+ * The {@code init} handle describes the initial value of an additional optional loop-local variable.
+ * In each iteration, this loop-local variable, if present, will be passed to the {@code body}
+ * and updated with the value returned from its invocation. The result of loop execution will be
+ * the final value of the additional loop-local variable (if present).
+ * <p>
+ * The following rules hold for these argument handles:<ul>
+ * <li>The {@code body} handle must not be {@code null}; its type must be of the form
+ * {@code (V A...)V}, where {@code V} is non-{@code void}, or else {@code (A...)void}.
+ * (In the {@code void} case, we assign the type {@code void} to the name {@code V},
+ * and we will write {@code (V A...)V} with the understanding that a {@code void} type {@code V}
+ * is quietly dropped from the parameter list, leaving {@code (A...)V}.)
+ * <li>The parameter list {@code (V A...)} of the body is called the <em>internal parameter list</em>.
+ * It will constrain the parameter lists of the other loop parts.
+ * <li>If the iteration variable type {@code V} is dropped from the internal parameter list, the resulting shorter
+ * list {@code (A...)} is called the <em>external parameter list</em>.
+ * <li>The body return type {@code V}, if non-{@code void}, determines the type of an
+ * additional state variable of the loop.
+ * The body must both accept and return a value of this type {@code V}.
+ * <li>If {@code init} is non-{@code null}, it must have return type {@code V}.
+ * Its parameter list (of some <a href="MethodHandles.html#astar">form {@code (A*)}</a>) must be
+ * <a href="MethodHandles.html#effid">effectively identical</a>
+ * to the external parameter list {@code (A...)}.
+ * <li>If {@code init} is {@code null}, the loop variable will be initialized to its
+ * {@linkplain #empty default value}.
+ * <li>The {@code pred} handle must not be {@code null}. It must have {@code boolean} as its return type.
+ * Its parameter list (either empty or of the form {@code (V A*)}) must be
+ * effectively identical to the internal parameter list.
+ * </ul>
+ * <p>
+ * The resulting loop handle's result type and parameter signature are determined as follows:<ul>
+ * <li>The loop handle's result type is the result type {@code V} of the body.
+ * <li>The loop handle's parameter types are the types {@code (A...)},
+ * from the external parameter list.
+ * </ul>
+ * <p>
+ * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the type / value of
+ * the sole loop variable as well as the result type of the loop; and {@code A}/{@code a}, that of the argument
+ * passed to the loop.
+ * <blockquote><pre>{@code
+ * V init(A...);
+ * boolean pred(V, A...);
+ * V body(V, A...);
+ * V doWhileLoop(A... a...) {
+ * V v = init(a...);
+ * do {
+ * v = body(v, a...);
+ * } while (pred(v, a...));
+ * return v;
+ * }
+ * }</pre></blockquote>
+ *
+ * @apiNote Example:
+ * <blockquote><pre>{@code
+ * // int i = 0; while (i < limit) { ++i; } return i; => limit
+ * static int zero(int limit) { return 0; }
+ * static int step(int i, int limit) { return i + 1; }
+ * static boolean pred(int i, int limit) { return i < limit; }
+ * // assume MH_zero, MH_step, and MH_pred are handles to the above methods
+ * MethodHandle loop = MethodHandles.doWhileLoop(MH_zero, MH_step, MH_pred);
+ * assertEquals(23, loop.invoke(23));
+ * }</pre></blockquote>
+ *
+ *
+ * @apiNote The implementation of this method can be expressed as follows:
+ * <blockquote><pre>{@code
+ * MethodHandle doWhileLoop(MethodHandle init, MethodHandle body, MethodHandle pred) {
+ * MethodHandle fini = (body.type().returnType() == void.class
+ * ? null : identity(body.type().returnType()));
+ * MethodHandle[] clause = { init, body, pred, fini };
+ * return loop(clause);
+ * }
+ * }</pre></blockquote>
+ *
+ * @param init optional initializer, providing the initial value of the loop variable.
+ * May be {@code null}, implying a default initial value. See above for other constraints.
+ * @param body body of the loop, which may not be {@code null}. It controls the loop parameters and result type.
+ * See above for other constraints.
+ * @param pred condition for the loop, which may not be {@code null}. Its result type must be {@code boolean}. See
+ * above for other constraints.
+ *
+ * @return a method handle implementing the {@code while} loop as described by the arguments.
+ * @throws IllegalArgumentException if the rules for the arguments are violated.
+ * @throws NullPointerException if {@code pred} or {@code body} are {@code null}.
+ *
+ * @see #loop(MethodHandle[][])
+ * @see #whileLoop(MethodHandle, MethodHandle, MethodHandle)
+ * @since 9
+ */
+ public static MethodHandle doWhileLoop(MethodHandle init, MethodHandle body, MethodHandle pred) {
+ whileLoopChecks(init, pred, body);
+ MethodHandle fini = identityOrVoid(body.type().returnType());
+ MethodHandle[] clause = {init, body, pred, fini };
+ return loop(clause);
+ }
+
+ private static void whileLoopChecks(MethodHandle init, MethodHandle pred, MethodHandle body) {
+ Objects.requireNonNull(pred);
+ Objects.requireNonNull(body);
+ MethodType bodyType = body.type();
+ Class<?> returnType = bodyType.returnType();
+ List<Class<?>> innerList = bodyType.parameterList();
+ List<Class<?>> outerList = innerList;
+ if (returnType == void.class) {
+ // OK
+ } else if (innerList.size() == 0 || innerList.get(0) != returnType) {
+ // leading V argument missing => error
+ MethodType expected = bodyType.insertParameterTypes(0, returnType);
+ throw misMatchedTypes("body function", bodyType, expected);
+ } else {
+ outerList = innerList.subList(1, innerList.size());
+ }
+ MethodType predType = pred.type();
+ if (predType.returnType() != boolean.class ||
+ !predType.effectivelyIdenticalParameters(0, innerList)) {
+ throw misMatchedTypes("loop predicate", predType, methodType(boolean.class, innerList));
+ }
+ if (init != null) {
+ MethodType initType = init.type();
+ if (initType.returnType() != returnType ||
+ !initType.effectivelyIdenticalParameters(0, outerList)) {
+ throw misMatchedTypes("loop initializer", initType, methodType(returnType, outerList));
+ }
+ }
+ }
+
+ /**
+ * Constructs a loop that runs a given number of iterations.
+ * This is a convenience wrapper for the {@linkplain #loop(MethodHandle[][]) generic loop combinator}.
+ * <p>
+ * The number of iterations is determined by the {@code iterations} handle evaluation result.
+ * The loop counter {@code i} is an extra loop iteration variable of type {@code int}.
+ * It will be initialized to 0 and incremented by 1 in each iteration.
+ * <p>
+ * If the {@code body} handle returns a non-{@code void} type {@code V}, a leading loop iteration variable
+ * of that type is also present. This variable is initialized using the optional {@code init} handle,
+ * or to the {@linkplain #empty default value} of type {@code V} if that handle is {@code null}.
+ * <p>
+ * In each iteration, the iteration variables are passed to an invocation of the {@code body} handle.
+ * A non-{@code void} value returned from the body (of type {@code V}) updates the leading
+ * iteration variable.
+ * The result of the loop handle execution will be the final {@code V} value of that variable
+ * (or {@code void} if there is no {@code V} variable).
+ * <p>
+ * The following rules hold for the argument handles:<ul>
+ * <li>The {@code iterations} handle must not be {@code null}, and must return
+ * the type {@code int}, referred to here as {@code I} in parameter type lists.
+ * <li>The {@code body} handle must not be {@code null}; its type must be of the form
+ * {@code (V I A...)V}, where {@code V} is non-{@code void}, or else {@code (I A...)void}.
+ * (In the {@code void} case, we assign the type {@code void} to the name {@code V},
+ * and we will write {@code (V I A...)V} with the understanding that a {@code void} type {@code V}
+ * is quietly dropped from the parameter list, leaving {@code (I A...)V}.)
+ * <li>The parameter list {@code (V I A...)} of the body contributes to a list
+ * of types called the <em>internal parameter list</em>.
+ * It will constrain the parameter lists of the other loop parts.
+ * <li>As a special case, if the body contributes only {@code V} and {@code I} types,
+ * with no additional {@code A} types, then the internal parameter list is extended by
+ * the argument types {@code A...} of the {@code iterations} handle.
+ * <li>If the iteration variable types {@code (V I)} are dropped from the internal parameter list, the resulting shorter
+ * list {@code (A...)} is called the <em>external parameter list</em>.
+ * <li>The body return type {@code V}, if non-{@code void}, determines the type of an
+ * additional state variable of the loop.
+ * The body must both accept a leading parameter and return a value of this type {@code V}.
+ * <li>If {@code init} is non-{@code null}, it must have return type {@code V}.
+ * Its parameter list (of some <a href="MethodHandles.html#astar">form {@code (A*)}</a>) must be
+ * <a href="MethodHandles.html#effid">effectively identical</a>
+ * to the external parameter list {@code (A...)}.
+ * <li>If {@code init} is {@code null}, the loop variable will be initialized to its
+ * {@linkplain #empty default value}.
+ * <li>The parameter list of {@code iterations} (of some form {@code (A*)}) must be
+ * effectively identical to the external parameter list {@code (A...)}.
+ * </ul>
+ * <p>
+ * The resulting loop handle's result type and parameter signature are determined as follows:<ul>
+ * <li>The loop handle's result type is the result type {@code V} of the body.
+ * <li>The loop handle's parameter types are the types {@code (A...)},
+ * from the external parameter list.
+ * </ul>
+ * <p>
+ * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the type / value of
+ * the second loop variable as well as the result type of the loop; and {@code A...}/{@code a...} represent
+ * arguments passed to the loop.
+ * <blockquote><pre>{@code
+ * int iterations(A...);
+ * V init(A...);
+ * V body(V, int, A...);
+ * V countedLoop(A... a...) {
+ * int end = iterations(a...);
+ * V v = init(a...);
+ * for (int i = 0; i < end; ++i) {
+ * v = body(v, i, a...);
+ * }
+ * return v;
+ * }
+ * }</pre></blockquote>
+ *
+ * @apiNote Example with a fully conformant body method:
+ * <blockquote><pre>{@code
+ * // String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s;
+ * // => a variation on a well known theme
+ * static String step(String v, int counter, String init) { return "na " + v; }
+ * // assume MH_step is a handle to the method above
+ * MethodHandle fit13 = MethodHandles.constant(int.class, 13);
+ * MethodHandle start = MethodHandles.identity(String.class);
+ * MethodHandle loop = MethodHandles.countedLoop(fit13, start, MH_step);
+ * assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("Lambdaman!"));
+ * }</pre></blockquote>
+ *
+ * @apiNote Example with the simplest possible body method type,
+ * and passing the number of iterations to the loop invocation:
+ * <blockquote><pre>{@code
+ * // String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s;
+ * // => a variation on a well known theme
+ * static String step(String v, int counter ) { return "na " + v; }
+ * // assume MH_step is a handle to the method above
+ * MethodHandle count = MethodHandles.dropArguments(MethodHandles.identity(int.class), 1, String.class);
+ * MethodHandle start = MethodHandles.dropArguments(MethodHandles.identity(String.class), 0, int.class);
+ * MethodHandle loop = MethodHandles.countedLoop(count, start, MH_step); // (v, i) -> "na " + v
+ * assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke(13, "Lambdaman!"));
+ * }</pre></blockquote>
+ *
+ * @apiNote Example that treats the number of iterations, string to append to, and string to append
+ * as loop parameters:
+ * <blockquote><pre>{@code
+ * // String s = "Lambdaman!", t = "na"; for (int i = 0; i < 13; ++i) { s = t + " " + s; } return s;
+ * // => a variation on a well known theme
+ * static String step(String v, int counter, int iterations_, String pre, String start_) { return pre + " " + v; }
+ * // assume MH_step is a handle to the method above
+ * MethodHandle count = MethodHandles.identity(int.class);
+ * MethodHandle start = MethodHandles.dropArguments(MethodHandles.identity(String.class), 0, int.class, String.class);
+ * MethodHandle loop = MethodHandles.countedLoop(count, start, MH_step); // (v, i, _, pre, _) -> pre + " " + v
+ * assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke(13, "na", "Lambdaman!"));
+ * }</pre></blockquote>
+ *
+ * @apiNote Example that illustrates the usage of {@link #dropArgumentsToMatch(MethodHandle, int, List, int)}
+ * to enforce a loop type:
+ * <blockquote><pre>{@code
+ * // String s = "Lambdaman!", t = "na"; for (int i = 0; i < 13; ++i) { s = t + " " + s; } return s;
+ * // => a variation on a well known theme
+ * static String step(String v, int counter, String pre) { return pre + " " + v; }
+ * // assume MH_step is a handle to the method above
+ * MethodType loopType = methodType(String.class, String.class, int.class, String.class);
+ * MethodHandle count = MethodHandles.dropArgumentsToMatch(MethodHandles.identity(int.class), 0, loopType.parameterList(), 1);
+ * MethodHandle start = MethodHandles.dropArgumentsToMatch(MethodHandles.identity(String.class), 0, loopType.parameterList(), 2);
+ * MethodHandle body = MethodHandles.dropArgumentsToMatch(MH_step, 2, loopType.parameterList(), 0);
+ * MethodHandle loop = MethodHandles.countedLoop(count, start, body); // (v, i, pre, _, _) -> pre + " " + v
+ * assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("na", 13, "Lambdaman!"));
+ * }</pre></blockquote>
+ *
+ * @apiNote The implementation of this method can be expressed as follows:
+ * <blockquote><pre>{@code
+ * MethodHandle countedLoop(MethodHandle iterations, MethodHandle init, MethodHandle body) {
+ * return countedLoop(empty(iterations.type()), iterations, init, body);
+ * }
+ * }</pre></blockquote>
+ *
+ * @param iterations a non-{@code null} handle to return the number of iterations this loop should run. The handle's
+ * result type must be {@code int}. See above for other constraints.
+ * @param init optional initializer, providing the initial value of the loop variable.
+ * May be {@code null}, implying a default initial value. See above for other constraints.
+ * @param body body of the loop, which may not be {@code null}.
+ * It controls the loop parameters and result type in the standard case (see above for details).
+ * It must accept its own return type (if non-void) plus an {@code int} parameter (for the counter),
+ * and may accept any number of additional types.
+ * See above for other constraints.
+ *
+ * @return a method handle representing the loop.
+ * @throws NullPointerException if either of the {@code iterations} or {@code body} handles is {@code null}.
+ * @throws IllegalArgumentException if any argument violates the rules formulated above.
+ *
+ * @see #countedLoop(MethodHandle, MethodHandle, MethodHandle, MethodHandle)
+ * @since 9
+ */
+ public static MethodHandle countedLoop(MethodHandle iterations, MethodHandle init, MethodHandle body) {
+ return countedLoop(empty(iterations.type()), iterations, init, body);
+ }
+
+ /**
+ * Constructs a loop that counts over a range of numbers.
+ * This is a convenience wrapper for the {@linkplain #loop(MethodHandle[][]) generic loop combinator}.
+ * <p>
+ * The loop counter {@code i} is a loop iteration variable of type {@code int}.
+ * The {@code start} and {@code end} handles determine the start (inclusive) and end (exclusive)
+ * values of the loop counter.
+ * The loop counter will be initialized to the {@code int} value returned from the evaluation of the
+ * {@code start} handle and run to the value returned from {@code end} (exclusively) with a step width of 1.
+ * <p>
+ * If the {@code body} handle returns a non-{@code void} type {@code V}, a leading loop iteration variable
+ * of that type is also present. This variable is initialized using the optional {@code init} handle,
+ * or to the {@linkplain #empty default value} of type {@code V} if that handle is {@code null}.
+ * <p>
+ * In each iteration, the iteration variables are passed to an invocation of the {@code body} handle.
+ * A non-{@code void} value returned from the body (of type {@code V}) updates the leading
+ * iteration variable.
+ * The result of the loop handle execution will be the final {@code V} value of that variable
+ * (or {@code void} if there is no {@code V} variable).
+ * <p>
+ * The following rules hold for the argument handles:<ul>
+ * <li>The {@code start} and {@code end} handles must not be {@code null}, and must both return
+ * the common type {@code int}, referred to here as {@code I} in parameter type lists.
+ * <li>The {@code body} handle must not be {@code null}; its type must be of the form
+ * {@code (V I A...)V}, where {@code V} is non-{@code void}, or else {@code (I A...)void}.
+ * (In the {@code void} case, we assign the type {@code void} to the name {@code V},
+ * and we will write {@code (V I A...)V} with the understanding that a {@code void} type {@code V}
+ * is quietly dropped from the parameter list, leaving {@code (I A...)V}.)
+ * <li>The parameter list {@code (V I A...)} of the body contributes to a list
+ * of types called the <em>internal parameter list</em>.
+ * It will constrain the parameter lists of the other loop parts.
+ * <li>As a special case, if the body contributes only {@code V} and {@code I} types,
+ * with no additional {@code A} types, then the internal parameter list is extended by
+ * the argument types {@code A...} of the {@code end} handle.
+ * <li>If the iteration variable types {@code (V I)} are dropped from the internal parameter list, the resulting shorter
+ * list {@code (A...)} is called the <em>external parameter list</em>.
+ * <li>The body return type {@code V}, if non-{@code void}, determines the type of an
+ * additional state variable of the loop.
+ * The body must both accept a leading parameter and return a value of this type {@code V}.
+ * <li>If {@code init} is non-{@code null}, it must have return type {@code V}.
+ * Its parameter list (of some <a href="MethodHandles.html#astar">form {@code (A*)}</a>) must be
+ * <a href="MethodHandles.html#effid">effectively identical</a>
+ * to the external parameter list {@code (A...)}.
+ * <li>If {@code init} is {@code null}, the loop variable will be initialized to its
+ * {@linkplain #empty default value}.
+ * <li>The parameter list of {@code start} (of some form {@code (A*)}) must be
+ * effectively identical to the external parameter list {@code (A...)}.
+ * <li>Likewise, the parameter list of {@code end} must be effectively identical
+ * to the external parameter list.
+ * </ul>
+ * <p>
+ * The resulting loop handle's result type and parameter signature are determined as follows:<ul>
+ * <li>The loop handle's result type is the result type {@code V} of the body.
+ * <li>The loop handle's parameter types are the types {@code (A...)},
+ * from the external parameter list.
+ * </ul>
+ * <p>
+ * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the type / value of
+ * the second loop variable as well as the result type of the loop; and {@code A...}/{@code a...} represent
+ * arguments passed to the loop.
+ * <blockquote><pre>{@code
+ * int start(A...);
+ * int end(A...);
+ * V init(A...);
+ * V body(V, int, A...);
+ * V countedLoop(A... a...) {
+ * int e = end(a...);
+ * int s = start(a...);
+ * V v = init(a...);
+ * for (int i = s; i < e; ++i) {
+ * v = body(v, i, a...);
+ * }
+ * return v;
+ * }
+ * }</pre></blockquote>
+ *
+ * @apiNote The implementation of this method can be expressed as follows:
+ * <blockquote><pre>{@code
+ * MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) {
+ * MethodHandle returnVar = dropArguments(identity(init.type().returnType()), 0, int.class, int.class);
+ * // assume MH_increment and MH_predicate are handles to implementation-internal methods with
+ * // the following semantics:
+ * // MH_increment: (int limit, int counter) -> counter + 1
+ * // MH_predicate: (int limit, int counter) -> counter < limit
+ * Class<?> counterType = start.type().returnType(); // int
+ * Class<?> returnType = body.type().returnType();
+ * MethodHandle incr = MH_increment, pred = MH_predicate, retv = null;
+ * if (returnType != void.class) { // ignore the V variable
+ * incr = dropArguments(incr, 1, returnType); // (limit, v, i) => (limit, i)
+ * pred = dropArguments(pred, 1, returnType); // ditto
+ * retv = dropArguments(identity(returnType), 0, counterType); // ignore limit
+ * }
+ * body = dropArguments(body, 0, counterType); // ignore the limit variable
+ * MethodHandle[]
+ * loopLimit = { end, null, pred, retv }, // limit = end(); i < limit || return v
+ * bodyClause = { init, body }, // v = init(); v = body(v, i)
+ * indexVar = { start, incr }; // i = start(); i = i + 1
+ * return loop(loopLimit, bodyClause, indexVar);
+ * }
+ * }</pre></blockquote>
+ *
+ * @param start a non-{@code null} handle to return the start value of the loop counter, which must be {@code int}.
+ * See above for other constraints.
+ * @param end a non-{@code null} handle to return the end value of the loop counter (the loop will run to
+ * {@code end-1}). The result type must be {@code int}. See above for other constraints.
+ * @param init optional initializer, providing the initial value of the loop variable.
+ * May be {@code null}, implying a default initial value. See above for other constraints.
+ * @param body body of the loop, which may not be {@code null}.
+ * It controls the loop parameters and result type in the standard case (see above for details).
+ * It must accept its own return type (if non-void) plus an {@code int} parameter (for the counter),
+ * and may accept any number of additional types.
+ * See above for other constraints.
+ *
+ * @return a method handle representing the loop.
+ * @throws NullPointerException if any of the {@code start}, {@code end}, or {@code body} handles is {@code null}.
+ * @throws IllegalArgumentException if any argument violates the rules formulated above.
+ *
+ * @see #countedLoop(MethodHandle, MethodHandle, MethodHandle)
+ * @since 9
+ */
+ public static MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) {
+ countedLoopChecks(start, end, init, body);
+ Class<?> counterType = start.type().returnType(); // int, but who's counting?
+ Class<?> limitType = end.type().returnType(); // yes, int again
+ Class<?> returnType = body.type().returnType();
+ // Android-changed: getConstantHandle is in MethodHandles.
+ // MethodHandle incr = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopStep);
+ // MethodHandle pred = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopPred);
+ MethodHandle incr = getConstantHandle(MH_countedLoopStep);
+ MethodHandle pred = getConstantHandle(MH_countedLoopPred);
+ MethodHandle retv = null;
+ if (returnType != void.class) {
+ incr = dropArguments(incr, 1, returnType); // (limit, v, i) => (limit, i)
+ pred = dropArguments(pred, 1, returnType); // ditto
+ retv = dropArguments(identity(returnType), 0, counterType);
+ }
+ body = dropArguments(body, 0, counterType); // ignore the limit variable
+ MethodHandle[]
+ loopLimit = { end, null, pred, retv }, // limit = end(); i < limit || return v
+ bodyClause = { init, body }, // v = init(); v = body(v, i)
+ indexVar = { start, incr }; // i = start(); i = i + 1
+ return loop(loopLimit, bodyClause, indexVar);
+ }
+
+ private static void countedLoopChecks(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) {
+ Objects.requireNonNull(start);
+ Objects.requireNonNull(end);
+ Objects.requireNonNull(body);
+ Class<?> counterType = start.type().returnType();
+ if (counterType != int.class) {
+ MethodType expected = start.type().changeReturnType(int.class);
+ throw misMatchedTypes("start function", start.type(), expected);
+ } else if (end.type().returnType() != counterType) {
+ MethodType expected = end.type().changeReturnType(counterType);
+ throw misMatchedTypes("end function", end.type(), expected);
+ }
+ MethodType bodyType = body.type();
+ Class<?> returnType = bodyType.returnType();
+ List<Class<?>> innerList = bodyType.parameterList();
+ // strip leading V value if present
+ int vsize = (returnType == void.class ? 0 : 1);
+ if (vsize != 0 && (innerList.size() == 0 || innerList.get(0) != returnType)) {
+ // argument list has no "V" => error
+ MethodType expected = bodyType.insertParameterTypes(0, returnType);
+ throw misMatchedTypes("body function", bodyType, expected);
+ } else if (innerList.size() <= vsize || innerList.get(vsize) != counterType) {
+ // missing I type => error
+ MethodType expected = bodyType.insertParameterTypes(vsize, counterType);
+ throw misMatchedTypes("body function", bodyType, expected);
+ }
+ List<Class<?>> outerList = innerList.subList(vsize + 1, innerList.size());
+ if (outerList.isEmpty()) {
+ // special case; take lists from end handle
+ outerList = end.type().parameterList();
+ innerList = bodyType.insertParameterTypes(vsize + 1, outerList).parameterList();
+ }
+ MethodType expected = methodType(counterType, outerList);
+ if (!start.type().effectivelyIdenticalParameters(0, outerList)) {
+ throw misMatchedTypes("start parameter types", start.type(), expected);
+ }
+ if (end.type() != start.type() &&
+ !end.type().effectivelyIdenticalParameters(0, outerList)) {
+ throw misMatchedTypes("end parameter types", end.type(), expected);
+ }
+ if (init != null) {
+ MethodType initType = init.type();
+ if (initType.returnType() != returnType ||
+ !initType.effectivelyIdenticalParameters(0, outerList)) {
+ throw misMatchedTypes("loop initializer", initType, methodType(returnType, outerList));
+ }
+ }
+ }
+
+ /**
+ * Constructs a loop that ranges over the values produced by an {@code Iterator<T>}.
+ * This is a convenience wrapper for the {@linkplain #loop(MethodHandle[][]) generic loop combinator}.
+ * <p>
+ * The iterator itself will be determined by the evaluation of the {@code iterator} handle.
+ * Each value it produces will be stored in a loop iteration variable of type {@code T}.
+ * <p>
+ * If the {@code body} handle returns a non-{@code void} type {@code V}, a leading loop iteration variable
+ * of that type is also present. This variable is initialized using the optional {@code init} handle,
+ * or to the {@linkplain #empty default value} of type {@code V} if that handle is {@code null}.
+ * <p>
+ * In each iteration, the iteration variables are passed to an invocation of the {@code body} handle.
+ * A non-{@code void} value returned from the body (of type {@code V}) updates the leading
+ * iteration variable.
+ * The result of the loop handle execution will be the final {@code V} value of that variable
+ * (or {@code void} if there is no {@code V} variable).
+ * <p>
+ * The following rules hold for the argument handles:<ul>
+ * <li>The {@code body} handle must not be {@code null}; its type must be of the form
+ * {@code (V T A...)V}, where {@code V} is non-{@code void}, or else {@code (T A...)void}.
+ * (In the {@code void} case, we assign the type {@code void} to the name {@code V},
+ * and we will write {@code (V T A...)V} with the understanding that a {@code void} type {@code V}
+ * is quietly dropped from the parameter list, leaving {@code (T A...)V}.)
+ * <li>The parameter list {@code (V T A...)} of the body contributes to a list
+ * of types called the <em>internal parameter list</em>.
+ * It will constrain the parameter lists of the other loop parts.
+ * <li>As a special case, if the body contributes only {@code V} and {@code T} types,
+ * with no additional {@code A} types, then the internal parameter list is extended by
+ * the argument types {@code A...} of the {@code iterator} handle; if it is {@code null} the
+ * single type {@code Iterable} is added and constitutes the {@code A...} list.
+ * <li>If the iteration variable types {@code (V T)} are dropped from the internal parameter list, the resulting shorter
+ * list {@code (A...)} is called the <em>external parameter list</em>.
+ * <li>The body return type {@code V}, if non-{@code void}, determines the type of an
+ * additional state variable of the loop.
+ * The body must both accept a leading parameter and return a value of this type {@code V}.
+ * <li>If {@code init} is non-{@code null}, it must have return type {@code V}.
+ * Its parameter list (of some <a href="MethodHandles.html#astar">form {@code (A*)}</a>) must be
+ * <a href="MethodHandles.html#effid">effectively identical</a>
+ * to the external parameter list {@code (A...)}.
+ * <li>If {@code init} is {@code null}, the loop variable will be initialized to its
+ * {@linkplain #empty default value}.
+ * <li>If the {@code iterator} handle is non-{@code null}, it must have the return
+ * type {@code java.util.Iterator} or a subtype thereof.
+ * The iterator it produces when the loop is executed will be assumed
+ * to yield values which can be converted to type {@code T}.
+ * <li>The parameter list of an {@code iterator} that is non-{@code null} (of some form {@code (A*)}) must be
+ * effectively identical to the external parameter list {@code (A...)}.
+ * <li>If {@code iterator} is {@code null} it defaults to a method handle which behaves
+ * like {@link java.lang.Iterable#iterator()}. In that case, the internal parameter list
+ * {@code (V T A...)} must have at least one {@code A} type, and the default iterator
+ * handle parameter is adjusted to accept the leading {@code A} type, as if by
+ * the {@link MethodHandle#asType asType} conversion method.
+ * The leading {@code A} type must be {@code Iterable} or a subtype thereof.
+ * This conversion step, done at loop construction time, must not throw a {@code WrongMethodTypeException}.
+ * </ul>
+ * <p>
+ * The type {@code T} may be either a primitive or reference.
+ * Since type {@code Iterator<T>} is erased in the method handle representation to the raw type {@code Iterator},
+ * the {@code iteratedLoop} combinator adjusts the leading argument type for {@code body} to {@code Object}
+ * as if by the {@link MethodHandle#asType asType} conversion method.
+ * Therefore, if an iterator of the wrong type appears as the loop is executed, runtime exceptions may occur
+ * as the result of dynamic conversions performed by {@link MethodHandle#asType(MethodType)}.
+ * <p>
+ * The resulting loop handle's result type and parameter signature are determined as follows:<ul>
+ * <li>The loop handle's result type is the result type {@code V} of the body.
+ * <li>The loop handle's parameter types are the types {@code (A...)},
+ * from the external parameter list.
+ * </ul>
+ * <p>
+ * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the type / value of
+ * the loop variable as well as the result type of the loop; {@code T}/{@code t}, that of the elements of the
+ * structure the loop iterates over, and {@code A...}/{@code a...} represent arguments passed to the loop.
+ * <blockquote><pre>{@code
+ * Iterator<T> iterator(A...); // defaults to Iterable::iterator
+ * V init(A...);
+ * V body(V,T,A...);
+ * V iteratedLoop(A... a...) {
+ * Iterator<T> it = iterator(a...);
+ * V v = init(a...);
+ * while (it.hasNext()) {
+ * T t = it.next();
+ * v = body(v, t, a...);
+ * }
+ * return v;
+ * }
+ * }</pre></blockquote>
+ *
+ * @apiNote Example:
+ * <blockquote><pre>{@code
+ * // get an iterator from a list
+ * static List<String> reverseStep(List<String> r, String e) {
+ * r.add(0, e);
+ * return r;
+ * }
+ * static List<String> newArrayList() { return new ArrayList<>(); }
+ * // assume MH_reverseStep and MH_newArrayList are handles to the above methods
+ * MethodHandle loop = MethodHandles.iteratedLoop(null, MH_newArrayList, MH_reverseStep);
+ * List<String> list = Arrays.asList("a", "b", "c", "d", "e");
+ * List<String> reversedList = Arrays.asList("e", "d", "c", "b", "a");
+ * assertEquals(reversedList, (List<String>) loop.invoke(list));
+ * }</pre></blockquote>
+ *
+ * @apiNote The implementation of this method can be expressed approximately as follows:
+ * <blockquote><pre>{@code
+ * MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body) {
+ * // assume MH_next, MH_hasNext, MH_startIter are handles to methods of Iterator/Iterable
+ * Class<?> returnType = body.type().returnType();
+ * Class<?> ttype = body.type().parameterType(returnType == void.class ? 0 : 1);
+ * MethodHandle nextVal = MH_next.asType(MH_next.type().changeReturnType(ttype));
+ * MethodHandle retv = null, step = body, startIter = iterator;
+ * if (returnType != void.class) {
+ * // the simple thing first: in (I V A...), drop the I to get V
+ * retv = dropArguments(identity(returnType), 0, Iterator.class);
+ * // body type signature (V T A...), internal loop types (I V A...)
+ * step = swapArguments(body, 0, 1); // swap V <-> T
+ * }
+ * if (startIter == null) startIter = MH_getIter;
+ * MethodHandle[]
+ * iterVar = { startIter, null, MH_hasNext, retv }, // it = iterator; while (it.hasNext())
+ * bodyClause = { init, filterArguments(step, 0, nextVal) }; // v = body(v, t, a)
+ * return loop(iterVar, bodyClause);
+ * }
+ * }</pre></blockquote>
+ *
+ * @param iterator an optional handle to return the iterator to start the loop.
+ * If non-{@code null}, the handle must return {@link java.util.Iterator} or a subtype.
+ * See above for other constraints.
+ * @param init optional initializer, providing the initial value of the loop variable.
+ * May be {@code null}, implying a default initial value. See above for other constraints.
+ * @param body body of the loop, which may not be {@code null}.
+ * It controls the loop parameters and result type in the standard case (see above for details).
+ * It must accept its own return type (if non-void) plus a {@code T} parameter (for the iterated values),
+ * and may accept any number of additional types.
+ * See above for other constraints.
+ *
+ * @return a method handle embodying the iteration loop functionality.
+ * @throws NullPointerException if the {@code body} handle is {@code null}.
+ * @throws IllegalArgumentException if any argument violates the above requirements.
+ *
+ * @since 9
+ */
+ public static MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body) {
+ Class<?> iterableType = iteratedLoopChecks(iterator, init, body);
+ Class<?> returnType = body.type().returnType();
+ // Android-changed: getConstantHandle is in MethodHandles.
+ // MethodHandle hasNext = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iteratePred);
+ // MethodHandle nextRaw = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iterateNext);
+ MethodHandle hasNext = getConstantHandle(MH_iteratePred);
+ MethodHandle nextRaw = getConstantHandle(MH_iterateNext);
+ MethodHandle startIter;
+ MethodHandle nextVal;
+ {
+ MethodType iteratorType;
+ if (iterator == null) {
+ // derive argument type from body, if available, else use Iterable
+ // Android-changed: getConstantHandle is in MethodHandles.
+ // startIter = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_initIterator);
+ startIter = getConstantHandle(MH_initIterator);
+ iteratorType = startIter.type().changeParameterType(0, iterableType);
+ } else {
+ // force return type to the internal iterator class
+ iteratorType = iterator.type().changeReturnType(Iterator.class);
+ startIter = iterator;
+ }
+ Class<?> ttype = body.type().parameterType(returnType == void.class ? 0 : 1);
+ MethodType nextValType = nextRaw.type().changeReturnType(ttype);
+
+ // perform the asType transforms under an exception transformer, as per spec.:
+ try {
+ startIter = startIter.asType(iteratorType);
+ nextVal = nextRaw.asType(nextValType);
+ } catch (WrongMethodTypeException ex) {
+ throw new IllegalArgumentException(ex);
+ }
+ }
+
+ MethodHandle retv = null, step = body;
+ if (returnType != void.class) {
+ // the simple thing first: in (I V A...), drop the I to get V
+ retv = dropArguments(identity(returnType), 0, Iterator.class);
+ // body type signature (V T A...), internal loop types (I V A...)
+ step = swapArguments(body, 0, 1); // swap V <-> T
+ }
+
+ MethodHandle[]
+ iterVar = { startIter, null, hasNext, retv },
+ bodyClause = { init, filterArgument(step, 0, nextVal) };
+ return loop(iterVar, bodyClause);
+ }
+
+ private static Class<?> iteratedLoopChecks(MethodHandle iterator, MethodHandle init, MethodHandle body) {
+ Objects.requireNonNull(body);
+ MethodType bodyType = body.type();
+ Class<?> returnType = bodyType.returnType();
+ List<Class<?>> internalParamList = bodyType.parameterList();
+ // strip leading V value if present
+ int vsize = (returnType == void.class ? 0 : 1);
+ if (vsize != 0 && (internalParamList.size() == 0 || internalParamList.get(0) != returnType)) {
+ // argument list has no "V" => error
+ MethodType expected = bodyType.insertParameterTypes(0, returnType);
+ throw misMatchedTypes("body function", bodyType, expected);
+ } else if (internalParamList.size() <= vsize) {
+ // missing T type => error
+ MethodType expected = bodyType.insertParameterTypes(vsize, Object.class);
+ throw misMatchedTypes("body function", bodyType, expected);
+ }
+ List<Class<?>> externalParamList = internalParamList.subList(vsize + 1, internalParamList.size());
+ Class<?> iterableType = null;
+ if (iterator != null) {
+ // special case; if the body handle only declares V and T then
+ // the external parameter list is obtained from iterator handle
+ if (externalParamList.isEmpty()) {
+ externalParamList = iterator.type().parameterList();
+ }
+ MethodType itype = iterator.type();
+ if (!Iterator.class.isAssignableFrom(itype.returnType())) {
+ throw newIllegalArgumentException("iteratedLoop first argument must have Iterator return type");
+ }
+ if (!itype.effectivelyIdenticalParameters(0, externalParamList)) {
+ MethodType expected = methodType(itype.returnType(), externalParamList);
+ throw misMatchedTypes("iterator parameters", itype, expected);
+ }
+ } else {
+ if (externalParamList.isEmpty()) {
+ // special case; if the iterator handle is null and the body handle
+ // only declares V and T then the external parameter list consists
+ // of Iterable
+ externalParamList = Arrays.asList(Iterable.class);
+ iterableType = Iterable.class;
+ } else {
+ // special case; if the iterator handle is null and the external
+ // parameter list is not empty then the first parameter must be
+ // assignable to Iterable
+ iterableType = externalParamList.get(0);
+ if (!Iterable.class.isAssignableFrom(iterableType)) {
+ throw newIllegalArgumentException(
+ "inferred first loop argument must inherit from Iterable: " + iterableType);
+ }
+ }
+ }
+ if (init != null) {
+ MethodType initType = init.type();
+ if (initType.returnType() != returnType ||
+ !initType.effectivelyIdenticalParameters(0, externalParamList)) {
+ throw misMatchedTypes("loop initializer", initType, methodType(returnType, externalParamList));
+ }
+ }
+ return iterableType; // help the caller a bit
+ }
+
+ /*non-public*/ static MethodHandle swapArguments(MethodHandle mh, int i, int j) {
+ // there should be a better way to uncross my wires
+ int arity = mh.type().parameterCount();
+ int[] order = new int[arity];
+ for (int k = 0; k < arity; k++) order[k] = k;
+ order[i] = j; order[j] = i;
+ Class<?>[] types = mh.type().parameterArray();
+ Class<?> ti = types[i]; types[i] = types[j]; types[j] = ti;
+ MethodType swapType = methodType(mh.type().returnType(), types);
+ return permuteArguments(mh, swapType, order);
+ }
+
+ /**
+ * Makes a method handle that adapts a {@code target} method handle by wrapping it in a {@code try-finally} block.
+ * Another method handle, {@code cleanup}, represents the functionality of the {@code finally} block. Any exception
+ * thrown during the execution of the {@code target} handle will be passed to the {@code cleanup} handle. The
+ * exception will be rethrown, unless {@code cleanup} handle throws an exception first. The
+ * value returned from the {@code cleanup} handle's execution will be the result of the execution of the
+ * {@code try-finally} handle.
+ * <p>
+ * The {@code cleanup} handle will be passed one or two additional leading arguments.
+ * The first is the exception thrown during the
+ * execution of the {@code target} handle, or {@code null} if no exception was thrown.
+ * The second is the result of the execution of the {@code target} handle, or, if it throws an exception,
+ * a {@code null}, zero, or {@code false} value of the required type is supplied as a placeholder.
+ * The second argument is not present if the {@code target} handle has a {@code void} return type.
+ * (Note that, except for argument type conversions, combinators represent {@code void} values in parameter lists
+ * by omitting the corresponding paradoxical arguments, not by inserting {@code null} or zero values.)
+ * <p>
+ * The {@code target} and {@code cleanup} handles must have the same corresponding argument and return types, except
+ * that the {@code cleanup} handle may omit trailing arguments. Also, the {@code cleanup} handle must have one or
+ * two extra leading parameters:<ul>
+ * <li>a {@code Throwable}, which will carry the exception thrown by the {@code target} handle (if any); and
+ * <li>a parameter of the same type as the return type of both {@code target} and {@code cleanup}, which will carry
+ * the result from the execution of the {@code target} handle.
+ * This parameter is not present if the {@code target} returns {@code void}.
+ * </ul>
+ * <p>
+ * The pseudocode for the resulting adapter looks as follows. In the code, {@code V} represents the result type of
+ * the {@code try/finally} construct; {@code A}/{@code a}, the types and values of arguments to the resulting
+ * handle consumed by the cleanup; and {@code B}/{@code b}, those of arguments to the resulting handle discarded by
+ * the cleanup.
+ * <blockquote><pre>{@code
+ * V target(A..., B...);
+ * V cleanup(Throwable, V, A...);
+ * V adapter(A... a, B... b) {
+ * V result = (zero value for V);
+ * Throwable throwable = null;
+ * try {
+ * result = target(a..., b...);
+ * } catch (Throwable t) {
+ * throwable = t;
+ * throw t;
+ * } finally {
+ * result = cleanup(throwable, result, a...);
+ * }
+ * return result;
+ * }
+ * }</pre></blockquote>
+ * <p>
+ * Note that the saved arguments ({@code a...} in the pseudocode) cannot
+ * be modified by execution of the target, and so are passed unchanged
+ * from the caller to the cleanup, if it is invoked.
+ * <p>
+ * The target and cleanup must return the same type, even if the cleanup
+ * always throws.
+ * To create such a throwing cleanup, compose the cleanup logic
+ * with {@link #throwException throwException},
+ * in order to create a method handle of the correct return type.
+ * <p>
+ * Note that {@code tryFinally} never converts exceptions into normal returns.
+ * In rare cases where exceptions must be converted in that way, first wrap
+ * the target with {@link #catchException(MethodHandle, Class, MethodHandle)}
+ * to capture an outgoing exception, and then wrap with {@code tryFinally}.
+ * <p>
+ * It is recommended that the first parameter type of {@code cleanup} be
+ * declared {@code Throwable} rather than a narrower subtype. This ensures
+ * {@code cleanup} will always be invoked with whatever exception that
+ * {@code target} throws. Declaring a narrower type may result in a
+ * {@code ClassCastException} being thrown by the {@code try-finally}
+ * handle if the type of the exception thrown by {@code target} is not
+ * assignable to the first parameter type of {@code cleanup}. Note that
+ * various exception types of {@code VirtualMachineError},
+ * {@code LinkageError}, and {@code RuntimeException} can in principle be
+ * thrown by almost any kind of Java code, and a finally clause that
+ * catches (say) only {@code IOException} would mask any of the others
+ * behind a {@code ClassCastException}.
+ *
+ * @param target the handle whose execution is to be wrapped in a {@code try} block.
+ * @param cleanup the handle that is invoked in the finally block.
+ *
+ * @return a method handle embodying the {@code try-finally} block composed of the two arguments.
+ * @throws NullPointerException if any argument is null
+ * @throws IllegalArgumentException if {@code cleanup} does not accept
+ * the required leading arguments, or if the method handle types do
+ * not match in their return types and their
+ * corresponding trailing parameters
+ *
+ * @see MethodHandles#catchException(MethodHandle, Class, MethodHandle)
+ * @since 9
+ */
+ public static MethodHandle tryFinally(MethodHandle target, MethodHandle cleanup) {
+ List<Class<?>> targetParamTypes = target.type().parameterList();
+ Class<?> rtype = target.type().returnType();
+
+ tryFinallyChecks(target, cleanup);
+
+ // Match parameter lists: if the cleanup has a shorter parameter list than the target, add ignored arguments.
+ // The cleanup parameter list (minus the leading Throwable and result parameters) must be a sublist of the
+ // target parameter list.
+ cleanup = dropArgumentsToMatch(cleanup, (rtype == void.class ? 1 : 2), targetParamTypes, 0);
+
+ // Ensure that the intrinsic type checks the instance thrown by the
+ // target against the first parameter of cleanup
+ cleanup = cleanup.asType(cleanup.type().changeParameterType(0, Throwable.class));
+
+ // Use asFixedArity() to avoid unnecessary boxing of last argument for VarargsCollector case.
+ // Android-changed: use Transformer implementation.
+ // return MethodHandleImpl.makeTryFinally(target.asFixedArity(), cleanup.asFixedArity(), rtype, targetParamTypes);
+ return new Transformers.TryFinally(target.asFixedArity(), cleanup.asFixedArity());
+ }
+
+ private static void tryFinallyChecks(MethodHandle target, MethodHandle cleanup) {
+ Class<?> rtype = target.type().returnType();
+ if (rtype != cleanup.type().returnType()) {
+ throw misMatchedTypes("target and return types", cleanup.type().returnType(), rtype);
+ }
+ MethodType cleanupType = cleanup.type();
+ if (!Throwable.class.isAssignableFrom(cleanupType.parameterType(0))) {
+ throw misMatchedTypes("cleanup first argument and Throwable", cleanup.type(), Throwable.class);
+ }
+ if (rtype != void.class && cleanupType.parameterType(1) != rtype) {
+ throw misMatchedTypes("cleanup second argument and target return type", cleanup.type(), rtype);
+ }
+ // The cleanup parameter list (minus the leading Throwable and result parameters) must be a sublist of the
+ // target parameter list.
+ int cleanupArgIndex = rtype == void.class ? 1 : 2;
+ if (!cleanupType.effectivelyIdenticalParameters(cleanupArgIndex, target.type().parameterList())) {
+ throw misMatchedTypes("cleanup parameters after (Throwable,result) and target parameter list prefix",
+ cleanup.type(), target.type());
+ }
+ }
+
+ /**
+ * Creates a table switch method handle, which can be used to switch over a set of target
+ * method handles, based on a given target index, called selector.
+ * <p>
+ * For a selector value of {@code n}, where {@code n} falls in the range {@code [0, N)},
+ * and where {@code N} is the number of target method handles, the table switch method
+ * handle will invoke the n-th target method handle from the list of target method handles.
+ * <p>
+ * For a selector value that does not fall in the range {@code [0, N)}, the table switch
+ * method handle will invoke the given fallback method handle.
+ * <p>
+ * All method handles passed to this method must have the same type, with the additional
+ * requirement that the leading parameter be of type {@code int}. The leading parameter
+ * represents the selector.
+ * <p>
+ * Any trailing parameters present in the type will appear on the returned table switch
+ * method handle as well. Any arguments assigned to these parameters will be forwarded,
+ * together with the selector value, to the selected method handle when invoking it.
+ *
+ * @apiNote Example:
+ * The cases each drop the {@code selector} value they are given, and take an additional
+ * {@code String} argument, which is concatenated (using {@link String#concat(String)})
+ * to a specific constant label string for each case:
+ * <blockquote><pre>{@code
+ * MethodHandles.Lookup lookup = MethodHandles.lookup();
+ * MethodHandle caseMh = lookup.findVirtual(String.class, "concat",
+ * MethodType.methodType(String.class, String.class));
+ * caseMh = MethodHandles.dropArguments(caseMh, 0, int.class);
+ *
+ * MethodHandle caseDefault = MethodHandles.insertArguments(caseMh, 1, "default: ");
+ * MethodHandle case0 = MethodHandles.insertArguments(caseMh, 1, "case 0: ");
+ * MethodHandle case1 = MethodHandles.insertArguments(caseMh, 1, "case 1: ");
+ *
+ * MethodHandle mhSwitch = MethodHandles.tableSwitch(
+ * caseDefault,
+ * case0,
+ * case1
+ * );
+ *
+ * assertEquals("default: data", (String) mhSwitch.invokeExact(-1, "data"));
+ * assertEquals("case 0: data", (String) mhSwitch.invokeExact(0, "data"));
+ * assertEquals("case 1: data", (String) mhSwitch.invokeExact(1, "data"));
+ * assertEquals("default: data", (String) mhSwitch.invokeExact(2, "data"));
+ * }</pre></blockquote>
+ *
+ * @param fallback the fallback method handle that is called when the selector is not
+ * within the range {@code [0, N)}.
+ * @param targets array of target method handles.
+ * @return the table switch method handle.
+ * @throws NullPointerException if {@code fallback}, the {@code targets} array, or any
+ * any of the elements of the {@code targets} array are
+ * {@code null}.
+ * @throws IllegalArgumentException if the {@code targets} array is empty, if the leading
+ * parameter of the fallback handle or any of the target
+ * handles is not {@code int}, or if the types of
+ * the fallback handle and all of target handles are
+ * not the same.
+ */
+ public static MethodHandle tableSwitch(MethodHandle fallback, MethodHandle... targets) {
+ Objects.requireNonNull(fallback);
+ Objects.requireNonNull(targets);
+ targets = targets.clone();
+ MethodType type = tableSwitchChecks(fallback, targets);
+ // Android-changed: use a Transformer for the implementation.
+ // return MethodHandleImpl.makeTableSwitch(type, fallback, targets);
+ return new Transformers.TableSwitch(type, fallback, targets);
+ }
+
+ private static MethodType tableSwitchChecks(MethodHandle defaultCase, MethodHandle[] caseActions) {
+ if (caseActions.length == 0)
+ throw new IllegalArgumentException("Not enough cases: " + Arrays.toString(caseActions));
+
+ MethodType expectedType = defaultCase.type();
+
+ if (!(expectedType.parameterCount() >= 1) || expectedType.parameterType(0) != int.class)
+ throw new IllegalArgumentException(
+ "Case actions must have int as leading parameter: " + Arrays.toString(caseActions));
+
+ for (MethodHandle mh : caseActions) {
+ Objects.requireNonNull(mh);
+ // Android-changed: MethodType's not interned.
+ // if (mh.type() != expectedType)
+ if (!mh.type().equals(expectedType))
+ throw new IllegalArgumentException(
+ "Case actions must have the same type: " + Arrays.toString(caseActions));
+ }
+
+ return expectedType;
+ }
+
+ // BEGIN Android-added: Code from OpenJDK's MethodHandleImpl.
+
+ /**
+ * This method is bound as the predicate in {@linkplain MethodHandles#countedLoop(MethodHandle, MethodHandle,
+ * MethodHandle) counting loops}.
+ *
+ * @param limit the upper bound of the parameter, statically bound at loop creation time.
+ * @param counter the counter parameter, passed in during loop execution.
+ *
+ * @return whether the counter has reached the limit.
+ * @hide
+ */
+ public static boolean countedLoopPredicate(int limit, int counter) {
+ return counter < limit;
+ }
+
+ /**
+ * This method is bound as the step function in {@linkplain MethodHandles#countedLoop(MethodHandle, MethodHandle,
+ * MethodHandle) counting loops} to increment the counter.
+ *
+ * @param limit the upper bound of the loop counter (ignored).
+ * @param counter the loop counter.
+ *
+ * @return the loop counter incremented by 1.
+ * @hide
+ */
+ public static int countedLoopStep(int limit, int counter) {
+ return counter + 1;
+ }
+
+ /**
+ * This is bound to initialize the loop-local iterator in {@linkplain MethodHandles#iteratedLoop iterating loops}.
+ *
+ * @param it the {@link Iterable} over which the loop iterates.
+ *
+ * @return an {@link Iterator} over the argument's elements.
+ * @hide
+ */
+ public static Iterator<?> initIterator(Iterable<?> it) {
+ return it.iterator();
+ }
+
+ /**
+ * This method is bound as the predicate in {@linkplain MethodHandles#iteratedLoop iterating loops}.
+ *
+ * @param it the iterator to be checked.
+ *
+ * @return {@code true} iff there are more elements to iterate over.
+ * @hide
+ */
+ public static boolean iteratePredicate(Iterator<?> it) {
+ return it.hasNext();
+ }
+
+ /**
+ * This method is bound as the step for retrieving the current value from the iterator in {@linkplain
+ * MethodHandles#iteratedLoop iterating loops}.
+ *
+ * @param it the iterator.
+ *
+ * @return the next element from the iterator.
+ * @hide
+ */
+ public static Object iterateNext(Iterator<?> it) {
+ return it.next();
+ }
+
+ // Indexes into constant method handles:
+ static final int
+ MH_cast = 0,
+ MH_selectAlternative = 1,
+ MH_copyAsPrimitiveArray = 2,
+ MH_fillNewTypedArray = 3,
+ MH_fillNewArray = 4,
+ MH_arrayIdentity = 5,
+ MH_countedLoopPred = 6,
+ MH_countedLoopStep = 7,
+ MH_initIterator = 8,
+ MH_iteratePred = 9,
+ MH_iterateNext = 10,
+ MH_Array_newInstance = 11,
+ MH_LIMIT = 12;
+
+ static MethodHandle getConstantHandle(int idx) {
+ MethodHandle handle = HANDLES[idx];
+ if (handle != null) {
+ return handle;
+ }
+ return setCachedHandle(idx, makeConstantHandle(idx));
+ }
+
+ private static synchronized MethodHandle setCachedHandle(int idx, final MethodHandle method) {
+ // Simulate a CAS, to avoid racy duplication of results.
+ MethodHandle prev = HANDLES[idx];
+ if (prev != null) {
+ return prev;
+ }
+ HANDLES[idx] = method;
+ return method;
+ }
+
+ // Local constant method handles:
+ private static final @Stable MethodHandle[] HANDLES = new MethodHandle[MH_LIMIT];
+
+ private static MethodHandle makeConstantHandle(int idx) {
+ try {
+ // Android-added: local IMPL_LOOKUP.
+ final Lookup IMPL_LOOKUP = MethodHandles.Lookup.IMPL_LOOKUP;
+ switch (idx) {
+ // Android-removed: not-used.
+ /*
+ case MH_cast:
+ return IMPL_LOOKUP.findVirtual(Class.class, "cast",
+ MethodType.methodType(Object.class, Object.class));
+ case MH_copyAsPrimitiveArray:
+ return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "copyAsPrimitiveArray",
+ MethodType.methodType(Object.class, Wrapper.class, Object[].class));
+ case MH_arrayIdentity:
+ return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "identity",
+ MethodType.methodType(Object[].class, Object[].class));
+ case MH_fillNewArray:
+ return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "fillNewArray",
+ MethodType.methodType(Object[].class, Integer.class, Object[].class));
+ case MH_fillNewTypedArray:
+ return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "fillNewTypedArray",
+ MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
+ case MH_selectAlternative:
+ return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "selectAlternative",
+ MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class));
+ */
+ case MH_countedLoopPred:
+ // Android-changed: methods moved to this file.
+ // return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "countedLoopPredicate",
+ // MethodType.methodType(boolean.class, int.class, int.class));
+ return IMPL_LOOKUP.findStatic(MethodHandles.class, "countedLoopPredicate",
+ MethodType.methodType(boolean.class, int.class, int.class));
+ case MH_countedLoopStep:
+ // Android-changed: methods moved to this file.
+ // return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "countedLoopStep",
+ // MethodType.methodType(int.class, int.class, int.class));
+ return IMPL_LOOKUP.findStatic(MethodHandles.class, "countedLoopStep",
+ MethodType.methodType(int.class, int.class, int.class));
+ case MH_initIterator:
+ // Android-changed: methods moved to this file.
+ // return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "initIterator",
+ // MethodType.methodType(Iterator.class, Iterable.class));
+ return IMPL_LOOKUP.findStatic(MethodHandles.class, "initIterator",
+ MethodType.methodType(Iterator.class, Iterable.class));
+ case MH_iteratePred:
+ // Android-changed: methods moved to this file.
+ // return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "iteratePredicate",
+ // MethodType.methodType(boolean.class, Iterator.class));
+ return IMPL_LOOKUP.findStatic(MethodHandles.class, "iteratePredicate",
+ MethodType.methodType(boolean.class, Iterator.class));
+ case MH_iterateNext:
+ // Android-changed: methods moved to this file.
+ // return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "iterateNext",
+ // MethodType.methodType(Object.class, Iterator.class));
+ return IMPL_LOOKUP.findStatic(MethodHandles.class, "iterateNext",
+ MethodType.methodType(Object.class, Iterator.class));
+ // Android-removed: not-used.
+ /*
+ case MH_Array_newInstance:
+ return IMPL_LOOKUP.findStatic(Array.class, "newInstance",
+ MethodType.methodType(Object.class, Class.class, int.class));
+ */
+ }
+ } catch (ReflectiveOperationException ex) {
+ throw newInternalError(ex);
+ }
+
+ throw newInternalError("Unknown function index: " + idx);
+ }
+ // END Android-added: Code from OpenJDK's MethodHandleImpl.
+}
diff --git a/android-35/java/lang/invoke/MethodType.java b/android-35/java/lang/invoke/MethodType.java
new file mode 100644
index 0000000..b23b51c
--- /dev/null
+++ b/android-35/java/lang/invoke/MethodType.java
@@ -0,0 +1,1404 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import sun.invoke.util.Wrapper;
+import java.lang.ref.WeakReference;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentHashMap;
+import sun.invoke.util.BytecodeDescriptor;
+import static java.lang.invoke.MethodHandleStatics.*;
+
+/**
+ * A method type represents the arguments and return type accepted and
+ * returned by a method handle, or the arguments and return type passed
+ * and expected by a method handle caller. Method types must be properly
+ * matched between a method handle and all its callers,
+ * and the JVM's operations enforce this matching at, specifically
+ * during calls to {@link MethodHandle#invokeExact MethodHandle.invokeExact}
+ * and {@link MethodHandle#invoke MethodHandle.invoke}, and during execution
+ * of {@code invokedynamic} instructions.
+ * <p>
+ * The structure is a return type accompanied by any number of parameter types.
+ * The types (primitive, {@code void}, and reference) are represented by {@link Class} objects.
+ * (For ease of exposition, we treat {@code void} as if it were a type.
+ * In fact, it denotes the absence of a return type.)
+ * <p>
+ * All instances of {@code MethodType} are immutable.
+ * Two instances are completely interchangeable if they compare equal.
+ * Equality depends on pairwise correspondence of the return and parameter types and on nothing else.
+ * <p>
+ * This type can be created only by factory methods.
+ * All factory methods may cache values, though caching is not guaranteed.
+ * Some factory methods are static, while others are virtual methods which
+ * modify precursor method types, e.g., by changing a selected parameter.
+ * <p>
+ * Factory methods which operate on groups of parameter types
+ * are systematically presented in two versions, so that both Java arrays and
+ * Java lists can be used to work with groups of parameter types.
+ * The query methods {@code parameterArray} and {@code parameterList}
+ * also provide a choice between arrays and lists.
+ * <p>
+ * {@code MethodType} objects are sometimes derived from bytecode instructions
+ * such as {@code invokedynamic}, specifically from the type descriptor strings associated
+ * with the instructions in a class file's constant pool.
+ * <p>
+ * Like classes and strings, method types can also be represented directly
+ * in a class file's constant pool as constants.
+ * A method type may be loaded by an {@code ldc} instruction which refers
+ * to a suitable {@code CONSTANT_MethodType} constant pool entry.
+ * The entry refers to a {@code CONSTANT_Utf8} spelling for the descriptor string.
+ * (For full details on method type constants,
+ * see sections 4.4.8 and 5.4.3.5 of the Java Virtual Machine Specification.)
+ * <p>
+ * When the JVM materializes a {@code MethodType} from a descriptor string,
+ * all classes named in the descriptor must be accessible, and will be loaded.
+ * (But the classes need not be initialized, as is the case with a {@code CONSTANT_Class}.)
+ * This loading may occur at any time before the {@code MethodType} object is first derived.
+ * @author John Rose, JSR 292 EG
+ */
+public final
+class MethodType
+ implements TypeDescriptor.OfMethod<Class<?>, MethodType>,
+ java.io.Serializable {
+ private static final long serialVersionUID = 292L; // {rtype, {ptype...}}
+
+ // The rtype and ptypes fields define the structural identity of the method type:
+ private final Class<?> rtype;
+ private final Class<?>[] ptypes;
+
+ // The remaining fields are caches of various sorts:
+ private @Stable MethodTypeForm form; // erased form, plus cached data about primitives
+ private @Stable MethodType wrapAlt; // alternative wrapped/unwrapped version
+ // Android-removed: Cache of higher order adapters.
+ // We're not dynamically generating any adapters at this point.
+ // private @Stable Invokers invokers; // cache of handy higher-order adapters
+ private @Stable String methodDescriptor; // cache for toMethodDescriptorString
+
+ /**
+ * Check the given parameters for validity and store them into the final fields.
+ */
+ private MethodType(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
+ checkRtype(rtype);
+ checkPtypes(ptypes);
+ this.rtype = rtype;
+ // defensively copy the array passed in by the user
+ this.ptypes = trusted ? ptypes : Arrays.copyOf(ptypes, ptypes.length);
+ }
+
+ /**
+ * Construct a temporary unchecked instance of MethodType for use only as a key to the intern table.
+ * Does not check the given parameters for validity, and must be discarded after it is used as a searching key.
+ * The parameters are reversed for this constructor, so that is is not accidentally used.
+ */
+ private MethodType(Class<?>[] ptypes, Class<?> rtype) {
+ this.rtype = rtype;
+ this.ptypes = ptypes;
+ }
+
+ /*trusted*/ MethodTypeForm form() { return form; }
+ // Android-changed: Make rtype()/ptypes() public @hide for implementation use.
+ // /*trusted*/ Class<?> rtype() { return rtype; }
+ // /*trusted*/ Class<?>[] ptypes() { return ptypes; }
+ /*trusted*/ /** @hide */ public Class<?> rtype() { return rtype; }
+ /*trusted*/ /** @hide */ public Class<?>[] ptypes() { return ptypes; }
+
+ // Android-removed: Implementation methods unused on Android.
+ // void setForm(MethodTypeForm f) { form = f; }
+
+ /** This number, mandated by the JVM spec as 255,
+ * is the maximum number of <em>slots</em>
+ * that any Java method can receive in its argument list.
+ * It limits both JVM signatures and method type objects.
+ * The longest possible invocation will look like
+ * {@code staticMethod(arg1, arg2, ..., arg255)} or
+ * {@code x.virtualMethod(arg1, arg2, ..., arg254)}.
+ */
+ /*non-public*/ static final int MAX_JVM_ARITY = 255; // this is mandated by the JVM spec.
+
+ /** This number is the maximum arity of a method handle, 254.
+ * It is derived from the absolute JVM-imposed arity by subtracting one,
+ * which is the slot occupied by the method handle itself at the
+ * beginning of the argument list used to invoke the method handle.
+ * The longest possible invocation will look like
+ * {@code mh.invoke(arg1, arg2, ..., arg254)}.
+ */
+ // Issue: Should we allow MH.invokeWithArguments to go to the full 255?
+ /*non-public*/ static final int MAX_MH_ARITY = MAX_JVM_ARITY-1; // deduct one for mh receiver
+
+ /** This number is the maximum arity of a method handle invoker, 253.
+ * It is derived from the absolute JVM-imposed arity by subtracting two,
+ * which are the slots occupied by invoke method handle, and the
+ * target method handle, which are both at the beginning of the argument
+ * list used to invoke the target method handle.
+ * The longest possible invocation will look like
+ * {@code invokermh.invoke(targetmh, arg1, arg2, ..., arg253)}.
+ */
+ /*non-public*/ static final int MAX_MH_INVOKER_ARITY = MAX_MH_ARITY-1; // deduct one more for invoker
+
+ private static void checkRtype(Class<?> rtype) {
+ Objects.requireNonNull(rtype);
+ }
+ private static void checkPtype(Class<?> ptype) {
+ Objects.requireNonNull(ptype);
+ if (ptype == void.class)
+ throw newIllegalArgumentException("parameter type cannot be void");
+ }
+ /** Return number of extra slots (count of long/double args). */
+ private static int checkPtypes(Class<?>[] ptypes) {
+ int slots = 0;
+ for (Class<?> ptype : ptypes) {
+ checkPtype(ptype);
+ if (ptype == double.class || ptype == long.class) {
+ slots++;
+ }
+ }
+ checkSlotCount(ptypes.length + slots);
+ return slots;
+ }
+ static void checkSlotCount(int count) {
+ assert((MAX_JVM_ARITY & (MAX_JVM_ARITY+1)) == 0);
+ // MAX_JVM_ARITY must be power of 2 minus 1 for following code trick to work:
+ if ((count & MAX_JVM_ARITY) != count)
+ throw newIllegalArgumentException("bad parameter count "+count);
+ }
+ private static IndexOutOfBoundsException newIndexOutOfBoundsException(Object num) {
+ if (num instanceof Integer) num = "bad index: "+num;
+ return new IndexOutOfBoundsException(num.toString());
+ }
+
+ static final ConcurrentWeakInternSet<MethodType> internTable = new ConcurrentWeakInternSet<>();
+
+ static final Class<?>[] NO_PTYPES = {};
+
+ /**
+ * Finds or creates an instance of the given method type.
+ * @param rtype the return type
+ * @param ptypes the parameter types
+ * @return a method type with the given components
+ * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
+ * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
+ */
+ public static
+ MethodType methodType(Class<?> rtype, Class<?>[] ptypes) {
+ return makeImpl(rtype, ptypes, false);
+ }
+
+ /**
+ * Finds or creates a method type with the given components.
+ * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+ * @param rtype the return type
+ * @param ptypes the parameter types
+ * @return a method type with the given components
+ * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
+ * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
+ */
+ public static
+ MethodType methodType(Class<?> rtype, List<Class<?>> ptypes) {
+ boolean notrust = false; // random List impl. could return evil ptypes array
+ return makeImpl(rtype, listToArray(ptypes), notrust);
+ }
+
+ private static Class<?>[] listToArray(List<Class<?>> ptypes) {
+ // sanity check the size before the toArray call, since size might be huge
+ checkSlotCount(ptypes.size());
+ return ptypes.toArray(NO_PTYPES);
+ }
+
+ /**
+ * Finds or creates a method type with the given components.
+ * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+ * The leading parameter type is prepended to the remaining array.
+ * @param rtype the return type
+ * @param ptype0 the first parameter type
+ * @param ptypes the remaining parameter types
+ * @return a method type with the given components
+ * @throws NullPointerException if {@code rtype} or {@code ptype0} or {@code ptypes} or any element of {@code ptypes} is null
+ * @throws IllegalArgumentException if {@code ptype0} or {@code ptypes} or any element of {@code ptypes} is {@code void.class}
+ */
+ public static
+ MethodType methodType(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) {
+ Class<?>[] ptypes1 = new Class<?>[1+ptypes.length];
+ ptypes1[0] = ptype0;
+ System.arraycopy(ptypes, 0, ptypes1, 1, ptypes.length);
+ return makeImpl(rtype, ptypes1, true);
+ }
+
+ /**
+ * Finds or creates a method type with the given components.
+ * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+ * The resulting method has no parameter types.
+ * @param rtype the return type
+ * @return a method type with the given return value
+ * @throws NullPointerException if {@code rtype} is null
+ */
+ public static
+ MethodType methodType(Class<?> rtype) {
+ return makeImpl(rtype, NO_PTYPES, true);
+ }
+
+ /**
+ * Finds or creates a method type with the given components.
+ * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+ * The resulting method has the single given parameter type.
+ * @param rtype the return type
+ * @param ptype0 the parameter type
+ * @return a method type with the given return value and parameter type
+ * @throws NullPointerException if {@code rtype} or {@code ptype0} is null
+ * @throws IllegalArgumentException if {@code ptype0} is {@code void.class}
+ */
+ public static
+ MethodType methodType(Class<?> rtype, Class<?> ptype0) {
+ return makeImpl(rtype, new Class<?>[]{ ptype0 }, true);
+ }
+
+ /**
+ * Finds or creates a method type with the given components.
+ * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+ * The resulting method has the same parameter types as {@code ptypes},
+ * and the specified return type.
+ * @param rtype the return type
+ * @param ptypes the method type which supplies the parameter types
+ * @return a method type with the given components
+ * @throws NullPointerException if {@code rtype} or {@code ptypes} is null
+ */
+ public static
+ MethodType methodType(Class<?> rtype, MethodType ptypes) {
+ return makeImpl(rtype, ptypes.ptypes, true);
+ }
+
+ /**
+ * Sole factory method to find or create an interned method type.
+ * @param rtype desired return type
+ * @param ptypes desired parameter types
+ * @param trusted whether the ptypes can be used without cloning
+ * @return the unique method type of the desired structure
+ */
+ /*trusted*/ static
+ MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
+ MethodType mt = internTable.get(new MethodType(ptypes, rtype));
+ if (mt != null)
+ return mt;
+ if (ptypes.length == 0) {
+ ptypes = NO_PTYPES; trusted = true;
+ }
+ mt = new MethodType(rtype, ptypes, trusted);
+ // promote the object to the Real Thing, and reprobe
+ mt.form = MethodTypeForm.findForm(mt);
+ return internTable.add(mt);
+ }
+ private static final MethodType[] objectOnlyTypes = new MethodType[20];
+
+ /**
+ * Finds or creates a method type whose components are {@code Object} with an optional trailing {@code Object[]} array.
+ * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+ * All parameters and the return type will be {@code Object},
+ * except the final array parameter if any, which will be {@code Object[]}.
+ * @param objectArgCount number of parameters (excluding the final array parameter if any)
+ * @param finalArray whether there will be a trailing array parameter, of type {@code Object[]}
+ * @return a generally applicable method type, for all calls of the given fixed argument count and a collected array of further arguments
+ * @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255 (or 254, if {@code finalArray} is true)
+ * @see #genericMethodType(int)
+ */
+ public static
+ MethodType genericMethodType(int objectArgCount, boolean finalArray) {
+ MethodType mt;
+ checkSlotCount(objectArgCount);
+ int ivarargs = (!finalArray ? 0 : 1);
+ int ootIndex = objectArgCount*2 + ivarargs;
+ if (ootIndex < objectOnlyTypes.length) {
+ mt = objectOnlyTypes[ootIndex];
+ if (mt != null) return mt;
+ }
+ Class<?>[] ptypes = new Class<?>[objectArgCount + ivarargs];
+ Arrays.fill(ptypes, Object.class);
+ if (ivarargs != 0) ptypes[objectArgCount] = Object[].class;
+ mt = makeImpl(Object.class, ptypes, true);
+ if (ootIndex < objectOnlyTypes.length) {
+ objectOnlyTypes[ootIndex] = mt; // cache it here also!
+ }
+ return mt;
+ }
+
+ /**
+ * Finds or creates a method type whose components are all {@code Object}.
+ * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+ * All parameters and the return type will be Object.
+ * @param objectArgCount number of parameters
+ * @return a generally applicable method type, for all calls of the given argument count
+ * @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255
+ * @see #genericMethodType(int, boolean)
+ */
+ public static
+ MethodType genericMethodType(int objectArgCount) {
+ return genericMethodType(objectArgCount, false);
+ }
+
+ /**
+ * Finds or creates a method type with a single different parameter type.
+ * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+ * @param num the index (zero-based) of the parameter type to change
+ * @param nptype a new parameter type to replace the old one with
+ * @return the same type, except with the selected parameter changed
+ * @throws IndexOutOfBoundsException if {@code num} is not a valid index into {@code parameterArray()}
+ * @throws IllegalArgumentException if {@code nptype} is {@code void.class}
+ * @throws NullPointerException if {@code nptype} is null
+ */
+ public MethodType changeParameterType(int num, Class<?> nptype) {
+ if (parameterType(num) == nptype) return this;
+ checkPtype(nptype);
+ Class<?>[] nptypes = ptypes.clone();
+ nptypes[num] = nptype;
+ return makeImpl(rtype, nptypes, true);
+ }
+
+ /**
+ * Finds or creates a method type with additional parameter types.
+ * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+ * @param num the position (zero-based) of the inserted parameter type(s)
+ * @param ptypesToInsert zero or more new parameter types to insert into the parameter list
+ * @return the same type, except with the selected parameter(s) inserted
+ * @throws IndexOutOfBoundsException if {@code num} is negative or greater than {@code parameterCount()}
+ * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
+ * or if the resulting method type would have more than 255 parameter slots
+ * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
+ */
+ public MethodType insertParameterTypes(int num, Class<?>... ptypesToInsert) {
+ int len = ptypes.length;
+ if (num < 0 || num > len)
+ throw newIndexOutOfBoundsException(num);
+ int ins = checkPtypes(ptypesToInsert);
+ checkSlotCount(parameterSlotCount() + ptypesToInsert.length + ins);
+ int ilen = ptypesToInsert.length;
+ if (ilen == 0) return this;
+ Class<?>[] nptypes = Arrays.copyOfRange(ptypes, 0, len+ilen);
+ System.arraycopy(nptypes, num, nptypes, num+ilen, len-num);
+ System.arraycopy(ptypesToInsert, 0, nptypes, num, ilen);
+ return makeImpl(rtype, nptypes, true);
+ }
+
+ /**
+ * Finds or creates a method type with additional parameter types.
+ * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+ * @param ptypesToInsert zero or more new parameter types to insert after the end of the parameter list
+ * @return the same type, except with the selected parameter(s) appended
+ * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
+ * or if the resulting method type would have more than 255 parameter slots
+ * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
+ */
+ public MethodType appendParameterTypes(Class<?>... ptypesToInsert) {
+ return insertParameterTypes(parameterCount(), ptypesToInsert);
+ }
+
+ /**
+ * Finds or creates a method type with additional parameter types.
+ * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+ * @param num the position (zero-based) of the inserted parameter type(s)
+ * @param ptypesToInsert zero or more new parameter types to insert into the parameter list
+ * @return the same type, except with the selected parameter(s) inserted
+ * @throws IndexOutOfBoundsException if {@code num} is negative or greater than {@code parameterCount()}
+ * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
+ * or if the resulting method type would have more than 255 parameter slots
+ * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
+ */
+ public MethodType insertParameterTypes(int num, List<Class<?>> ptypesToInsert) {
+ return insertParameterTypes(num, listToArray(ptypesToInsert));
+ }
+
+ /**
+ * Finds or creates a method type with additional parameter types.
+ * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+ * @param ptypesToInsert zero or more new parameter types to insert after the end of the parameter list
+ * @return the same type, except with the selected parameter(s) appended
+ * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
+ * or if the resulting method type would have more than 255 parameter slots
+ * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
+ */
+ public MethodType appendParameterTypes(List<Class<?>> ptypesToInsert) {
+ return insertParameterTypes(parameterCount(), ptypesToInsert);
+ }
+
+ /**
+ * Finds or creates a method type with modified parameter types.
+ * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+ * @param start the position (zero-based) of the first replaced parameter type(s)
+ * @param end the position (zero-based) after the last replaced parameter type(s)
+ * @param ptypesToInsert zero or more new parameter types to insert into the parameter list
+ * @return the same type, except with the selected parameter(s) replaced
+ * @throws IndexOutOfBoundsException if {@code start} is negative or greater than {@code parameterCount()}
+ * or if {@code end} is negative or greater than {@code parameterCount()}
+ * or if {@code start} is greater than {@code end}
+ * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
+ * or if the resulting method type would have more than 255 parameter slots
+ * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
+ */
+ /*non-public*/ MethodType replaceParameterTypes(int start, int end, Class<?>... ptypesToInsert) {
+ if (start == end)
+ return insertParameterTypes(start, ptypesToInsert);
+ int len = ptypes.length;
+ if (!(0 <= start && start <= end && end <= len))
+ throw newIndexOutOfBoundsException("start="+start+" end="+end);
+ int ilen = ptypesToInsert.length;
+ if (ilen == 0)
+ return dropParameterTypes(start, end);
+ return dropParameterTypes(start, end).insertParameterTypes(start, ptypesToInsert);
+ }
+
+ /** Replace the last arrayLength parameter types with the component type of arrayType.
+ * @param arrayType any array type
+ * @param pos position at which to spread
+ * @param arrayLength the number of parameter types to change
+ * @return the resulting type
+ */
+ /*non-public*/ MethodType asSpreaderType(Class<?> arrayType, int pos, int arrayLength) {
+ assert(parameterCount() >= arrayLength);
+ int spreadPos = pos;
+ if (arrayLength == 0) return this; // nothing to change
+ if (arrayType == Object[].class) {
+ if (isGeneric()) return this; // nothing to change
+ if (spreadPos == 0) {
+ // no leading arguments to preserve; go generic
+ MethodType res = genericMethodType(arrayLength);
+ if (rtype != Object.class) {
+ res = res.changeReturnType(rtype);
+ }
+ return res;
+ }
+ }
+ Class<?> elemType = arrayType.getComponentType();
+ assert(elemType != null);
+ for (int i = spreadPos; i < spreadPos + arrayLength; i++) {
+ if (ptypes[i] != elemType) {
+ Class<?>[] fixedPtypes = ptypes.clone();
+ Arrays.fill(fixedPtypes, i, spreadPos + arrayLength, elemType);
+ return methodType(rtype, fixedPtypes);
+ }
+ }
+ return this; // arguments check out; no change
+ }
+
+ /** Return the leading parameter type, which must exist and be a reference.
+ * @return the leading parameter type, after error checks
+ */
+ /*non-public*/ Class<?> leadingReferenceParameter() {
+ Class<?> ptype;
+ if (ptypes.length == 0 ||
+ (ptype = ptypes[0]).isPrimitive())
+ throw newIllegalArgumentException("no leading reference parameter");
+ return ptype;
+ }
+
+ /** Delete the last parameter type and replace it with arrayLength copies of the component type of arrayType.
+ * @param arrayType any array type
+ * @param pos position at which to insert parameters
+ * @param arrayLength the number of parameter types to insert
+ * @return the resulting type
+ */
+ /*non-public*/ MethodType asCollectorType(Class<?> arrayType, int pos, int arrayLength) {
+ assert(parameterCount() >= 1);
+ assert(pos < ptypes.length);
+ assert(ptypes[pos].isAssignableFrom(arrayType));
+ MethodType res;
+ if (arrayType == Object[].class) {
+ res = genericMethodType(arrayLength);
+ if (rtype != Object.class) {
+ res = res.changeReturnType(rtype);
+ }
+ } else {
+ Class<?> elemType = arrayType.getComponentType();
+ assert(elemType != null);
+ res = methodType(rtype, Collections.nCopies(arrayLength, elemType));
+ }
+ if (ptypes.length == 1) {
+ return res;
+ } else {
+ // insert after (if need be), then before
+ if (pos < ptypes.length - 1) {
+ res = res.insertParameterTypes(arrayLength, Arrays.copyOfRange(ptypes, pos + 1, ptypes.length));
+ }
+ return res.insertParameterTypes(0, Arrays.copyOf(ptypes, pos));
+ }
+ }
+
+ /**
+ * Finds or creates a method type with some parameter types omitted.
+ * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+ * @param start the index (zero-based) of the first parameter type to remove
+ * @param end the index (greater than {@code start}) of the first parameter type after not to remove
+ * @return the same type, except with the selected parameter(s) removed
+ * @throws IndexOutOfBoundsException if {@code start} is negative or greater than {@code parameterCount()}
+ * or if {@code end} is negative or greater than {@code parameterCount()}
+ * or if {@code start} is greater than {@code end}
+ */
+ public MethodType dropParameterTypes(int start, int end) {
+ int len = ptypes.length;
+ if (!(0 <= start && start <= end && end <= len))
+ throw newIndexOutOfBoundsException("start="+start+" end="+end);
+ if (start == end) return this;
+ Class<?>[] nptypes;
+ if (start == 0) {
+ if (end == len) {
+ // drop all parameters
+ nptypes = NO_PTYPES;
+ } else {
+ // drop initial parameter(s)
+ nptypes = Arrays.copyOfRange(ptypes, end, len);
+ }
+ } else {
+ if (end == len) {
+ // drop trailing parameter(s)
+ nptypes = Arrays.copyOfRange(ptypes, 0, start);
+ } else {
+ int tail = len - end;
+ nptypes = Arrays.copyOfRange(ptypes, 0, start + tail);
+ System.arraycopy(ptypes, end, nptypes, start, tail);
+ }
+ }
+ return makeImpl(rtype, nptypes, true);
+ }
+
+ /**
+ * Finds or creates a method type with a different return type.
+ * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+ * @param nrtype a return parameter type to replace the old one with
+ * @return the same type, except with the return type change
+ * @throws NullPointerException if {@code nrtype} is null
+ */
+ public MethodType changeReturnType(Class<?> nrtype) {
+ if (returnType() == nrtype) return this;
+ return makeImpl(nrtype, ptypes, true);
+ }
+
+ /**
+ * Reports if this type contains a primitive argument or return value.
+ * The return type {@code void} counts as a primitive.
+ * @return true if any of the types are primitives
+ */
+ public boolean hasPrimitives() {
+ return form.hasPrimitives();
+ }
+
+ /**
+ * Reports if this type contains a wrapper argument or return value.
+ * Wrappers are types which box primitive values, such as {@link Integer}.
+ * The reference type {@code java.lang.Void} counts as a wrapper,
+ * if it occurs as a return type.
+ * @return true if any of the types are wrappers
+ */
+ public boolean hasWrappers() {
+ return unwrap() != this;
+ }
+
+ /**
+ * Erases all reference types to {@code Object}.
+ * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+ * All primitive types (including {@code void}) will remain unchanged.
+ * @return a version of the original type with all reference types replaced
+ */
+ public MethodType erase() {
+ return form.erasedType();
+ }
+
+ // BEGIN Android-removed: Implementation methods unused on Android.
+ /*
+ /**
+ * Erases all reference types to {@code Object}, and all subword types to {@code int}.
+ * This is the reduced type polymorphism used by private methods
+ * such as {@link MethodHandle#invokeBasic invokeBasic}.
+ * @return a version of the original type with all reference and subword types replaced
+ *
+ /*non-public* MethodType basicType() {
+ return form.basicType();
+ }
+
+ /**
+ * @return a version of the original type with MethodHandle prepended as the first argument
+ *
+ /*non-public* MethodType invokerType() {
+ return insertParameterTypes(0, MethodHandle.class);
+ }
+ */
+ // END Android-removed: Implementation methods unused on Android.
+
+ /**
+ * Converts all types, both reference and primitive, to {@code Object}.
+ * Convenience method for {@link #genericMethodType(int) genericMethodType}.
+ * The expression {@code type.wrap().erase()} produces the same value
+ * as {@code type.generic()}.
+ * @return a version of the original type with all types replaced
+ */
+ public MethodType generic() {
+ return genericMethodType(parameterCount());
+ }
+
+ /*non-public*/ boolean isGeneric() {
+ return this == erase() && !hasPrimitives();
+ }
+
+ /**
+ * Converts all primitive types to their corresponding wrapper types.
+ * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+ * All reference types (including wrapper types) will remain unchanged.
+ * A {@code void} return type is changed to the type {@code java.lang.Void}.
+ * The expression {@code type.wrap().erase()} produces the same value
+ * as {@code type.generic()}.
+ * @return a version of the original type with all primitive types replaced
+ */
+ public MethodType wrap() {
+ return hasPrimitives() ? wrapWithPrims(this) : this;
+ }
+
+ /**
+ * Converts all wrapper types to their corresponding primitive types.
+ * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+ * All primitive types (including {@code void}) will remain unchanged.
+ * A return type of {@code java.lang.Void} is changed to {@code void}.
+ * @return a version of the original type with all wrapper types replaced
+ */
+ public MethodType unwrap() {
+ MethodType noprims = !hasPrimitives() ? this : wrapWithPrims(this);
+ return unwrapWithNoPrims(noprims);
+ }
+
+ private static MethodType wrapWithPrims(MethodType pt) {
+ assert(pt.hasPrimitives());
+ MethodType wt = pt.wrapAlt;
+ if (wt == null) {
+ // fill in lazily
+ wt = MethodTypeForm.canonicalize(pt, MethodTypeForm.WRAP, MethodTypeForm.WRAP);
+ assert(wt != null);
+ pt.wrapAlt = wt;
+ }
+ return wt;
+ }
+
+ private static MethodType unwrapWithNoPrims(MethodType wt) {
+ assert(!wt.hasPrimitives());
+ MethodType uwt = wt.wrapAlt;
+ if (uwt == null) {
+ // fill in lazily
+ uwt = MethodTypeForm.canonicalize(wt, MethodTypeForm.UNWRAP, MethodTypeForm.UNWRAP);
+ if (uwt == null)
+ uwt = wt; // type has no wrappers or prims at all
+ wt.wrapAlt = uwt;
+ }
+ return uwt;
+ }
+
+ /**
+ * Returns the parameter type at the specified index, within this method type.
+ * @param num the index (zero-based) of the desired parameter type
+ * @return the selected parameter type
+ * @throws IndexOutOfBoundsException if {@code num} is not a valid index into {@code parameterArray()}
+ */
+ public Class<?> parameterType(int num) {
+ return ptypes[num];
+ }
+ /**
+ * Returns the number of parameter types in this method type.
+ * @return the number of parameter types
+ */
+ public int parameterCount() {
+ return ptypes.length;
+ }
+ /**
+ * Returns the return type of this method type.
+ * @return the return type
+ */
+ public Class<?> returnType() {
+ return rtype;
+ }
+
+ /**
+ * Presents the parameter types as a list (a convenience method).
+ * The list will be immutable.
+ * @return the parameter types (as an immutable list)
+ */
+ public List<Class<?>> parameterList() {
+ return Collections.unmodifiableList(Arrays.asList(ptypes.clone()));
+ }
+
+ /**
+ * Returns the last parameter type of this method type.
+ * If this type has no parameters, the sentinel value
+ * {@code void.class} is returned instead.
+ * @apiNote
+ * <p>
+ * The sentinel value is chosen so that reflective queries can be
+ * made directly against the result value.
+ * The sentinel value cannot be confused with a real parameter,
+ * since {@code void} is never acceptable as a parameter type.
+ * For variable arity invocation modes, the expression
+ * {@link Class#getComponentType lastParameterType().getComponentType()}
+ * is useful to query the type of the "varargs" parameter.
+ * @return the last parameter type if any, else {@code void.class}
+ * @since 10
+ */
+ public Class<?> lastParameterType() {
+ int len = ptypes.length;
+ return len == 0 ? void.class : ptypes[len-1];
+ }
+
+ /**
+ * Presents the parameter types as an array (a convenience method).
+ * Changes to the array will not result in changes to the type.
+ * @return the parameter types (as a fresh copy if necessary)
+ */
+ public Class<?>[] parameterArray() {
+ return ptypes.clone();
+ }
+
+ /**
+ * Compares the specified object with this type for equality.
+ * That is, it returns <tt>true</tt> if and only if the specified object
+ * is also a method type with exactly the same parameters and return type.
+ * @param x object to compare
+ * @see Object#equals(Object)
+ */
+ @Override
+ public boolean equals(Object x) {
+ return this == x || x instanceof MethodType && equals((MethodType)x);
+ }
+
+ private boolean equals(MethodType that) {
+ return this.rtype == that.rtype
+ && Arrays.equals(this.ptypes, that.ptypes);
+ }
+
+ /**
+ * Returns the hash code value for this method type.
+ * It is defined to be the same as the hashcode of a List
+ * whose elements are the return type followed by the
+ * parameter types.
+ * @return the hash code value for this method type
+ * @see Object#hashCode()
+ * @see #equals(Object)
+ * @see List#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ int hashCode = 31 + rtype.hashCode();
+ for (Class<?> ptype : ptypes)
+ hashCode = 31*hashCode + ptype.hashCode();
+ return hashCode;
+ }
+
+ /**
+ * Returns a string representation of the method type,
+ * of the form {@code "(PT0,PT1...)RT"}.
+ * The string representation of a method type is a
+ * parenthesis enclosed, comma separated list of type names,
+ * followed immediately by the return type.
+ * <p>
+ * Each type is represented by its
+ * {@link java.lang.Class#getSimpleName simple name}.
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("(");
+ for (int i = 0; i < ptypes.length; i++) {
+ if (i > 0) sb.append(",");
+ sb.append(ptypes[i].getSimpleName());
+ }
+ sb.append(")");
+ sb.append(rtype.getSimpleName());
+ return sb.toString();
+ }
+
+ /** True if my parameter list is effectively identical to the given full list,
+ * after skipping the given number of my own initial parameters.
+ * In other words, after disregarding {@code skipPos} parameters,
+ * my remaining parameter list is no longer than the {@code fullList}, and
+ * is equal to the same-length initial sublist of {@code fullList}.
+ */
+ /*non-public*/
+ boolean effectivelyIdenticalParameters(int skipPos, List<Class<?>> fullList) {
+ int myLen = ptypes.length, fullLen = fullList.size();
+ if (skipPos > myLen || myLen - skipPos > fullLen)
+ return false;
+ List<Class<?>> myList = Arrays.asList(ptypes);
+ if (skipPos != 0) {
+ myList = myList.subList(skipPos, myLen);
+ myLen -= skipPos;
+ }
+ if (fullLen == myLen)
+ return myList.equals(fullList);
+ else
+ return myList.equals(fullList.subList(0, myLen));
+ }
+
+ // BEGIN Android-removed: Implementation methods unused on Android.
+ /*
+ /** True if the old return type can always be viewed (w/o casting) under new return type,
+ * and the new parameters can be viewed (w/o casting) under the old parameter types.
+ *
+ /*non-public*
+ boolean isViewableAs(MethodType newType, boolean keepInterfaces) {
+ if (!VerifyType.isNullConversion(returnType(), newType.returnType(), keepInterfaces))
+ return false;
+ return parametersAreViewableAs(newType, keepInterfaces);
+ }
+ /** True if the new parameters can be viewed (w/o casting) under the old parameter types. *
+ /*non-public*
+ boolean parametersAreViewableAs(MethodType newType, boolean keepInterfaces) {
+ if (form == newType.form && form.erasedType == this)
+ return true; // my reference parameters are all Object
+ if (ptypes == newType.ptypes)
+ return true;
+ int argc = parameterCount();
+ if (argc != newType.parameterCount())
+ return false;
+ for (int i = 0; i < argc; i++) {
+ if (!VerifyType.isNullConversion(newType.parameterType(i), parameterType(i), keepInterfaces))
+ return false;
+ }
+ return true;
+ }
+ */
+ // END Android-removed: Implementation methods unused on Android.
+
+ /*non-public*/
+ boolean isConvertibleTo(MethodType newType) {
+ // Android-removed: use of MethodTypeForm does not apply to Android implementation.
+ // MethodTypeForm oldForm = this.form();
+ // MethodTypeForm newForm = newType.form();
+ // if (oldForm == newForm)
+ // // same parameter count, same primitive/object mix
+ // return true;
+ if (!canConvert(returnType(), newType.returnType()))
+ return false;
+ Class<?>[] srcTypes = newType.ptypes;
+ Class<?>[] dstTypes = ptypes;
+ if (srcTypes == dstTypes)
+ return true;
+ int argc;
+ if ((argc = srcTypes.length) != dstTypes.length)
+ return false;
+ if (argc <= 1) {
+ if (argc == 1 && !canConvert(srcTypes[0], dstTypes[0]))
+ return false;
+ return true;
+ }
+ // Android-removed: use of MethodTypeForm does not apply to Android implementation.
+ // if ((oldForm.primitiveParameterCount() == 0 && oldForm.erasedType == this) ||
+ // (newForm.primitiveParameterCount() == 0 && newForm.erasedType == newType)) {
+ // // Somewhat complicated test to avoid a loop of 2 or more trips.
+ // // If either type has only Object parameters, we know we can convert.
+ // assert(canConvertParameters(srcTypes, dstTypes));
+ // return true;
+ // }
+ return canConvertParameters(srcTypes, dstTypes);
+ }
+
+ /** Returns true if MHs.explicitCastArguments produces the same result as MH.asType.
+ * If the type conversion is impossible for either, the result should be false.
+ */
+ /*non-public*/
+ boolean explicitCastEquivalentToAsType(MethodType newType) {
+ if (this == newType) return true;
+ if (!explicitCastEquivalentToAsType(rtype, newType.rtype)) {
+ return false;
+ }
+ Class<?>[] srcTypes = newType.ptypes;
+ Class<?>[] dstTypes = ptypes;
+ if (dstTypes == srcTypes) {
+ return true;
+ }
+ assert(dstTypes.length == srcTypes.length);
+ for (int i = 0; i < dstTypes.length; i++) {
+ if (!explicitCastEquivalentToAsType(srcTypes[i], dstTypes[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /** Reports true if the src can be converted to the dst, by both asType and MHs.eCE,
+ * and with the same effect.
+ * MHs.eCA has the following "upgrades" to MH.asType:
+ * 1. interfaces are unchecked (that is, treated as if aliased to Object)
+ * Therefore, {@code Object->CharSequence} is possible in both cases but has different semantics
+ * 2a. the full matrix of primitive-to-primitive conversions is supported
+ * Narrowing like {@code long->byte} and basic-typing like {@code boolean->int}
+ * are not supported by asType, but anything supported by asType is equivalent
+ * with MHs.eCE.
+ * 2b. conversion of void->primitive means explicit cast has to insert zero/false/null.
+ * 3a. unboxing conversions can be followed by the full matrix of primitive conversions
+ * 3b. unboxing of null is permitted (creates a zero primitive value)
+ * Other than interfaces, reference-to-reference conversions are the same.
+ * Boxing primitives to references is the same for both operators.
+ */
+ private static boolean explicitCastEquivalentToAsType(Class<?> src, Class<?> dst) {
+ if (src == dst || dst == Object.class || dst == void.class) return true;
+ if (src.isPrimitive()) {
+ // Could be a prim/prim conversion, where casting is a strict superset.
+ // Or a boxing conversion, which is always to an exact wrapper class.
+ return canConvert(src, dst);
+ } else if (dst.isPrimitive()) {
+ // Unboxing behavior is different between MHs.eCA & MH.asType (see 3b).
+ return false;
+ } else {
+ // R->R always works, but we have to avoid a check-cast to an interface.
+ return !dst.isInterface() || dst.isAssignableFrom(src);
+ }
+ }
+
+ private boolean canConvertParameters(Class<?>[] srcTypes, Class<?>[] dstTypes) {
+ for (int i = 0; i < srcTypes.length; i++) {
+ if (!canConvert(srcTypes[i], dstTypes[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /*non-public*/
+ static boolean canConvert(Class<?> src, Class<?> dst) {
+ // short-circuit a few cases:
+ if (src == dst || src == Object.class || dst == Object.class) return true;
+ // the remainder of this logic is documented in MethodHandle.asType
+ if (src.isPrimitive()) {
+ // can force void to an explicit null, a la reflect.Method.invoke
+ // can also force void to a primitive zero, by analogy
+ if (src == void.class) return true; //or !dst.isPrimitive()?
+ Wrapper sw = Wrapper.forPrimitiveType(src);
+ if (dst.isPrimitive()) {
+ // P->P must widen
+ return Wrapper.forPrimitiveType(dst).isConvertibleFrom(sw);
+ } else {
+ // P->R must box and widen
+ return dst.isAssignableFrom(sw.wrapperType());
+ }
+ } else if (dst.isPrimitive()) {
+ // any value can be dropped
+ if (dst == void.class) return true;
+ Wrapper dw = Wrapper.forPrimitiveType(dst);
+ // R->P must be able to unbox (from a dynamically chosen type) and widen
+ // For example:
+ // Byte/Number/Comparable/Object -> dw:Byte -> byte.
+ // Character/Comparable/Object -> dw:Character -> char
+ // Boolean/Comparable/Object -> dw:Boolean -> boolean
+ // This means that dw must be cast-compatible with src.
+ if (src.isAssignableFrom(dw.wrapperType())) {
+ return true;
+ }
+ // The above does not work if the source reference is strongly typed
+ // to a wrapper whose primitive must be widened. For example:
+ // Byte -> unbox:byte -> short/int/long/float/double
+ // Character -> unbox:char -> int/long/float/double
+ if (Wrapper.isWrapperType(src) &&
+ dw.isConvertibleFrom(Wrapper.forWrapperType(src))) {
+ // can unbox from src and then widen to dst
+ return true;
+ }
+ // We have already covered cases which arise due to runtime unboxing
+ // of a reference type which covers several wrapper types:
+ // Object -> cast:Integer -> unbox:int -> long/float/double
+ // Serializable -> cast:Byte -> unbox:byte -> byte/short/int/long/float/double
+ // An marginal case is Number -> dw:Character -> char, which would be OK if there were a
+ // subclass of Number which wraps a value that can convert to char.
+ // Since there is none, we don't need an extra check here to cover char or boolean.
+ return false;
+ } else {
+ // R->R always works, since null is always valid dynamically
+ return true;
+ }
+ }
+
+ /// Queries which have to do with the bytecode architecture
+
+ /** Reports the number of JVM stack slots required to invoke a method
+ * of this type. Note that (for historical reasons) the JVM requires
+ * a second stack slot to pass long and double arguments.
+ * So this method returns {@link #parameterCount() parameterCount} plus the
+ * number of long and double parameters (if any).
+ * <p>
+ * This method is included for the benefit of applications that must
+ * generate bytecodes that process method handles and invokedynamic.
+ * @return the number of JVM stack slots for this type's parameters
+ */
+ /*non-public*/ int parameterSlotCount() {
+ return form.parameterSlotCount();
+ }
+
+ // BEGIN Android-removed: Cache of higher order adapters.
+ /*
+ /*non-public* Invokers invokers() {
+ Invokers inv = invokers;
+ if (inv != null) return inv;
+ invokers = inv = new Invokers(this);
+ return inv;
+ }
+ */
+ // END Android-removed: Cache of higher order adapters.
+
+ // BEGIN Android-removed: Implementation methods unused on Android.
+ /*
+ /** Reports the number of JVM stack slots which carry all parameters including and after
+ * the given position, which must be in the range of 0 to
+ * {@code parameterCount} inclusive. Successive parameters are
+ * more shallowly stacked, and parameters are indexed in the bytecodes
+ * according to their trailing edge. Thus, to obtain the depth
+ * in the outgoing call stack of parameter {@code N}, obtain
+ * the {@code parameterSlotDepth} of its trailing edge
+ * at position {@code N+1}.
+ * <p>
+ * Parameters of type {@code long} and {@code double} occupy
+ * two stack slots (for historical reasons) and all others occupy one.
+ * Therefore, the number returned is the number of arguments
+ * <em>including</em> and <em>after</em> the given parameter,
+ * <em>plus</em> the number of long or double arguments
+ * at or after after the argument for the given parameter.
+ * <p>
+ * This method is included for the benefit of applications that must
+ * generate bytecodes that process method handles and invokedynamic.
+ * @param num an index (zero-based, inclusive) within the parameter types
+ * @return the index of the (shallowest) JVM stack slot transmitting the
+ * given parameter
+ * @throws IllegalArgumentException if {@code num} is negative or greater than {@code parameterCount()}
+ *
+ /*non-public* int parameterSlotDepth(int num) {
+ if (num < 0 || num > ptypes.length)
+ parameterType(num); // force a range check
+ return form.parameterToArgSlot(num-1);
+ }
+
+ /** Reports the number of JVM stack slots required to receive a return value
+ * from a method of this type.
+ * If the {@link #returnType() return type} is void, it will be zero,
+ * else if the return type is long or double, it will be two, else one.
+ * <p>
+ * This method is included for the benefit of applications that must
+ * generate bytecodes that process method handles and invokedynamic.
+ * @return the number of JVM stack slots (0, 1, or 2) for this type's return value
+ * Will be removed for PFD.
+ *
+ /*non-public* int returnSlotCount() {
+ return form.returnSlotCount();
+ }
+ */
+ // END Android-removed: Implementation methods unused on Android.
+
+ /**
+ * Finds or creates an instance of a method type, given the spelling of its bytecode descriptor.
+ * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+ * Any class or interface name embedded in the descriptor string
+ * will be resolved by calling {@link ClassLoader#loadClass(java.lang.String)}
+ * on the given loader (or if it is null, on the system class loader).
+ * <p>
+ * Note that it is possible to encounter method types which cannot be
+ * constructed by this method, because their component types are
+ * not all reachable from a common class loader.
+ * <p>
+ * This method is included for the benefit of applications that must
+ * generate bytecodes that process method handles and {@code invokedynamic}.
+ * @param descriptor a bytecode-level type descriptor string "(T...)T"
+ * @param loader the class loader in which to look up the types
+ * @return a method type matching the bytecode-level type descriptor
+ * @throws NullPointerException if the string is null
+ * @throws IllegalArgumentException if the string is not well-formed
+ * @throws TypeNotPresentException if a named type cannot be found
+ */
+ public static MethodType fromMethodDescriptorString(String descriptor, ClassLoader loader)
+ throws IllegalArgumentException, TypeNotPresentException
+ {
+ if (!descriptor.startsWith("(") || // also generates NPE if needed
+ descriptor.indexOf(')') < 0 ||
+ descriptor.indexOf('.') >= 0)
+ throw newIllegalArgumentException("not a method descriptor: "+descriptor);
+ List<Class<?>> types = BytecodeDescriptor.parseMethod(descriptor, loader);
+ Class<?> rtype = types.remove(types.size() - 1);
+ checkSlotCount(types.size());
+ Class<?>[] ptypes = listToArray(types);
+ return makeImpl(rtype, ptypes, true);
+ }
+
+ /**
+ * Produces a bytecode descriptor representation of the method type.
+ * <p>
+ * Note that this is not a strict inverse of {@link #fromMethodDescriptorString fromMethodDescriptorString}.
+ * Two distinct classes which share a common name but have different class loaders
+ * will appear identical when viewed within descriptor strings.
+ * <p>
+ * This method is included for the benefit of applications that must
+ * generate bytecodes that process method handles and {@code invokedynamic}.
+ * {@link #fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader) fromMethodDescriptorString},
+ * because the latter requires a suitable class loader argument.
+ * @return the bytecode type descriptor representation
+ */
+ public String toMethodDescriptorString() {
+ String desc = methodDescriptor;
+ if (desc == null) {
+ desc = BytecodeDescriptor.unparse(this);
+ methodDescriptor = desc;
+ }
+ return desc;
+ }
+
+ // Android-changed: Remove MethodTypeDesc from javadoc until MethodTypeDesc is added.
+ /**
+ * Returns a descriptor string for this method type.
+ *
+ * <p>
+ * If this method type can be <a href="#descriptor">described nominally</a>,
+ * then the result is a method type descriptor (JVMS {@jvms 4.3.3}).
+ * <p>
+ * If this method type cannot be <a href="#descriptor">described nominally</a>
+ * and the result is a string of the form:
+ * <blockquote>{@code "(<parameter-descriptors>)<return-descriptor>"}</blockquote>
+ * where {@code <parameter-descriptors>} is the concatenation of the
+ * {@linkplain Class#descriptorString() descriptor string} of all
+ * of the parameter types and the {@linkplain Class#descriptorString() descriptor string}
+ * of the return type.
+ *
+ * @return the descriptor string for this method type
+ * @since 12
+ * @jvms 4.3.3 Method Descriptors
+ * @see <a href="#descriptor">Nominal Descriptor for {@code MethodType}</a>
+ */
+ @Override
+ public String descriptorString() {
+ return toMethodDescriptorString();
+ }
+
+ /*non-public*/
+ static String toFieldDescriptorString(Class<?> cls) {
+ return BytecodeDescriptor.unparse(cls);
+ }
+
+ /// Serialization.
+
+ /**
+ * There are no serializable fields for {@code MethodType}.
+ */
+ private static final java.io.ObjectStreamField[] serialPersistentFields = { };
+
+ /**
+ * Save the {@code MethodType} instance to a stream.
+ *
+ * @serialData
+ * For portability, the serialized format does not refer to named fields.
+ * Instead, the return type and parameter type arrays are written directly
+ * from the {@code writeObject} method, using two calls to {@code s.writeObject}
+ * as follows:
+ * <blockquote><pre>{@code
+s.writeObject(this.returnType());
+s.writeObject(this.parameterArray());
+ * }</pre></blockquote>
+ * <p>
+ * The deserialized field values are checked as if they were
+ * provided to the factory method {@link #methodType(Class,Class[]) methodType}.
+ * For example, null values, or {@code void} parameter types,
+ * will lead to exceptions during deserialization.
+ * @param s the stream to write the object to
+ * @throws java.io.IOException if there is a problem writing the object
+ */
+ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
+ s.defaultWriteObject(); // requires serialPersistentFields to be an empty array
+ s.writeObject(returnType());
+ s.writeObject(parameterArray());
+ }
+
+ /**
+ * Reconstitute the {@code MethodType} instance from a stream (that is,
+ * deserialize it).
+ * This instance is a scratch object with bogus final fields.
+ * It provides the parameters to the factory method called by
+ * {@link #readResolve readResolve}.
+ * After that call it is discarded.
+ * @param s the stream to read the object from
+ * @throws java.io.IOException if there is a problem reading the object
+ * @throws ClassNotFoundException if one of the component classes cannot be resolved
+ * @see #MethodType()
+ * @see #readResolve
+ * @see #writeObject
+ */
+ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
+ s.defaultReadObject(); // requires serialPersistentFields to be an empty array
+
+ Class<?> returnType = (Class<?>) s.readObject();
+ Class<?>[] parameterArray = (Class<?>[]) s.readObject();
+
+ // Probably this object will never escape, but let's check
+ // the field values now, just to be sure.
+ checkRtype(returnType);
+ checkPtypes(parameterArray);
+
+ parameterArray = parameterArray.clone(); // make sure it is unshared
+ MethodType_init(returnType, parameterArray);
+ }
+
+ /**
+ * For serialization only.
+ * Sets the final fields to null, pending {@code Unsafe.putObject}.
+ */
+ private MethodType() {
+ this.rtype = null;
+ this.ptypes = null;
+ }
+ private void MethodType_init(Class<?> rtype, Class<?>[] ptypes) {
+ // In order to communicate these values to readResolve, we must
+ // store them into the implementation-specific final fields.
+ checkRtype(rtype);
+ checkPtypes(ptypes);
+ UNSAFE.putObject(this, rtypeOffset, rtype);
+ UNSAFE.putObject(this, ptypesOffset, ptypes);
+ }
+
+ // Support for resetting final fields while deserializing
+ private static final long rtypeOffset, ptypesOffset;
+ static {
+ try {
+ rtypeOffset = UNSAFE.objectFieldOffset
+ (MethodType.class.getDeclaredField("rtype"));
+ ptypesOffset = UNSAFE.objectFieldOffset
+ (MethodType.class.getDeclaredField("ptypes"));
+ } catch (Exception ex) {
+ throw new Error(ex);
+ }
+ }
+
+ /**
+ * Resolves and initializes a {@code MethodType} object
+ * after serialization.
+ * @return the fully initialized {@code MethodType} object
+ */
+ private Object readResolve() {
+ // Do not use a trusted path for deserialization:
+ //return makeImpl(rtype, ptypes, true);
+ // Verify all operands, and make sure ptypes is unshared:
+ return methodType(rtype, ptypes);
+ }
+
+ /**
+ * Simple implementation of weak concurrent intern set.
+ *
+ * @param <T> interned type
+ */
+ private static class ConcurrentWeakInternSet<T> {
+
+ private final ConcurrentMap<WeakEntry<T>, WeakEntry<T>> map;
+ private final ReferenceQueue<T> stale;
+
+ public ConcurrentWeakInternSet() {
+ this.map = new ConcurrentHashMap<>();
+ this.stale = new ReferenceQueue<>();
+ }
+
+ /**
+ * Get the existing interned element.
+ * This method returns null if no element is interned.
+ *
+ * @param elem element to look up
+ * @return the interned element
+ */
+ public T get(T elem) {
+ if (elem == null) throw new NullPointerException();
+ expungeStaleElements();
+
+ WeakEntry<T> value = map.get(new WeakEntry<>(elem));
+ if (value != null) {
+ T res = value.get();
+ if (res != null) {
+ return res;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Interns the element.
+ * Always returns non-null element, matching the one in the intern set.
+ * Under the race against another add(), it can return <i>different</i>
+ * element, if another thread beats us to interning it.
+ *
+ * @param elem element to add
+ * @return element that was actually added
+ */
+ public T add(T elem) {
+ if (elem == null) throw new NullPointerException();
+
+ // Playing double race here, and so spinloop is required.
+ // First race is with two concurrent updaters.
+ // Second race is with GC purging weak ref under our feet.
+ // Hopefully, we almost always end up with a single pass.
+ T interned;
+ WeakEntry<T> e = new WeakEntry<>(elem, stale);
+ do {
+ expungeStaleElements();
+ WeakEntry<T> exist = map.putIfAbsent(e, e);
+ interned = (exist == null) ? elem : exist.get();
+ } while (interned == null);
+ return interned;
+ }
+
+ private void expungeStaleElements() {
+ Reference<? extends T> reference;
+ while ((reference = stale.poll()) != null) {
+ map.remove(reference);
+ }
+ }
+
+ private static class WeakEntry<T> extends WeakReference<T> {
+
+ public final int hashcode;
+
+ public WeakEntry(T key, ReferenceQueue<T> queue) {
+ super(key, queue);
+ hashcode = key.hashCode();
+ }
+
+ public WeakEntry(T key) {
+ super(key);
+ hashcode = key.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof WeakEntry) {
+ Object that = ((WeakEntry) obj).get();
+ Object mine = get();
+ return (that == null || mine == null) ? (this == obj) : mine.equals(that);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return hashcode;
+ }
+
+ }
+ }
+
+}
diff --git a/android-35/java/lang/invoke/MethodTypeForm.java b/android-35/java/lang/invoke/MethodTypeForm.java
new file mode 100644
index 0000000..6f6c2a8
--- /dev/null
+++ b/android-35/java/lang/invoke/MethodTypeForm.java
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import sun.invoke.util.Wrapper;
+import java.lang.ref.SoftReference;
+import static java.lang.invoke.MethodHandleStatics.*;
+
+/**
+ * Shared information for a group of method types, which differ
+ * only by reference types, and therefore share a common erasure
+ * and wrapping.
+ * <p>
+ * For an empirical discussion of the structure of method types,
+ * see <a href="http://groups.google.com/group/jvm-languages/browse_thread/thread/ac9308ae74da9b7e/">
+ * the thread "Avoiding Boxing" on jvm-languages</a>.
+ * There are approximately 2000 distinct erased method types in the JDK.
+ * There are a little over 10 times that number of unerased types.
+ * No more than half of these are likely to be loaded at once.
+ * @author John Rose
+ */
+final class MethodTypeForm {
+ final int[] argToSlotTable, slotToArgTable;
+ final long argCounts; // packed slot & value counts
+ final long primCounts; // packed prim & double counts
+ final MethodType erasedType; // the canonical erasure
+ final MethodType basicType; // the canonical erasure, with primitives simplified
+
+ // BEGIN Android-removed: Cached adaptors / lambda forms.
+ // The upstream caching mechanism will not work on Android because of fundamental differences
+ // in the Android runtime/implementation of MethodHandle. LambdaForm is not supported on
+ // Android for similar reasons.
+ /*
+ // Cached adapter information:
+ @Stable final SoftReference<MethodHandle>[] methodHandles;
+ // Indexes into methodHandles:
+ static final int
+ MH_BASIC_INV = 0, // cached instance of MH.invokeBasic
+ MH_NF_INV = 1, // cached helper for LF.NamedFunction
+ MH_UNINIT_CS = 2, // uninitialized call site
+ MH_LIMIT = 3;
+
+ // Cached lambda form information, for basic types only:
+ final @Stable SoftReference<LambdaForm>[] lambdaForms;
+ // Indexes into lambdaForms:
+ static final int
+ LF_INVVIRTUAL = 0, // DMH invokeVirtual
+ LF_INVSTATIC = 1,
+ LF_INVSPECIAL = 2,
+ LF_NEWINVSPECIAL = 3,
+ LF_INVINTERFACE = 4,
+ LF_INVSTATIC_INIT = 5, // DMH invokeStatic with <clinit> barrier
+ LF_INTERPRET = 6, // LF interpreter
+ LF_REBIND = 7, // BoundMethodHandle
+ LF_DELEGATE = 8, // DelegatingMethodHandle
+ LF_DELEGATE_BLOCK_INLINING = 9, // Counting DelegatingMethodHandle w/ @DontInline
+ LF_EX_LINKER = 10, // invokeExact_MT (for invokehandle)
+ LF_EX_INVOKER = 11, // MHs.invokeExact
+ LF_GEN_LINKER = 12, // generic invoke_MT (for invokehandle)
+ LF_GEN_INVOKER = 13, // generic MHs.invoke
+ LF_CS_LINKER = 14, // linkToCallSite_CS
+ LF_MH_LINKER = 15, // linkToCallSite_MH
+ LF_GWC = 16, // guardWithCatch (catchException)
+ LF_GWT = 17, // guardWithTest
+ LF_LIMIT = 18;
+ */
+ // END Android-removed: Cached adaptors / lambda forms.
+
+ /** Return the type corresponding uniquely (1-1) to this MT-form.
+ * It might have any primitive returns or arguments, but will have no references except Object.
+ */
+ public MethodType erasedType() {
+ return erasedType;
+ }
+
+ /** Return the basic type derived from the erased type of this MT-form.
+ * A basic type is erased (all references Object) and also has all primitive
+ * types (except int, long, float, double, void) normalized to int.
+ * Such basic types correspond to low-level JVM calling sequences.
+ */
+ public MethodType basicType() {
+ return basicType;
+ }
+
+ private boolean assertIsBasicType() {
+ // primitives must be flattened also
+ assert(erasedType == basicType)
+ : "erasedType: " + erasedType + " != basicType: " + basicType;
+ return true;
+ }
+
+ // BEGIN Android-removed: Cached adaptors / lambda forms.
+ /*
+ public MethodHandle cachedMethodHandle(int which) {
+ assert(assertIsBasicType());
+ SoftReference<MethodHandle> entry = methodHandles[which];
+ return (entry != null) ? entry.get() : null;
+ }
+
+ synchronized public MethodHandle setCachedMethodHandle(int which, MethodHandle mh) {
+ // Simulate a CAS, to avoid racy duplication of results.
+ SoftReference<MethodHandle> entry = methodHandles[which];
+ if (entry != null) {
+ MethodHandle prev = entry.get();
+ if (prev != null) {
+ return prev;
+ }
+ }
+ methodHandles[which] = new SoftReference<>(mh);
+ return mh;
+ }
+
+ public LambdaForm cachedLambdaForm(int which) {
+ assert(assertIsBasicType());
+ SoftReference<LambdaForm> entry = lambdaForms[which];
+ return (entry != null) ? entry.get() : null;
+ }
+
+ synchronized public LambdaForm setCachedLambdaForm(int which, LambdaForm form) {
+ // Simulate a CAS, to avoid racy duplication of results.
+ SoftReference<LambdaForm> entry = lambdaForms[which];
+ if (entry != null) {
+ LambdaForm prev = entry.get();
+ if (prev != null) {
+ return prev;
+ }
+ }
+ lambdaForms[which] = new SoftReference<>(form);
+ return form;
+ }
+ */
+ // END Android-removed: Cached adaptors / lambda forms.
+
+ /**
+ * Build an MTF for a given type, which must have all references erased to Object.
+ * This MTF will stand for that type and all un-erased variations.
+ * Eagerly compute some basic properties of the type, common to all variations.
+ */
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ protected MethodTypeForm(MethodType erasedType) {
+ this.erasedType = erasedType;
+
+ Class<?>[] ptypes = erasedType.ptypes();
+ int ptypeCount = ptypes.length;
+ int pslotCount = ptypeCount; // temp. estimate
+ int rtypeCount = 1; // temp. estimate
+ int rslotCount = 1; // temp. estimate
+
+ int[] argToSlotTab = null, slotToArgTab = null;
+
+ // Walk the argument types, looking for primitives.
+ int pac = 0, lac = 0, prc = 0, lrc = 0;
+ Class<?>[] epts = ptypes;
+ Class<?>[] bpts = epts;
+ for (int i = 0; i < epts.length; i++) {
+ Class<?> pt = epts[i];
+ if (pt != Object.class) {
+ ++pac;
+ Wrapper w = Wrapper.forPrimitiveType(pt);
+ if (w.isDoubleWord()) ++lac;
+ if (w.isSubwordOrInt() && pt != int.class) {
+ if (bpts == epts)
+ bpts = bpts.clone();
+ bpts[i] = int.class;
+ }
+ }
+ }
+ pslotCount += lac; // #slots = #args + #longs
+ Class<?> rt = erasedType.returnType();
+ Class<?> bt = rt;
+ if (rt != Object.class) {
+ ++prc; // even void.class counts as a prim here
+ Wrapper w = Wrapper.forPrimitiveType(rt);
+ if (w.isDoubleWord()) ++lrc;
+ if (w.isSubwordOrInt() && rt != int.class)
+ bt = int.class;
+ // adjust #slots, #args
+ if (rt == void.class)
+ rtypeCount = rslotCount = 0;
+ else
+ rslotCount += lrc;
+ }
+ if (epts == bpts && bt == rt) {
+ this.basicType = erasedType;
+ } else {
+ this.basicType = MethodType.makeImpl(bt, bpts, true);
+ // fill in rest of data from the basic type:
+ MethodTypeForm that = this.basicType.form();
+ assert(this != that);
+ this.primCounts = that.primCounts;
+ this.argCounts = that.argCounts;
+ this.argToSlotTable = that.argToSlotTable;
+ this.slotToArgTable = that.slotToArgTable;
+ // Android-removed: Cached adaptors / lambda forms.
+ // this.methodHandles = null;
+ // this.lambdaForms = null;
+ return;
+ }
+ if (lac != 0) {
+ int slot = ptypeCount + lac;
+ slotToArgTab = new int[slot+1];
+ argToSlotTab = new int[1+ptypeCount];
+ argToSlotTab[0] = slot; // argument "-1" is past end of slots
+ for (int i = 0; i < epts.length; i++) {
+ Class<?> pt = epts[i];
+ Wrapper w = Wrapper.forBasicType(pt);
+ if (w.isDoubleWord()) --slot;
+ --slot;
+ slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
+ argToSlotTab[1+i] = slot;
+ }
+ assert(slot == 0); // filled the table
+ } else if (pac != 0) {
+ // have primitives but no long primitives; share slot counts with generic
+ assert(ptypeCount == pslotCount);
+ MethodTypeForm that = MethodType.genericMethodType(ptypeCount).form();
+ assert(this != that);
+ slotToArgTab = that.slotToArgTable;
+ argToSlotTab = that.argToSlotTable;
+ } else {
+ int slot = ptypeCount; // first arg is deepest in stack
+ slotToArgTab = new int[slot+1];
+ argToSlotTab = new int[1+ptypeCount];
+ argToSlotTab[0] = slot; // argument "-1" is past end of slots
+ for (int i = 0; i < ptypeCount; i++) {
+ --slot;
+ slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
+ argToSlotTab[1+i] = slot;
+ }
+ }
+ this.primCounts = pack(lrc, prc, lac, pac);
+ this.argCounts = pack(rslotCount, rtypeCount, pslotCount, ptypeCount);
+ this.argToSlotTable = argToSlotTab;
+ this.slotToArgTable = slotToArgTab;
+
+ if (pslotCount >= 256) throw newIllegalArgumentException("too many arguments");
+
+ // Initialize caches, but only for basic types
+ assert(basicType == erasedType);
+ // Android-removed: Cached adaptors / lambda forms.
+ // this.lambdaForms = new SoftReference[LF_LIMIT];
+ // this.methodHandles = new SoftReference[MH_LIMIT];
+ }
+
+ private static long pack(int a, int b, int c, int d) {
+ assert(((a|b|c|d) & ~0xFFFF) == 0);
+ long hw = ((a << 16) | b), lw = ((c << 16) | d);
+ return (hw << 32) | lw;
+ }
+ private static char unpack(long packed, int word) { // word==0 => return a, ==3 => return d
+ assert(word <= 3);
+ return (char)(packed >> ((3-word) * 16));
+ }
+
+ public int parameterCount() { // # outgoing values
+ return unpack(argCounts, 3);
+ }
+ public int parameterSlotCount() { // # outgoing interpreter slots
+ return unpack(argCounts, 2);
+ }
+ public int returnCount() { // = 0 (V), or 1
+ return unpack(argCounts, 1);
+ }
+ public int returnSlotCount() { // = 0 (V), 2 (J/D), or 1
+ return unpack(argCounts, 0);
+ }
+ public int primitiveParameterCount() {
+ return unpack(primCounts, 3);
+ }
+ public int longPrimitiveParameterCount() {
+ return unpack(primCounts, 2);
+ }
+ public int primitiveReturnCount() { // = 0 (obj), or 1
+ return unpack(primCounts, 1);
+ }
+ public int longPrimitiveReturnCount() { // = 1 (J/D), or 0
+ return unpack(primCounts, 0);
+ }
+ public boolean hasPrimitives() {
+ return primCounts != 0;
+ }
+ public boolean hasNonVoidPrimitives() {
+ if (primCounts == 0) return false;
+ if (primitiveParameterCount() != 0) return true;
+ return (primitiveReturnCount() != 0 && returnCount() != 0);
+ }
+ public boolean hasLongPrimitives() {
+ return (longPrimitiveParameterCount() | longPrimitiveReturnCount()) != 0;
+ }
+ public int parameterToArgSlot(int i) {
+ return argToSlotTable[1+i];
+ }
+ public int argSlotToParameter(int argSlot) {
+ // Note: Empty slots are represented by zero in this table.
+ // Valid arguments slots contain incremented entries, so as to be non-zero.
+ // We return -1 the caller to mean an empty slot.
+ return slotToArgTable[argSlot] - 1;
+ }
+
+ static MethodTypeForm findForm(MethodType mt) {
+ MethodType erased = canonicalize(mt, ERASE, ERASE);
+ if (erased == null) {
+ // It is already erased. Make a new MethodTypeForm.
+ return new MethodTypeForm(mt);
+ } else {
+ // Share the MethodTypeForm with the erased version.
+ return erased.form();
+ }
+ }
+
+ /** Codes for {@link #canonicalize(java.lang.Class, int)}.
+ * ERASE means change every reference to {@code Object}.
+ * WRAP means convert primitives (including {@code void} to their
+ * corresponding wrapper types. UNWRAP means the reverse of WRAP.
+ * INTS means convert all non-void primitive types to int or long,
+ * according to size. LONGS means convert all non-void primitives
+ * to long, regardless of size. RAW_RETURN means convert a type
+ * (assumed to be a return type) to int if it is smaller than an int,
+ * or if it is void.
+ */
+ public static final int NO_CHANGE = 0, ERASE = 1, WRAP = 2, UNWRAP = 3, INTS = 4, LONGS = 5, RAW_RETURN = 6;
+
+ /** Canonicalize the types in the given method type.
+ * If any types change, intern the new type, and return it.
+ * Otherwise return null.
+ */
+ public static MethodType canonicalize(MethodType mt, int howRet, int howArgs) {
+ Class<?>[] ptypes = mt.ptypes();
+ Class<?>[] ptc = MethodTypeForm.canonicalizeAll(ptypes, howArgs);
+ Class<?> rtype = mt.returnType();
+ Class<?> rtc = MethodTypeForm.canonicalize(rtype, howRet);
+ if (ptc == null && rtc == null) {
+ // It is already canonical.
+ return null;
+ }
+ // Find the erased version of the method type:
+ if (rtc == null) rtc = rtype;
+ if (ptc == null) ptc = ptypes;
+ return MethodType.makeImpl(rtc, ptc, true);
+ }
+
+ /** Canonicalize the given return or param type.
+ * Return null if the type is already canonicalized.
+ */
+ static Class<?> canonicalize(Class<?> t, int how) {
+ Class<?> ct;
+ if (t == Object.class) {
+ // no change, ever
+ } else if (!t.isPrimitive()) {
+ switch (how) {
+ case UNWRAP:
+ ct = Wrapper.asPrimitiveType(t);
+ if (ct != t) return ct;
+ break;
+ case RAW_RETURN:
+ case ERASE:
+ return Object.class;
+ }
+ } else if (t == void.class) {
+ // no change, usually
+ switch (how) {
+ case RAW_RETURN:
+ return int.class;
+ case WRAP:
+ return Void.class;
+ }
+ } else {
+ // non-void primitive
+ switch (how) {
+ case WRAP:
+ return Wrapper.asWrapperType(t);
+ case INTS:
+ if (t == int.class || t == long.class)
+ return null; // no change
+ if (t == double.class)
+ return long.class;
+ return int.class;
+ case LONGS:
+ if (t == long.class)
+ return null; // no change
+ return long.class;
+ case RAW_RETURN:
+ if (t == int.class || t == long.class ||
+ t == float.class || t == double.class)
+ return null; // no change
+ // everything else returns as an int
+ return int.class;
+ }
+ }
+ // no change; return null to signify
+ return null;
+ }
+
+ /** Canonicalize each param type in the given array.
+ * Return null if all types are already canonicalized.
+ */
+ static Class<?>[] canonicalizeAll(Class<?>[] ts, int how) {
+ Class<?>[] cs = null;
+ for (int imax = ts.length, i = 0; i < imax; i++) {
+ Class<?> c = canonicalize(ts[i], how);
+ if (c == void.class)
+ c = null; // a Void parameter was unwrapped to void; ignore
+ if (c != null) {
+ if (cs == null)
+ cs = ts.clone();
+ cs[i] = c;
+ }
+ }
+ return cs;
+ }
+
+ @Override
+ public String toString() {
+ return "Form"+erasedType;
+ }
+}
diff --git a/android-35/java/lang/invoke/MutableCallSite.java b/android-35/java/lang/invoke/MutableCallSite.java
new file mode 100644
index 0000000..305579f
--- /dev/null
+++ b/android-35/java/lang/invoke/MutableCallSite.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+// Android-changed: removed references to MutableCallSite.syncAll().
+/**
+ * A {@code MutableCallSite} is a {@link CallSite} whose target variable
+ * behaves like an ordinary field.
+ * An {@code invokedynamic} instruction linked to a {@code MutableCallSite} delegates
+ * all calls to the site's current target.
+ * The {@linkplain CallSite#dynamicInvoker dynamic invoker} of a mutable call site
+ * also delegates each call to the site's current target.
+ * <p>
+ * Here is an example of a mutable call site which introduces a
+ * state variable into a method handle chain.
+ * <!-- JavaDocExamplesTest.testMutableCallSite -->
+ * <blockquote><pre>{@code
+MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class));
+MethodHandle MH_name = name.dynamicInvoker();
+MethodType MT_str1 = MethodType.methodType(String.class);
+MethodHandle MH_upcase = MethodHandles.lookup()
+ .findVirtual(String.class, "toUpperCase", MT_str1);
+MethodHandle worker1 = MethodHandles.filterReturnValue(MH_name, MH_upcase);
+name.setTarget(MethodHandles.constant(String.class, "Rocky"));
+assertEquals("ROCKY", (String) worker1.invokeExact());
+name.setTarget(MethodHandles.constant(String.class, "Fred"));
+assertEquals("FRED", (String) worker1.invokeExact());
+// (mutation can be continued indefinitely)
+ * }</pre></blockquote>
+ * <p>
+ * The same call site may be used in several places at once.
+ * <blockquote><pre>{@code
+MethodType MT_str2 = MethodType.methodType(String.class, String.class);
+MethodHandle MH_cat = lookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+MethodHandle MH_dear = MethodHandles.insertArguments(MH_cat, 1, ", dear?");
+MethodHandle worker2 = MethodHandles.filterReturnValue(MH_name, MH_dear);
+assertEquals("Fred, dear?", (String) worker2.invokeExact());
+name.setTarget(MethodHandles.constant(String.class, "Wilma"));
+assertEquals("WILMA", (String) worker1.invokeExact());
+assertEquals("Wilma, dear?", (String) worker2.invokeExact());
+ * }</pre></blockquote>
+ * <p>
+ * <em>Non-synchronization of target values:</em>
+ * A write to a mutable call site's target does not force other threads
+ * to become aware of the updated value. Threads which do not perform
+ * suitable synchronization actions relative to the updated call site
+ * may cache the old target value and delay their use of the new target
+ * value indefinitely.
+ * (This is a normal consequence of the Java Memory Model as applied
+ * to object fields.)
+ * <p>
+ * For target values which will be frequently updated, consider using
+ * a {@linkplain VolatileCallSite volatile call site} instead.
+ * @author John Rose, JSR 292 EG
+ */
+public class MutableCallSite extends CallSite {
+ /**
+ * Creates a blank call site object with the given method type.
+ * The initial target is set to a method handle of the given type
+ * which will throw an {@link IllegalStateException} if called.
+ * <p>
+ * The type of the call site is permanently set to the given type.
+ * <p>
+ * Before this {@code CallSite} object is returned from a bootstrap method,
+ * or invoked in some other manner,
+ * it is usually provided with a more useful target method,
+ * via a call to {@link CallSite#setTarget(MethodHandle) setTarget}.
+ * @param type the method type that this call site will have
+ * @throws NullPointerException if the proposed type is null
+ */
+ public MutableCallSite(MethodType type) {
+ super(type);
+ }
+
+ /**
+ * Creates a call site object with an initial target method handle.
+ * The type of the call site is permanently set to the initial target's type.
+ * @param target the method handle that will be the initial target of the call site
+ * @throws NullPointerException if the proposed target is null
+ */
+ public MutableCallSite(MethodHandle target) {
+ super(target);
+ }
+
+ /**
+ * Returns the target method of the call site, which behaves
+ * like a normal field of the {@code MutableCallSite}.
+ * <p>
+ * The interactions of {@code getTarget} with memory are the same
+ * as of a read from an ordinary variable, such as an array element or a
+ * non-volatile, non-final field.
+ * <p>
+ * In particular, the current thread may choose to reuse the result
+ * of a previous read of the target from memory, and may fail to see
+ * a recent update to the target by another thread.
+ *
+ * @return the linkage state of this call site, a method handle which can change over time
+ * @see #setTarget
+ */
+ @Override public final MethodHandle getTarget() {
+ return target;
+ }
+
+ /**
+ * Updates the target method of this call site, as a normal variable.
+ * The type of the new target must agree with the type of the old target.
+ * <p>
+ * The interactions with memory are the same
+ * as of a write to an ordinary variable, such as an array element or a
+ * non-volatile, non-final field.
+ * <p>
+ * In particular, unrelated threads may fail to see the updated target
+ * until they perform a read from memory.
+ * Stronger guarantees can be created by putting appropriate operations
+ * into the bootstrap method and/or the target methods used
+ * at any given call site.
+ *
+ * @param newTarget the new target
+ * @throws NullPointerException if the proposed new target is null
+ * @throws WrongMethodTypeException if the proposed new target
+ * has a method type that differs from the previous target
+ * @see #getTarget
+ */
+ @Override public void setTarget(MethodHandle newTarget) {
+ checkTargetChange(this.target, newTarget);
+ setTargetNormal(newTarget);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final MethodHandle dynamicInvoker() {
+ return makeDynamicInvoker();
+ }
+
+ // BEGIN Android-removed: syncAll() implementation is incomplete.
+ /**
+ * Performs a synchronization operation on each call site in the given array,
+ * forcing all other threads to throw away any cached values previously
+ * loaded from the target of any of the call sites.
+ * <p>
+ * This operation does not reverse any calls that have already started
+ * on an old target value.
+ * (Java supports {@linkplain java.lang.Object#wait() forward time travel} only.)
+ * <p>
+ * The overall effect is to force all future readers of each call site's target
+ * to accept the most recently stored value.
+ * ("Most recently" is reckoned relative to the {@code syncAll} itself.)
+ * Conversely, the {@code syncAll} call may block until all readers have
+ * (somehow) decached all previous versions of each call site's target.
+ * <p>
+ * To avoid race conditions, calls to {@code setTarget} and {@code syncAll}
+ * should generally be performed under some sort of mutual exclusion.
+ * Note that reader threads may observe an updated target as early
+ * as the {@code setTarget} call that install the value
+ * (and before the {@code syncAll} that confirms the value).
+ * On the other hand, reader threads may observe previous versions of
+ * the target until the {@code syncAll} call returns
+ * (and after the {@code setTarget} that attempts to convey the updated version).
+ * <p>
+ * This operation is likely to be expensive and should be used sparingly.
+ * If possible, it should be buffered for batch processing on sets of call sites.
+ * <p>
+ * If {@code sites} contains a null element,
+ * a {@code NullPointerException} will be raised.
+ * In this case, some non-null elements in the array may be
+ * processed before the method returns abnormally.
+ * Which elements these are (if any) is implementation-dependent.
+ *
+ * <h1>Java Memory Model details</h1>
+ * In terms of the Java Memory Model, this operation performs a synchronization
+ * action which is comparable in effect to the writing of a volatile variable
+ * by the current thread, and an eventual volatile read by every other thread
+ * that may access one of the affected call sites.
+ * <p>
+ * The following effects are apparent, for each individual call site {@code S}:
+ * <ul>
+ * <li>A new volatile variable {@code V} is created, and written by the current thread.
+ * As defined by the JMM, this write is a global synchronization event.
+ * <li>As is normal with thread-local ordering of write events,
+ * every action already performed by the current thread is
+ * taken to happen before the volatile write to {@code V}.
+ * (In some implementations, this means that the current thread
+ * performs a global release operation.)
+ * <li>Specifically, the write to the current target of {@code S} is
+ * taken to happen before the volatile write to {@code V}.
+ * <li>The volatile write to {@code V} is placed
+ * (in an implementation specific manner)
+ * in the global synchronization order.
+ * <li>Consider an arbitrary thread {@code T} (other than the current thread).
+ * If {@code T} executes a synchronization action {@code A}
+ * after the volatile write to {@code V} (in the global synchronization order),
+ * it is therefore required to see either the current target
+ * of {@code S}, or a later write to that target,
+ * if it executes a read on the target of {@code S}.
+ * (This constraint is called "synchronization-order consistency".)
+ * <li>The JMM specifically allows optimizing compilers to elide
+ * reads or writes of variables that are known to be useless.
+ * Such elided reads and writes have no effect on the happens-before
+ * relation. Regardless of this fact, the volatile {@code V}
+ * will not be elided, even though its written value is
+ * indeterminate and its read value is not used.
+ * </ul>
+ * Because of the last point, the implementation behaves as if a
+ * volatile read of {@code V} were performed by {@code T}
+ * immediately after its action {@code A}. In the local ordering
+ * of actions in {@code T}, this read happens before any future
+ * read of the target of {@code S}. It is as if the
+ * implementation arbitrarily picked a read of {@code S}'s target
+ * by {@code T}, and forced a read of {@code V} to precede it,
+ * thereby ensuring communication of the new target value.
+ * <p>
+ * As long as the constraints of the Java Memory Model are obeyed,
+ * implementations may delay the completion of a {@code syncAll}
+ * operation while other threads ({@code T} above) continue to
+ * use previous values of {@code S}'s target.
+ * However, implementations are (as always) encouraged to avoid
+ * livelock, and to eventually require all threads to take account
+ * of the updated target.
+ *
+ * <p style="font-size:smaller;">
+ * <em>Discussion:</em>
+ * For performance reasons, {@code syncAll} is not a virtual method
+ * on a single call site, but rather applies to a set of call sites.
+ * Some implementations may incur a large fixed overhead cost
+ * for processing one or more synchronization operations,
+ * but a small incremental cost for each additional call site.
+ * In any case, this operation is likely to be costly, since
+ * other threads may have to be somehow interrupted
+ * in order to make them notice the updated target value.
+ * However, it may be observed that a single call to synchronize
+ * several sites has the same formal effect as many calls,
+ * each on just one of the sites.
+ *
+ * <p style="font-size:smaller;">
+ * <em>Implementation Note:</em>
+ * Simple implementations of {@code MutableCallSite} may use
+ * a volatile variable for the target of a mutable call site.
+ * In such an implementation, the {@code syncAll} method can be a no-op,
+ * and yet it will conform to the JMM behavior documented above.
+ *
+ * @param sites an array of call sites to be synchronized
+ * @throws NullPointerException if the {@code sites} array reference is null
+ * or the array contains a null
+ *
+ public static void syncAll(MutableCallSite[] sites) {
+ if (sites.length == 0) return;
+ STORE_BARRIER.lazySet(0);
+ for (int i = 0; i < sites.length; i++) {
+ sites[i].getClass(); // trigger NPE on first null
+ }
+ // FIXME: NYI
+ }
+ private static final AtomicInteger STORE_BARRIER = new AtomicInteger();
+ */
+ // END Android-removed: syncAll() implementation is incomplete.
+}
diff --git a/android-35/java/lang/invoke/SerializedLambda.java b/android-35/java/lang/invoke/SerializedLambda.java
new file mode 100644
index 0000000..55ec670
--- /dev/null
+++ b/android-35/java/lang/invoke/SerializedLambda.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.invoke;
+
+import java.io.Serializable;
+
+public final class SerializedLambda implements Serializable {
+
+ public SerializedLambda(Class<?> capturingClass,
+ String functionalInterfaceClass,
+ String functionalInterfaceMethodName,
+ String functionalInterfaceMethodSignature,
+ int implMethodKind,
+ String implClass,
+ String implMethodName,
+ String implMethodSignature,
+ String instantiatedMethodType,
+ Object[] capturedArgs) { }
+
+ public String getCapturingClass() { return null; }
+
+ public String getFunctionalInterfaceClass() {
+ return null;
+ }
+
+ public String getFunctionalInterfaceMethodName() {
+ return null;
+ }
+
+ public String getFunctionalInterfaceMethodSignature() { return null; }
+
+ public String getImplClass() {
+ return null;
+ }
+
+ public String getImplMethodName() {
+ return null;
+ }
+
+ public String getImplMethodSignature() {
+ return null;
+ }
+
+ public int getImplMethodKind() {
+ return 0;
+ }
+
+ public final String getInstantiatedMethodType() {
+ return null;
+ }
+
+ public int getCapturedArgCount() {
+ return 0;
+ }
+
+ public Object getCapturedArg(int i) {
+ return null;
+ }
+
+}
diff --git a/android-35/java/lang/invoke/Stable.java b/android-35/java/lang/invoke/Stable.java
new file mode 100644
index 0000000..a0a413e
--- /dev/null
+++ b/android-35/java/lang/invoke/Stable.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import java.lang.annotation.*;
+
+/**
+ * A field may be annotated as stable if all of its component variables
+ * changes value at most once.
+ * A field's value counts as its component value.
+ * If the field is typed as an array, then all the non-null components
+ * of the array, of depth up to the rank of the field's array type,
+ * also count as component values.
+ * By extension, any variable (either array or field) which has annotated
+ * as stable is called a stable variable, and its non-null or non-zero
+ * value is called a stable value.
+ * <p>
+ * Since all fields begin with a default value of null for references
+ * (resp., zero for primitives), it follows that this annotation indicates
+ * that the first non-null (resp., non-zero) value stored in the field
+ * will never be changed.
+ * <p>
+ * If the field is not of an array type, there are no array elements,
+ * then the value indicated as stable is simply the value of the field.
+ * If the dynamic type of the field value is an array but the static type
+ * is not, the components of the array are <em>not</em> regarded as stable.
+ * <p>
+ * If the field is an array type, then both the field value and
+ * all the components of the field value (if the field value is non-null)
+ * are indicated to be stable.
+ * If the field type is an array type with rank {@code N > 1},
+ * then each component of the field value (if the field value is non-null),
+ * is regarded as a stable array of rank {@code N-1}.
+ * <p>
+ * Fields which are declared {@code final} may also be annotated as stable.
+ * Since final fields already behave as stable values, such an annotation
+ * indicates no additional information, unless the type of the field is
+ * an array type.
+ * <p>
+ * It is (currently) undefined what happens if a field annotated as stable
+ * is given a third value. In practice, if the JVM relies on this annotation
+ * to promote a field reference to a constant, it may be that the Java memory
+ * model would appear to be broken, if such a constant (the second value of the field)
+ * is used as the value of the field even after the field value has changed.
+ */
+/* package-private */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+@interface Stable {
+}
diff --git a/android-35/java/lang/invoke/StaticFieldVarHandle.java b/android-35/java/lang/invoke/StaticFieldVarHandle.java
new file mode 100644
index 0000000..e5faeb7
--- /dev/null
+++ b/android-35/java/lang/invoke/StaticFieldVarHandle.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.lang.invoke;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+/**
+ * A VarHandle that's associated with a static field.
+ * @hide
+ */
+final class StaticFieldVarHandle extends FieldVarHandle {
+ private final Class declaringClass;
+
+ private StaticFieldVarHandle(Field staticField) {
+ super(staticField);
+ declaringClass = staticField.getDeclaringClass();
+ }
+
+ static StaticFieldVarHandle create(Field staticField) {
+ assert Modifier.isStatic(staticField.getModifiers());
+ return new StaticFieldVarHandle(staticField);
+ }
+}
diff --git a/android-35/java/lang/invoke/Transformers.java b/android-35/java/lang/invoke/Transformers.java
new file mode 100644
index 0000000..57e0967
--- /dev/null
+++ b/android-35/java/lang/invoke/Transformers.java
@@ -0,0 +1,3151 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. The Android Open Source
+ * Project designates this particular file as subject to the "Classpath"
+ * exception as provided by The Android Open Source Project in the LICENSE
+ * file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package java.lang.invoke;
+
+import static dalvik.system.EmulatedStackFrame.StackFrameAccessor.copyNext;
+
+import dalvik.system.EmulatedStackFrame;
+import dalvik.system.EmulatedStackFrame.Range;
+import dalvik.system.EmulatedStackFrame.RandomOrderStackFrameReader;
+import dalvik.system.EmulatedStackFrame.StackFrameAccessor;
+import dalvik.system.EmulatedStackFrame.StackFrameReader;
+import dalvik.system.EmulatedStackFrame.StackFrameWriter;
+
+import sun.invoke.util.Wrapper;
+import sun.misc.Unsafe;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+
+/** @hide Public for testing only. */
+public class Transformers {
+ private Transformers() {}
+
+ static {
+ try {
+ TRANSFORM_INTERNAL =
+ MethodHandle.class.getDeclaredMethod(
+ "transformInternal", EmulatedStackFrame.class);
+ } catch (NoSuchMethodException nsme) {
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * Method reference to the private {@code MethodHandle.transformInternal} method. This is cached
+ * here because it's the point of entry for all transformers.
+ */
+ private static final Method TRANSFORM_INTERNAL;
+
+ /** @hide */
+ public abstract static class Transformer extends MethodHandle implements Cloneable {
+ protected Transformer(MethodType type) {
+ super(TRANSFORM_INTERNAL.getArtMethod(), MethodHandle.INVOKE_TRANSFORM, type);
+ }
+
+ protected Transformer(MethodType type, int invokeKind) {
+ super(TRANSFORM_INTERNAL.getArtMethod(), invokeKind, type);
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+ /**
+ * Performs a MethodHandle.invoke() call with arguments held in an
+ * EmulatedStackFrame.
+ * @param target the method handle to invoke
+ * @param stackFrame the stack frame containing arguments for the invocation
+ */
+ protected static void invokeFromTransform(MethodHandle target,
+ EmulatedStackFrame stackFrame) throws Throwable {
+ if (target instanceof Transformer) {
+ ((Transformer) target).transform(stackFrame);
+ } else {
+ final MethodHandle adaptedTarget = target.asType(stackFrame.getMethodType());
+ adaptedTarget.invokeExactWithFrame(stackFrame);
+ }
+ }
+
+ /**
+ * Performs a MethodHandle.invokeExact() call with arguments held in an
+ * EmulatedStackFrame.
+ * @param target the method handle to invoke
+ * @param stackFrame the stack frame containing arguments for the invocation
+ */
+ protected void invokeExactFromTransform(MethodHandle target,
+ EmulatedStackFrame stackFrame) throws Throwable {
+ if (target instanceof Transformer) {
+ ((Transformer) target).transform(stackFrame);
+ } else {
+ target.invokeExactWithFrame(stackFrame);
+ }
+ }
+ }
+
+ /** Implements {@code MethodHandles.throwException}. */
+ static class AlwaysThrow extends Transformer {
+ private final Class<? extends Throwable> exceptionType;
+
+ AlwaysThrow(Class<?> nominalReturnType, Class<? extends Throwable> exType) {
+ super(MethodType.methodType(nominalReturnType, exType));
+ this.exceptionType = exType;
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+ throw emulatedStackFrame.getReference(0, exceptionType);
+ }
+ }
+
+ /** Implements {@code MethodHandles.dropArguments}. */
+ static class DropArguments extends Transformer {
+ private final MethodHandle delegate;
+ private final EmulatedStackFrame.Range range1;
+ private final EmulatedStackFrame.Range range2;
+
+ DropArguments(MethodType type, MethodHandle delegate, int startPos, int numDropped) {
+ super(type);
+
+ this.delegate = delegate;
+
+ // We pre-calculate the ranges of values we have to copy through to the delegate
+ // handle at the time of instantiation so that the actual invoke is performant.
+ this.range1 = EmulatedStackFrame.Range.of(type, 0, startPos);
+ this.range2 = EmulatedStackFrame.Range.from(type, startPos + numDropped);
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+ EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(delegate.type());
+
+ emulatedStackFrame.copyRangeTo(
+ calleeFrame, range1, 0 /* referencesStart */, 0 /* stackFrameStart */);
+ emulatedStackFrame.copyRangeTo(
+ calleeFrame, range2, range1.numReferences, range1.numBytes);
+
+ invokeFromTransform(delegate, calleeFrame);
+ calleeFrame.copyReturnValueTo(emulatedStackFrame);
+ }
+ }
+
+ /** Implements {@code MethodHandles.catchException}. */
+ static class CatchException extends Transformer {
+ private final MethodHandle target;
+ private final MethodHandle handler;
+ private final Class<?> exType;
+
+ private final EmulatedStackFrame.Range handlerArgsRange;
+
+ CatchException(MethodHandle target, MethodHandle handler, Class<?> exType) {
+ super(target.type());
+
+ this.target = target;
+ this.handler = handler;
+ this.exType = exType;
+
+ // We only copy the first "count" args, dropping others if required. Note that
+ // we subtract one because the first handler arg is the exception thrown by the
+ // target.
+ handlerArgsRange =
+ EmulatedStackFrame.Range.of(
+ target.type(), 0, (handler.type().parameterCount() - 1));
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+ try {
+ invokeFromTransform(target, emulatedStackFrame);
+ } catch (Throwable th) {
+ if (th.getClass() == exType) {
+ // We've gotten an exception of the appropriate type, so we need to call
+ // the handler. Create a new frame of the appropriate size.
+ EmulatedStackFrame fallback = EmulatedStackFrame.create(handler.type());
+
+ // The first argument to the handler is the actual exception.
+ fallback.setReference(0, th);
+
+ // We then copy other arguments that need to be passed through to the handler.
+ // Note that we might drop arguments at the end, if needed. Note that
+ // referencesStart == 1 because the first argument is the exception type.
+ emulatedStackFrame.copyRangeTo(
+ fallback,
+ handlerArgsRange,
+ 1 /* referencesStart */,
+ 0 /* stackFrameStart */);
+
+ // Perform the invoke and return the appropriate value.
+ invokeFromTransform(handler, fallback);
+ fallback.copyReturnValueTo(emulatedStackFrame);
+ } else {
+ // The exception is not of the expected type, we throw it.
+ throw th;
+ }
+ }
+ }
+ }
+
+ /** Implements {@code MethodHandles.tryFinally}. */
+ static class TryFinally extends Transformer {
+ /** The target handle to try. */
+ private final MethodHandle target;
+
+ /** The cleanup handle to invoke after the target. */
+ private final MethodHandle cleanup;
+
+ TryFinally(MethodHandle target, MethodHandle cleanup) {
+ super(target.type());
+ this.target = target;
+ this.cleanup = cleanup;
+ }
+
+ @Override
+ protected void transform(EmulatedStackFrame callerFrame) throws Throwable {
+ Throwable throwable = null;
+ try {
+ invokeExactFromTransform(target, callerFrame);
+ } catch (Throwable t) {
+ throwable = t;
+ throw t;
+ } finally {
+ final EmulatedStackFrame cleanupFrame = prepareCleanupFrame(callerFrame, throwable);
+ invokeExactFromTransform(cleanup, cleanupFrame);
+ if (cleanup.type().returnType() != void.class) {
+ cleanupFrame.copyReturnValueTo(callerFrame);
+ }
+ }
+ }
+
+ /** Prepares the frame used to invoke the cleanup handle. */
+ private EmulatedStackFrame prepareCleanupFrame(final EmulatedStackFrame callerFrame,
+ final Throwable throwable) {
+ final EmulatedStackFrame cleanupFrame = EmulatedStackFrame.create(cleanup.type());
+ final StackFrameWriter cleanupWriter = new StackFrameWriter();
+ cleanupWriter.attach(cleanupFrame);
+
+ // The first argument to `cleanup` is (any) pending exception kind.
+ cleanupWriter.putNextReference(throwable, Throwable.class);
+ int added = 1;
+
+ // The second argument to `cleanup` is the result from `target` (if not void).
+ Class<?> targetReturnType = target.type().returnType();
+ StackFrameReader targetReader = new StackFrameReader();
+ targetReader.attach(callerFrame);
+ if (targetReturnType != void.class) {
+ targetReader.makeReturnValueAccessor();
+ copyNext(targetReader, cleanupWriter, targetReturnType);
+ added += 1;
+ // Reset `targetReader` to reference the arguments in `callerFrame`.
+ targetReader.attach(callerFrame);
+ }
+
+ // The final arguments from the invocation of target. As many are copied as the cleanup
+ // handle expects (it may be fewer than the arguments provided to target).
+ Class<?> [] cleanupTypes = cleanup.type().parameterArray();
+ for (; added != cleanupTypes.length; ++added) {
+ copyNext(targetReader, cleanupWriter, cleanupTypes[added]);
+ }
+ return cleanupFrame;
+ }
+ }
+
+ /** Implements {@code MethodHandles.GuardWithTest}. */
+ static class GuardWithTest extends Transformer {
+ private final MethodHandle test;
+ private final MethodHandle target;
+ private final MethodHandle fallback;
+
+ private final EmulatedStackFrame.Range testArgsRange;
+
+ GuardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback) {
+ super(target.type());
+
+ this.test = test;
+ this.target = target;
+ this.fallback = fallback;
+
+ // The test method might have a subset of the arguments of the handle / target.
+ testArgsRange =
+ EmulatedStackFrame.Range.of(target.type(), 0, test.type().parameterCount());
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+ EmulatedStackFrame testFrame = EmulatedStackFrame.create(test.type());
+ emulatedStackFrame.copyRangeTo(testFrame, testArgsRange, 0, 0);
+
+ // We know that the return value for test is going to be boolean.class.
+ StackFrameReader reader = new StackFrameReader();
+ reader.attach(testFrame);
+ reader.makeReturnValueAccessor();
+ invokeFromTransform(test, testFrame);
+ final boolean testResult = (boolean) reader.nextBoolean();
+ if (testResult) {
+ invokeFromTransform(target, emulatedStackFrame);
+ } else {
+ invokeFromTransform(fallback, emulatedStackFrame);
+ }
+ }
+ }
+
+ /** Implements {@code MethodHandles.arrayElementGetter}. */
+ static class ReferenceArrayElementGetter extends Transformer {
+ private final Class<?> arrayClass;
+
+ ReferenceArrayElementGetter(Class<?> arrayClass) {
+ super(
+ MethodType.methodType(
+ arrayClass.getComponentType(), new Class<?>[] {arrayClass, int.class}));
+ this.arrayClass = arrayClass;
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+ final StackFrameReader reader = new StackFrameReader();
+ reader.attach(emulatedStackFrame);
+
+ // Read the array object and the index from the stack frame.
+ final Object[] array = (Object[]) reader.nextReference(arrayClass);
+ final int index = reader.nextInt();
+
+ // Write the array element back to the stack frame.
+ final StackFrameWriter writer = new StackFrameWriter();
+ writer.attach(emulatedStackFrame);
+ writer.makeReturnValueAccessor();
+ writer.putNextReference(array[index], arrayClass.getComponentType());
+ }
+ }
+
+ /** Implements {@code MethodHandles.arrayElementSetter}. */
+ static class ReferenceArrayElementSetter extends Transformer {
+ private final Class<?> arrayClass;
+
+ ReferenceArrayElementSetter(Class<?> arrayClass) {
+ super(
+ MethodType.methodType(
+ void.class,
+ new Class<?>[] {arrayClass, int.class, arrayClass.getComponentType()}));
+ this.arrayClass = arrayClass;
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+ final StackFrameReader reader = new StackFrameReader();
+ reader.attach(emulatedStackFrame);
+
+ // Read the array object, index and the value to write from the stack frame.
+ final Object[] array = (Object[]) reader.nextReference(arrayClass);
+ final int index = reader.nextInt();
+ final Object value = reader.nextReference(arrayClass.getComponentType());
+
+ array[index] = value;
+ }
+ }
+
+ /** Implements {@code MethodHandles.identity}. */
+ static class ReferenceIdentity extends Transformer {
+ private final Class<?> type;
+
+ ReferenceIdentity(Class<?> type) {
+ super(MethodType.methodType(type, type));
+ this.type = type;
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+ final StackFrameReader reader = new StackFrameReader();
+ reader.attach(emulatedStackFrame);
+
+ final StackFrameWriter writer = new StackFrameWriter();
+ writer.attach(emulatedStackFrame);
+ writer.makeReturnValueAccessor();
+ writer.putNextReference(reader.nextReference(type), type);
+ }
+ }
+
+ /** Implements {@code MethodHandles.makeZero}. */
+ static class ZeroValue extends Transformer {
+ public ZeroValue(Class<?> type) {
+ super(MethodType.methodType(type));
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+ // Return-value is zero-initialized in emulatedStackFrame.
+ }
+ }
+
+ /** Implements {@code MethodHandles.arrayConstructor}. */
+ static class ArrayConstructor extends Transformer {
+ private final Class<?> componentType;
+
+ ArrayConstructor(Class<?> arrayType) {
+ super(MethodType.methodType(arrayType, int.class));
+ componentType = arrayType.getComponentType();
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+ final StackFrameReader reader = new StackFrameReader();
+ reader.attach(emulatedStackFrame);
+ final int length = reader.nextInt();
+ final Object array = Array.newInstance(componentType, length);
+ emulatedStackFrame.setReturnValueTo(array);
+ }
+ }
+
+ /** Implements {@code MethodHandles.arrayLength}. */
+ static class ArrayLength extends Transformer {
+ private final Class<?> arrayType;
+
+ ArrayLength(Class<?> arrayType) {
+ super(MethodType.methodType(int.class, arrayType));
+ this.arrayType = arrayType;
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+ final StackFrameReader reader = new StackFrameReader();
+ reader.attach(emulatedStackFrame);
+ final Object arrayObject = reader.nextReference(arrayType);
+
+ int length;
+ switch (Wrapper.basicTypeChar(arrayType.getComponentType())) {
+ case 'L':
+ length = ((Object[]) arrayObject).length;
+ break;
+ case 'Z':
+ length = ((boolean[]) arrayObject).length;
+ break;
+ case 'B':
+ length = ((byte[]) arrayObject).length;
+ break;
+ case 'C':
+ length = ((char[]) arrayObject).length;
+ break;
+ case 'S':
+ length = ((short[]) arrayObject).length;
+ break;
+ case 'I':
+ length = ((int[]) arrayObject).length;
+ break;
+ case 'J':
+ length = ((long[]) arrayObject).length;
+ break;
+ case 'F':
+ length = ((float[]) arrayObject).length;
+ break;
+ case 'D':
+ length = ((double[]) arrayObject).length;
+ break;
+ default:
+ throw new IllegalStateException("Unsupported type: " + arrayType);
+ }
+
+ final StackFrameWriter writer = new StackFrameWriter();
+ writer.attach(emulatedStackFrame).makeReturnValueAccessor();
+ writer.putNextInt(length);
+ }
+ }
+
+ /** Implements {@code MethodHandles.createMethodHandleForConstructor}. */
+ static class Construct extends Transformer {
+ private final MethodHandle constructorHandle;
+ private final EmulatedStackFrame.Range callerRange;
+
+ Construct(MethodHandle constructorHandle, MethodType returnedType) {
+ super(returnedType);
+ this.constructorHandle = constructorHandle;
+ this.callerRange = EmulatedStackFrame.Range.all(type());
+ }
+
+ MethodHandle getConstructorHandle() {
+ return constructorHandle;
+ }
+
+ private static boolean isAbstract(Class<?> klass) {
+ return (klass.getModifiers() & Modifier.ABSTRACT) == Modifier.ABSTRACT;
+ }
+
+ private static void checkInstantiable(Class<?> klass) throws InstantiationException {
+ if (isAbstract(klass)) {
+ String s = klass.isInterface() ? "interface " : "abstract class ";
+ throw new InstantiationException("Can't instantiate " + s + klass);
+ }
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+ final Class<?> receiverType = constructorHandle.type().parameterType(0);
+ checkInstantiable(receiverType);
+
+ // Allocate memory for receiver.
+ Object receiver = Unsafe.getUnsafe().allocateInstance(receiverType);
+
+ // The MethodHandle type for the caller has the form of
+ // {rtype=T,ptypes=A1..An}. The constructor MethodHandle is of
+ // the form {rtype=void,ptypes=T,A1...An}. So the frame for
+ // the constructor needs to have a slot with the receiver
+ // in position 0.
+ EmulatedStackFrame constructorFrame =
+ EmulatedStackFrame.create(constructorHandle.type());
+ constructorFrame.setReference(0, receiver);
+ emulatedStackFrame.copyRangeTo(constructorFrame, callerRange, 1, 0);
+ invokeExactFromTransform(constructorHandle, constructorFrame);
+
+ // Set return result for caller.
+ emulatedStackFrame.setReturnValueTo(receiver);
+ }
+ }
+
+ /** Implements {@code MethodHandle.bindTo}. */
+ static class BindTo extends Transformer {
+ private final MethodHandle delegate;
+ private final Object receiver;
+
+ private final EmulatedStackFrame.Range range;
+
+ BindTo(MethodHandle delegate, Object receiver) {
+ super(delegate.type().dropParameterTypes(0, 1));
+
+ this.delegate = delegate;
+ this.receiver = receiver;
+
+ this.range = EmulatedStackFrame.Range.all(this.type());
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+ // Create a new emulated stack frame with the full type (including the leading
+ // receiver reference).
+ EmulatedStackFrame stackFrame = EmulatedStackFrame.create(delegate.type());
+
+ // The first reference argument must be the receiver.
+ stackFrame.setReference(0, receiver);
+ // Copy all other arguments.
+ emulatedStackFrame.copyRangeTo(
+ stackFrame, range, 1 /* referencesStart */, 0 /* stackFrameStart */);
+
+ // Perform the invoke.
+ invokeFromTransform(delegate, stackFrame);
+ stackFrame.copyReturnValueTo(emulatedStackFrame);
+ }
+ }
+
+ /** Implements {@code MethodHandle.filterReturnValue}. */
+ static class FilterReturnValue extends Transformer {
+ private final MethodHandle target;
+ private final MethodHandle filter;
+
+ private final EmulatedStackFrame.Range allArgs;
+
+ FilterReturnValue(MethodHandle target, MethodHandle filter) {
+ super(MethodType.methodType(filter.type().rtype(), target.type().ptypes()));
+
+ this.target = target;
+ this.filter = filter;
+
+ allArgs = EmulatedStackFrame.Range.all(type());
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+ // Create a new frame with the target's type and copy all arguments over.
+ // This frame differs in return type with |emulatedStackFrame| but will have
+ // the same parameter shapes.
+ EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
+ emulatedStackFrame.copyRangeTo(targetFrame, allArgs, 0, 0);
+ invokeFromTransform(target, targetFrame);
+
+ // Create an emulated frame for the filter and move the return value from
+ // target to the argument of the filter.
+ final EmulatedStackFrame filterFrame = EmulatedStackFrame.create(filter.type());
+ final Class<?> filterArgumentType = target.type().rtype();
+ if (filterArgumentType != void.class) {
+ final StackFrameReader returnValueReader = new StackFrameReader();
+ returnValueReader.attach(targetFrame).makeReturnValueAccessor();
+
+ final StackFrameWriter filterWriter = new StackFrameWriter();
+ filterWriter.attach(filterFrame);
+ StackFrameAccessor.copyNext(returnValueReader, filterWriter, filterArgumentType);
+ }
+
+ // Invoke the filter and copy its return value back to the original frame.
+ invokeExactFromTransform(filter, filterFrame);
+ filterFrame.copyReturnValueTo(emulatedStackFrame);
+ }
+ }
+
+ /** Implements {@code MethodHandles.permuteArguments}. */
+ static class PermuteArguments extends Transformer {
+ private final MethodHandle target;
+ private final int[] reorder;
+
+ PermuteArguments(MethodType type, MethodHandle target, int[] reorder) {
+ super(type);
+
+ this.target = target;
+ this.reorder = reorder;
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+ final RandomOrderStackFrameReader reader = new RandomOrderStackFrameReader();
+ reader.attach(emulatedStackFrame);
+
+ final EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(target.type());
+ final StackFrameWriter writer = new StackFrameWriter();
+ writer.attach(calleeFrame);
+
+ final Class<?> [] ptypes = emulatedStackFrame.getMethodType().parameterArray();
+ for (int i = 0; i < reorder.length; ++i) {
+ final int readerIndex = reorder[i];
+ reader.moveTo(readerIndex);
+ StackFrameAccessor.copyNext(reader, writer, ptypes[readerIndex]);
+ }
+
+ invokeFromTransform(target, calleeFrame);
+ calleeFrame.copyReturnValueTo(emulatedStackFrame);
+ }
+ }
+
+ /** Implements {@code MethodHandle.asVarargsCollector}. */
+ static class VarargsCollector extends Transformer {
+ final MethodHandle target;
+ private final Class<?> arrayType;
+
+ VarargsCollector(MethodHandle target) {
+ super(target.type());
+
+ Class<?>[] parameterTypes = target.type().ptypes();
+ if (!lastParameterTypeIsAnArray(parameterTypes)) {
+ throw new IllegalArgumentException("target does not have array as last parameter");
+ }
+ this.target = target;
+ this.arrayType = parameterTypes[parameterTypes.length - 1];
+ }
+
+ private static boolean lastParameterTypeIsAnArray(Class<?>[] parameterTypes) {
+ if (parameterTypes.length == 0) return false;
+ return parameterTypes[parameterTypes.length - 1].isArray();
+ }
+
+ @Override
+ public boolean isVarargsCollector() {
+ return true;
+ }
+
+ @Override
+ public MethodHandle asFixedArity() {
+ return target;
+ }
+
+ @Override
+ MethodHandle asTypeUncached(MethodType newType) {
+ // asType() behavior is specialized per:
+ //
+ // https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/invoke/MethodHandle.html#asVarargsCollector(java.lang.Class)
+ //
+ // "The behavior of asType is also specialized for variable arity adapters, to maintain
+ // the invariant that plain, inexact invoke is always equivalent to an asType call to
+ // adjust the target type, followed by invokeExact. Therefore, a variable arity
+ // adapter responds to an asType request by building a fixed arity collector, if and
+ // only if the adapter and requested type differ either in arity or trailing argument
+ // type. The resulting fixed arity collector has its type further adjusted
+ // (if necessary) to the requested type by pairwise conversion, as if by another
+ // application of asType."
+ final MethodType currentType = type();
+ final MethodHandle currentFixedArity = asFixedArity();
+ if (currentType.parameterCount() == newType.parameterCount()
+ && currentType
+ .lastParameterType()
+ .isAssignableFrom(newType.lastParameterType())) {
+ return asTypeCache = currentFixedArity.asType(newType);
+ }
+
+ final int arrayLength = newType.parameterCount() - currentType.parameterCount() + 1;
+ if (arrayLength < 0) {
+ // arrayType is definitely array per VarargsCollector constructor.
+ throwWrongMethodTypeException(currentType, newType);
+ }
+
+ MethodHandle collector = null;
+ try {
+ collector = currentFixedArity.asCollector(arrayType, arrayLength).asType(newType);
+ } catch (IllegalArgumentException ex) {
+ throwWrongMethodTypeException(currentType, newType);
+ }
+ return asTypeCache = collector;
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame callerFrame) throws Throwable {
+ MethodType callerFrameType = callerFrame.getMethodType();
+ Class<?>[] callerPTypes = callerFrameType.ptypes();
+ Class<?>[] targetPTypes = type().ptypes();
+
+ int lastTargetIndex = targetPTypes.length - 1;
+ if (callerPTypes.length == targetPTypes.length
+ && targetPTypes[lastTargetIndex].isAssignableFrom(
+ callerPTypes[lastTargetIndex])) {
+ // Caller frame matches target frame in the arity array parameter. Invoke
+ // immediately, and let the invoke() dispatch perform any necessary conversions
+ // on the other parameters present.
+ invokeFromTransform(target, callerFrame);
+ return;
+ }
+
+ if (callerPTypes.length < targetPTypes.length - 1) {
+ // Too few arguments to be compatible with variable arity invocation.
+ throwWrongMethodTypeException(callerFrameType, type());
+ }
+
+ if (!MethodType.canConvert(type().rtype(), callerFrameType.rtype())) {
+ // Incompatible return type.
+ throwWrongMethodTypeException(callerFrameType, type());
+ }
+
+ Class<?> elementType = targetPTypes[lastTargetIndex].getComponentType();
+ if (!arityArgumentsConvertible(callerPTypes, lastTargetIndex, elementType)) {
+ // Wrong types to be compatible with variable arity invocation.
+ throwWrongMethodTypeException(callerFrameType, type());
+ }
+
+ // Allocate targetFrame.
+ MethodType targetFrameType = makeTargetFrameType(callerFrameType, type());
+ EmulatedStackFrame targetFrame = EmulatedStackFrame.create(targetFrameType);
+ prepareFrame(callerFrame, targetFrame);
+
+ // Invoke target.
+ invokeExactFromTransform(target, targetFrame);
+
+ // Copy return value to the caller's frame.
+ targetFrame.copyReturnValueTo(callerFrame);
+ }
+
+ @Override
+ public MethodHandle withVarargs(boolean makeVarargs) {
+ return makeVarargs ? this : target;
+ }
+
+ private static void throwWrongMethodTypeException(MethodType from, MethodType to) {
+ throw new WrongMethodTypeException("Cannot convert " + from + " to " + to);
+ }
+
+ private static boolean arityArgumentsConvertible(
+ Class<?>[] ptypes, int arityStart, Class<?> elementType) {
+ if (ptypes.length - 1 == arityStart) {
+ if (ptypes[arityStart].isArray()
+ && ptypes[arityStart].getComponentType() == elementType) {
+ // The last ptype is in the same position as the arity
+ // array and has the same type.
+ return true;
+ }
+ }
+
+ for (int i = arityStart; i < ptypes.length; ++i) {
+ if (!MethodType.canConvert(ptypes[i], elementType)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static Object referenceArray(
+ StackFrameReader reader,
+ Class<?>[] ptypes,
+ Class<?> elementType,
+ int offset,
+ int length) {
+ Object arityArray = Array.newInstance(elementType, length);
+ for (int i = 0; i < length; ++i) {
+ Class<?> argumentType = ptypes[i + offset];
+ Object o = null;
+ switch (Wrapper.basicTypeChar(argumentType)) {
+ case 'L':
+ o = reader.nextReference(argumentType);
+ break;
+ case 'I':
+ o = reader.nextInt();
+ break;
+ case 'J':
+ o = reader.nextLong();
+ break;
+ case 'B':
+ o = reader.nextByte();
+ break;
+ case 'S':
+ o = reader.nextShort();
+ break;
+ case 'C':
+ o = reader.nextChar();
+ break;
+ case 'Z':
+ o = reader.nextBoolean();
+ break;
+ case 'F':
+ o = reader.nextFloat();
+ break;
+ case 'D':
+ o = reader.nextDouble();
+ break;
+ }
+ Array.set(arityArray, i, elementType.cast(o));
+ }
+ return arityArray;
+ }
+
+ private static Object intArray(
+ StackFrameReader reader, Class<?> ptypes[], int offset, int length) {
+ int[] arityArray = new int[length];
+ for (int i = 0; i < length; ++i) {
+ Class<?> argumentType = ptypes[i + offset];
+ switch (Wrapper.basicTypeChar(argumentType)) {
+ case 'I':
+ arityArray[i] = reader.nextInt();
+ break;
+ case 'S':
+ arityArray[i] = reader.nextShort();
+ break;
+ case 'B':
+ arityArray[i] = reader.nextByte();
+ break;
+ default:
+ arityArray[i] = (Integer) reader.nextReference(argumentType);
+ break;
+ }
+ }
+ return arityArray;
+ }
+
+ private static Object longArray(
+ StackFrameReader reader, Class<?> ptypes[], int offset, int length) {
+ long[] arityArray = new long[length];
+ for (int i = 0; i < length; ++i) {
+ Class<?> argumentType = ptypes[i + offset];
+ switch (Wrapper.basicTypeChar(argumentType)) {
+ case 'J':
+ arityArray[i] = reader.nextLong();
+ break;
+ case 'I':
+ arityArray[i] = reader.nextInt();
+ break;
+ case 'S':
+ arityArray[i] = reader.nextShort();
+ break;
+ case 'B':
+ arityArray[i] = reader.nextByte();
+ break;
+ default:
+ arityArray[i] = (Long) reader.nextReference(argumentType);
+ break;
+ }
+ }
+ return arityArray;
+ }
+
+ private static Object byteArray(
+ StackFrameReader reader, Class<?> ptypes[], int offset, int length) {
+ byte[] arityArray = new byte[length];
+ for (int i = 0; i < length; ++i) {
+ Class<?> argumentType = ptypes[i + offset];
+ switch (Wrapper.basicTypeChar(argumentType)) {
+ case 'B':
+ arityArray[i] = reader.nextByte();
+ break;
+ default:
+ arityArray[i] = (Byte) reader.nextReference(argumentType);
+ break;
+ }
+ }
+ return arityArray;
+ }
+
+ private static Object shortArray(
+ StackFrameReader reader, Class<?> ptypes[], int offset, int length) {
+ short[] arityArray = new short[length];
+ for (int i = 0; i < length; ++i) {
+ Class<?> argumentType = ptypes[i + offset];
+ switch (Wrapper.basicTypeChar(argumentType)) {
+ case 'S':
+ arityArray[i] = reader.nextShort();
+ break;
+ case 'B':
+ arityArray[i] = reader.nextByte();
+ break;
+ default:
+ arityArray[i] = (Short) reader.nextReference(argumentType);
+ break;
+ }
+ }
+ return arityArray;
+ }
+
+ private static Object charArray(
+ StackFrameReader reader, Class<?> ptypes[], int offset, int length) {
+ char[] arityArray = new char[length];
+ for (int i = 0; i < length; ++i) {
+ Class<?> argumentType = ptypes[i + offset];
+ switch (Wrapper.basicTypeChar(argumentType)) {
+ case 'C':
+ arityArray[i] = reader.nextChar();
+ break;
+ default:
+ arityArray[i] = (Character) reader.nextReference(argumentType);
+ break;
+ }
+ }
+ return arityArray;
+ }
+
+ private static Object booleanArray(
+ StackFrameReader reader, Class<?> ptypes[], int offset, int length) {
+ boolean[] arityArray = new boolean[length];
+ for (int i = 0; i < length; ++i) {
+ Class<?> argumentType = ptypes[i + offset];
+ switch (Wrapper.basicTypeChar(argumentType)) {
+ case 'Z':
+ arityArray[i] = reader.nextBoolean();
+ break;
+ default:
+ arityArray[i] = (Boolean) reader.nextReference(argumentType);
+ break;
+ }
+ }
+ return arityArray;
+ }
+
+ private static Object floatArray(
+ StackFrameReader reader, Class<?> ptypes[], int offset, int length) {
+ float[] arityArray = new float[length];
+ for (int i = 0; i < length; ++i) {
+ Class<?> argumentType = ptypes[i + offset];
+ switch (Wrapper.basicTypeChar(argumentType)) {
+ case 'F':
+ arityArray[i] = reader.nextFloat();
+ break;
+ case 'J':
+ arityArray[i] = reader.nextLong();
+ break;
+ case 'I':
+ arityArray[i] = reader.nextInt();
+ break;
+ case 'S':
+ arityArray[i] = reader.nextShort();
+ break;
+ case 'B':
+ arityArray[i] = reader.nextByte();
+ break;
+ default:
+ arityArray[i] = (Float) reader.nextReference(argumentType);
+ break;
+ }
+ }
+ return arityArray;
+ }
+
+ private static Object doubleArray(
+ StackFrameReader reader, Class<?> ptypes[], int offset, int length) {
+ double[] arityArray = new double[length];
+ for (int i = 0; i < length; ++i) {
+ Class<?> argumentType = ptypes[i + offset];
+ switch (Wrapper.basicTypeChar(argumentType)) {
+ case 'D':
+ arityArray[i] = reader.nextDouble();
+ break;
+ case 'F':
+ arityArray[i] = reader.nextFloat();
+ break;
+ case 'J':
+ arityArray[i] = reader.nextLong();
+ break;
+ case 'I':
+ arityArray[i] = reader.nextInt();
+ break;
+ case 'S':
+ arityArray[i] = reader.nextShort();
+ break;
+ case 'B':
+ arityArray[i] = reader.nextByte();
+ break;
+ default:
+ arityArray[i] = (Double) reader.nextReference(argumentType);
+ break;
+ }
+ }
+ return arityArray;
+ }
+
+ private static Object makeArityArray(
+ MethodType callerFrameType,
+ StackFrameReader callerFrameReader,
+ int indexOfArityArray,
+ Class<?> arityArrayType) {
+ int arityArrayLength = callerFrameType.ptypes().length - indexOfArityArray;
+ Class<?> elementType = arityArrayType.getComponentType();
+ Class<?>[] callerPTypes = callerFrameType.ptypes();
+
+ char elementBasicType = Wrapper.basicTypeChar(elementType);
+ switch (elementBasicType) {
+ case 'L':
+ return referenceArray(
+ callerFrameReader,
+ callerPTypes,
+ elementType,
+ indexOfArityArray,
+ arityArrayLength);
+ case 'I':
+ return intArray(
+ callerFrameReader, callerPTypes,
+ indexOfArityArray, arityArrayLength);
+ case 'J':
+ return longArray(
+ callerFrameReader, callerPTypes,
+ indexOfArityArray, arityArrayLength);
+ case 'B':
+ return byteArray(
+ callerFrameReader, callerPTypes,
+ indexOfArityArray, arityArrayLength);
+ case 'S':
+ return shortArray(
+ callerFrameReader, callerPTypes,
+ indexOfArityArray, arityArrayLength);
+ case 'C':
+ return charArray(
+ callerFrameReader, callerPTypes,
+ indexOfArityArray, arityArrayLength);
+ case 'Z':
+ return booleanArray(
+ callerFrameReader, callerPTypes,
+ indexOfArityArray, arityArrayLength);
+ case 'F':
+ return floatArray(
+ callerFrameReader, callerPTypes,
+ indexOfArityArray, arityArrayLength);
+ case 'D':
+ return doubleArray(
+ callerFrameReader, callerPTypes,
+ indexOfArityArray, arityArrayLength);
+ }
+ throw new InternalError("Unexpected type: " + elementType);
+ }
+
+ public static Object collectArguments(
+ char basicComponentType,
+ Class<?> componentType,
+ StackFrameReader reader,
+ Class<?>[] types,
+ int startIdx,
+ int length) {
+ switch (basicComponentType) {
+ case 'L':
+ return referenceArray(reader, types, componentType, startIdx, length);
+ case 'I':
+ return intArray(reader, types, startIdx, length);
+ case 'J':
+ return longArray(reader, types, startIdx, length);
+ case 'B':
+ return byteArray(reader, types, startIdx, length);
+ case 'S':
+ return shortArray(reader, types, startIdx, length);
+ case 'C':
+ return charArray(reader, types, startIdx, length);
+ case 'Z':
+ return booleanArray(reader, types, startIdx, length);
+ case 'F':
+ return floatArray(reader, types, startIdx, length);
+ case 'D':
+ return doubleArray(reader, types, startIdx, length);
+ }
+ throw new InternalError("Unexpected type: " + basicComponentType);
+ }
+
+ private static void copyParameter(
+ StackFrameReader reader, StackFrameWriter writer, Class<?> ptype) {
+ switch (Wrapper.basicTypeChar(ptype)) {
+ case 'L':
+ writer.putNextReference(reader.nextReference(ptype), ptype);
+ break;
+ case 'I':
+ writer.putNextInt(reader.nextInt());
+ break;
+ case 'J':
+ writer.putNextLong(reader.nextLong());
+ break;
+ case 'B':
+ writer.putNextByte(reader.nextByte());
+ break;
+ case 'S':
+ writer.putNextShort(reader.nextShort());
+ break;
+ case 'C':
+ writer.putNextChar(reader.nextChar());
+ break;
+ case 'Z':
+ writer.putNextBoolean(reader.nextBoolean());
+ break;
+ case 'F':
+ writer.putNextFloat(reader.nextFloat());
+ break;
+ case 'D':
+ writer.putNextDouble(reader.nextDouble());
+ break;
+ default:
+ throw new InternalError("Unexpected type: " + ptype);
+ }
+ }
+
+ private static void prepareFrame(
+ EmulatedStackFrame callerFrame, EmulatedStackFrame targetFrame) {
+ StackFrameWriter targetWriter = new StackFrameWriter();
+ targetWriter.attach(targetFrame);
+ StackFrameReader callerReader = new StackFrameReader();
+ callerReader.attach(callerFrame);
+
+ // Copy parameters from |callerFrame| to |targetFrame| leaving room for arity array.
+ MethodType targetMethodType = targetFrame.getMethodType();
+ int indexOfArityArray = targetMethodType.ptypes().length - 1;
+ for (int i = 0; i < indexOfArityArray; ++i) {
+ Class<?> ptype = targetMethodType.ptypes()[i];
+ copyParameter(callerReader, targetWriter, ptype);
+ }
+
+ // Add arity array as last parameter in |targetFrame|.
+ Class<?> arityArrayType = targetMethodType.ptypes()[indexOfArityArray];
+ Object arityArray =
+ makeArityArray(
+ callerFrame.getMethodType(),
+ callerReader,
+ indexOfArityArray,
+ arityArrayType);
+ targetWriter.putNextReference(arityArray, arityArrayType);
+ }
+
+ /**
+ * Computes the frame type to invoke the target method handle with. This is the same as the
+ * caller frame type, but with the trailing argument being the array type that is the
+ * trailing argument in the target method handle.
+ *
+ * <p>Suppose the targetType is (T0, T1, T2[])RT and the callerType is (C0, C1, C2, C3)RC
+ * then the constructed type is (C0, C1, T2[])RC.
+ */
+ private static MethodType makeTargetFrameType(
+ MethodType callerType, MethodType targetType) {
+ final int ptypesLength = targetType.ptypes().length;
+ final Class<?>[] ptypes = new Class<?>[ptypesLength];
+ // Copy types from caller types to new methodType.
+ System.arraycopy(callerType.ptypes(), 0, ptypes, 0, ptypesLength - 1);
+ // Set the last element in the type array to be the
+ // varargs array of the target.
+ ptypes[ptypesLength - 1] = targetType.ptypes()[ptypesLength - 1];
+ return MethodType.methodType(callerType.rtype(), ptypes);
+ }
+ }
+
+ /** Implements {@code MethodHandles.invoker} and {@code MethodHandles.exactInvoker}. */
+ static class Invoker extends Transformer {
+ private final MethodType targetType;
+ private final boolean isExactInvoker;
+ private final EmulatedStackFrame.Range copyRange;
+
+ Invoker(MethodType targetType, boolean isExactInvoker) {
+ super(targetType.insertParameterTypes(0, MethodHandle.class));
+ this.targetType = targetType;
+ this.isExactInvoker = isExactInvoker;
+ copyRange = EmulatedStackFrame.Range.from(type(), 1);
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+ // The first argument to the stack frame is the handle that needs to be invoked.
+ MethodHandle target = emulatedStackFrame.getReference(0, MethodHandle.class);
+
+ // All other arguments must be copied to the target frame.
+ EmulatedStackFrame targetFrame = EmulatedStackFrame.create(targetType);
+ emulatedStackFrame.copyRangeTo(targetFrame, copyRange, 0, 0);
+
+ // Finally, invoke the handle and copy the return value.
+ if (isExactInvoker) {
+ invokeExactFromTransform(target, targetFrame);
+ } else {
+ invokeFromTransform(target, targetFrame);
+ }
+ targetFrame.copyReturnValueTo(emulatedStackFrame);
+ }
+
+ /**
+ * Checks whether two method types are compatible as an exact match. The exact match is
+ * based on the erased form (all reference types treated as Object).
+ *
+ * @param callsiteType the MethodType associated with the invocation.
+ * @param targetType the MethodType of the MethodHandle being invoked.
+ * @return true if {@code callsiteType} and {@code targetType} are an exact match.
+ */
+ private static boolean exactMatch(MethodType callsiteType, MethodType targetType) {
+ final int parameterCount = callsiteType.parameterCount();
+ if (callsiteType.parameterCount() != targetType.parameterCount()) {
+ return false;
+ }
+
+ for (int i = 0; i < parameterCount; ++i) {
+ Class argumentType = callsiteType.parameterType(i);
+ Class parameterType = targetType.parameterType(i);
+ if (!exactMatch(argumentType, parameterType)) {
+ return false;
+ }
+ }
+ // Check return type, noting it's always okay to discard the return value.
+ return callsiteType.returnType() == Void.TYPE
+ || exactMatch(callsiteType.returnType(), targetType.returnType());
+ }
+
+ /**
+ * Checks whether two types are an exact match. The exact match is based on the erased types
+ * so any two reference types match, but primitive types must be the same.
+ *
+ * @param lhs first class to compare.
+ * @param rhs second class to compare.
+ * @return true if both classes satisfy the exact match criteria.
+ */
+ private static boolean exactMatch(Class lhs, Class rhs) {
+ if (lhs.isPrimitive() || rhs.isPrimitive()) {
+ return lhs == rhs;
+ }
+ return true; // Both types are references, compatibility is checked at the point of use.
+ }
+ }
+
+ /** Implements {@code MethodHandle.asSpreader}. */
+ static class Spreader extends Transformer {
+ /** The method handle we're delegating to. */
+ private final MethodHandle target;
+
+ /**
+ * The offset of the trailing array argument in the list of arguments to this transformer.
+ * The array argument is always the last argument.
+ */
+ private final int arrayOffset;
+
+ /** The component type of the array. */
+ private final Class<?> componentType;
+
+ /**
+ * The number of input arguments that will be present in the array. In other words, this is
+ * the expected array length.
+ */
+ private final int numArrayArgs;
+
+ /**
+ * Range of arguments to copy verbatim from the input frame, This will cover all arguments
+ * that aren't a part of the trailing array.
+ */
+ private final Range leadingRange;
+ private final Range trailingRange;
+
+ Spreader(MethodHandle target, MethodType spreaderType, int spreadArgPos, int numArrayArgs) {
+ super(spreaderType);
+ this.target = target;
+ arrayOffset = spreadArgPos;
+ componentType = spreaderType.ptypes()[arrayOffset].getComponentType();
+ if (componentType == null) {
+ throw new AssertionError("Argument " + spreadArgPos + " must be an array.");
+ }
+ this.numArrayArgs = numArrayArgs;
+ // Copy all args except the spreader array.
+ leadingRange = EmulatedStackFrame.Range.of(spreaderType, 0, arrayOffset);
+ trailingRange = EmulatedStackFrame.Range.from(spreaderType, arrayOffset + 1);
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame callerFrame) throws Throwable {
+ // Get the array reference and check that its length is as expected.
+ final Class<?> arrayType = type().parameterType(arrayOffset);
+ final Object arrayObj = callerFrame.getReference(arrayOffset, arrayType);
+
+ // The incoming array may be null if the expected number of array arguments is zero.
+ final int arrayLength =
+ (numArrayArgs == 0 && arrayObj == null) ? 0 : Array.getLength(arrayObj);
+ if (arrayLength != numArrayArgs) {
+ throw new IllegalArgumentException(
+ "Invalid array length " + arrayLength + " expected " + numArrayArgs);
+ }
+
+ // Create a new stack frame for the callee.
+ EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
+
+ // Copy ranges not affected by the spreading.
+ callerFrame.copyRangeTo(targetFrame, leadingRange, 0, 0);
+ if (componentType.isPrimitive()) {
+ final int elementBytes = EmulatedStackFrame.getSize(componentType);
+ final int spreadBytes = elementBytes * arrayLength;
+ callerFrame.copyRangeTo(targetFrame, trailingRange,
+ leadingRange.numReferences, leadingRange.numBytes + spreadBytes);
+ } else {
+ callerFrame.copyRangeTo(targetFrame, trailingRange,
+ leadingRange.numReferences + numArrayArgs, leadingRange.numBytes);
+ }
+
+ if (arrayLength != 0) {
+ StackFrameWriter writer = new StackFrameWriter();
+ writer.attach(targetFrame,
+ arrayOffset,
+ leadingRange.numReferences,
+ leadingRange.numBytes);
+ spreadArray(arrayType, arrayObj, writer);
+ }
+
+ invokeExactFromTransform(target, targetFrame);
+ targetFrame.copyReturnValueTo(callerFrame);
+ }
+
+ private void spreadArray(Class<?> arrayType, Object arrayObj, StackFrameWriter writer) {
+ final Class<?> componentType = arrayType.getComponentType();
+ switch (Wrapper.basicTypeChar(componentType)) {
+ case 'L':
+ {
+ final Object[] array = (Object[]) arrayObj;
+ for (int i = 0; i < array.length; ++i) {
+ writer.putNextReference(array[i], componentType);
+ }
+ break;
+ }
+ case 'I':
+ {
+ final int[] array = (int[]) arrayObj;
+ for (int i = 0; i < array.length; ++i) {
+ writer.putNextInt(array[i]);
+ }
+ break;
+ }
+ case 'J':
+ {
+ final long[] array = (long[]) arrayObj;
+ for (int i = 0; i < array.length; ++i) {
+ writer.putNextLong(array[i]);
+ }
+ break;
+ }
+ case 'B':
+ {
+ final byte[] array = (byte[]) arrayObj;
+ for (int i = 0; i < array.length; ++i) {
+ writer.putNextByte(array[i]);
+ }
+ break;
+ }
+ case 'S':
+ {
+ final short[] array = (short[]) arrayObj;
+ for (int i = 0; i < array.length; ++i) {
+ writer.putNextShort(array[i]);
+ }
+ break;
+ }
+ case 'C':
+ {
+ final char[] array = (char[]) arrayObj;
+ for (int i = 0; i < array.length; ++i) {
+ writer.putNextChar(array[i]);
+ }
+ break;
+ }
+ case 'Z':
+ {
+ final boolean[] array = (boolean[]) arrayObj;
+ for (int i = 0; i < array.length; ++i) {
+ writer.putNextBoolean(array[i]);
+ }
+ break;
+ }
+ case 'F':
+ {
+ final float[] array = (float[]) arrayObj;
+ for (int i = 0; i < array.length; ++i) {
+ writer.putNextFloat(array[i]);
+ }
+ break;
+ }
+ case 'D':
+ {
+ final double[] array = (double[]) arrayObj;
+ for (int i = 0; i < array.length; ++i) {
+ writer.putNextDouble(array[i]);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ /** Implements {@code MethodHandle.asCollector}. */
+ static class Collector extends Transformer {
+ private final MethodHandle target;
+
+ /**
+ * The array start is the position in the target outputs of the array collecting arguments
+ * and the position in the source inputs where collection starts.
+ */
+ private final int arrayOffset;
+
+ /**
+ * The array length is the number of arguments to be collected.
+ */
+ private final int arrayLength;
+
+ /** The type of the array. */
+ private final Class arrayType;
+
+ /**
+ * Range of arguments to copy verbatim from the start of the input frame.
+ */
+ private final Range leadingRange;
+
+ /**
+ * Range of arguments to copy verbatim from the end of the input frame.
+ */
+ private final Range trailingRange;
+
+ Collector(MethodHandle delegate, Class<?> arrayType, int start, int length) {
+ super(delegate.type().asCollectorType(arrayType, start, length));
+ this.target = delegate;
+ this.arrayOffset = start;
+ this.arrayLength = length;
+ this.arrayType = arrayType;
+
+ // Build ranges of arguments to be copied.
+ leadingRange = EmulatedStackFrame.Range.of(type(), 0, arrayOffset);
+ trailingRange = EmulatedStackFrame.Range.from(type(), arrayOffset + arrayLength);
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame callerFrame) throws Throwable {
+ // Create a new stack frame for the callee.
+ final EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
+
+ // Copy arguments before the collector array.
+ callerFrame.copyRangeTo(targetFrame, leadingRange, 0, 0);
+
+ // Copy arguments after the collector array.
+ callerFrame.copyRangeTo(targetFrame, trailingRange,
+ leadingRange.numReferences + 1, leadingRange.numBytes);
+
+ // Collect arguments between arrayOffset and arrayOffset + arrayLength.
+ final StackFrameWriter writer = new StackFrameWriter();
+ writer.attach(targetFrame, arrayOffset, leadingRange.numReferences, leadingRange.numBytes);
+ final StackFrameReader reader = new StackFrameReader();
+ reader.attach(callerFrame, arrayOffset, leadingRange.numReferences, leadingRange.numBytes);
+
+ final char arrayTypeChar = Wrapper.basicTypeChar(arrayType.getComponentType());
+ switch (arrayTypeChar) {
+ case 'L':
+ {
+ // Reference arrays are the only case where the component type of the
+ // array we construct might differ from the type of the reference we read
+ // from the stack frame.
+ final Class<?> targetType = target.type().ptypes()[arrayOffset];
+ final Class<?> arrayComponentType = arrayType.getComponentType();
+ Object[] arr =
+ (Object[]) Array.newInstance(arrayComponentType, arrayLength);
+ for (int i = 0; i < arrayLength; ++i) {
+ arr[i] = reader.nextReference(arrayComponentType);
+ }
+ writer.putNextReference(arr, targetType);
+ break;
+ }
+ case 'I':
+ {
+ int[] array = new int[arrayLength];
+ for (int i = 0; i < arrayLength; ++i) {
+ array[i] = reader.nextInt();
+ }
+ writer.putNextReference(array, int[].class);
+ break;
+ }
+ case 'J':
+ {
+ long[] array = new long[arrayLength];
+ for (int i = 0; i < arrayLength; ++i) {
+ array[i] = reader.nextLong();
+ }
+ writer.putNextReference(array, long[].class);
+ break;
+ }
+ case 'B':
+ {
+ byte[] array = new byte[arrayLength];
+ for (int i = 0; i < arrayLength; ++i) {
+ array[i] = reader.nextByte();
+ }
+ writer.putNextReference(array, byte[].class);
+ break;
+ }
+ case 'S':
+ {
+ short[] array = new short[arrayLength];
+ for (int i = 0; i < arrayLength; ++i) {
+ array[i] = reader.nextShort();
+ }
+ writer.putNextReference(array, short[].class);
+ break;
+ }
+ case 'C':
+ {
+ char[] array = new char[arrayLength];
+ for (int i = 0; i < arrayLength; ++i) {
+ array[i] = reader.nextChar();
+ }
+ writer.putNextReference(array, char[].class);
+ break;
+ }
+ case 'Z':
+ {
+ boolean[] array = new boolean[arrayLength];
+ for (int i = 0; i < arrayLength; ++i) {
+ array[i] = reader.nextBoolean();
+ }
+ writer.putNextReference(array, boolean[].class);
+ break;
+ }
+ case 'F':
+ {
+ float[] array = new float[arrayLength];
+ for (int i = 0; i < arrayLength; ++i) {
+ array[i] = reader.nextFloat();
+ }
+ writer.putNextReference(array, float[].class);
+ break;
+ }
+ case 'D':
+ {
+ double[] array = new double[arrayLength];
+ for (int i = 0; i < arrayLength; ++i) {
+ array[i] = reader.nextDouble();
+ }
+ writer.putNextReference(array, double[].class);
+ break;
+ }
+ }
+
+ invokeFromTransform(target, targetFrame);
+ targetFrame.copyReturnValueTo(callerFrame);
+ }
+ }
+
+ /** Implements {@code MethodHandles.filterArguments}. */
+ static class FilterArguments extends Transformer {
+ /** The target handle. */
+ private final MethodHandle target;
+ /** Index of the first argument to filter */
+ private final int pos;
+ /** The list of filters to apply */
+ private final MethodHandle[] filters;
+
+ FilterArguments(MethodHandle target, int pos, MethodHandle... filters) {
+ super(deriveType(target, pos, filters));
+
+ this.target = target;
+ this.pos = pos;
+ this.filters = filters;
+ }
+
+ private static MethodType deriveType(MethodHandle target, int pos, MethodHandle[] filters) {
+ final Class<?>[] filterArgs = new Class<?>[filters.length];
+ for (int i = 0; i < filters.length; ++i) {
+ MethodHandle filter = filters[i];
+ if (filter != null) {
+ filterArgs[i] = filter.type().parameterType(0);
+ } else {
+ // null filters are treated as identity functions.
+ filterArgs[i] = target.type().parameterType(i);
+ }
+ }
+
+ return target.type().replaceParameterTypes(pos, pos + filters.length, filterArgs);
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame stackFrame) throws Throwable {
+ final StackFrameReader reader = new StackFrameReader();
+ reader.attach(stackFrame);
+
+ EmulatedStackFrame transformedFrame = EmulatedStackFrame.create(target.type());
+ final StackFrameWriter writer = new StackFrameWriter();
+ writer.attach(transformedFrame);
+
+ final Class<?>[] ptypes = target.type().ptypes();
+ for (int i = 0; i < ptypes.length; ++i) {
+ // Check whether the current argument has a filter associated with it.
+ // If it has no filter, no further action need be taken.
+ final Class<?> ptype = ptypes[i];
+ final MethodHandle filter;
+ if (i < pos) {
+ filter = null;
+ } else if (i >= pos + filters.length) {
+ filter = null;
+ } else {
+ filter = filters[i - pos];
+ }
+
+ if (filter != null) {
+ // Note that filter.type() must be (ptype)ptype - this is checked before
+ // this transformer is created.
+ EmulatedStackFrame filterFrame = EmulatedStackFrame.create(filter.type());
+
+ // Copy the next argument from the stack frame to the filter frame.
+ final StackFrameWriter filterWriter = new StackFrameWriter();
+ filterWriter.attach(filterFrame);
+ copyNext(reader, filterWriter, filter.type().ptypes()[0]);
+
+ invokeFromTransform(filter, filterFrame);
+
+ // Copy the argument back from the filter frame to the stack frame.
+ final StackFrameReader filterReader = new StackFrameReader();
+ filterReader.attach(filterFrame);
+ filterReader.makeReturnValueAccessor();
+ copyNext(filterReader, writer, ptype);
+ } else {
+ // There's no filter associated with this frame, just copy the next argument
+ // over.
+ copyNext(reader, writer, ptype);
+ }
+ }
+
+ invokeFromTransform(target, transformedFrame);
+ transformedFrame.copyReturnValueTo(stackFrame);
+ }
+ }
+
+ /** Implements {@code MethodHandles.collectArguments}. */
+ static class CollectArguments extends Transformer {
+ private final MethodHandle target;
+ private final MethodHandle collector;
+ private final int pos;
+
+ /** The range of input arguments we copy to the collector. */
+ private final Range collectorRange;
+
+ /**
+ * The first range of arguments we copy to the target. These are arguments in the range [0,
+ * pos). Note that arg[pos] is the return value of the filter.
+ */
+ private final Range range1;
+
+ /**
+ * The second range of arguments we copy to the target. These are arguments in the range
+ * (pos, N], where N is the number of target arguments.
+ */
+ private final Range range2;
+
+ private final int referencesOffset;
+ private final int stackFrameOffset;
+
+ CollectArguments(
+ MethodHandle target, MethodHandle collector, int pos, MethodType adapterType) {
+ super(adapterType);
+
+ this.target = target;
+ this.collector = collector;
+ this.pos = pos;
+
+ final int numFilterArgs = collector.type().parameterCount();
+ collectorRange = Range.of(type(), pos, pos + numFilterArgs);
+
+ range1 = Range.of(type(), 0, pos);
+ this.range2 = Range.from(type(), pos + numFilterArgs);
+
+ // Calculate the number of primitive bytes (or references) we copy to the
+ // target frame based on the return value of the combiner.
+ final Class<?> collectorRType = collector.type().rtype();
+ if (collectorRType == void.class) {
+ stackFrameOffset = 0;
+ referencesOffset = 0;
+ } else if (collectorRType.isPrimitive()) {
+ stackFrameOffset = EmulatedStackFrame.getSize(collectorRType);
+ referencesOffset = 0;
+ } else {
+ stackFrameOffset = 0;
+ referencesOffset = 1;
+ }
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame stackFrame) throws Throwable {
+ // First invoke the collector.
+ EmulatedStackFrame filterFrame = EmulatedStackFrame.create(collector.type());
+ stackFrame.copyRangeTo(filterFrame, collectorRange, 0, 0);
+ invokeFromTransform(collector, filterFrame);
+
+ // Start constructing the target frame.
+ EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
+ stackFrame.copyRangeTo(targetFrame, range1, 0, 0);
+
+ // If one of these offsets is not zero, we have a return value to copy.
+ if (referencesOffset != 0 || stackFrameOffset != 0) {
+ final StackFrameReader reader = new StackFrameReader();
+ reader.attach(filterFrame).makeReturnValueAccessor();
+ final StackFrameWriter writer = new StackFrameWriter();
+ writer.attach(targetFrame, pos, range1.numReferences, range1.numBytes);
+ copyNext(reader, writer, target.type().ptypes()[pos]);
+ }
+
+ stackFrame.copyRangeTo(
+ targetFrame,
+ range2,
+ range1.numReferences + referencesOffset,
+ range1.numBytes + stackFrameOffset);
+
+ invokeFromTransform(target, targetFrame);
+ targetFrame.copyReturnValueTo(stackFrame);
+ }
+ }
+
+ /** Implements {@code MethodHandles.foldArguments}. */
+ static class FoldArguments extends Transformer {
+ private final MethodHandle target;
+ private final MethodHandle combiner;
+ private final int position;
+
+ /** The range of arguments in our frame passed to the combiner. */
+ private final Range combinerArgs;
+
+ /** The range of arguments in our frame copied to the start of the target frame. */
+ private final Range leadingArgs;
+
+ /** The range of arguments in our frame copied to the end of the target frame. */
+ private final Range trailingArgs;
+
+ private final int referencesOffset;
+ private final int stackFrameOffset;
+
+ FoldArguments(MethodHandle target, int position, MethodHandle combiner) {
+ super(deriveType(target, position, combiner));
+
+ this.target = target;
+ this.combiner = combiner;
+ this.position = position;
+
+ this.combinerArgs =
+ Range.of(type(), position, position + combiner.type().parameterCount());
+ this.leadingArgs = Range.of(type(), 0, position);
+ this.trailingArgs = Range.from(type(), position);
+
+ final Class<?> combinerRType = combiner.type().rtype();
+ if (combinerRType == void.class) {
+ stackFrameOffset = 0;
+ referencesOffset = 0;
+ } else if (combinerRType.isPrimitive()) {
+ stackFrameOffset = EmulatedStackFrame.getSize(combinerRType);
+ referencesOffset = 0;
+ } else {
+ // combinerRType is a reference.
+ stackFrameOffset = 0;
+ referencesOffset = 1;
+ }
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame stackFrame) throws Throwable {
+ // First construct the combiner frame and invoke the combiner.
+ EmulatedStackFrame combinerFrame = EmulatedStackFrame.create(combiner.type());
+ stackFrame.copyRangeTo(combinerFrame, combinerArgs, 0, 0);
+ invokeExactFromTransform(combiner, combinerFrame);
+
+ // Create the stack frame for the target and copy leading arguments to it.
+ EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
+ stackFrame.copyRangeTo(targetFrame, leadingArgs, 0, 0);
+
+ // If one of these offsets is not zero, we have to slot the return value from the
+ // combiner into the target frame.
+ if (referencesOffset != 0 || stackFrameOffset != 0) {
+ final StackFrameReader reader = new StackFrameReader();
+ reader.attach(combinerFrame).makeReturnValueAccessor();
+ final StackFrameWriter writer = new StackFrameWriter();
+ writer.attach(targetFrame,
+ position,
+ leadingArgs.numReferences,
+ leadingArgs.numBytes);
+ copyNext(reader, writer, target.type().ptypes()[position]);
+ }
+
+ // Copy the arguments provided to the combiner to the tail of the target frame.
+ stackFrame.copyRangeTo(
+ targetFrame,
+ trailingArgs,
+ leadingArgs.numReferences + referencesOffset,
+ leadingArgs.numBytes + stackFrameOffset);
+
+ // Call the target and propagate return value.
+ invokeExactFromTransform(target, targetFrame);
+ targetFrame.copyReturnValueTo(stackFrame);
+ }
+
+ private static MethodType deriveType(MethodHandle target,
+ int position,
+ MethodHandle combiner) {
+ if (combiner.type().rtype() == void.class) {
+ return target.type();
+ }
+ return target.type().dropParameterTypes(position, position + 1);
+ }
+ }
+
+ /** Implements {@code MethodHandles.insertArguments}. */
+ static class InsertArguments extends Transformer {
+ private final MethodHandle target;
+ private final int pos;
+ private final Object[] values;
+
+ private final Range range1;
+ private final Range range2;
+
+ InsertArguments(MethodHandle target, int pos, Object[] values) {
+ super(target.type().dropParameterTypes(pos, pos + values.length));
+ this.target = target;
+ this.pos = pos;
+ this.values = values;
+
+ final MethodType type = type();
+ range1 = EmulatedStackFrame.Range.of(type, 0, pos);
+ range2 = Range.of(type, pos, type.parameterCount());
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame stackFrame) throws Throwable {
+ EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(target.type());
+
+ // Copy all arguments before |pos|.
+ stackFrame.copyRangeTo(calleeFrame, range1, 0, 0);
+
+ // Attach a stack frame writer so that we can copy the next |values.length|
+ // arguments.
+ final StackFrameWriter writer = new StackFrameWriter();
+ writer.attach(calleeFrame, pos, range1.numReferences, range1.numBytes);
+
+ // Copy all the arguments supplied in |values|.
+ int referencesCopied = 0;
+ int bytesCopied = 0;
+ final Class<?>[] ptypes = target.type().ptypes();
+ for (int i = 0; i < values.length; ++i) {
+ final Class<?> ptype = ptypes[i + pos];
+ final char typeChar = Wrapper.basicTypeChar(ptype);
+ if (typeChar == 'L') {
+ writer.putNextReference(values[i], ptype);
+ referencesCopied++;
+ } else {
+ switch (typeChar) {
+ case 'Z':
+ writer.putNextBoolean((boolean) values[i]);
+ break;
+ case 'B':
+ writer.putNextByte((byte) values[i]);
+ break;
+ case 'C':
+ writer.putNextChar((char) values[i]);
+ break;
+ case 'S':
+ writer.putNextShort((short) values[i]);
+ break;
+ case 'I':
+ writer.putNextInt((int) values[i]);
+ break;
+ case 'J':
+ writer.putNextLong((long) values[i]);
+ break;
+ case 'F':
+ writer.putNextFloat((float) values[i]);
+ break;
+ case 'D':
+ writer.putNextDouble((double) values[i]);
+ break;
+ }
+ bytesCopied += EmulatedStackFrame.getSize(ptype);
+ }
+ }
+
+ // Copy all remaining arguments.
+ if (range2 != null) {
+ stackFrame.copyRangeTo(
+ calleeFrame,
+ range2,
+ range1.numReferences + referencesCopied,
+ range1.numBytes + bytesCopied);
+ }
+
+ invokeFromTransform(target, calleeFrame);
+ calleeFrame.copyReturnValueTo(stackFrame);
+ }
+ }
+
+ /** Implements {@code MethodHandle.asType}. */
+ static class AsTypeAdapter extends Transformer {
+ private final MethodHandle target;
+
+ AsTypeAdapter(MethodHandle target, MethodType type) {
+ super(type);
+ this.target = target;
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame callerFrame) throws Throwable {
+ final EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
+ final StackFrameReader reader = new StackFrameReader();
+ final StackFrameWriter writer = new StackFrameWriter();
+
+ // Adapt arguments
+ reader.attach(callerFrame);
+ writer.attach(targetFrame);
+ adaptArguments(reader, writer);
+
+ // Invoke target
+ invokeFromTransform(target, targetFrame);
+
+ if (callerFrame.getMethodType().rtype() != void.class) {
+ // Adapt return value
+ reader.attach(targetFrame).makeReturnValueAccessor();
+ writer.attach(callerFrame).makeReturnValueAccessor();
+ adaptReturnValue(reader, writer);
+ }
+ }
+
+ private void adaptArguments(final StackFrameReader reader, final StackFrameWriter writer) {
+ final Class<?>[] fromTypes = type().ptypes();
+ final Class<?>[] toTypes = target.type().ptypes();
+ for (int i = 0; i < fromTypes.length; ++i) {
+ adaptArgument(reader, fromTypes[i], writer, toTypes[i]);
+ }
+ }
+
+ private void adaptReturnValue(
+ final StackFrameReader reader, final StackFrameWriter writer) {
+ final Class<?> fromType = target.type().rtype();
+ final Class<?> toType = type().rtype();
+ adaptArgument(reader, fromType, writer, toType);
+ }
+
+ private void throwWrongMethodTypeException() throws WrongMethodTypeException {
+ throw new WrongMethodTypeException(
+ "Cannot convert from " + type() + " to " + target.type());
+ }
+
+ private static void throwClassCastException(Class from, Class to)
+ throws ClassCastException {
+ throw new ClassCastException("Cannot cast from " + from + " to " + to);
+ }
+
+ private void writePrimitiveByteAs(final StackFrameWriter writer, char baseType, byte value)
+ throws WrongMethodTypeException {
+ switch (baseType) {
+ case 'B':
+ writer.putNextByte(value);
+ return;
+ case 'S':
+ writer.putNextShort((short) value);
+ return;
+ case 'I':
+ writer.putNextInt((int) value);
+ return;
+ case 'J':
+ writer.putNextLong((long) value);
+ return;
+ case 'F':
+ writer.putNextFloat((float) value);
+ return;
+ case 'D':
+ writer.putNextDouble((double) value);
+ return;
+ default:
+ throwWrongMethodTypeException();
+ }
+ }
+
+ private void writePrimitiveShortAs(
+ final StackFrameWriter writer, char baseType, short value)
+ throws WrongMethodTypeException {
+ switch (baseType) {
+ case 'S':
+ writer.putNextShort(value);
+ return;
+ case 'I':
+ writer.putNextInt((int) value);
+ return;
+ case 'J':
+ writer.putNextLong((long) value);
+ return;
+ case 'F':
+ writer.putNextFloat((float) value);
+ return;
+ case 'D':
+ writer.putNextDouble((double) value);
+ return;
+ default:
+ throwWrongMethodTypeException();
+ }
+ }
+
+ private void writePrimitiveCharAs(final StackFrameWriter writer, char baseType, char value)
+ throws WrongMethodTypeException {
+ switch (baseType) {
+ case 'C':
+ writer.putNextChar(value);
+ return;
+ case 'I':
+ writer.putNextInt((int) value);
+ return;
+ case 'J':
+ writer.putNextLong((long) value);
+ return;
+ case 'F':
+ writer.putNextFloat((float) value);
+ return;
+ case 'D':
+ writer.putNextDouble((double) value);
+ return;
+ default:
+ throwWrongMethodTypeException();
+ }
+ }
+
+ private void writePrimitiveIntAs(final StackFrameWriter writer, char baseType, int value)
+ throws WrongMethodTypeException {
+ switch (baseType) {
+ case 'I':
+ writer.putNextInt(value);
+ return;
+ case 'J':
+ writer.putNextLong((long) value);
+ return;
+ case 'F':
+ writer.putNextFloat((float) value);
+ return;
+ case 'D':
+ writer.putNextDouble((double) value);
+ return;
+ default:
+ throwWrongMethodTypeException();
+ }
+ throwWrongMethodTypeException();
+ }
+
+ private void writePrimitiveLongAs(final StackFrameWriter writer, char baseType, long value)
+ throws WrongMethodTypeException {
+ switch (baseType) {
+ case 'J':
+ writer.putNextLong(value);
+ return;
+ case 'F':
+ writer.putNextFloat((float) value);
+ return;
+ case 'D':
+ writer.putNextDouble((double) value);
+ return;
+ default:
+ throwWrongMethodTypeException();
+ }
+ }
+
+ private void writePrimitiveFloatAs(
+ final StackFrameWriter writer, char baseType, float value)
+ throws WrongMethodTypeException {
+ switch (baseType) {
+ case 'F':
+ writer.putNextFloat(value);
+ return;
+ case 'D':
+ writer.putNextDouble((double) value);
+ return;
+ default:
+ throwWrongMethodTypeException();
+ }
+ }
+
+ private void writePrimitiveDoubleAs(
+ final StackFrameWriter writer, char baseType, double value)
+ throws WrongMethodTypeException {
+ switch (baseType) {
+ case 'D':
+ writer.putNextDouble(value);
+ return;
+ default:
+ throwWrongMethodTypeException();
+ }
+ }
+
+ private void writePrimitiveVoidAs(final StackFrameWriter writer, char baseType) {
+ switch (baseType) {
+ case 'Z':
+ writer.putNextBoolean(false);
+ return;
+ case 'B':
+ writer.putNextByte((byte) 0);
+ return;
+ case 'S':
+ writer.putNextShort((short) 0);
+ return;
+ case 'C':
+ writer.putNextChar((char) 0);
+ return;
+ case 'I':
+ writer.putNextInt(0);
+ return;
+ case 'J':
+ writer.putNextLong(0L);
+ return;
+ case 'F':
+ writer.putNextFloat(0.0f);
+ return;
+ case 'D':
+ writer.putNextDouble(0.0);
+ return;
+ default:
+ throwWrongMethodTypeException();
+ }
+ }
+
+ private static Class getBoxedPrimitiveClass(char baseType) {
+ switch (baseType) {
+ case 'Z':
+ return Boolean.class;
+ case 'B':
+ return Byte.class;
+ case 'S':
+ return Short.class;
+ case 'C':
+ return Character.class;
+ case 'I':
+ return Integer.class;
+ case 'J':
+ return Long.class;
+ case 'F':
+ return Float.class;
+ case 'D':
+ return Double.class;
+ default:
+ return null;
+ }
+ }
+
+ private void adaptArgument(
+ final StackFrameReader reader,
+ final Class<?> from,
+ final StackFrameWriter writer,
+ final Class<?> to) {
+ if (from.equals(to)) {
+ StackFrameAccessor.copyNext(reader, writer, from);
+ return;
+ }
+
+ if (to.isPrimitive()) {
+ if (from.isPrimitive()) {
+ final char fromBaseType = Wrapper.basicTypeChar(from);
+ final char toBaseType = Wrapper.basicTypeChar(to);
+ switch (fromBaseType) {
+ case 'B':
+ writePrimitiveByteAs(writer, toBaseType, reader.nextByte());
+ return;
+ case 'S':
+ writePrimitiveShortAs(writer, toBaseType, reader.nextShort());
+ return;
+ case 'C':
+ writePrimitiveCharAs(writer, toBaseType, reader.nextChar());
+ return;
+ case 'I':
+ writePrimitiveIntAs(writer, toBaseType, reader.nextInt());
+ return;
+ case 'J':
+ writePrimitiveLongAs(writer, toBaseType, reader.nextLong());
+ return;
+ case 'F':
+ writePrimitiveFloatAs(writer, toBaseType, reader.nextFloat());
+ return;
+ case 'V':
+ writePrimitiveVoidAs(writer, toBaseType);
+ return;
+ default:
+ throwWrongMethodTypeException();
+ }
+ } else {
+ final Object value = reader.nextReference(Object.class);
+ if (to == void.class) {
+ return;
+ }
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ if (!Wrapper.isWrapperType(value.getClass())) {
+ throwClassCastException(value.getClass(), to);
+ }
+ final Wrapper fromWrapper = Wrapper.forWrapperType(value.getClass());
+ final Wrapper toWrapper = Wrapper.forPrimitiveType(to);
+ if (!toWrapper.isConvertibleFrom(fromWrapper)) {
+ throwClassCastException(from, to);
+ }
+
+ final char toChar = toWrapper.basicTypeChar();
+ switch (fromWrapper.basicTypeChar()) {
+ case 'Z':
+ writer.putNextBoolean(((Boolean) value).booleanValue());
+ return;
+ case 'B':
+ writePrimitiveByteAs(writer, toChar, ((Byte) value).byteValue());
+ return;
+ case 'S':
+ writePrimitiveShortAs(writer, toChar, ((Short) value).shortValue());
+ return;
+ case 'C':
+ writePrimitiveCharAs(writer, toChar, ((Character) value).charValue());
+ return;
+ case 'I':
+ writePrimitiveIntAs(writer, toChar, ((Integer) value).intValue());
+ return;
+ case 'J':
+ writePrimitiveLongAs(writer, toChar, ((Long) value).longValue());
+ return;
+ case 'F':
+ writePrimitiveFloatAs(writer, toChar, ((Float) value).floatValue());
+ return;
+ case 'D':
+ writePrimitiveDoubleAs(writer, toChar, ((Double) value).doubleValue());
+ return;
+ default:
+ throw new IllegalStateException();
+ }
+ }
+ } else {
+ if (from.isPrimitive()) {
+ // Boxing conversion
+ final char fromBaseType = Wrapper.basicTypeChar(from);
+ final Class fromBoxed = getBoxedPrimitiveClass(fromBaseType);
+ // 'to' maybe a super class of the boxed `from` type, e.g. Number.
+ if (fromBoxed != null && !to.isAssignableFrom(fromBoxed)) {
+ throwWrongMethodTypeException();
+ }
+
+ Object boxed;
+ switch (fromBaseType) {
+ case 'Z':
+ boxed = Boolean.valueOf(reader.nextBoolean());
+ break;
+ case 'B':
+ boxed = Byte.valueOf(reader.nextByte());
+ break;
+ case 'S':
+ boxed = Short.valueOf(reader.nextShort());
+ break;
+ case 'C':
+ boxed = Character.valueOf(reader.nextChar());
+ break;
+ case 'I':
+ boxed = Integer.valueOf(reader.nextInt());
+ break;
+ case 'J':
+ boxed = Long.valueOf(reader.nextLong());
+ break;
+ case 'F':
+ boxed = Float.valueOf(reader.nextFloat());
+ break;
+ case 'D':
+ boxed = Double.valueOf(reader.nextDouble());
+ break;
+ case 'V':
+ boxed = null;
+ break;
+ default:
+ throw new IllegalStateException();
+ }
+ writer.putNextReference(boxed, to);
+ return;
+ } else {
+ // Cast
+ Object value = reader.nextReference(Object.class);
+ if (value != null && !to.isAssignableFrom(value.getClass())) {
+ throwClassCastException(value.getClass(), to);
+ }
+ writer.putNextReference(value, to);
+ }
+ }
+ }
+ }
+
+ /** Implements {@code MethodHandles.explicitCastArguments}. */
+ static class ExplicitCastArguments extends Transformer {
+ private final MethodHandle target;
+
+ ExplicitCastArguments(MethodHandle target, MethodType type) {
+ super(type);
+ this.target = target;
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame callerFrame) throws Throwable {
+ // Create a new stack frame for the target.
+ EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
+
+ explicitCastArguments(callerFrame, targetFrame);
+ invokeFromTransform(target, targetFrame);
+ explicitCastReturnValue(callerFrame, targetFrame);
+ }
+
+ private void explicitCastArguments(
+ final EmulatedStackFrame callerFrame, final EmulatedStackFrame targetFrame) {
+ final StackFrameReader reader = new StackFrameReader();
+ reader.attach(callerFrame);
+ final StackFrameWriter writer = new StackFrameWriter();
+ writer.attach(targetFrame);
+
+ final Class<?>[] fromTypes = type().ptypes();
+ final Class<?>[] toTypes = target.type().ptypes();
+ for (int i = 0; i < fromTypes.length; ++i) {
+ explicitCast(reader, fromTypes[i], writer, toTypes[i]);
+ }
+ }
+
+ private void explicitCastReturnValue(
+ final EmulatedStackFrame callerFrame, final EmulatedStackFrame targetFrame) {
+ Class<?> from = target.type().rtype();
+ Class<?> to = type().rtype();
+ if (to != void.class) {
+ final StackFrameWriter writer = new StackFrameWriter();
+ writer.attach(callerFrame);
+ writer.makeReturnValueAccessor();
+ if (from == void.class) {
+ if (to.isPrimitive()) {
+ unboxNull(writer, to);
+ } else {
+ writer.putNextReference(null, to);
+ }
+ } else {
+ final StackFrameReader reader = new StackFrameReader();
+ reader.attach(targetFrame);
+ reader.makeReturnValueAccessor();
+ explicitCast(reader, target.type().rtype(), writer, type().rtype());
+ }
+ }
+ }
+
+ private static void throwUnexpectedType(final Class<?> unexpectedType) {
+ throw new InternalError("Unexpected type: " + unexpectedType);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static void badCast(final Class<?> from, final Class<?> to) {
+ throw new ClassCastException("Cannot cast " + from.getName() + " to " + to.getName());
+ }
+
+ /**
+ * Converts byte value to boolean according to {@link
+ * java.lang.invoke.MethodHandles#explicitCast()}
+ */
+ private static boolean toBoolean(byte value) {
+ return (value & 1) == 1;
+ }
+
+ private static byte readPrimitiveAsByte(
+ final StackFrameReader reader, final Class<?> from) {
+ switch (Wrapper.basicTypeChar(from)) {
+ case 'B':
+ return (byte) reader.nextByte();
+ case 'C':
+ return (byte) reader.nextChar();
+ case 'S':
+ return (byte) reader.nextShort();
+ case 'I':
+ return (byte) reader.nextInt();
+ case 'J':
+ return (byte) reader.nextLong();
+ case 'F':
+ return (byte) reader.nextFloat();
+ case 'D':
+ return (byte) reader.nextDouble();
+ case 'Z':
+ return reader.nextBoolean() ? (byte) 1 : (byte) 0;
+ default:
+ throwUnexpectedType(from);
+ return 0;
+ }
+ }
+
+ private static char readPrimitiveAsChar(
+ final StackFrameReader reader, final Class<?> from) {
+ switch (Wrapper.basicTypeChar(from)) {
+ case 'B':
+ return (char) reader.nextByte();
+ case 'C':
+ return (char) reader.nextChar();
+ case 'S':
+ return (char) reader.nextShort();
+ case 'I':
+ return (char) reader.nextInt();
+ case 'J':
+ return (char) reader.nextLong();
+ case 'F':
+ return (char) reader.nextFloat();
+ case 'D':
+ return (char) reader.nextDouble();
+ case 'Z':
+ return reader.nextBoolean() ? (char) 1 : (char) 0;
+ default:
+ throwUnexpectedType(from);
+ return 0;
+ }
+ }
+
+ private static short readPrimitiveAsShort(
+ final StackFrameReader reader, final Class<?> from) {
+ switch (Wrapper.basicTypeChar(from)) {
+ case 'B':
+ return (short) reader.nextByte();
+ case 'C':
+ return (short) reader.nextChar();
+ case 'S':
+ return (short) reader.nextShort();
+ case 'I':
+ return (short) reader.nextInt();
+ case 'J':
+ return (short) reader.nextLong();
+ case 'F':
+ return (short) reader.nextFloat();
+ case 'D':
+ return (short) reader.nextDouble();
+ case 'Z':
+ return reader.nextBoolean() ? (short) 1 : (short) 0;
+ default:
+ throwUnexpectedType(from);
+ return 0;
+ }
+ }
+
+ private static int readPrimitiveAsInt(final StackFrameReader reader, final Class<?> from) {
+ switch (Wrapper.basicTypeChar(from)) {
+ case 'B':
+ return (int) reader.nextByte();
+ case 'C':
+ return (int) reader.nextChar();
+ case 'S':
+ return (int) reader.nextShort();
+ case 'I':
+ return (int) reader.nextInt();
+ case 'J':
+ return (int) reader.nextLong();
+ case 'F':
+ return (int) reader.nextFloat();
+ case 'D':
+ return (int) reader.nextDouble();
+ case 'Z':
+ return reader.nextBoolean() ? 1 : 0;
+ default:
+ throwUnexpectedType(from);
+ return 0;
+ }
+ }
+
+ private static long readPrimitiveAsLong(
+ final StackFrameReader reader, final Class<?> from) {
+ switch (Wrapper.basicTypeChar(from)) {
+ case 'B':
+ return (long) reader.nextByte();
+ case 'C':
+ return (long) reader.nextChar();
+ case 'S':
+ return (long) reader.nextShort();
+ case 'I':
+ return (long) reader.nextInt();
+ case 'J':
+ return (long) reader.nextLong();
+ case 'F':
+ return (long) reader.nextFloat();
+ case 'D':
+ return (long) reader.nextDouble();
+ case 'Z':
+ return reader.nextBoolean() ? 1L : 0L;
+ default:
+ throwUnexpectedType(from);
+ return 0;
+ }
+ }
+
+ private static float readPrimitiveAsFloat(
+ final StackFrameReader reader, final Class<?> from) {
+ switch (Wrapper.basicTypeChar(from)) {
+ case 'B':
+ return (float) reader.nextByte();
+ case 'C':
+ return (float) reader.nextChar();
+ case 'S':
+ return (float) reader.nextShort();
+ case 'I':
+ return (float) reader.nextInt();
+ case 'J':
+ return (float) reader.nextLong();
+ case 'F':
+ return (float) reader.nextFloat();
+ case 'D':
+ return (float) reader.nextDouble();
+ case 'Z':
+ return reader.nextBoolean() ? 1.0f : 0.0f;
+ default:
+ throwUnexpectedType(from);
+ return 0;
+ }
+ }
+
+ private static double readPrimitiveAsDouble(
+ final StackFrameReader reader, final Class<?> from) {
+ switch (Wrapper.basicTypeChar(from)) {
+ case 'B':
+ return (double) reader.nextByte();
+ case 'C':
+ return (double) reader.nextChar();
+ case 'S':
+ return (double) reader.nextShort();
+ case 'I':
+ return (double) reader.nextInt();
+ case 'J':
+ return (double) reader.nextLong();
+ case 'F':
+ return (double) reader.nextFloat();
+ case 'D':
+ return (double) reader.nextDouble();
+ case 'Z':
+ return reader.nextBoolean() ? 1.0 : 0.0;
+ default:
+ throwUnexpectedType(from);
+ return 0;
+ }
+ }
+
+ private static void explicitCastPrimitives(
+ final StackFrameReader reader,
+ final Class<?> from,
+ final StackFrameWriter writer,
+ final Class<?> to) {
+ switch (Wrapper.basicTypeChar(to)) {
+ case 'B':
+ writer.putNextByte(readPrimitiveAsByte(reader, from));
+ break;
+ case 'C':
+ writer.putNextChar(readPrimitiveAsChar(reader, from));
+ break;
+ case 'S':
+ writer.putNextShort(readPrimitiveAsShort(reader, from));
+ break;
+ case 'I':
+ writer.putNextInt(readPrimitiveAsInt(reader, from));
+ break;
+ case 'J':
+ writer.putNextLong(readPrimitiveAsLong(reader, from));
+ break;
+ case 'F':
+ writer.putNextFloat(readPrimitiveAsFloat(reader, from));
+ break;
+ case 'D':
+ writer.putNextDouble(readPrimitiveAsDouble(reader, from));
+ break;
+ case 'Z':
+ writer.putNextBoolean(toBoolean(readPrimitiveAsByte(reader, from)));
+ break;
+ default:
+ throwUnexpectedType(to);
+ break;
+ }
+ }
+
+ private static void unboxNull(final StackFrameWriter writer, final Class<?> to) {
+ switch (Wrapper.basicTypeChar(to)) {
+ case 'Z':
+ writer.putNextBoolean(false);
+ break;
+ case 'B':
+ writer.putNextByte((byte) 0);
+ break;
+ case 'C':
+ writer.putNextChar((char) 0);
+ break;
+ case 'S':
+ writer.putNextShort((short) 0);
+ break;
+ case 'I':
+ writer.putNextInt((int) 0);
+ break;
+ case 'J':
+ writer.putNextLong((long) 0);
+ break;
+ case 'F':
+ writer.putNextFloat((float) 0);
+ break;
+ case 'D':
+ writer.putNextDouble((double) 0);
+ break;
+ default:
+ throwUnexpectedType(to);
+ break;
+ }
+ }
+
+ private static void unboxNonNull(
+ final Object ref,
+ final StackFrameWriter writer,
+ final Class<?> to) {
+ final Class<?> from = ref.getClass();
+ final Class<?> unboxedFromType = Wrapper.asPrimitiveType(from);
+ switch (Wrapper.basicTypeChar(unboxedFromType)) {
+ case 'Z':
+ boolean z = (boolean) ref;
+ switch (Wrapper.basicTypeChar(to)) {
+ case 'Z':
+ writer.putNextBoolean(z);
+ break;
+ case 'B':
+ writer.putNextByte(z ? (byte) 1 : (byte) 0);
+ break;
+ case 'S':
+ writer.putNextShort(z ? (short) 1 : (short) 0);
+ break;
+ case 'C':
+ writer.putNextChar(z ? (char) 1 : (char) 0);
+ break;
+ case 'I':
+ writer.putNextInt(z ? 1 : 0);
+ break;
+ case 'J':
+ writer.putNextLong(z ? 1l : 0l);
+ break;
+ case 'F':
+ writer.putNextFloat(z ? 1.0f : 0.0f);
+ break;
+ case 'D':
+ writer.putNextDouble(z ? 1.0 : 0.0);
+ break;
+ default:
+ badCast(from, to);
+ break;
+ }
+ break;
+ case 'B':
+ byte b = (byte) ref;
+ switch (Wrapper.basicTypeChar(to)) {
+ case 'B':
+ writer.putNextByte(b);
+ break;
+ case 'Z':
+ writer.putNextBoolean(toBoolean(b));
+ break;
+ case 'S':
+ writer.putNextShort((short) b);
+ break;
+ case 'C':
+ writer.putNextChar((char) b);
+ break;
+ case 'I':
+ writer.putNextInt((int) b);
+ break;
+ case 'J':
+ writer.putNextLong((long) b);
+ break;
+ case 'F':
+ writer.putNextFloat((float) b);
+ break;
+ case 'D':
+ writer.putNextDouble((double) b);
+ break;
+ default:
+ badCast(from, to);
+ break;
+ }
+ break;
+ case 'S':
+ short s = (short) ref;
+ switch (Wrapper.basicTypeChar(to)) {
+ case 'Z':
+ writer.putNextBoolean((s & 1) == 1);
+ break;
+ case 'B':
+ writer.putNextByte((byte) s);
+ break;
+ case 'S':
+ writer.putNextShort(s);
+ break;
+ case 'C':
+ writer.putNextChar((char) s);
+ break;
+ case 'I':
+ writer.putNextInt((int) s);
+ break;
+ case 'J':
+ writer.putNextLong((long) s);
+ break;
+ case 'F':
+ writer.putNextFloat((float) s);
+ break;
+ case 'D':
+ writer.putNextDouble((double) s);
+ break;
+ default:
+ badCast(from, to);
+ break;
+ }
+ break;
+ case 'C':
+ char c = (char) ref;
+ switch (Wrapper.basicTypeChar(to)) {
+ case 'Z':
+ writer.putNextBoolean((c & (char) 1) == (char) 1);
+ break;
+ case 'B':
+ writer.putNextByte((byte) c);
+ break;
+ case 'S':
+ writer.putNextShort((short) c);
+ break;
+ case 'C':
+ writer.putNextChar(c);
+ break;
+ case 'I':
+ writer.putNextInt((int) c);
+ break;
+ case 'J':
+ writer.putNextLong((long) c);
+ break;
+ case 'F':
+ writer.putNextFloat((float) c);
+ break;
+ case 'D':
+ writer.putNextDouble((double) c);
+ break;
+ default:
+ badCast(from, to);
+ break;
+ }
+ break;
+ case 'I':
+ int i = (int) ref;
+ switch (Wrapper.basicTypeChar(to)) {
+ case 'Z':
+ writer.putNextBoolean((i & 1) == 1);
+ break;
+ case 'B':
+ writer.putNextByte((byte) i);
+ break;
+ case 'S':
+ writer.putNextShort((short) i);
+ break;
+ case 'C':
+ writer.putNextChar((char) i);
+ break;
+ case 'I':
+ writer.putNextInt(i);
+ break;
+ case 'J':
+ writer.putNextLong((long) i);
+ break;
+ case 'F':
+ writer.putNextFloat((float) i);
+ break;
+ case 'D':
+ writer.putNextDouble((double) i);
+ break;
+ default:
+ badCast(from, to);
+ }
+ break;
+ case 'J':
+ long j = (long) ref;
+ switch (Wrapper.basicTypeChar(to)) {
+ case 'Z':
+ writer.putNextBoolean((j & 1l) == 1l);
+ break;
+ case 'B':
+ writer.putNextByte((byte) j);
+ break;
+ case 'S':
+ writer.putNextShort((short) j);
+ break;
+ case 'C':
+ writer.putNextChar((char) j);
+ break;
+ case 'I':
+ writer.putNextInt((int) j);
+ break;
+ case 'J':
+ writer.putNextLong(j);
+ break;
+ case 'F':
+ writer.putNextFloat((float) j);
+ break;
+ case 'D':
+ writer.putNextDouble((double) j);
+ break;
+ default:
+ badCast(from, to);
+ break;
+ }
+ break;
+ case 'F':
+ float f = (float) ref;
+ switch (Wrapper.basicTypeChar(to)) {
+ case 'Z':
+ writer.putNextBoolean(((byte) f & 1) != 0);
+ break;
+ case 'B':
+ writer.putNextByte((byte) f);
+ break;
+ case 'S':
+ writer.putNextShort((short) f);
+ break;
+ case 'C':
+ writer.putNextChar((char) f);
+ break;
+ case 'I':
+ writer.putNextInt((int) f);
+ break;
+ case 'J':
+ writer.putNextLong((long) f);
+ break;
+ case 'F':
+ writer.putNextFloat(f);
+ break;
+ case 'D':
+ writer.putNextDouble((double) f);
+ break;
+ default:
+ badCast(from, to);
+ break;
+ }
+ break;
+ case 'D':
+ double d = (double) ref;
+ switch (Wrapper.basicTypeChar(to)) {
+ case 'Z':
+ writer.putNextBoolean(((byte) d & 1) != 0);
+ break;
+ case 'B':
+ writer.putNextByte((byte) d);
+ break;
+ case 'S':
+ writer.putNextShort((short) d);
+ break;
+ case 'C':
+ writer.putNextChar((char) d);
+ break;
+ case 'I':
+ writer.putNextInt((int) d);
+ break;
+ case 'J':
+ writer.putNextLong((long) d);
+ break;
+ case 'F':
+ writer.putNextFloat((float) d);
+ break;
+ case 'D':
+ writer.putNextDouble(d);
+ break;
+ default:
+ badCast(from, to);
+ break;
+ }
+ break;
+ default:
+ badCast(from, to);
+ break;
+ }
+ }
+
+ private static void unbox(
+ final Object ref,
+ final StackFrameWriter writer,
+ final Class<?> to) {
+ if (ref == null) {
+ unboxNull(writer, to);
+ } else {
+ unboxNonNull(ref, writer, to);
+ }
+ }
+
+ private static void box(
+ final StackFrameReader reader,
+ final Class<?> from,
+ final StackFrameWriter writer,
+ final Class<?> to) {
+ Object boxed = null;
+ switch (Wrapper.basicTypeChar(from)) {
+ case 'Z':
+ boxed = Boolean.valueOf(reader.nextBoolean());
+ break;
+ case 'B':
+ boxed = Byte.valueOf(reader.nextByte());
+ break;
+ case 'C':
+ boxed = Character.valueOf(reader.nextChar());
+ break;
+ case 'S':
+ boxed = Short.valueOf(reader.nextShort());
+ break;
+ case 'I':
+ boxed = Integer.valueOf(reader.nextInt());
+ break;
+ case 'J':
+ boxed = Long.valueOf(reader.nextLong());
+ break;
+ case 'F':
+ boxed = Float.valueOf(reader.nextFloat());
+ break;
+ case 'D':
+ boxed = Double.valueOf(reader.nextDouble());
+ break;
+ default:
+ throwUnexpectedType(from);
+ break;
+ }
+ writer.putNextReference(to.cast(boxed), to);
+ }
+
+ private static void explicitCast(
+ final StackFrameReader reader,
+ final Class<?> from,
+ final StackFrameWriter writer,
+ final Class<?> to) {
+ if (from.equals(to)) {
+ StackFrameAccessor.copyNext(reader, writer, from);
+ return;
+ }
+
+ if (from.isPrimitive()) {
+ if (to.isPrimitive()) {
+ // |from| and |to| are primitive types.
+ explicitCastPrimitives(reader, from, writer, to);
+ } else {
+ // |from| is a primitive type, |to| is a reference type.
+ box(reader, from, writer, to);
+ }
+ } else {
+ // |from| is a reference type.
+ Object ref = reader.nextReference(from);
+ if (to.isPrimitive()) {
+ // |from| is a reference type, |to| is a primitive type,
+ unbox(ref, writer, to);
+ } else if (to.isInterface()) {
+ // Pass from without a cast according to description for
+ // {@link java.lang.invoke.MethodHandles#explicitCastArguments()}.
+ writer.putNextReference(ref, to);
+ } else {
+ // |to| and from |from| are reference types, perform class cast check.
+ writer.putNextReference(to.cast(ref), to);
+ }
+ }
+ }
+ }
+
+ /** Implements {@code MethodHandles.loop}. */
+ static class Loop extends Transformer {
+
+ /** Loop variable initialization methods. */
+ final MethodHandle[] inits;
+
+ /** Loop variable step methods. */
+ final MethodHandle[] steps;
+
+ /** Loop variable predicate methods. */
+ final MethodHandle[] preds;
+
+ /** Loop return value calculating methods. */
+ final MethodHandle[] finis;
+
+ /** Synthetic method type for frame used to hold loop variables. */
+ final MethodType loopVarsType;
+
+ /** Range of loop variables in the frame used for loop variables. */
+ final Range loopVarsRange;
+
+ /** Range of suffix variables in the caller frame. */
+ final Range suffixRange;
+
+ public Loop(Class<?> loopReturnType,
+ List<Class<?>> commonSuffix,
+ MethodHandle[] finit,
+ MethodHandle[] fstep,
+ MethodHandle[] fpred,
+ MethodHandle[] ffini) {
+ super(MethodType.methodType(loopReturnType, commonSuffix));
+
+ inits = finit;
+ steps = fstep;
+ preds = fpred;
+ finis = ffini;
+
+ loopVarsType = deduceLoopVarsType(finit);
+ loopVarsRange = EmulatedStackFrame.Range.all(loopVarsType);
+ suffixRange = EmulatedStackFrame.Range.all(type());
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame callerFrame) throws Throwable {
+ final EmulatedStackFrame loopVarsFrame = EmulatedStackFrame.create(loopVarsType);
+ final StackFrameWriter loopVarsWriter = new StackFrameWriter();
+
+ init(callerFrame, loopVarsFrame, loopVarsWriter);
+
+ for (;;) {
+ loopVarsWriter.attach(loopVarsFrame);
+ for (int i = 0; i < steps.length; ++i) {
+ // Future optimization opportunity: there is a good deal of StackFrame
+ // allocation here, one is allocated per MH invocation. Consider caching
+ // frames <method-type:stack-frame> and passing the cache on the stack.
+ doStep(steps[i], callerFrame, loopVarsFrame, loopVarsWriter);
+ boolean keepGoing = doPredicate(preds[i], callerFrame, loopVarsFrame);
+ if (!keepGoing) {
+ doFinish(finis[i], callerFrame, loopVarsFrame);
+ return;
+ }
+ }
+ }
+ }
+
+ private static MethodType deduceLoopVarsType(final MethodHandle[] inits) {
+ List<Class<?>> loopVarTypes = new ArrayList(inits.length);
+ for (MethodHandle init : inits) {
+ Class<?> returnType = init.type().returnType();
+ if (returnType != void.class) {
+ loopVarTypes.add(returnType);
+ }
+ }
+ return MethodType.methodType(void.class, loopVarTypes);
+ }
+
+ private void init(final EmulatedStackFrame callerFrame,
+ final EmulatedStackFrame loopVarsFrame,
+ final StackFrameWriter loopVarsWriter) throws Throwable {
+ loopVarsWriter.attach(loopVarsFrame);
+ for (MethodHandle init : inits) {
+ EmulatedStackFrame initFrame = EmulatedStackFrame.create(init.type());
+ callerFrame.copyRangeTo(initFrame, suffixRange, 0, 0);
+
+ invokeExactFromTransform(init, initFrame);
+
+ final Class<?> loopVarType = init.type().returnType();
+ if (loopVarType != void.class) {
+ StackFrameReader initReader = new StackFrameReader();
+ initReader.attach(initFrame).makeReturnValueAccessor();
+ copyNext(initReader, loopVarsWriter, loopVarType);
+ }
+ }
+ }
+
+ /**
+ * Creates a frame for invoking a method of specified type.
+ *
+ * The frame arguments are the loop variables followed by the arguments provided to the
+ * loop MethodHandle.
+ *
+ * @param mt the type of the method to be invoked.
+ * @param callerFrame the frame invoking the loop MethodHandle.
+ * @param loopVarsFrame the frame holding loop variables.
+ * @return an EmulatedStackFrame initialized with the required arguments.
+ */
+ private EmulatedStackFrame prepareFrame(final MethodType mt,
+ final EmulatedStackFrame callerFrame,
+ final EmulatedStackFrame loopVarsFrame) {
+ EmulatedStackFrame frame = EmulatedStackFrame.create(mt);
+
+ // Copy loop variables.
+ loopVarsFrame.copyRangeTo(frame, loopVarsRange, 0, 0);
+
+ // Copy arguments provided in the loop invoke().
+ callerFrame.copyRangeTo(frame,
+ suffixRange,
+ loopVarsRange.numReferences,
+ loopVarsRange.numBytes);
+ return frame;
+ }
+
+ private void doStep(final MethodHandle step,
+ final EmulatedStackFrame callerFrame,
+ final EmulatedStackFrame loopVarsFrame,
+ final StackFrameWriter loopVarsWriter) throws Throwable {
+ final EmulatedStackFrame stepFrame =
+ prepareFrame(step.type(), callerFrame, loopVarsFrame);
+ invokeExactFromTransform(step, stepFrame);
+
+ final Class<?> loopVarType = step.type().returnType();
+ if (loopVarType != void.class) {
+ final StackFrameReader stepReader = new StackFrameReader();
+ stepReader.attach(stepFrame).makeReturnValueAccessor();
+ copyNext(stepReader, loopVarsWriter, loopVarType);
+ }
+ }
+
+ private boolean doPredicate(final MethodHandle pred,
+ final EmulatedStackFrame callerFrame,
+ final EmulatedStackFrame loopVarsFrame) throws Throwable {
+ final EmulatedStackFrame predFrame =
+ prepareFrame(pred.type(), callerFrame, loopVarsFrame);
+ invokeExactFromTransform(pred, predFrame);
+
+ final StackFrameReader predReader = new StackFrameReader();
+ predReader.attach(predFrame).makeReturnValueAccessor();
+ return predReader.nextBoolean();
+ }
+
+ private void doFinish(final MethodHandle fini,
+ final EmulatedStackFrame callerFrame,
+ final EmulatedStackFrame loopVarsFrame) throws Throwable {
+ final EmulatedStackFrame finiFrame =
+ prepareFrame(fini.type(), callerFrame, loopVarsFrame);
+ invokeExactFromTransform(fini, finiFrame);
+ finiFrame.copyReturnValueTo(callerFrame);
+ }
+ }
+
+ /** Implements {@code MethodHandles.tableSwitch}. */
+ static class TableSwitch extends Transformer {
+ private final MethodHandle fallback;
+ private final MethodHandle[] targets;
+
+ TableSwitch(MethodType type, MethodHandle fallback, MethodHandle[] targets) {
+ super(type);
+ this.fallback = fallback;
+ this.targets = targets;
+ }
+
+ @Override
+ public void transform(EmulatedStackFrame callerFrame) throws Throwable {
+ final MethodHandle selected = selectMethodHandle(callerFrame);
+ invokeExactFromTransform(selected, callerFrame);
+ }
+
+ private MethodHandle selectMethodHandle(EmulatedStackFrame callerFrame) {
+ StackFrameReader reader = new StackFrameReader();
+ reader.attach(callerFrame);
+ final int index = reader.nextInt();
+
+ if (index >= 0 && index < targets.length) {
+ return targets[index];
+ } else {
+ return fallback;
+ }
+ }
+ }
+}
diff --git a/android-35/java/lang/invoke/TypeDescriptor.java b/android-35/java/lang/invoke/TypeDescriptor.java
new file mode 100644
index 0000000..ac18908
--- /dev/null
+++ b/android-35/java/lang/invoke/TypeDescriptor.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.invoke;
+
+import java.util.List;
+
+/**
+ * An entity that has a type descriptor.
+ *
+ * @since 12
+ */
+public interface TypeDescriptor {
+ /**
+ * Returns the descriptor string for this {@code TypeDescriptor} object.
+ *
+ * If this {@code TypeDescriptor} object can be described in nominal form,
+ * then this method returns a type descriptor as specified in JVMS {@jvms 4.3}.
+ * The result descriptor string can be used to produce
+ * a {@code java.lang.constant.ConstantDesc nominal descriptor}.
+ *
+ * Otherwise, the result string is not a type descriptor.
+ * No {@code java.lang.constant.ConstantDesc nominal descriptor}
+ * can be produced from the result string.
+ *
+ * @return the descriptor string for this {@code TypeDescriptor} object
+ * @jvms 4.3.2 Field Descriptors
+ * @jvms 4.3.3 Method Descriptors
+ */
+ String descriptorString();
+
+
+ // Android-changed: Remove Class#describeConstable from javadoc until MethodType is updated
+ /**
+ * An entity that has a field type descriptor.
+ * Field descriptors conforming to JVMS {@jvms 4.3.2} can be described
+ *
+ * @param <F> the class implementing {@linkplain TypeDescriptor.OfField}
+ * @jvms 4.3.2 Field Descriptors
+ * @since 12
+ */
+ interface OfField<F extends TypeDescriptor.OfField<F>> extends TypeDescriptor {
+ /**
+ * Does this field descriptor describe an array type?
+ * @return whether this field descriptor describes an array type
+ */
+ boolean isArray();
+
+ /**
+ * Does this field descriptor describe a primitive type (including void.)
+ *
+ * @return whether this field descriptor describes a primitive type
+ */
+ boolean isPrimitive();
+
+ /**
+ * If this field descriptor describes an array type, return
+ * a descriptor for its component type, otherwise return {@code null}.
+ * @return the component type, or {@code null} if this field descriptor does
+ * not describe an array type
+ */
+ F componentType();
+
+ /**
+ * Return a descriptor for the array type whose component type is described by this
+ * descriptor
+ * @return the descriptor for the array type
+ */
+ F arrayType();
+ }
+
+
+ // Android-changed: Remove MethodType#describeConstable from javadoc until MethodType is updated
+ /**
+ * An entity that has a method type descriptor
+ * Method descriptors conforming to JVMS {@jvms 4.3.3} can be described
+ *
+ * @param <F> the type representing field type descriptors
+ * @param <M> the class implementing {@linkplain TypeDescriptor.OfMethod}
+ * @jvms 4.3.2 Field Descriptors
+ * @jvms 4.3.3 Method Descriptors
+ * @since 12
+ */
+ interface OfMethod<F extends TypeDescriptor.OfField<F>, M extends TypeDescriptor.OfMethod<F, M>>
+ extends TypeDescriptor {
+
+ /**
+ * Return the number of parameters in the method type
+ * @return the number of parameters
+ */
+ int parameterCount();
+
+ /**
+ * Return a field descriptor describing the requested parameter of the method type
+ * described by this descriptor
+ * @param i the index of the parameter
+ * @return a field descriptor for the requested parameter type
+ * @throws IndexOutOfBoundsException if the index is outside the half-open
+ * range {[0, parameterCount)}
+ */
+ F parameterType(int i);
+
+ /**
+ * Return a field descriptor describing the return type of the method type described
+ * by this descriptor
+ * @return a field descriptor for the return type
+ */
+ F returnType();
+
+ /**
+ * Return an array of field descriptors for the parameter types of the method type
+ * described by this descriptor
+ * @return field descriptors for the parameter types
+ */
+ F[] parameterArray();
+
+ /**
+ * Return an immutable list of field descriptors for the parameter types of the method type
+ * described by this descriptor
+ * @return field descriptors for the parameter types
+ */
+ List<F> parameterList();
+
+ /**
+ * Return a method descriptor that is identical to this one, except that the return
+ * type has been changed to the specified type
+ *
+ * @param newReturn a field descriptor for the new return type
+ * @throws NullPointerException if any argument is {@code null}
+ * @return the new method descriptor
+ */
+ M changeReturnType(F newReturn);
+
+ /**
+ * Return a method descriptor that is identical to this one,
+ * except that a single parameter type has been changed to the specified type.
+ *
+ * @param index the index of the parameter to change
+ * @param paramType a field descriptor describing the new parameter type
+ * @return the new method descriptor
+ * @throws NullPointerException if any argument is {@code null}
+ * @throws IndexOutOfBoundsException if the index is outside the half-open
+ * range {[0, parameterCount)}
+ */
+ M changeParameterType(int index, F paramType);
+
+ /**
+ * Return a method descriptor that is identical to this one,
+ * except that a range of parameter types have been removed.
+ *
+ * @param start the index of the first parameter to remove
+ * @param end the index after the last parameter to remove
+ * @return the new method descriptor
+ *
+ * @throws IndexOutOfBoundsException if {@code start} is outside the half-open
+ * range {@code [0, parameterCount)}, or {@code end} is outside the closed range
+ * {@code [0, parameterCount]}, or if {@code start > end}
+ */
+ M dropParameterTypes(int start, int end);
+
+ /**
+ * Return a method descriptor that is identical to this one,
+ * except that a range of additional parameter types have been inserted.
+ *
+ * @param pos the index at which to insert the first inserted parameter
+ * @param paramTypes field descriptors describing the new parameter types
+ * to insert
+ * @return the new method descriptor
+ * @throws NullPointerException if any argument is {@code null}
+ * @throws IndexOutOfBoundsException if {@code pos} is outside the closed
+ * range {[0, parameterCount]}
+ */
+ @SuppressWarnings("unchecked")
+ M insertParameterTypes(int pos, F... paramTypes);
+ }
+}
diff --git a/android-35/java/lang/invoke/VarHandle.java b/android-35/java/lang/invoke/VarHandle.java
new file mode 100644
index 0000000..9bd81b4
--- /dev/null
+++ b/android-35/java/lang/invoke/VarHandle.java
@@ -0,0 +1,2528 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import dalvik.system.VMRuntime;
+import jdk.internal.vm.annotation.IntrinsicCandidate;
+import java.lang.constant.ClassDesc;
+import java.lang.constant.Constable;
+import java.lang.constant.ConstantDesc;
+import java.lang.constant.ConstantDescs;
+import java.lang.constant.DirectMethodHandleDesc;
+import java.lang.constant.DynamicConstantDesc;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * A VarHandle is a dynamically strongly typed reference to a variable, or to a
+ * parametrically-defined family of variables, including static fields,
+ * non-static fields, array elements, or components of an off-heap data
+ * structure. Access to such variables is supported under various
+ * <em>access modes</em>, including plain read/write access, volatile
+ * read/write access, and compare-and-set.
+ *
+ * <p>VarHandles are immutable and have no visible state. VarHandles cannot be
+ * subclassed by the user.
+ *
+ * <p>A VarHandle has:
+ * <ul>
+ * <li>a {@link #varType variable type} T, the type of every variable referenced
+ * by this VarHandle; and
+ * <li>a list of {@link #coordinateTypes coordinate types}
+ * {@code CT1, CT2, ..., CTn}, the types of <em>coordinate expressions</em> that
+ * jointly locate a variable referenced by this VarHandle.
+ * </ul>
+ * Variable and coordinate types may be primitive or reference, and are
+ * represented by {@code Class} objects. The list of coordinate types may be
+ * empty.
+ *
+ * <p>Factory methods that produce or {@link java.lang.invoke.MethodHandles.Lookup
+ * lookup} VarHandle instances document the supported variable type and the list
+ * of coordinate types.
+ *
+ * <p>Each access mode is associated with one <em>access mode method</em>, a
+ * <a href="MethodHandle.html#sigpoly">signature polymorphic</a> method named
+ * for the access mode. When an access mode method is invoked on a VarHandle
+ * instance, the initial arguments to the invocation are coordinate expressions
+ * that indicate in precisely which object the variable is to be accessed.
+ * Trailing arguments to the invocation represent values of importance to the
+ * access mode. For example, the various compare-and-set or compare-and-exchange
+ * access modes require two trailing arguments for the variable's expected value
+ * and new value.
+ *
+ * <p>The arity and types of arguments to the invocation of an access mode
+ * method are not checked statically. Instead, each access mode method
+ * specifies an {@link #accessModeType(AccessMode) access mode type},
+ * represented as an instance of {@link MethodType}, that serves as a kind of
+ * method signature against which the arguments are checked dynamically. An
+ * access mode type gives formal parameter types in terms of the coordinate
+ * types of a VarHandle instance and the types for values of importance to the
+ * access mode. An access mode type also gives a return type, often in terms of
+ * the variable type of a VarHandle instance. When an access mode method is
+ * invoked on a VarHandle instance, the symbolic type descriptor at the
+ * call site, the run time types of arguments to the invocation, and the run
+ * time type of the return value, must <a href="#invoke">match</a> the types
+ * given in the access mode type. A runtime exception will be thrown if the
+ * match fails.
+ *
+ * For example, the access mode method {@link #compareAndSet} specifies that if
+ * its receiver is a VarHandle instance with coordinate types
+ * {@code CT1, ..., CTn} and variable type {@code T}, then its access mode type
+ * is {@code (CT1 c1, ..., CTn cn, T expectedValue, T newValue)boolean}.
+ * Suppose that a VarHandle instance can access array elements, and that its
+ * coordinate types are {@code String[]} and {@code int} while its variable type
+ * is {@code String}. The access mode type for {@code compareAndSet} on this
+ * VarHandle instance would be
+ * {@code (String[] c1, int c2, String expectedValue, String newValue)boolean}.
+ * Such a VarHandle instance may be produced by the
+ * {@link MethodHandles#arrayElementVarHandle(Class) array factory method} and
+ * access array elements as follows:
+ * <pre> {@code
+ * String[] sa = ...
+ * VarHandle avh = MethodHandles.arrayElementVarHandle(String[].class);
+ * boolean r = avh.compareAndSet(sa, 10, "expected", "new");
+ * }</pre>
+ *
+ * <p>Access modes control atomicity and consistency properties.
+ * <em>Plain</em> read ({@code get}) and write ({@code set})
+ * accesses are guaranteed to be bitwise atomic only for references
+ * and for primitive values of at most 32 bits, and impose no observable
+ * ordering constraints with respect to threads other than the
+ * executing thread. <em>Opaque</em> operations are bitwise atomic and
+ * coherently ordered with respect to accesses to the same variable.
+ * In addition to obeying Opaque properties, <em>Acquire</em> mode
+ * reads and their subsequent accesses are ordered after matching
+ * <em>Release</em> mode writes and their previous accesses. In
+ * addition to obeying Acquire and Release properties, all
+ * <em>Volatile</em> operations are totally ordered with respect to
+ * each other.
+ *
+ * <p>Access modes are grouped into the following categories:
+ * <ul>
+ * <li>read access modes that get the value of a variable under specified
+ * memory ordering effects.
+ * The set of corresponding access mode methods belonging to this group
+ * consists of the methods
+ * {@link #get get},
+ * {@link #getVolatile getVolatile},
+ * {@link #getAcquire getAcquire},
+ * {@link #getOpaque getOpaque}.
+ * <li>write access modes that set the value of a variable under specified
+ * memory ordering effects.
+ * The set of corresponding access mode methods belonging to this group
+ * consists of the methods
+ * {@link #set set},
+ * {@link #setVolatile setVolatile},
+ * {@link #setRelease setRelease},
+ * {@link #setOpaque setOpaque}.
+ * <li>atomic update access modes that, for example, atomically compare and set
+ * the value of a variable under specified memory ordering effects.
+ * The set of corresponding access mode methods belonging to this group
+ * consists of the methods
+ * {@link #compareAndSet compareAndSet},
+ * {@link #weakCompareAndSetPlain weakCompareAndSetPlain},
+ * {@link #weakCompareAndSet weakCompareAndSet},
+ * {@link #weakCompareAndSetAcquire weakCompareAndSetAcquire},
+ * {@link #weakCompareAndSetRelease weakCompareAndSetRelease},
+ * {@link #compareAndExchangeAcquire compareAndExchangeAcquire},
+ * {@link #compareAndExchange compareAndExchange},
+ * {@link #compareAndExchangeRelease compareAndExchangeRelease},
+ * {@link #getAndSet getAndSet},
+ * {@link #getAndSetAcquire getAndSetAcquire},
+ * {@link #getAndSetRelease getAndSetRelease}.
+ * <li>numeric atomic update access modes that, for example, atomically get and
+ * set with addition the value of a variable under specified memory ordering
+ * effects.
+ * The set of corresponding access mode methods belonging to this group
+ * consists of the methods
+ * {@link #getAndAdd getAndAdd},
+ * {@link #getAndAddAcquire getAndAddAcquire},
+ * {@link #getAndAddRelease getAndAddRelease},
+ * <li>bitwise atomic update access modes that, for example, atomically get and
+ * bitwise OR the value of a variable under specified memory ordering
+ * effects.
+ * The set of corresponding access mode methods belonging to this group
+ * consists of the methods
+ * {@link #getAndBitwiseOr getAndBitwiseOr},
+ * {@link #getAndBitwiseOrAcquire getAndBitwiseOrAcquire},
+ * {@link #getAndBitwiseOrRelease getAndBitwiseOrRelease},
+ * {@link #getAndBitwiseAnd getAndBitwiseAnd},
+ * {@link #getAndBitwiseAndAcquire getAndBitwiseAndAcquire},
+ * {@link #getAndBitwiseAndRelease getAndBitwiseAndRelease},
+ * {@link #getAndBitwiseXor getAndBitwiseXor},
+ * {@link #getAndBitwiseXorAcquire getAndBitwiseXorAcquire},
+ * {@link #getAndBitwiseXorRelease getAndBitwiseXorRelease}.
+ * </ul>
+ *
+ * <p>Factory methods that produce or {@link java.lang.invoke.MethodHandles.Lookup
+ * lookup} VarHandle instances document the set of access modes that are
+ * supported, which may also include documenting restrictions based on the
+ * variable type and whether a variable is read-only. If an access mode is not
+ * supported then the corresponding access mode method will on invocation throw
+ * an {@code UnsupportedOperationException}. Factory methods should document
+ * any additional undeclared exceptions that may be thrown by access mode
+ * methods.
+ * The {@link #get get} access mode is supported for all
+ * VarHandle instances and the corresponding method never throws
+ * {@code UnsupportedOperationException}.
+ * If a VarHandle references a read-only variable (for example a {@code final}
+ * field) then write, atomic update, numeric atomic update, and bitwise atomic
+ * update access modes are not supported and corresponding methods throw
+ * {@code UnsupportedOperationException}.
+ * Read/write access modes (if supported), with the exception of
+ * {@code get} and {@code set}, provide atomic access for
+ * reference types and all primitive types.
+ * Unless stated otherwise in the documentation of a factory method, the access
+ * modes {@code get} and {@code set} (if supported) provide atomic access for
+ * reference types and all primitives types, with the exception of {@code long}
+ * and {@code double} on 32-bit platforms.
+ *
+ * <p>Access modes will override any memory ordering effects specified at
+ * the declaration site of a variable. For example, a VarHandle accessing
+ * a field using the {@code get} access mode will access the field as
+ * specified <em>by its access mode</em> even if that field is declared
+ * {@code volatile}. When mixed access is performed extreme care should be
+ * taken since the Java Memory Model may permit surprising results.
+ *
+ * <p>In addition to supporting access to variables under various access modes,
+ * a set of static methods, referred to as memory fence methods, is also
+ * provided for fine-grained control of memory ordering.
+ *
+ * The Java Language Specification permits other threads to observe operations
+ * as if they were executed in orders different than are apparent in program
+ * source code, subject to constraints arising, for example, from the use of
+ * locks, {@code volatile} fields or VarHandles. The static methods,
+ * {@link #fullFence fullFence}, {@link #acquireFence acquireFence},
+ * {@link #releaseFence releaseFence}, {@link #loadLoadFence loadLoadFence} and
+ * {@link #storeStoreFence storeStoreFence}, can also be used to impose
+ * constraints. Their specifications, as is the case for certain access modes,
+ * are phrased in terms of the lack of "reorderings" -- observable ordering
+ * effects that might otherwise occur if the fence was not present. More
+ * precise phrasing of the specification of access mode methods and memory fence
+ * methods may accompany future updates of the Java Language Specification.
+ *
+ * <h1>Compiling invocation of access mode methods</h1>
+ * A Java method call expression naming an access mode method can invoke a
+ * VarHandle from Java source code. From the viewpoint of source code, these
+ * methods can take any arguments and their polymorphic result (if expressed)
+ * can be cast to any return type. Formally this is accomplished by giving the
+ * access mode methods variable arity {@code Object} arguments and
+ * {@code Object} return types (if the return type is polymorphic), but they
+ * have an additional quality called <em>signature polymorphism</em> which
+ * connects this freedom of invocation directly to the JVM execution stack.
+ * <p>
+ * As is usual with virtual methods, source-level calls to access mode methods
+ * compile to an {@code invokevirtual} instruction. More unusually, the
+ * compiler must record the actual argument types, and may not perform method
+ * invocation conversions on the arguments. Instead, it must generate
+ * instructions to push them on the stack according to their own unconverted
+ * types. The VarHandle object itself will be pushed on the stack before the
+ * arguments. The compiler then generates an {@code invokevirtual} instruction
+ * that invokes the access mode method with a symbolic type descriptor which
+ * describes the argument and return types.
+ * <p>
+ * To issue a complete symbolic type descriptor, the compiler must also
+ * determine the return type (if polymorphic). This is based on a cast on the
+ * method invocation expression, if there is one, or else {@code Object} if the
+ * invocation is an expression, or else {@code void} if the invocation is a
+ * statement. The cast may be to a primitive type (but not {@code void}).
+ * <p>
+ * As a corner case, an uncasted {@code null} argument is given a symbolic type
+ * descriptor of {@code java.lang.Void}. The ambiguity with the type
+ * {@code Void} is harmless, since there are no references of type {@code Void}
+ * except the null reference.
+ *
+ *
+ * <h1><a id="invoke">Performing invocation of access mode methods</a></h1>
+ * The first time an {@code invokevirtual} instruction is executed it is linked
+ * by symbolically resolving the names in the instruction and verifying that
+ * the method call is statically legal. This also holds for calls to access mode
+ * methods. In this case, the symbolic type descriptor emitted by the compiler
+ * is checked for correct syntax, and names it contains are resolved. Thus, an
+ * {@code invokevirtual} instruction which invokes an access mode method will
+ * always link, as long as the symbolic type descriptor is syntactically
+ * well-formed and the types exist.
+ * <p>
+ * When the {@code invokevirtual} is executed after linking, the receiving
+ * VarHandle's access mode type is first checked by the JVM to ensure that it
+ * matches the symbolic type descriptor. If the type
+ * match fails, it means that the access mode method which the caller is
+ * invoking is not present on the individual VarHandle being invoked.
+ *
+ * <p>
+ * Invocation of an access mode method behaves as if an invocation of
+ * {@link MethodHandle#invoke}, where the receiving method handle accepts the
+ * VarHandle instance as the leading argument. More specifically, the
+ * following, where {@code {access-mode}} corresponds to the access mode method
+ * name:
+ * <pre> {@code
+ * VarHandle vh = ..
+ * R r = (R) vh.{access-mode}(p1, p2, ..., pN);
+ * }</pre>
+ * behaves as if:
+ * <pre> {@code
+ * VarHandle vh = ..
+ * VarHandle.AccessMode am = VarHandle.AccessMode.valueFromMethodName("{access-mode}");
+ * MethodHandle mh = MethodHandles.varHandleExactInvoker(
+ * am,
+ * vh.accessModeType(am));
+ *
+ * R r = (R) mh.invoke(vh, p1, p2, ..., pN)
+ * }</pre>
+ * (modulo access mode methods do not declare throwing of {@code Throwable}).
+ * This is equivalent to:
+ * <pre> {@code
+ * MethodHandle mh = MethodHandles.lookup().findVirtual(
+ * VarHandle.class,
+ * "{access-mode}",
+ * MethodType.methodType(R, p1, p2, ..., pN));
+ *
+ * R r = (R) mh.invokeExact(vh, p1, p2, ..., pN)
+ * }</pre>
+ * where the desired method type is the symbolic type descriptor and a
+ * {@link MethodHandle#invokeExact} is performed, since before invocation of the
+ * target, the handle will apply reference casts as necessary and box, unbox, or
+ * widen primitive values, as if by {@link MethodHandle#asType asType} (see also
+ * {@link MethodHandles#varHandleInvoker}).
+ *
+ * More concisely, such behaviour is equivalent to:
+ * <pre> {@code
+ * VarHandle vh = ..
+ * VarHandle.AccessMode am = VarHandle.AccessMode.valueFromMethodName("{access-mode}");
+ * MethodHandle mh = vh.toMethodHandle(am);
+ *
+ * R r = (R) mh.invoke(p1, p2, ..., pN)
+ * }</pre>
+ * Where, in this case, the method handle is bound to the VarHandle instance.
+ *
+ *
+ * <h1>Invocation checking</h1>
+ * In typical programs, VarHandle access mode type matching will usually
+ * succeed. But if a match fails, the JVM will throw a
+ * {@link WrongMethodTypeException}.
+ * <p>
+ * Thus, an access mode type mismatch which might show up as a linkage error
+ * in a statically typed program can show up as a dynamic
+ * {@code WrongMethodTypeException} in a program which uses VarHandles.
+ * <p>
+ * Because access mode types contain "live" {@code Class} objects, method type
+ * matching takes into account both type names and class loaders.
+ * Thus, even if a VarHandle {@code VH} is created in one class loader
+ * {@code L1} and used in another {@code L2}, VarHandle access mode method
+ * calls are type-safe, because the caller's symbolic type descriptor, as
+ * resolved in {@code L2}, is matched against the original callee method's
+ * symbolic type descriptor, as resolved in {@code L1}. The resolution in
+ * {@code L1} happens when {@code VH} is created and its access mode types are
+ * assigned, while the resolution in {@code L2} happens when the
+ * {@code invokevirtual} instruction is linked.
+ * <p>
+ * Apart from type descriptor checks, a VarHandles's capability to
+ * access it's variables is unrestricted.
+ * If a VarHandle is formed on a non-public variable by a class that has access
+ * to that variable, the resulting VarHandle can be used in any place by any
+ * caller who receives a reference to it.
+ * <p>
+ * Unlike with the Core Reflection API, where access is checked every time a
+ * reflective method is invoked, VarHandle access checking is performed
+ * <a href="MethodHandles.Lookup.html#access">when the VarHandle is
+ * created</a>.
+ * Thus, VarHandles to non-public variables, or to variables in non-public
+ * classes, should generally be kept secret. They should not be passed to
+ * untrusted code unless their use from the untrusted code would be harmless.
+ *
+ *
+ * <h1>VarHandle creation</h1>
+ * Java code can create a VarHandle that directly accesses any field that is
+ * accessible to that code. This is done via a reflective, capability-based
+ * API called {@link java.lang.invoke.MethodHandles.Lookup
+ * MethodHandles.Lookup}.
+ * For example, a VarHandle for a non-static field can be obtained
+ * from {@link java.lang.invoke.MethodHandles.Lookup#findVarHandle
+ * Lookup.findVarHandle}.
+ * There is also a conversion method from Core Reflection API objects,
+ * {@link java.lang.invoke.MethodHandles.Lookup#unreflectVarHandle
+ * Lookup.unreflectVarHandle}.
+ * <p>
+ * Access to protected field members is restricted to receivers only of the
+ * accessing class, or one of its subclasses, and the accessing class must in
+ * turn be a subclass (or package sibling) of the protected member's defining
+ * class. If a VarHandle refers to a protected non-static field of a declaring
+ * class outside the current package, the receiver argument will be narrowed to
+ * the type of the accessing class.
+ *
+ * <h1>Interoperation between VarHandles and the Core Reflection API</h1>
+ * Using factory methods in the {@link java.lang.invoke.MethodHandles.Lookup
+ * Lookup} API, any field represented by a Core Reflection API object
+ * can be converted to a behaviorally equivalent VarHandle.
+ * For example, a reflective {@link java.lang.reflect.Field Field} can
+ * be converted to a VarHandle using
+ * {@link java.lang.invoke.MethodHandles.Lookup#unreflectVarHandle
+ * Lookup.unreflectVarHandle}.
+ * The resulting VarHandles generally provide more direct and efficient
+ * access to the underlying fields.
+ * <p>
+ * As a special case, when the Core Reflection API is used to view the
+ * signature polymorphic access mode methods in this class, they appear as
+ * ordinary non-polymorphic methods. Their reflective appearance, as viewed by
+ * {@link java.lang.Class#getDeclaredMethod Class.getDeclaredMethod},
+ * is unaffected by their special status in this API.
+ * For example, {@link java.lang.reflect.Method#getModifiers
+ * Method.getModifiers}
+ * will report exactly those modifier bits required for any similarly
+ * declared method, including in this case {@code native} and {@code varargs}
+ * bits.
+ * <p>
+ * As with any reflected method, these methods (when reflected) may be invoked
+ * directly via {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke},
+ * via JNI, or indirectly via
+ * {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect}.
+ * However, such reflective calls do not result in access mode method
+ * invocations. Such a call, if passed the required argument (a single one, of
+ * type {@code Object[]}), will ignore the argument and will throw an
+ * {@code UnsupportedOperationException}.
+ * <p>
+ * Since {@code invokevirtual} instructions can natively invoke VarHandle
+ * access mode methods under any symbolic type descriptor, this reflective view
+ * conflicts with the normal presentation of these methods via bytecodes.
+ * Thus, these native methods, when reflectively viewed by
+ * {@code Class.getDeclaredMethod}, may be regarded as placeholders only.
+ * <p>
+ * In order to obtain an invoker method for a particular access mode type,
+ * use {@link java.lang.invoke.MethodHandles#varHandleExactInvoker} or
+ * {@link java.lang.invoke.MethodHandles#varHandleInvoker}. The
+ * {@link java.lang.invoke.MethodHandles.Lookup#findVirtual Lookup.findVirtual}
+ * API is also able to return a method handle to call an access mode method for
+ * any specified access mode type and is equivalent in behaviour to
+ * {@link java.lang.invoke.MethodHandles#varHandleInvoker}.
+ *
+ * <h1>Interoperation between VarHandles and Java generics</h1>
+ * A VarHandle can be obtained for a variable, such as a field, which is
+ * declared with Java generic types. As with the Core Reflection API, the
+ * VarHandle's variable type will be constructed from the erasure of the
+ * source-level type. When a VarHandle access mode method is invoked, the
+ * types
+ * of its arguments or the return value cast type may be generic types or type
+ * instances. If this occurs, the compiler will replace those types by their
+ * erasures when it constructs the symbolic type descriptor for the
+ * {@code invokevirtual} instruction.
+ *
+ * @see MethodHandle
+ * @see MethodHandles
+ * @see MethodType
+ * @since 9
+ */
+public abstract class VarHandle {
+ // Android-added: Using sun.misc.Unsafe for fence implementation.
+ private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
+
+ // BEGIN Android-removed: No VarForm in Android implementation.
+ /*
+ final VarForm vform;
+
+ VarHandle(VarForm vform) {
+ this.vform = vform;
+ }
+ */
+ // END Android-removed: No VarForm in Android implementation.
+
+ // BEGIN Android-added: fields for common metadata.
+ /** The target type for accesses. */
+ private final Class<?> varType;
+
+ /** This VarHandle's first coordinate, or null if this VarHandle has no coordinates. */
+ private final Class<?> coordinateType0;
+
+ /** This VarHandle's second coordinate, or null if this VarHandle has less than two
+ * coordinates. */
+ private final Class<?> coordinateType1;
+
+ /** BitMask of supported access mode indexed by AccessMode.ordinal(). */
+ private final int accessModesBitMask;
+ // END Android-added: fields for common metadata.
+
+ // Plain accessors
+
+ /**
+ * Returns the value of a variable, with memory semantics of reading as
+ * if the variable was declared non-{@code volatile}. Commonly referred to
+ * as plain read access.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn)T}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code get}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.GET)} on this VarHandle.
+ *
+ * <p>This access mode is supported by all VarHandle instances and never
+ * throws {@code UnsupportedOperationException}.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn)}
+ * , statically represented using varargs.
+ * @return the signature-polymorphic result that is the value of the
+ * variable
+ * , statically represented using {@code Object}.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ Object get(Object... args);
+
+ /**
+ * Sets the value of a variable to the {@code newValue}, with memory
+ * semantics of setting as if the variable was declared non-{@code volatile}
+ * and non-{@code final}. Commonly referred to as plain write access.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T newValue)void}
+ *
+ * <p>The symbolic type descriptor at the call site of {@code set}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.SET)} on this VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T newValue)}
+ * , statically represented using varargs.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ void set(Object... args);
+
+
+ // Volatile accessors
+
+ /**
+ * Returns the value of a variable, with memory semantics of reading as if
+ * the variable was declared {@code volatile}.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn)T}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code getVolatile}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.GET_VOLATILE)} on this
+ * VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn)}
+ * , statically represented using varargs.
+ * @return the signature-polymorphic result that is the value of the
+ * variable
+ * , statically represented using {@code Object}.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ Object getVolatile(Object... args);
+
+ /**
+ * Sets the value of a variable to the {@code newValue}, with memory
+ * semantics of setting as if the variable was declared {@code volatile}.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T newValue)void}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code setVolatile}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.SET_VOLATILE)} on this
+ * VarHandle.
+ *
+ * @apiNote
+ * Ignoring the many semantic differences from C and C++, this method has
+ * memory ordering effects compatible with {@code memory_order_seq_cst}.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T newValue)}
+ * , statically represented using varargs.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ void setVolatile(Object... args);
+
+
+ /**
+ * Returns the value of a variable, accessed in program order, but with no
+ * assurance of memory ordering effects with respect to other threads.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn)T}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code getOpaque}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.GET_OPAQUE)} on this
+ * VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn)}
+ * , statically represented using varargs.
+ * @return the signature-polymorphic result that is the value of the
+ * variable
+ * , statically represented using {@code Object}.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ Object getOpaque(Object... args);
+
+ /**
+ * Sets the value of a variable to the {@code newValue}, in program order,
+ * but with no assurance of memory ordering effects with respect to other
+ * threads.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T newValue)void}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code setOpaque}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.SET_OPAQUE)} on this
+ * VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T newValue)}
+ * , statically represented using varargs.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ void setOpaque(Object... args);
+
+
+ // Lazy accessors
+
+ /**
+ * Returns the value of a variable, and ensures that subsequent loads and
+ * stores are not reordered before this access.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn)T}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code getAcquire}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.GET_ACQUIRE)} on this
+ * VarHandle.
+ *
+ * @apiNote
+ * Ignoring the many semantic differences from C and C++, this method has
+ * memory ordering effects compatible with {@code memory_order_acquire}
+ * ordering.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn)}
+ * , statically represented using varargs.
+ * @return the signature-polymorphic result that is the value of the
+ * variable
+ * , statically represented using {@code Object}.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ Object getAcquire(Object... args);
+
+ /**
+ * Sets the value of a variable to the {@code newValue}, and ensures that
+ * prior loads and stores are not reordered after this access.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T newValue)void}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code setRelease}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.SET_RELEASE)} on this
+ * VarHandle.
+ *
+ * @apiNote
+ * Ignoring the many semantic differences from C and C++, this method has
+ * memory ordering effects compatible with {@code memory_order_release}
+ * ordering.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T newValue)}
+ * , statically represented using varargs.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ void setRelease(Object... args);
+
+
+ // Compare and set accessors
+
+ /**
+ * Atomically sets the value of a variable to the {@code newValue} with the
+ * memory semantics of {@link #setVolatile} if the variable's current value,
+ * referred to as the <em>witness value</em>, {@code ==} the
+ * {@code expectedValue}, as accessed with the memory semantics of
+ * {@link #getVolatile}.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)boolean}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code
+ * compareAndSet} must match the access mode type that is the result of
+ * calling {@code accessModeType(VarHandle.AccessMode.COMPARE_AND_SET)} on
+ * this VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)}
+ * , statically represented using varargs.
+ * @return {@code true} if successful, otherwise {@code false} if the
+ * witness value was not the same as the {@code expectedValue}.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ * @see #setVolatile(Object...)
+ * @see #getVolatile(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ boolean compareAndSet(Object... args);
+
+ /**
+ * Atomically sets the value of a variable to the {@code newValue} with the
+ * memory semantics of {@link #setVolatile} if the variable's current value,
+ * referred to as the <em>witness value</em>, {@code ==} the
+ * {@code expectedValue}, as accessed with the memory semantics of
+ * {@link #getVolatile}.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)T}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code
+ * compareAndExchange}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.COMPARE_AND_EXCHANGE)}
+ * on this VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)}
+ * , statically represented using varargs.
+ * @return the signature-polymorphic result that is the witness value, which
+ * will be the same as the {@code expectedValue} if successful
+ * , statically represented using {@code Object}.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type is not
+ * compatible with the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type is compatible with the
+ * caller's symbolic type descriptor, but a reference cast fails.
+ * @see #setVolatile(Object...)
+ * @see #getVolatile(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ Object compareAndExchange(Object... args);
+
+ /**
+ * Atomically sets the value of a variable to the {@code newValue} with the
+ * memory semantics of {@link #set} if the variable's current value,
+ * referred to as the <em>witness value</em>, {@code ==} the
+ * {@code expectedValue}, as accessed with the memory semantics of
+ * {@link #getAcquire}.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)T}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code
+ * compareAndExchangeAcquire}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)} on
+ * this VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)}
+ * , statically represented using varargs.
+ * @return the signature-polymorphic result that is the witness value, which
+ * will be the same as the {@code expectedValue} if successful
+ * , statically represented using {@code Object}.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ * @see #set(Object...)
+ * @see #getAcquire(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ Object compareAndExchangeAcquire(Object... args);
+
+ /**
+ * Atomically sets the value of a variable to the {@code newValue} with the
+ * memory semantics of {@link #setRelease} if the variable's current value,
+ * referred to as the <em>witness value</em>, {@code ==} the
+ * {@code expectedValue}, as accessed with the memory semantics of
+ * {@link #get}.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)T}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code
+ * compareAndExchangeRelease}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)}
+ * on this VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)}
+ * , statically represented using varargs.
+ * @return the signature-polymorphic result that is the witness value, which
+ * will be the same as the {@code expectedValue} if successful
+ * , statically represented using {@code Object}.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ * @see #setRelease(Object...)
+ * @see #get(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ Object compareAndExchangeRelease(Object... args);
+
+ // Weak (spurious failures allowed)
+
+ /**
+ * Possibly atomically sets the value of a variable to the {@code newValue}
+ * with the semantics of {@link #set} if the variable's current value,
+ * referred to as the <em>witness value</em>, {@code ==} the
+ * {@code expectedValue}, as accessed with the memory semantics of
+ * {@link #get}.
+ *
+ * <p>This operation may fail spuriously (typically, due to memory
+ * contention) even if the witness value does match the expected value.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)boolean}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code
+ * weakCompareAndSetPlain} must match the access mode type that is the result of
+ * calling {@code accessModeType(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN)}
+ * on this VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)}
+ * , statically represented using varargs.
+ * @return {@code true} if successful, otherwise {@code false} if the
+ * witness value was not the same as the {@code expectedValue} or if this
+ * operation spuriously failed.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ * @see #set(Object...)
+ * @see #get(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ boolean weakCompareAndSetPlain(Object... args);
+
+ /**
+ * Possibly atomically sets the value of a variable to the {@code newValue}
+ * with the memory semantics of {@link #setVolatile} if the variable's
+ * current value, referred to as the <em>witness value</em>, {@code ==} the
+ * {@code expectedValue}, as accessed with the memory semantics of
+ * {@link #getVolatile}.
+ *
+ * <p>This operation may fail spuriously (typically, due to memory
+ * contention) even if the witness value does match the expected value.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)boolean}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code
+ * weakCompareAndSet} must match the access mode type that is the
+ * result of calling {@code accessModeType(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)}
+ * on this VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)}
+ * , statically represented using varargs.
+ * @return {@code true} if successful, otherwise {@code false} if the
+ * witness value was not the same as the {@code expectedValue} or if this
+ * operation spuriously failed.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ * @see #setVolatile(Object...)
+ * @see #getVolatile(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ boolean weakCompareAndSet(Object... args);
+
+ /**
+ * Possibly atomically sets the value of a variable to the {@code newValue}
+ * with the semantics of {@link #set} if the variable's current value,
+ * referred to as the <em>witness value</em>, {@code ==} the
+ * {@code expectedValue}, as accessed with the memory semantics of
+ * {@link #getAcquire}.
+ *
+ * <p>This operation may fail spuriously (typically, due to memory
+ * contention) even if the witness value does match the expected value.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)boolean}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code
+ * weakCompareAndSetAcquire}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)}
+ * on this VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)}
+ * , statically represented using varargs.
+ * @return {@code true} if successful, otherwise {@code false} if the
+ * witness value was not the same as the {@code expectedValue} or if this
+ * operation spuriously failed.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ * @see #set(Object...)
+ * @see #getAcquire(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ boolean weakCompareAndSetAcquire(Object... args);
+
+ /**
+ * Possibly atomically sets the value of a variable to the {@code newValue}
+ * with the semantics of {@link #setRelease} if the variable's current
+ * value, referred to as the <em>witness value</em>, {@code ==} the
+ * {@code expectedValue}, as accessed with the memory semantics of
+ * {@link #get}.
+ *
+ * <p>This operation may fail spuriously (typically, due to memory
+ * contention) even if the witness value does match the expected value.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)boolean}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code
+ * weakCompareAndSetRelease}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)}
+ * on this VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)}
+ * , statically represented using varargs.
+ * @return {@code true} if successful, otherwise {@code false} if the
+ * witness value was not the same as the {@code expectedValue} or if this
+ * operation spuriously failed.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ * @see #setRelease(Object...)
+ * @see #get(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ boolean weakCompareAndSetRelease(Object... args);
+
+ /**
+ * Atomically sets the value of a variable to the {@code newValue} with the
+ * memory semantics of {@link #setVolatile} and returns the variable's
+ * previous value, as accessed with the memory semantics of
+ * {@link #getVolatile}.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T newValue)T}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code getAndSet}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.GET_AND_SET)} on this
+ * VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T newValue)}
+ * , statically represented using varargs.
+ * @return the signature-polymorphic result that is the previous value of
+ * the variable
+ * , statically represented using {@code Object}.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ * @see #setVolatile(Object...)
+ * @see #getVolatile(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ Object getAndSet(Object... args);
+
+ /**
+ * Atomically sets the value of a variable to the {@code newValue} with the
+ * memory semantics of {@link #set} and returns the variable's
+ * previous value, as accessed with the memory semantics of
+ * {@link #getAcquire}.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T newValue)T}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code getAndSetAcquire}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.GET_AND_SET_ACQUIRE)} on this
+ * VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T newValue)}
+ * , statically represented using varargs.
+ * @return the signature-polymorphic result that is the previous value of
+ * the variable
+ * , statically represented using {@code Object}.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ * @see #setVolatile(Object...)
+ * @see #getVolatile(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ Object getAndSetAcquire(Object... args);
+
+ /**
+ * Atomically sets the value of a variable to the {@code newValue} with the
+ * memory semantics of {@link #setRelease} and returns the variable's
+ * previous value, as accessed with the memory semantics of
+ * {@link #get}.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T newValue)T}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code getAndSetRelease}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.GET_AND_SET_RELEASE)} on this
+ * VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T newValue)}
+ * , statically represented using varargs.
+ * @return the signature-polymorphic result that is the previous value of
+ * the variable
+ * , statically represented using {@code Object}.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ * @see #setVolatile(Object...)
+ * @see #getVolatile(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ Object getAndSetRelease(Object... args);
+
+ // Primitive adders
+ // Throw UnsupportedOperationException for refs
+
+ /**
+ * Atomically adds the {@code value} to the current value of a variable with
+ * the memory semantics of {@link #setVolatile}, and returns the variable's
+ * previous value, as accessed with the memory semantics of
+ * {@link #getVolatile}.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T value)T}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code getAndAdd}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.GET_AND_ADD)} on this
+ * VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T value)}
+ * , statically represented using varargs.
+ * @return the signature-polymorphic result that is the previous value of
+ * the variable
+ * , statically represented using {@code Object}.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ * @see #setVolatile(Object...)
+ * @see #getVolatile(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ Object getAndAdd(Object... args);
+
+ /**
+ * Atomically adds the {@code value} to the current value of a variable with
+ * the memory semantics of {@link #set}, and returns the variable's
+ * previous value, as accessed with the memory semantics of
+ * {@link #getAcquire}.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T value)T}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code getAndAddAcquire}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.GET_AND_ADD_ACQUIRE)} on this
+ * VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T value)}
+ * , statically represented using varargs.
+ * @return the signature-polymorphic result that is the previous value of
+ * the variable
+ * , statically represented using {@code Object}.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ * @see #setVolatile(Object...)
+ * @see #getVolatile(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ Object getAndAddAcquire(Object... args);
+
+ /**
+ * Atomically adds the {@code value} to the current value of a variable with
+ * the memory semantics of {@link #setRelease}, and returns the variable's
+ * previous value, as accessed with the memory semantics of
+ * {@link #get}.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T value)T}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code getAndAddRelease}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.GET_AND_ADD_RELEASE)} on this
+ * VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T value)}
+ * , statically represented using varargs.
+ * @return the signature-polymorphic result that is the previous value of
+ * the variable
+ * , statically represented using {@code Object}.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ * @see #setVolatile(Object...)
+ * @see #getVolatile(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ Object getAndAddRelease(Object... args);
+
+
+ // Bitwise operations
+ // Throw UnsupportedOperationException for refs
+
+ /**
+ * Atomically sets the value of a variable to the result of
+ * bitwise OR between the variable's current value and the {@code mask}
+ * with the memory semantics of {@link #setVolatile} and returns the
+ * variable's previous value, as accessed with the memory semantics of
+ * {@link #getVolatile}.
+ *
+ * <p>If the variable type is the non-integral {@code boolean} type then a
+ * logical OR is performed instead of a bitwise OR.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T mask)T}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code getAndBitwiseOr}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.GET_AND_BITWISE_OR)} on this
+ * VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T mask)}
+ * , statically represented using varargs.
+ * @return the signature-polymorphic result that is the previous value of
+ * the variable
+ * , statically represented using {@code Object}.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ * @see #setVolatile(Object...)
+ * @see #getVolatile(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ Object getAndBitwiseOr(Object... args);
+
+ /**
+ * Atomically sets the value of a variable to the result of
+ * bitwise OR between the variable's current value and the {@code mask}
+ * with the memory semantics of {@link #set} and returns the
+ * variable's previous value, as accessed with the memory semantics of
+ * {@link #getAcquire}.
+ *
+ * <p>If the variable type is the non-integral {@code boolean} type then a
+ * logical OR is performed instead of a bitwise OR.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T mask)T}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code getAndBitwiseOrAcquire}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE)} on this
+ * VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T mask)}
+ * , statically represented using varargs.
+ * @return the signature-polymorphic result that is the previous value of
+ * the variable
+ * , statically represented using {@code Object}.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ * @see #set(Object...)
+ * @see #getAcquire(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ Object getAndBitwiseOrAcquire(Object... args);
+
+ /**
+ * Atomically sets the value of a variable to the result of
+ * bitwise OR between the variable's current value and the {@code mask}
+ * with the memory semantics of {@link #setRelease} and returns the
+ * variable's previous value, as accessed with the memory semantics of
+ * {@link #get}.
+ *
+ * <p>If the variable type is the non-integral {@code boolean} type then a
+ * logical OR is performed instead of a bitwise OR.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T mask)T}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code getAndBitwiseOrRelease}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE)} on this
+ * VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T mask)}
+ * , statically represented using varargs.
+ * @return the signature-polymorphic result that is the previous value of
+ * the variable
+ * , statically represented using {@code Object}.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ * @see #setRelease(Object...)
+ * @see #get(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ Object getAndBitwiseOrRelease(Object... args);
+
+ /**
+ * Atomically sets the value of a variable to the result of
+ * bitwise AND between the variable's current value and the {@code mask}
+ * with the memory semantics of {@link #setVolatile} and returns the
+ * variable's previous value, as accessed with the memory semantics of
+ * {@link #getVolatile}.
+ *
+ * <p>If the variable type is the non-integral {@code boolean} type then a
+ * logical AND is performed instead of a bitwise AND.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T mask)T}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code getAndBitwiseAnd}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.GET_AND_BITWISE_AND)} on this
+ * VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T mask)}
+ * , statically represented using varargs.
+ * @return the signature-polymorphic result that is the previous value of
+ * the variable
+ * , statically represented using {@code Object}.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ * @see #setVolatile(Object...)
+ * @see #getVolatile(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ Object getAndBitwiseAnd(Object... args);
+
+ /**
+ * Atomically sets the value of a variable to the result of
+ * bitwise AND between the variable's current value and the {@code mask}
+ * with the memory semantics of {@link #set} and returns the
+ * variable's previous value, as accessed with the memory semantics of
+ * {@link #getAcquire}.
+ *
+ * <p>If the variable type is the non-integral {@code boolean} type then a
+ * logical AND is performed instead of a bitwise AND.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T mask)T}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code getAndBitwiseAndAcquire}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE)} on this
+ * VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T mask)}
+ * , statically represented using varargs.
+ * @return the signature-polymorphic result that is the previous value of
+ * the variable
+ * , statically represented using {@code Object}.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ * @see #set(Object...)
+ * @see #getAcquire(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ Object getAndBitwiseAndAcquire(Object... args);
+
+ /**
+ * Atomically sets the value of a variable to the result of
+ * bitwise AND between the variable's current value and the {@code mask}
+ * with the memory semantics of {@link #setRelease} and returns the
+ * variable's previous value, as accessed with the memory semantics of
+ * {@link #get}.
+ *
+ * <p>If the variable type is the non-integral {@code boolean} type then a
+ * logical AND is performed instead of a bitwise AND.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T mask)T}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code getAndBitwiseAndRelease}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE)} on this
+ * VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T mask)}
+ * , statically represented using varargs.
+ * @return the signature-polymorphic result that is the previous value of
+ * the variable
+ * , statically represented using {@code Object}.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ * @see #setRelease(Object...)
+ * @see #get(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ Object getAndBitwiseAndRelease(Object... args);
+
+ /**
+ * Atomically sets the value of a variable to the result of
+ * bitwise XOR between the variable's current value and the {@code mask}
+ * with the memory semantics of {@link #setVolatile} and returns the
+ * variable's previous value, as accessed with the memory semantics of
+ * {@link #getVolatile}.
+ *
+ * <p>If the variable type is the non-integral {@code boolean} type then a
+ * logical XOR is performed instead of a bitwise XOR.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T mask)T}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code getAndBitwiseXor}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.GET_AND_BITWISE_XOR)} on this
+ * VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T mask)}
+ * , statically represented using varargs.
+ * @return the signature-polymorphic result that is the previous value of
+ * the variable
+ * , statically represented using {@code Object}.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ * @see #setVolatile(Object...)
+ * @see #getVolatile(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ Object getAndBitwiseXor(Object... args);
+
+ /**
+ * Atomically sets the value of a variable to the result of
+ * bitwise XOR between the variable's current value and the {@code mask}
+ * with the memory semantics of {@link #set} and returns the
+ * variable's previous value, as accessed with the memory semantics of
+ * {@link #getAcquire}.
+ *
+ * <p>If the variable type is the non-integral {@code boolean} type then a
+ * logical XOR is performed instead of a bitwise XOR.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T mask)T}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code getAndBitwiseXorAcquire}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE)} on this
+ * VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T mask)}
+ * , statically represented using varargs.
+ * @return the signature-polymorphic result that is the previous value of
+ * the variable
+ * , statically represented using {@code Object}.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ * @see #set(Object...)
+ * @see #getAcquire(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ Object getAndBitwiseXorAcquire(Object... args);
+
+ /**
+ * Atomically sets the value of a variable to the result of
+ * bitwise XOR between the variable's current value and the {@code mask}
+ * with the memory semantics of {@link #setRelease} and returns the
+ * variable's previous value, as accessed with the memory semantics of
+ * {@link #get}.
+ *
+ * <p>If the variable type is the non-integral {@code boolean} type then a
+ * logical XOR is performed instead of a bitwise XOR.
+ *
+ * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T mask)T}.
+ *
+ * <p>The symbolic type descriptor at the call site of {@code getAndBitwiseXorRelease}
+ * must match the access mode type that is the result of calling
+ * {@code accessModeType(VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE)} on this
+ * VarHandle.
+ *
+ * @param args the signature-polymorphic parameter list of the form
+ * {@code (CT1 ct1, ..., CTn ctn, T mask)}
+ * , statically represented using varargs.
+ * @return the signature-polymorphic result that is the previous value of
+ * the variable
+ * , statically represented using {@code Object}.
+ * @throws UnsupportedOperationException if the access mode is unsupported
+ * for this VarHandle.
+ * @throws WrongMethodTypeException if the access mode type does not
+ * match the caller's symbolic type descriptor.
+ * @throws ClassCastException if the access mode type matches the caller's
+ * symbolic type descriptor, but a reference cast fails.
+ * @see #setRelease(Object...)
+ * @see #get(Object...)
+ */
+ public final native
+ @MethodHandle.PolymorphicSignature
+ @IntrinsicCandidate
+ Object getAndBitwiseXorRelease(Object... args);
+
+
+ // Android-changed: remove unused return type in AccessType constructor.
+ enum AccessType {
+ GET,
+ SET,
+ COMPARE_AND_SET,
+ COMPARE_AND_EXCHANGE,
+ GET_AND_UPDATE,
+ // Android-added: Finer grained access types.
+ // These are used to help categorize the access modes that a VarHandle supports.
+ GET_AND_UPDATE_BITWISE,
+ GET_AND_UPDATE_NUMERIC;
+
+ MethodType accessModeType(Class<?> receiver, Class<?> value,
+ Class<?>... intermediate) {
+ Class<?>[] ps;
+ int i;
+ switch (this) {
+ case GET:
+ ps = allocateParameters(0, receiver, intermediate);
+ fillParameters(ps, receiver, intermediate);
+ return MethodType.methodType(value, ps);
+ case SET:
+ ps = allocateParameters(1, receiver, intermediate);
+ i = fillParameters(ps, receiver, intermediate);
+ ps[i] = value;
+ return MethodType.methodType(void.class, ps);
+ case COMPARE_AND_SET:
+ ps = allocateParameters(2, receiver, intermediate);
+ i = fillParameters(ps, receiver, intermediate);
+ ps[i++] = value;
+ ps[i] = value;
+ return MethodType.methodType(boolean.class, ps);
+ case COMPARE_AND_EXCHANGE:
+ ps = allocateParameters(2, receiver, intermediate);
+ i = fillParameters(ps, receiver, intermediate);
+ ps[i++] = value;
+ ps[i] = value;
+ return MethodType.methodType(value, ps);
+ case GET_AND_UPDATE:
+ case GET_AND_UPDATE_BITWISE:
+ case GET_AND_UPDATE_NUMERIC:
+ ps = allocateParameters(1, receiver, intermediate);
+ i = fillParameters(ps, receiver, intermediate);
+ ps[i] = value;
+ return MethodType.methodType(value, ps);
+ default:
+ throw new InternalError("Unknown AccessType");
+ }
+ }
+
+ private static Class<?>[] allocateParameters(int values,
+ Class<?> receiver, Class<?>... intermediate) {
+ int size = ((receiver != null) ? 1 : 0) + intermediate.length + values;
+ return new Class<?>[size];
+ }
+
+ private static int fillParameters(Class<?>[] ps,
+ Class<?> receiver, Class<?>... intermediate) {
+ int i = 0;
+ if (receiver != null)
+ ps[i++] = receiver;
+ for (int j = 0; j < intermediate.length; j++)
+ ps[i++] = intermediate[j];
+ return i;
+ }
+ }
+
+ /**
+ * The set of access modes that specify how a variable, referenced by a
+ * VarHandle, is accessed.
+ */
+ public enum AccessMode {
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#get VarHandle.get}
+ */
+ GET("get", AccessType.GET),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#set VarHandle.set}
+ */
+ SET("set", AccessType.SET),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#getVolatile VarHandle.getVolatile}
+ */
+ GET_VOLATILE("getVolatile", AccessType.GET),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#setVolatile VarHandle.setVolatile}
+ */
+ SET_VOLATILE("setVolatile", AccessType.SET),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#getAcquire VarHandle.getAcquire}
+ */
+ GET_ACQUIRE("getAcquire", AccessType.GET),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#setRelease VarHandle.setRelease}
+ */
+ SET_RELEASE("setRelease", AccessType.SET),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#getOpaque VarHandle.getOpaque}
+ */
+ GET_OPAQUE("getOpaque", AccessType.GET),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#setOpaque VarHandle.setOpaque}
+ */
+ SET_OPAQUE("setOpaque", AccessType.SET),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#compareAndSet VarHandle.compareAndSet}
+ */
+ COMPARE_AND_SET("compareAndSet", AccessType.COMPARE_AND_SET),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#compareAndExchange VarHandle.compareAndExchange}
+ */
+ COMPARE_AND_EXCHANGE("compareAndExchange", AccessType.COMPARE_AND_EXCHANGE),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#compareAndExchangeAcquire VarHandle.compareAndExchangeAcquire}
+ */
+ COMPARE_AND_EXCHANGE_ACQUIRE("compareAndExchangeAcquire", AccessType.COMPARE_AND_EXCHANGE),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#compareAndExchangeRelease VarHandle.compareAndExchangeRelease}
+ */
+ COMPARE_AND_EXCHANGE_RELEASE("compareAndExchangeRelease", AccessType.COMPARE_AND_EXCHANGE),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#weakCompareAndSetPlain VarHandle.weakCompareAndSetPlain}
+ */
+ WEAK_COMPARE_AND_SET_PLAIN("weakCompareAndSetPlain", AccessType.COMPARE_AND_SET),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#weakCompareAndSet VarHandle.weakCompareAndSet}
+ */
+ WEAK_COMPARE_AND_SET("weakCompareAndSet", AccessType.COMPARE_AND_SET),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#weakCompareAndSetAcquire VarHandle.weakCompareAndSetAcquire}
+ */
+ WEAK_COMPARE_AND_SET_ACQUIRE("weakCompareAndSetAcquire", AccessType.COMPARE_AND_SET),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#weakCompareAndSetRelease VarHandle.weakCompareAndSetRelease}
+ */
+ WEAK_COMPARE_AND_SET_RELEASE("weakCompareAndSetRelease", AccessType.COMPARE_AND_SET),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#getAndSet VarHandle.getAndSet}
+ */
+ GET_AND_SET("getAndSet", AccessType.GET_AND_UPDATE),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#getAndSetAcquire VarHandle.getAndSetAcquire}
+ */
+ GET_AND_SET_ACQUIRE("getAndSetAcquire", AccessType.GET_AND_UPDATE),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#getAndSetRelease VarHandle.getAndSetRelease}
+ */
+ GET_AND_SET_RELEASE("getAndSetRelease", AccessType.GET_AND_UPDATE),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#getAndAdd VarHandle.getAndAdd}
+ */
+ GET_AND_ADD("getAndAdd", AccessType.GET_AND_UPDATE_NUMERIC),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#getAndAddAcquire VarHandle.getAndAddAcquire}
+ */
+ GET_AND_ADD_ACQUIRE("getAndAddAcquire", AccessType.GET_AND_UPDATE_NUMERIC),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#getAndAddRelease VarHandle.getAndAddRelease}
+ */
+ GET_AND_ADD_RELEASE("getAndAddRelease", AccessType.GET_AND_UPDATE_NUMERIC),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#getAndBitwiseOr VarHandle.getAndBitwiseOr}
+ */
+ GET_AND_BITWISE_OR("getAndBitwiseOr", AccessType.GET_AND_UPDATE_BITWISE),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#getAndBitwiseOrRelease VarHandle.getAndBitwiseOrRelease}
+ */
+ GET_AND_BITWISE_OR_RELEASE("getAndBitwiseOrRelease", AccessType.GET_AND_UPDATE_BITWISE),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#getAndBitwiseOrAcquire VarHandle.getAndBitwiseOrAcquire}
+ */
+ GET_AND_BITWISE_OR_ACQUIRE("getAndBitwiseOrAcquire", AccessType.GET_AND_UPDATE_BITWISE),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#getAndBitwiseAnd VarHandle.getAndBitwiseAnd}
+ */
+ GET_AND_BITWISE_AND("getAndBitwiseAnd", AccessType.GET_AND_UPDATE_BITWISE),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#getAndBitwiseAndRelease VarHandle.getAndBitwiseAndRelease}
+ */
+ GET_AND_BITWISE_AND_RELEASE("getAndBitwiseAndRelease", AccessType.GET_AND_UPDATE_BITWISE),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#getAndBitwiseAndAcquire VarHandle.getAndBitwiseAndAcquire}
+ */
+ GET_AND_BITWISE_AND_ACQUIRE("getAndBitwiseAndAcquire", AccessType.GET_AND_UPDATE_BITWISE),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#getAndBitwiseXor VarHandle.getAndBitwiseXor}
+ */
+ GET_AND_BITWISE_XOR("getAndBitwiseXor", AccessType.GET_AND_UPDATE_BITWISE),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#getAndBitwiseXorRelease VarHandle.getAndBitwiseXorRelease}
+ */
+ GET_AND_BITWISE_XOR_RELEASE("getAndBitwiseXorRelease", AccessType.GET_AND_UPDATE_BITWISE),
+ /**
+ * The access mode whose access is specified by the corresponding
+ * method
+ * {@link VarHandle#getAndBitwiseXorAcquire VarHandle.getAndBitwiseXorAcquire}
+ */
+ GET_AND_BITWISE_XOR_ACQUIRE("getAndBitwiseXorAcquire", AccessType.GET_AND_UPDATE_BITWISE),
+ ;
+
+ static final Map<String, AccessMode> methodNameToAccessMode;
+ static {
+ AccessMode[] values = AccessMode.values();
+ // Initial capacity of # values divided by the load factor is sufficient
+ // to avoid resizes for the smallest table size (64)
+ int initialCapacity = (int)(values.length / 0.75f) + 1;
+ methodNameToAccessMode = new HashMap<>(initialCapacity);
+ for (AccessMode am : values) {
+ methodNameToAccessMode.put(am.methodName, am);
+ }
+ }
+
+ final String methodName;
+ final AccessType at;
+
+ AccessMode(final String methodName, AccessType at) {
+ this.methodName = methodName;
+ this.at = at;
+ }
+
+ /**
+ * Returns the {@code VarHandle} signature-polymorphic method name
+ * associated with this {@code AccessMode} value.
+ *
+ * @return the signature-polymorphic method name
+ * @see #valueFromMethodName
+ */
+ public String methodName() {
+ return methodName;
+ }
+
+ /**
+ * Returns the {@code AccessMode} value associated with the specified
+ * {@code VarHandle} signature-polymorphic method name.
+ *
+ * @param methodName the signature-polymorphic method name
+ * @return the {@code AccessMode} value
+ * @throws IllegalArgumentException if there is no {@code AccessMode}
+ * value associated with method name (indicating the method
+ * name does not correspond to a {@code VarHandle}
+ * signature-polymorphic method name).
+ * @see #methodName()
+ */
+ public static AccessMode valueFromMethodName(String methodName) {
+ AccessMode am = methodNameToAccessMode.get(methodName);
+ if (am != null) return am;
+ throw new IllegalArgumentException("No AccessMode value for method name " + methodName);
+ }
+
+ // BEGIN Android-removed: MemberName and VarForm are not used in the Android implementation.
+ /*
+ @ForceInline
+ static MemberName getMemberName(int ordinal, VarForm vform) {
+ return vform.memberName_table[ordinal];
+ }
+ */
+ // END Android-removed: MemberName and VarForm are not used in the Android implementation.
+ }
+
+ // BEGIN Android-removed: AccessDescriptor not used in Android implementation.
+ /*
+ static final class AccessDescriptor {
+ final MethodType symbolicMethodTypeErased;
+ final MethodType symbolicMethodTypeInvoker;
+ final Class<?> returnType;
+ final int type;
+ final int mode;
+
+ public AccessDescriptor(MethodType symbolicMethodType, int type, int mode) {
+ this.symbolicMethodTypeErased = symbolicMethodType.erase();
+ this.symbolicMethodTypeInvoker = symbolicMethodType.insertParameterTypes(0, VarHandle.class);
+ this.returnType = symbolicMethodType.returnType();
+ this.type = type;
+ this.mode = mode;
+ }
+ }
+ */
+ // END Android-removed: AccessDescriptor not used in Android implementation.
+
+ /**
+ * Returns a compact textual description of this {@linkplain VarHandle},
+ * including the type of variable described, and a description of its coordinates.
+ *
+ * @return A compact textual description of this {@linkplain VarHandle}
+ */
+ @Override
+ public final String toString() {
+ return String.format("VarHandle[varType=%s, coord=%s]",
+ varType().getName(),
+ coordinateTypes());
+ }
+
+ /**
+ * Returns the variable type of variables referenced by this VarHandle.
+ *
+ * @return the variable type of variables referenced by this VarHandle
+ */
+ public final Class<?> varType() {
+ // Android-removed: existing implementation.
+ // MethodType typeSet = accessModeType(AccessMode.SET);
+ // return typeSet.parameterType(typeSet.parameterCount() - 1)
+ // Android-added: return instance field.
+ return varType;
+ }
+
+ /**
+ * Returns the coordinate types for this VarHandle.
+ *
+ * @return the coordinate types for this VarHandle. The returned
+ * list is unmodifiable
+ */
+ public final List<Class<?>> coordinateTypes() {
+ // Android-removed: existing implementation.
+ // MethodType typeGet = accessModeType(AccessMode.GET);
+ // return typeGet.parameterList();
+ // Android-added: Android specific implementation.
+ if (coordinateType0 == null) {
+ return Collections.EMPTY_LIST;
+ } else if (coordinateType1 == null) {
+ return Collections.singletonList(coordinateType0);
+ } else {
+ return Collections.unmodifiableList(Arrays.asList(coordinateType0, coordinateType1));
+ }
+ }
+
+ /**
+ * Obtains the access mode type for this VarHandle and a given access mode.
+ *
+ * <p>The access mode type's parameter types will consist of a prefix that
+ * is the coordinate types of this VarHandle followed by further
+ * types as defined by the access mode method.
+ * The access mode type's return type is defined by the return type of the
+ * access mode method.
+ *
+ * @param accessMode the access mode, corresponding to the
+ * signature-polymorphic method of the same name
+ * @return the access mode type for the given access mode
+ */
+ public final MethodType accessModeType(AccessMode accessMode) {
+ // BEGIN Android-removed: Relies on internal class that is not part of the
+ // Android implementation.
+ /*
+ TypesAndInvokers tis = getTypesAndInvokers();
+ MethodType mt = tis.methodType_table[accessMode.at.ordinal()];
+ if (mt == null) {
+ mt = tis.methodType_table[accessMode.at.ordinal()] =
+ accessModeTypeUncached(accessMode);
+ }
+ return mt;
+ */
+ // END Android-removed: Relies on internal class that is not part of the
+ // Android implementation.
+ // Android-added: alternative implementation.
+ if (coordinateType1 == null) {
+ // accessModeType() treats the first argument as the
+ // receiver and adapts accordingly if it is null.
+ return accessMode.at.accessModeType(coordinateType0, varType);
+ } else {
+ return accessMode.at.accessModeType(coordinateType0, varType, coordinateType1);
+ }
+ }
+
+ // Android-removed: Not part of the Android implementation.
+ // abstract MethodType accessModeTypeUncached(AccessMode accessMode);
+
+ /**
+ * Returns {@code true} if the given access mode is supported, otherwise
+ * {@code false}.
+ *
+ * <p>The return of a {@code false} value for a given access mode indicates
+ * that an {@code UnsupportedOperationException} is thrown on invocation
+ * of the corresponding access mode method.
+ *
+ * @param accessMode the access mode, corresponding to the
+ * signature-polymorphic method of the same name
+ * @return {@code true} if the given access mode is supported, otherwise
+ * {@code false}.
+ */
+ public final boolean isAccessModeSupported(AccessMode accessMode) {
+ // Android-removed: Refers to unused field vform.
+ // return AccessMode.getMemberName(accessMode.ordinal(), vform) != null;
+ // Android-added: use accessModesBitsMask field.
+ final int testBit = 1 << accessMode.ordinal();
+ return (accessModesBitMask & testBit) == testBit;
+ }
+
+ /**
+ * Obtains a method handle bound to this VarHandle and the given access
+ * mode.
+ *
+ * @apiNote This method, for a VarHandle {@code vh} and access mode
+ * {@code {access-mode}}, returns a method handle that is equivalent to
+ * method handle {@code bmh} in the following code (though it may be more
+ * efficient):
+ * <pre>{@code
+ * MethodHandle mh = MethodHandles.varHandleExactInvoker(
+ * vh.accessModeType(VarHandle.AccessMode.{access-mode}));
+ *
+ * MethodHandle bmh = mh.bindTo(vh);
+ * }</pre>
+ *
+ * @param accessMode the access mode, corresponding to the
+ * signature-polymorphic method of the same name
+ * @return a method handle bound to this VarHandle and the given access mode
+ */
+ public final MethodHandle toMethodHandle(AccessMode accessMode) {
+ // BEGIN Android-removed: no vform field in Android implementation.
+ /*
+ MemberName mn = AccessMode.getMemberName(accessMode.ordinal(), vform);
+ if (mn != null) {
+ MethodHandle mh = getMethodHandle(accessMode.ordinal());
+ return mh.bindTo(this);
+ }
+ else {
+ // Ensure an UnsupportedOperationException is thrown
+ return MethodHandles.varHandleInvoker(accessMode, accessModeType(accessMode)).
+ bindTo(this);
+ }
+ */
+ // END Android-removed: no vform field in Android implementation.
+
+ // Android-added: basic implementation following description in javadoc for this method.
+ MethodType type = accessModeType(accessMode);
+ return MethodHandles.varHandleExactInvoker(accessMode, type).bindTo(this);
+ }
+
+ // BEGIN Android-removed: Not used in Android implementation.
+ /*
+ @Stable
+ TypesAndInvokers typesAndInvokers;
+
+ static class TypesAndInvokers {
+ final @Stable
+ MethodType[] methodType_table =
+ new MethodType[VarHandle.AccessType.values().length];
+
+ final @Stable
+ MethodHandle[] methodHandle_table =
+ new MethodHandle[AccessMode.values().length];
+ }
+
+ @ForceInline
+ private final TypesAndInvokers getTypesAndInvokers() {
+ TypesAndInvokers tis = typesAndInvokers;
+ if (tis == null) {
+ tis = typesAndInvokers = new TypesAndInvokers();
+ }
+ return tis;
+ }
+
+ @ForceInline
+ final MethodHandle getMethodHandle(int mode) {
+ TypesAndInvokers tis = getTypesAndInvokers();
+ MethodHandle mh = tis.methodHandle_table[mode];
+ if (mh == null) {
+ mh = tis.methodHandle_table[mode] = getMethodHandleUncached(mode);
+ }
+ return mh;
+ }
+ private final MethodHandle getMethodHandleUncached(int mode) {
+ MethodType mt = accessModeType(AccessMode.values()[mode]).
+ insertParameterTypes(0, VarHandle.class);
+ MemberName mn = vform.getMemberName(mode);
+ DirectMethodHandle dmh = DirectMethodHandle.make(mn);
+ // Such a method handle must not be publically exposed directly
+ // otherwise it can be cracked, it must be transformed or rebound
+ // before exposure
+ MethodHandle mh = dmh.copyWith(mt, dmh.form);
+ assert mh.type().erase() == mn.getMethodType().erase();
+ return mh;
+ }
+ */
+ // END Android-removed: Not used in Android implementation.
+
+ // BEGIN Android-removed: No VarForm in Android implementation.
+ /*non-public*/
+ /*
+ final void updateVarForm(VarForm newVForm) {
+ if (vform == newVForm) return;
+ UNSAFE.putObject(this, VFORM_OFFSET, newVForm);
+ UNSAFE.fullFence();
+ }
+
+ static final BiFunction<String, List<Integer>, ArrayIndexOutOfBoundsException>
+ AIOOBE_SUPPLIER = Preconditions.outOfBoundsExceptionFormatter(
+ new Function<String, ArrayIndexOutOfBoundsException>() {
+ @Override
+ public ArrayIndexOutOfBoundsException apply(String s) {
+ return new ArrayIndexOutOfBoundsException(s);
+ }
+ });
+
+ private static final long VFORM_OFFSET;
+
+ static {
+ VFORM_OFFSET = UNSAFE.objectFieldOffset(VarHandle.class, "vform");
+
+ // The VarHandleGuards must be initialized to ensure correct
+ // compilation of the guard methods
+ UNSAFE.ensureClassInitialized(VarHandleGuards.class);
+ }
+ */
+ // END Android-removed: No VarForm in Android implementation.
+
+ // Fence methods
+
+ /**
+ * Ensures that loads and stores before the fence will not be reordered
+ * with
+ * loads and stores after the fence.
+ *
+ * @apiNote Ignoring the many semantic differences from C and C++, this
+ * method has memory ordering effects compatible with
+ * {@code atomic_thread_fence(memory_order_seq_cst)}
+ */
+ // Android-removed: @ForceInline is an unsupported attribute.
+ // @ForceInline
+ public static void fullFence() {
+ UNSAFE.fullFence();
+ }
+
+ /**
+ * Ensures that loads before the fence will not be reordered with loads and
+ * stores after the fence.
+ *
+ * @apiNote Ignoring the many semantic differences from C and C++, this
+ * method has memory ordering effects compatible with
+ * {@code atomic_thread_fence(memory_order_acquire)}
+ */
+ // Android-removed: @ForceInline is an unsupported attribute.
+ // @ForceInline
+ public static void acquireFence() {
+ UNSAFE.loadFence();
+ }
+
+ /**
+ * Ensures that loads and stores before the fence will not be
+ * reordered with stores after the fence.
+ *
+ * @apiNote Ignoring the many semantic differences from C and C++, this
+ * method has memory ordering effects compatible with
+ * {@code atomic_thread_fence(memory_order_release)}
+ */
+ // Android-removed: @ForceInline is an unsupported attribute.
+ // @ForceInline
+ public static void releaseFence() {
+ UNSAFE.storeFence();
+ }
+
+ /**
+ * Ensures that loads before the fence will not be reordered with
+ * loads after the fence.
+ */
+ // Android-removed: @ForceInline is an unsupported attribute.
+ // @ForceInline
+ public static void loadLoadFence() {
+ // Android-changed: Not using UNSAFE.loadLoadFence() as not present on Android.
+ // NB The compiler recognizes all the fences here as intrinsics.
+ UNSAFE.loadFence();
+ }
+
+ /**
+ * Ensures that stores before the fence will not be reordered with
+ * stores after the fence.
+ */
+ // Android-removed: @ForceInline is an unsupported attribute.
+ // @ForceInline
+ public static void storeStoreFence() {
+ // Android-changed: Not using UNSAFE.storeStoreFence() as not present on Android.
+ // NB The compiler recognizes all the fences here as intrinsics.
+ UNSAFE.storeFence();
+ }
+
+ // BEGIN Android-added: package private constructors.
+ /**
+ * Constructor for VarHandle with no coordinates.
+ *
+ * @param varType the variable type of variables to be referenced
+ * @param isFinal whether the target variables are final (non-modifiable)
+ * @hide
+ */
+ VarHandle(Class<?> varType, boolean isFinal) {
+ this.varType = Objects.requireNonNull(varType);
+ this.coordinateType0 = null;
+ this.coordinateType1 = null;
+ this.accessModesBitMask = alignedAccessModesBitMask(varType, isFinal);
+ }
+
+ /**
+ * Constructor for VarHandle with one coordinate.
+ *
+ * @param varType the variable type of variables to be referenced
+ * @param isFinal whether the target variables are final (non-modifiable)
+ * @param coordinateType the coordinate
+ * @hide
+ */
+ VarHandle(Class<?> varType, boolean isFinal, Class<?> coordinateType) {
+ this.varType = Objects.requireNonNull(varType);
+ this.coordinateType0 = Objects.requireNonNull(coordinateType);
+ this.coordinateType1 = null;
+ this.accessModesBitMask = alignedAccessModesBitMask(varType, isFinal);
+ }
+
+ /**
+ * Constructor for VarHandle with two coordinates.
+ *
+ * @param varType the variable type of variables to be referenced
+ * @param backingArrayType the type of the array accesses will be performed on
+ * @param isFinal whether the target variables are final (non-modifiable)
+ * @param coordinateType0 the first coordinate
+ * @param coordinateType1 the second coordinate
+ * @hide
+ */
+ VarHandle(Class<?> varType, Class<?> backingArrayType, boolean isFinal,
+ Class<?> coordinateType0, Class<?> coordinateType1) {
+ this.varType = Objects.requireNonNull(varType);
+ this.coordinateType0 = Objects.requireNonNull(coordinateType0);
+ this.coordinateType1 = Objects.requireNonNull(coordinateType1);
+ Objects.requireNonNull(backingArrayType);
+ Class<?> backingArrayComponentType = backingArrayType.getComponentType();
+ if (backingArrayComponentType != varType && backingArrayComponentType != byte.class) {
+ throw new InternalError("Unsupported backingArrayType: " + backingArrayType);
+ }
+
+ if (backingArrayType.getComponentType() == varType) {
+ this.accessModesBitMask = alignedAccessModesBitMask(varType, isFinal);
+ } else {
+ this.accessModesBitMask = unalignedAccessModesBitMask(varType);
+ }
+ }
+ // END Android-added: package private constructors.
+
+ // BEGIN Android-added: helper state for VarHandle properties.
+
+ /** BitMask of access modes that do not change the memory referenced by a VarHandle.
+ * An example being a read of a variable with volatile ordering effects. */
+ private final static int READ_ACCESS_MODES_BIT_MASK;
+
+ /** BitMask of access modes that write to the memory referenced by
+ * a VarHandle. This does not include any compare and update
+ * access modes, nor any bitwise or numeric access modes. An
+ * example being a write to variable with release ordering
+ * effects.
+ */
+ private final static int WRITE_ACCESS_MODES_BIT_MASK;
+
+ /** BitMask of access modes that are applicable to types
+ * supporting for atomic updates. This includes access modes that
+ * both read and write a variable such as compare-and-set.
+ */
+ private final static int ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK;
+
+ /** BitMask of access modes that are applicable to types
+ * supporting numeric atomic update operations. */
+ private final static int NUMERIC_ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK;
+
+ /** BitMask of access modes that are applicable to types
+ * supporting bitwise atomic update operations. */
+ private final static int BITWISE_ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK;
+
+ /** BitMask of all access modes. */
+ private final static int ALL_MODES_BIT_MASK;
+
+ static {
+ // Check we're not about to overflow the storage of the
+ // bitmasks here and in the accessModesBitMask field.
+ if (AccessMode.values().length > Integer.SIZE) {
+ throw new InternalError("accessModes overflow");
+ }
+
+ // Access modes bit mask declarations and initialization order
+ // follows the presentation order in JEP193.
+ READ_ACCESS_MODES_BIT_MASK = accessTypesToBitMask(EnumSet.of(AccessType.GET));
+
+ WRITE_ACCESS_MODES_BIT_MASK = accessTypesToBitMask(EnumSet.of(AccessType.SET));
+
+ ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK =
+ accessTypesToBitMask(EnumSet.of(AccessType.COMPARE_AND_EXCHANGE,
+ AccessType.COMPARE_AND_SET,
+ AccessType.GET_AND_UPDATE));
+
+ NUMERIC_ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK =
+ accessTypesToBitMask(EnumSet.of(AccessType.GET_AND_UPDATE_NUMERIC));
+
+ BITWISE_ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK =
+ accessTypesToBitMask(EnumSet.of(AccessType.GET_AND_UPDATE_BITWISE));
+
+ ALL_MODES_BIT_MASK = (READ_ACCESS_MODES_BIT_MASK |
+ WRITE_ACCESS_MODES_BIT_MASK |
+ ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK |
+ NUMERIC_ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK |
+ BITWISE_ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK);
+ }
+
+ static int accessTypesToBitMask(final EnumSet<AccessType> accessTypes) {
+ int m = 0;
+ for (AccessMode accessMode : AccessMode.values()) {
+ if (accessTypes.contains(accessMode.at)) {
+ m |= 1 << accessMode.ordinal();
+ }
+ }
+ return m;
+ }
+
+ static int alignedAccessModesBitMask(Class<?> varType, boolean isFinal) {
+ // For aligned accesses, the supported access modes are described in:
+ // @see java.lang.invoke.MethodHandles.Lookup#findVarHandle
+ int bitMask = ALL_MODES_BIT_MASK;
+
+ // If the field is declared final, keep only the read access modes.
+ if (isFinal) {
+ bitMask &= READ_ACCESS_MODES_BIT_MASK;
+ }
+
+ // If the field is anything other than byte, short, char, int,
+ // long, float, double then remove the numeric atomic update
+ // access modes.
+ if (varType != byte.class && varType != short.class && varType != char.class &&
+ varType != int.class && varType != long.class
+ && varType != float.class && varType != double.class) {
+ bitMask &= ~NUMERIC_ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK;
+ }
+
+ // If the field is not integral, remove the bitwise atomic update access modes.
+ if (varType != boolean.class && varType != byte.class && varType != short.class &&
+ varType != char.class && varType != int.class && varType != long.class) {
+ bitMask &= ~BITWISE_ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK;
+ }
+ return bitMask;
+ }
+
+ static int unalignedAccessModesBitMask(Class<?> varType) {
+ // The VarHandle refers to a view of byte array or a
+ // view of a byte buffer. The corresponding accesses
+ // maybe unaligned so the access modes are more
+ // restrictive than field or array element accesses.
+ //
+ // The supported access modes are described in:
+ // @see java.lang.invoke.MethodHandles#byteArrayViewVarHandle
+
+ // Read/write access modes supported for all types including
+ // long and double on 32-bit platforms (though these accesses
+ // may not be atomic).
+ int bitMask = READ_ACCESS_MODES_BIT_MASK | WRITE_ACCESS_MODES_BIT_MASK;
+
+ // int, long, float, double support atomic update modes per documentation.
+ if (varType == int.class || varType == long.class ||
+ varType == float.class || varType == double.class) {
+ bitMask |= ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK;
+ }
+
+ // int and long support numeric updates per documentation.
+ if (varType == int.class || varType == long.class) {
+ bitMask |= NUMERIC_ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK;
+ }
+
+ // int and long support bitwise updates per documentation.
+ if (varType == int.class || varType == long.class) {
+ bitMask |= BITWISE_ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK;
+ }
+ return bitMask;
+ }
+ // END Android-added: helper state for VarHandle properties.
+
+ // BEGIN Android-added: Add VarHandleDesc from OpenJDK 17. http://b/270028670
+ /**
+ * A <a href="{@docRoot}/java.base/java/lang/constant/package-summary.html#nominal">nominal descriptor</a> for a
+ * {@link VarHandle} constant.
+ *
+ * @since 12
+ * @hide
+ */
+ public static final class VarHandleDesc extends DynamicConstantDesc<VarHandle> {
+
+ /**
+ * Kinds of variable handle descs
+ */
+ private enum Kind {
+ FIELD(ConstantDescs.BSM_VARHANDLE_FIELD),
+ STATIC_FIELD(ConstantDescs.BSM_VARHANDLE_STATIC_FIELD),
+ ARRAY(ConstantDescs.BSM_VARHANDLE_ARRAY);
+
+ final DirectMethodHandleDesc bootstrapMethod;
+
+ Kind(DirectMethodHandleDesc bootstrapMethod) {
+ this.bootstrapMethod = bootstrapMethod;
+ }
+
+ ConstantDesc[] toBSMArgs(ClassDesc declaringClass, ClassDesc varType) {
+ return switch (this) {
+ case FIELD, STATIC_FIELD -> new ConstantDesc[]{declaringClass, varType};
+ case ARRAY -> new ConstantDesc[]{declaringClass};
+ default -> throw new InternalError("Cannot reach here");
+ };
+ }
+ }
+
+ private final Kind kind;
+ private final ClassDesc declaringClass;
+ private final ClassDesc varType;
+
+ /**
+ * Construct a {@linkplain VarHandleDesc} given a kind, name, and declaring
+ * class.
+ *
+ * @param kind the kind of the var handle
+ * @param name the unqualified name of the field, for field var handles; otherwise ignored
+ * @param declaringClass a {@link ClassDesc} describing the declaring class,
+ * for field var handles
+ * @param varType a {@link ClassDesc} describing the type of the variable
+ * @throws NullPointerException if any required argument is null
+ * @jvms 4.2.2 Unqualified Names
+ */
+ private VarHandleDesc(Kind kind, String name, ClassDesc declaringClass, ClassDesc varType) {
+ super(kind.bootstrapMethod, name,
+ ConstantDescs.CD_VarHandle,
+ kind.toBSMArgs(declaringClass, varType));
+ this.kind = kind;
+ this.declaringClass = declaringClass;
+ this.varType = varType;
+ }
+
+ /**
+ * Returns a {@linkplain VarHandleDesc} corresponding to a {@link VarHandle}
+ * for an instance field.
+ *
+ * @param name the unqualified name of the field
+ * @param declaringClass a {@link ClassDesc} describing the declaring class,
+ * for field var handles
+ * @param fieldType a {@link ClassDesc} describing the type of the field
+ * @return the {@linkplain VarHandleDesc}
+ * @throws NullPointerException if any of the arguments are null
+ * @jvms 4.2.2 Unqualified Names
+ */
+ public static VarHandleDesc ofField(ClassDesc declaringClass, String name, ClassDesc fieldType) {
+ Objects.requireNonNull(declaringClass);
+ Objects.requireNonNull(name);
+ Objects.requireNonNull(fieldType);
+ return new VarHandleDesc(Kind.FIELD, name, declaringClass, fieldType);
+ }
+
+ /**
+ * Returns a {@linkplain VarHandleDesc} corresponding to a {@link VarHandle}
+ * for a static field.
+ *
+ * @param name the unqualified name of the field
+ * @param declaringClass a {@link ClassDesc} describing the declaring class,
+ * for field var handles
+ * @param fieldType a {@link ClassDesc} describing the type of the field
+ * @return the {@linkplain VarHandleDesc}
+ * @throws NullPointerException if any of the arguments are null
+ * @jvms 4.2.2 Unqualified Names
+ */
+ public static VarHandleDesc ofStaticField(ClassDesc declaringClass, String name, ClassDesc fieldType) {
+ Objects.requireNonNull(declaringClass);
+ Objects.requireNonNull(name);
+ Objects.requireNonNull(fieldType);
+ return new VarHandleDesc(Kind.STATIC_FIELD, name, declaringClass, fieldType);
+ }
+
+ /**
+ * Returns a {@linkplain VarHandleDesc} corresponding to a {@link VarHandle}
+ * for an array type.
+ *
+ * @param arrayClass a {@link ClassDesc} describing the type of the array
+ * @return the {@linkplain VarHandleDesc}
+ * @throws NullPointerException if any of the arguments are null
+ */
+ public static VarHandleDesc ofArray(ClassDesc arrayClass) {
+ Objects.requireNonNull(arrayClass);
+ if (!arrayClass.isArray())
+ throw new IllegalArgumentException("Array class argument not an array: " + arrayClass);
+ return new VarHandleDesc(Kind.ARRAY, ConstantDescs.DEFAULT_NAME, arrayClass, arrayClass.componentType());
+ }
+
+ /**
+ * Returns a {@link ClassDesc} describing the type of the variable described
+ * by this descriptor.
+ *
+ * @return the variable type
+ */
+ public ClassDesc varType() {
+ return varType;
+ }
+
+ @Override
+ public VarHandle resolveConstantDesc(MethodHandles.Lookup lookup)
+ throws ReflectiveOperationException {
+ return switch (kind) {
+ case FIELD -> lookup.findVarHandle((Class<?>) declaringClass.resolveConstantDesc(lookup),
+ constantName(),
+ (Class<?>) varType.resolveConstantDesc(lookup));
+ case STATIC_FIELD -> lookup.findStaticVarHandle((Class<?>) declaringClass.resolveConstantDesc(lookup),
+ constantName(),
+ (Class<?>) varType.resolveConstantDesc(lookup));
+ case ARRAY -> MethodHandles.arrayElementVarHandle((Class<?>) declaringClass.resolveConstantDesc(lookup));
+ default -> throw new InternalError("Cannot reach here");
+ };
+ }
+
+ /**
+ * Returns a compact textual description of this constant description.
+ * For a field {@linkplain VarHandle}, includes the owner, name, and type
+ * of the field, and whether it is static; for an array {@linkplain VarHandle},
+ * the name of the component type.
+ *
+ * @return A compact textual description of this descriptor
+ */
+ @Override
+ public String toString() {
+ return switch (kind) {
+ case FIELD, STATIC_FIELD -> String.format("VarHandleDesc[%s%s.%s:%s]",
+ (kind == Kind.STATIC_FIELD) ? "static " : "",
+ declaringClass.displayName(), constantName(), varType.displayName());
+ case ARRAY -> String.format("VarHandleDesc[%s[]]", declaringClass.displayName());
+ default -> throw new InternalError("Cannot reach here");
+ };
+ }
+ }
+ // END Android-added: Add VarHandleDesc from OpenJDK 17. http://b/270028670
+}
diff --git a/android-35/java/lang/invoke/VolatileCallSite.java b/android-35/java/lang/invoke/VolatileCallSite.java
new file mode 100644
index 0000000..47d2689
--- /dev/null
+++ b/android-35/java/lang/invoke/VolatileCallSite.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+// Android-changed: Removed references to MutableCallSite.syncAll().
+/**
+ * A {@code VolatileCallSite} is a {@link CallSite} whose target acts like a volatile variable.
+ * An {@code invokedynamic} instruction linked to a {@code VolatileCallSite} sees updates
+ * to its call site target immediately, even if the update occurs in another thread.
+ * There may be a performance penalty for such tight coupling between threads.
+ * <p>
+ * In other respects, a {@code VolatileCallSite} is interchangeable
+ * with {@code MutableCallSite}.
+ * @see MutableCallSite
+ * @author John Rose, JSR 292 EG
+ */
+public class VolatileCallSite extends CallSite {
+ /**
+ * Creates a call site with a volatile binding to its target.
+ * The initial target is set to a method handle
+ * of the given type which will throw an {@code IllegalStateException} if called.
+ * @param type the method type that this call site will have
+ * @throws NullPointerException if the proposed type is null
+ */
+ public VolatileCallSite(MethodType type) {
+ super(type);
+ }
+
+ /**
+ * Creates a call site with a volatile binding to its target.
+ * The target is set to the given value.
+ * @param target the method handle that will be the initial target of the call site
+ * @throws NullPointerException if the proposed target is null
+ */
+ public VolatileCallSite(MethodHandle target) {
+ super(target);
+ }
+
+ /**
+ * Returns the target method of the call site, which behaves
+ * like a {@code volatile} field of the {@code VolatileCallSite}.
+ * <p>
+ * The interactions of {@code getTarget} with memory are the same
+ * as of a read from a {@code volatile} field.
+ * <p>
+ * In particular, the current thread is required to issue a fresh
+ * read of the target from memory, and must not fail to see
+ * a recent update to the target by another thread.
+ *
+ * @return the linkage state of this call site, a method handle which can change over time
+ * @see #setTarget
+ */
+ @Override public final MethodHandle getTarget() {
+ return getTargetVolatile();
+ }
+
+ /**
+ * Updates the target method of this call site, as a volatile variable.
+ * The type of the new target must agree with the type of the old target.
+ * <p>
+ * The interactions with memory are the same as of a write to a volatile field.
+ * In particular, any threads is guaranteed to see the updated target
+ * the next time it calls {@code getTarget}.
+ * @param newTarget the new target
+ * @throws NullPointerException if the proposed new target is null
+ * @throws WrongMethodTypeException if the proposed new target
+ * has a method type that differs from the previous target
+ * @see #getTarget
+ */
+ @Override public void setTarget(MethodHandle newTarget) {
+ checkTargetChange(getTargetVolatile(), newTarget);
+ setTargetVolatile(newTarget);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final MethodHandle dynamicInvoker() {
+ return makeDynamicInvoker();
+ }
+}
diff --git a/android-35/java/lang/invoke/WrongMethodTypeException.java b/android-35/java/lang/invoke/WrongMethodTypeException.java
new file mode 100644
index 0000000..d55e3cd
--- /dev/null
+++ b/android-35/java/lang/invoke/WrongMethodTypeException.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+/**
+ * Thrown to indicate that code has attempted to call a method handle
+ * via the wrong method type. As with the bytecode representation of
+ * normal Java method calls, method handle calls are strongly typed
+ * to a specific type descriptor associated with a call site.
+ * <p>
+ * This exception may also be thrown when two method handles are
+ * composed, and the system detects that their types cannot be
+ * matched up correctly. This amounts to an early evaluation
+ * of the type mismatch, at method handle construction time,
+ * instead of when the mismatched method handle is called.
+ *
+ * @author John Rose, JSR 292 EG
+ * @since 1.7
+ */
+public class WrongMethodTypeException extends RuntimeException {
+ private static final long serialVersionUID = 292L;
+
+ /**
+ * Constructs a {@code WrongMethodTypeException} with no detail message.
+ */
+ public WrongMethodTypeException() {
+ super();
+ }
+
+ /**
+ * Constructs a {@code WrongMethodTypeException} with the specified
+ * detail message.
+ *
+ * @param s the detail message.
+ */
+ public WrongMethodTypeException(String s) {
+ super(s);
+ }
+
+ /**
+ * Constructs a {@code WrongMethodTypeException} with the specified
+ * detail message and cause.
+ *
+ * @param s the detail message.
+ * @param cause the cause of the exception, or null.
+ */
+ //FIXME: make this public in MR1
+ /*non-public*/ WrongMethodTypeException(String s, Throwable cause) {
+ super(s, cause);
+ }
+
+ /**
+ * Constructs a {@code WrongMethodTypeException} with the specified
+ * cause.
+ *
+ * @param cause the cause of the exception, or null.
+ */
+ //FIXME: make this public in MR1
+ /*non-public*/ WrongMethodTypeException(Throwable cause) {
+ super(cause);
+ }
+}