1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/MethodHandleImpl.java Sat Aug 09 11:11:13 2014 +0200
1.3 @@ -0,0 +1,1013 @@
1.4 +/*
1.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1.7 + *
1.8 + * This code is free software; you can redistribute it and/or modify it
1.9 + * under the terms of the GNU General Public License version 2 only, as
1.10 + * published by the Free Software Foundation. Oracle designates this
1.11 + * particular file as subject to the "Classpath" exception as provided
1.12 + * by Oracle in the LICENSE file that accompanied this code.
1.13 + *
1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1.17 + * version 2 for more details (a copy is included in the LICENSE file that
1.18 + * accompanied this code).
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License version
1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1.23 + *
1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1.25 + * or visit www.oracle.com if you need additional information or have any
1.26 + * questions.
1.27 + */
1.28 +
1.29 +package java.lang.invoke;
1.30 +
1.31 +import java.security.AccessController;
1.32 +import java.security.PrivilegedAction;
1.33 +import java.util.ArrayList;
1.34 +import java.util.Arrays;
1.35 +import java.util.HashMap;
1.36 +import sun.invoke.empty.Empty;
1.37 +import sun.invoke.util.ValueConversions;
1.38 +import sun.invoke.util.VerifyType;
1.39 +import sun.invoke.util.Wrapper;
1.40 +import sun.reflect.CallerSensitive;
1.41 +import sun.reflect.Reflection;
1.42 +import static java.lang.invoke.LambdaForm.*;
1.43 +import static java.lang.invoke.MethodHandleStatics.*;
1.44 +import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
1.45 +
1.46 +/**
1.47 + * Trusted implementation code for MethodHandle.
1.48 + * @author jrose
1.49 + */
1.50 +/*non-public*/ abstract class MethodHandleImpl {
1.51 + /// Factory methods to create method handles:
1.52 +
1.53 + static void initStatics() {
1.54 + // Trigger selected static initializations.
1.55 + MemberName.Factory.INSTANCE.getClass();
1.56 + }
1.57 +
1.58 + static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, boolean isSetter) {
1.59 + if (!arrayClass.isArray())
1.60 + throw newIllegalArgumentException("not an array: "+arrayClass);
1.61 + MethodHandle accessor = ArrayAccessor.getAccessor(arrayClass, isSetter);
1.62 + MethodType srcType = accessor.type().erase();
1.63 + MethodType lambdaType = srcType.invokerType();
1.64 + Name[] names = arguments(1, lambdaType);
1.65 + Name[] args = Arrays.copyOfRange(names, 1, 1 + srcType.parameterCount());
1.66 + names[names.length - 1] = new Name(accessor.asType(srcType), (Object[]) args);
1.67 + LambdaForm form = new LambdaForm("getElement", lambdaType.parameterCount(), names);
1.68 + MethodHandle mh = SimpleMethodHandle.make(srcType, form);
1.69 + if (ArrayAccessor.needCast(arrayClass)) {
1.70 + mh = mh.bindTo(arrayClass);
1.71 + }
1.72 + mh = mh.asType(ArrayAccessor.correctType(arrayClass, isSetter));
1.73 + return mh;
1.74 + }
1.75 +
1.76 + static final class ArrayAccessor {
1.77 + /// Support for array element access
1.78 + static final HashMap<Class<?>, MethodHandle> GETTER_CACHE = new HashMap<>(); // TODO use it
1.79 + static final HashMap<Class<?>, MethodHandle> SETTER_CACHE = new HashMap<>(); // TODO use it
1.80 +
1.81 + static int getElementI(int[] a, int i) { return a[i]; }
1.82 + static long getElementJ(long[] a, int i) { return a[i]; }
1.83 + static float getElementF(float[] a, int i) { return a[i]; }
1.84 + static double getElementD(double[] a, int i) { return a[i]; }
1.85 + static boolean getElementZ(boolean[] a, int i) { return a[i]; }
1.86 + static byte getElementB(byte[] a, int i) { return a[i]; }
1.87 + static short getElementS(short[] a, int i) { return a[i]; }
1.88 + static char getElementC(char[] a, int i) { return a[i]; }
1.89 + static Object getElementL(Object[] a, int i) { return a[i]; }
1.90 +
1.91 + static void setElementI(int[] a, int i, int x) { a[i] = x; }
1.92 + static void setElementJ(long[] a, int i, long x) { a[i] = x; }
1.93 + static void setElementF(float[] a, int i, float x) { a[i] = x; }
1.94 + static void setElementD(double[] a, int i, double x) { a[i] = x; }
1.95 + static void setElementZ(boolean[] a, int i, boolean x) { a[i] = x; }
1.96 + static void setElementB(byte[] a, int i, byte x) { a[i] = x; }
1.97 + static void setElementS(short[] a, int i, short x) { a[i] = x; }
1.98 + static void setElementC(char[] a, int i, char x) { a[i] = x; }
1.99 + static void setElementL(Object[] a, int i, Object x) { a[i] = x; }
1.100 +
1.101 + static Object getElementL(Class<?> arrayClass, Object[] a, int i) { arrayClass.cast(a); return a[i]; }
1.102 + static void setElementL(Class<?> arrayClass, Object[] a, int i, Object x) { arrayClass.cast(a); a[i] = x; }
1.103 +
1.104 + // Weakly typed wrappers of Object[] accessors:
1.105 + static Object getElementL(Object a, int i) { return getElementL((Object[])a, i); }
1.106 + static void setElementL(Object a, int i, Object x) { setElementL((Object[]) a, i, x); }
1.107 + static Object getElementL(Object arrayClass, Object a, int i) { return getElementL((Class<?>) arrayClass, (Object[])a, i); }
1.108 + static void setElementL(Object arrayClass, Object a, int i, Object x) { setElementL((Class<?>) arrayClass, (Object[])a, i, x); }
1.109 +
1.110 + static boolean needCast(Class<?> arrayClass) {
1.111 + Class<?> elemClass = arrayClass.getComponentType();
1.112 + return !elemClass.isPrimitive() && elemClass != Object.class;
1.113 + }
1.114 + static String name(Class<?> arrayClass, boolean isSetter) {
1.115 + Class<?> elemClass = arrayClass.getComponentType();
1.116 + if (elemClass == null) throw new IllegalArgumentException();
1.117 + return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(elemClass);
1.118 + }
1.119 + static final boolean USE_WEAKLY_TYPED_ARRAY_ACCESSORS = false; // FIXME: decide
1.120 + static MethodType type(Class<?> arrayClass, boolean isSetter) {
1.121 + Class<?> elemClass = arrayClass.getComponentType();
1.122 + Class<?> arrayArgClass = arrayClass;
1.123 + if (!elemClass.isPrimitive()) {
1.124 + arrayArgClass = Object[].class;
1.125 + if (USE_WEAKLY_TYPED_ARRAY_ACCESSORS)
1.126 + arrayArgClass = Object.class;
1.127 + }
1.128 + if (!needCast(arrayClass)) {
1.129 + return !isSetter ?
1.130 + MethodType.methodType(elemClass, arrayArgClass, int.class) :
1.131 + MethodType.methodType(void.class, arrayArgClass, int.class, elemClass);
1.132 + } else {
1.133 + Class<?> classArgClass = Class.class;
1.134 + if (USE_WEAKLY_TYPED_ARRAY_ACCESSORS)
1.135 + classArgClass = Object.class;
1.136 + return !isSetter ?
1.137 + MethodType.methodType(Object.class, classArgClass, arrayArgClass, int.class) :
1.138 + MethodType.methodType(void.class, classArgClass, arrayArgClass, int.class, Object.class);
1.139 + }
1.140 + }
1.141 + static MethodType correctType(Class<?> arrayClass, boolean isSetter) {
1.142 + Class<?> elemClass = arrayClass.getComponentType();
1.143 + return !isSetter ?
1.144 + MethodType.methodType(elemClass, arrayClass, int.class) :
1.145 + MethodType.methodType(void.class, arrayClass, int.class, elemClass);
1.146 + }
1.147 + static MethodHandle getAccessor(Class<?> arrayClass, boolean isSetter) {
1.148 + String name = name(arrayClass, isSetter);
1.149 + MethodType type = type(arrayClass, isSetter);
1.150 + try {
1.151 + return IMPL_LOOKUP.findStatic(ArrayAccessor.class, name, type);
1.152 + } catch (ReflectiveOperationException ex) {
1.153 + throw uncaughtException(ex);
1.154 + }
1.155 + }
1.156 + }
1.157 +
1.158 + /**
1.159 + * Create a JVM-level adapter method handle to conform the given method
1.160 + * handle to the similar newType, using only pairwise argument conversions.
1.161 + * For each argument, convert incoming argument to the exact type needed.
1.162 + * The argument conversions allowed are casting, boxing and unboxing,
1.163 + * integral widening or narrowing, and floating point widening or narrowing.
1.164 + * @param srcType required call type
1.165 + * @param target original method handle
1.166 + * @param level which strength of conversion is allowed
1.167 + * @return an adapter to the original handle with the desired new type,
1.168 + * or the original target if the types are already identical
1.169 + * or null if the adaptation cannot be made
1.170 + */
1.171 + static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, int level) {
1.172 + assert(level >= 0 && level <= 2);
1.173 + MethodType dstType = target.type();
1.174 + assert(dstType.parameterCount() == target.type().parameterCount());
1.175 + if (srcType == dstType)
1.176 + return target;
1.177 +
1.178 + // Calculate extra arguments (temporaries) required in the names array.
1.179 + // FIXME: Use an ArrayList<Name>. Some arguments require more than one conversion step.
1.180 + final int INARG_COUNT = srcType.parameterCount();
1.181 + int conversions = 0;
1.182 + boolean[] needConv = new boolean[1+INARG_COUNT];
1.183 + for (int i = 0; i <= INARG_COUNT; i++) {
1.184 + Class<?> src = (i == INARG_COUNT) ? dstType.returnType() : srcType.parameterType(i);
1.185 + Class<?> dst = (i == INARG_COUNT) ? srcType.returnType() : dstType.parameterType(i);
1.186 + if (!VerifyType.isNullConversion(src, dst) ||
1.187 + level <= 1 && dst.isInterface() && !dst.isAssignableFrom(src)) {
1.188 + needConv[i] = true;
1.189 + conversions++;
1.190 + }
1.191 + }
1.192 + boolean retConv = needConv[INARG_COUNT];
1.193 +
1.194 + final int IN_MH = 0;
1.195 + final int INARG_BASE = 1;
1.196 + final int INARG_LIMIT = INARG_BASE + INARG_COUNT;
1.197 + final int NAME_LIMIT = INARG_LIMIT + conversions + 1;
1.198 + final int RETURN_CONV = (!retConv ? -1 : NAME_LIMIT - 1);
1.199 + final int OUT_CALL = (!retConv ? NAME_LIMIT : RETURN_CONV) - 1;
1.200 +
1.201 + // Now build a LambdaForm.
1.202 + MethodType lambdaType = srcType.basicType().invokerType();
1.203 + Name[] names = arguments(NAME_LIMIT - INARG_LIMIT, lambdaType);
1.204 +
1.205 + // Collect the arguments to the outgoing call, maybe with conversions:
1.206 + final int OUTARG_BASE = 0; // target MH is Name.function, name Name.arguments[0]
1.207 + Object[] outArgs = new Object[OUTARG_BASE + INARG_COUNT];
1.208 +
1.209 + int nameCursor = INARG_LIMIT;
1.210 + for (int i = 0; i < INARG_COUNT; i++) {
1.211 + Class<?> src = srcType.parameterType(i);
1.212 + Class<?> dst = dstType.parameterType(i);
1.213 +
1.214 + if (!needConv[i]) {
1.215 + // do nothing: difference is trivial
1.216 + outArgs[OUTARG_BASE + i] = names[INARG_BASE + i];
1.217 + continue;
1.218 + }
1.219 +
1.220 + // Tricky case analysis follows.
1.221 + MethodHandle fn = null;
1.222 + if (src.isPrimitive()) {
1.223 + if (dst.isPrimitive()) {
1.224 + fn = ValueConversions.convertPrimitive(src, dst);
1.225 + } else {
1.226 + Wrapper w = Wrapper.forPrimitiveType(src);
1.227 + MethodHandle boxMethod = ValueConversions.box(w);
1.228 + if (dst == w.wrapperType())
1.229 + fn = boxMethod;
1.230 + else
1.231 + fn = boxMethod.asType(MethodType.methodType(dst, src));
1.232 + }
1.233 + } else {
1.234 + if (dst.isPrimitive()) {
1.235 + // Caller has boxed a primitive. Unbox it for the target.
1.236 + Wrapper w = Wrapper.forPrimitiveType(dst);
1.237 + if (level == 0 || VerifyType.isNullConversion(src, w.wrapperType())) {
1.238 + fn = ValueConversions.unbox(dst);
1.239 + } else if (src == Object.class || !Wrapper.isWrapperType(src)) {
1.240 + // Examples: Object->int, Number->int, Comparable->int; Byte->int, Character->int
1.241 + // must include additional conversions
1.242 + // src must be examined at runtime, to detect Byte, Character, etc.
1.243 + MethodHandle unboxMethod = (level == 1
1.244 + ? ValueConversions.unbox(dst)
1.245 + : ValueConversions.unboxCast(dst));
1.246 + fn = unboxMethod;
1.247 + } else {
1.248 + // Example: Byte->int
1.249 + // Do this by reformulating the problem to Byte->byte.
1.250 + Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType();
1.251 + MethodHandle unbox = ValueConversions.unbox(srcPrim);
1.252 + // Compose the two conversions. FIXME: should make two Names for this job
1.253 + fn = unbox.asType(MethodType.methodType(dst, src));
1.254 + }
1.255 + } else {
1.256 + // Simple reference conversion.
1.257 + // Note: Do not check for a class hierarchy relation
1.258 + // between src and dst. In all cases a 'null' argument
1.259 + // will pass the cast conversion.
1.260 + fn = ValueConversions.cast(dst);
1.261 + }
1.262 + }
1.263 + Name conv = new Name(fn, names[INARG_BASE + i]);
1.264 + assert(names[nameCursor] == null);
1.265 + names[nameCursor++] = conv;
1.266 + assert(outArgs[OUTARG_BASE + i] == null);
1.267 + outArgs[OUTARG_BASE + i] = conv;
1.268 + }
1.269 +
1.270 + // Build argument array for the call.
1.271 + assert(nameCursor == OUT_CALL);
1.272 + names[OUT_CALL] = new Name(target, outArgs);
1.273 +
1.274 + if (RETURN_CONV < 0) {
1.275 + assert(OUT_CALL == names.length-1);
1.276 + } else {
1.277 + Class<?> needReturn = srcType.returnType();
1.278 + Class<?> haveReturn = dstType.returnType();
1.279 + MethodHandle fn;
1.280 + Object[] arg = { names[OUT_CALL] };
1.281 + if (haveReturn == void.class) {
1.282 + // synthesize a zero value for the given void
1.283 + Object zero = Wrapper.forBasicType(needReturn).zero();
1.284 + fn = MethodHandles.constant(needReturn, zero);
1.285 + arg = new Object[0]; // don't pass names[OUT_CALL] to conversion
1.286 + } else {
1.287 + MethodHandle identity = MethodHandles.identity(needReturn);
1.288 + MethodType needConversion = identity.type().changeParameterType(0, haveReturn);
1.289 + fn = makePairwiseConvert(identity, needConversion, level);
1.290 + }
1.291 + assert(names[RETURN_CONV] == null);
1.292 + names[RETURN_CONV] = new Name(fn, arg);
1.293 + assert(RETURN_CONV == names.length-1);
1.294 + }
1.295 +
1.296 + LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names);
1.297 + return SimpleMethodHandle.make(srcType, form);
1.298 + }
1.299 +
1.300 + static MethodHandle makeReferenceIdentity(Class<?> refType) {
1.301 + MethodType lambdaType = MethodType.genericMethodType(1).invokerType();
1.302 + Name[] names = arguments(1, lambdaType);
1.303 + names[names.length - 1] = new Name(ValueConversions.identity(), names[1]);
1.304 + LambdaForm form = new LambdaForm("identity", lambdaType.parameterCount(), names);
1.305 + return SimpleMethodHandle.make(MethodType.methodType(refType, refType), form);
1.306 + }
1.307 +
1.308 + static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
1.309 + MethodType type = target.type();
1.310 + int last = type.parameterCount() - 1;
1.311 + if (type.parameterType(last) != arrayType)
1.312 + target = target.asType(type.changeParameterType(last, arrayType));
1.313 + target = target.asFixedArity(); // make sure this attribute is turned off
1.314 + return new AsVarargsCollector(target, target.type(), arrayType);
1.315 + }
1.316 +
1.317 + static class AsVarargsCollector extends MethodHandle {
1.318 + private final MethodHandle target;
1.319 + private final Class<?> arrayType;
1.320 + private /*@Stable*/ MethodHandle asCollectorCache;
1.321 +
1.322 + AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) {
1.323 + super(type, reinvokerForm(target));
1.324 + this.target = target;
1.325 + this.arrayType = arrayType;
1.326 + this.asCollectorCache = target.asCollector(arrayType, 0);
1.327 + }
1.328 +
1.329 + @Override MethodHandle reinvokerTarget() { return target; }
1.330 +
1.331 + @Override
1.332 + public boolean isVarargsCollector() {
1.333 + return true;
1.334 + }
1.335 +
1.336 + @Override
1.337 + public MethodHandle asFixedArity() {
1.338 + return target;
1.339 + }
1.340 +
1.341 + @Override
1.342 + public MethodHandle asTypeUncached(MethodType newType) {
1.343 + MethodType type = this.type();
1.344 + int collectArg = type.parameterCount() - 1;
1.345 + int newArity = newType.parameterCount();
1.346 + if (newArity == collectArg+1 &&
1.347 + type.parameterType(collectArg).isAssignableFrom(newType.parameterType(collectArg))) {
1.348 + // if arity and trailing parameter are compatible, do normal thing
1.349 + return asTypeCache = asFixedArity().asType(newType);
1.350 + }
1.351 + // check cache
1.352 + MethodHandle acc = asCollectorCache;
1.353 + if (acc != null && acc.type().parameterCount() == newArity)
1.354 + return asTypeCache = acc.asType(newType);
1.355 + // build and cache a collector
1.356 + int arrayLength = newArity - collectArg;
1.357 + MethodHandle collector;
1.358 + try {
1.359 + collector = asFixedArity().asCollector(arrayType, arrayLength);
1.360 + assert(collector.type().parameterCount() == newArity) : "newArity="+newArity+" but collector="+collector;
1.361 + } catch (IllegalArgumentException ex) {
1.362 + throw new WrongMethodTypeException("cannot build collector", ex);
1.363 + }
1.364 + asCollectorCache = collector;
1.365 + return asTypeCache = collector.asType(newType);
1.366 + }
1.367 +
1.368 + @Override
1.369 + MethodHandle setVarargs(MemberName member) {
1.370 + if (member.isVarargs()) return this;
1.371 + return asFixedArity();
1.372 + }
1.373 +
1.374 + @Override
1.375 + MethodHandle viewAsType(MethodType newType) {
1.376 + if (newType.lastParameterType() != type().lastParameterType())
1.377 + throw new InternalError();
1.378 + MethodHandle newTarget = asFixedArity().viewAsType(newType);
1.379 + // put back the varargs bit:
1.380 + return new AsVarargsCollector(newTarget, newType, arrayType);
1.381 + }
1.382 +
1.383 + @Override
1.384 + MemberName internalMemberName() {
1.385 + return asFixedArity().internalMemberName();
1.386 + }
1.387 + @Override
1.388 + Class<?> internalCallerClass() {
1.389 + return asFixedArity().internalCallerClass();
1.390 + }
1.391 +
1.392 + /*non-public*/
1.393 + @Override
1.394 + boolean isInvokeSpecial() {
1.395 + return asFixedArity().isInvokeSpecial();
1.396 + }
1.397 +
1.398 +
1.399 + @Override
1.400 + MethodHandle bindArgument(int pos, char basicType, Object value) {
1.401 + return asFixedArity().bindArgument(pos, basicType, value);
1.402 + }
1.403 +
1.404 + @Override
1.405 + MethodHandle bindReceiver(Object receiver) {
1.406 + return asFixedArity().bindReceiver(receiver);
1.407 + }
1.408 +
1.409 + @Override
1.410 + MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
1.411 + return asFixedArity().dropArguments(srcType, pos, drops);
1.412 + }
1.413 +
1.414 + @Override
1.415 + MethodHandle permuteArguments(MethodType newType, int[] reorder) {
1.416 + return asFixedArity().permuteArguments(newType, reorder);
1.417 + }
1.418 + }
1.419 +
1.420 + /** Factory method: Spread selected argument. */
1.421 + static MethodHandle makeSpreadArguments(MethodHandle target,
1.422 + Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
1.423 + MethodType targetType = target.type();
1.424 +
1.425 + for (int i = 0; i < spreadArgCount; i++) {
1.426 + Class<?> arg = VerifyType.spreadArgElementType(spreadArgType, i);
1.427 + if (arg == null) arg = Object.class;
1.428 + targetType = targetType.changeParameterType(spreadArgPos + i, arg);
1.429 + }
1.430 + target = target.asType(targetType);
1.431 +
1.432 + MethodType srcType = targetType
1.433 + .replaceParameterTypes(spreadArgPos, spreadArgPos + spreadArgCount, spreadArgType);
1.434 + // Now build a LambdaForm.
1.435 + MethodType lambdaType = srcType.invokerType();
1.436 + Name[] names = arguments(spreadArgCount + 2, lambdaType);
1.437 + int nameCursor = lambdaType.parameterCount();
1.438 + int[] indexes = new int[targetType.parameterCount()];
1.439 +
1.440 + for (int i = 0, argIndex = 1; i < targetType.parameterCount() + 1; i++, argIndex++) {
1.441 + Class<?> src = lambdaType.parameterType(i);
1.442 + if (i == spreadArgPos) {
1.443 + // Spread the array.
1.444 + MethodHandle aload = MethodHandles.arrayElementGetter(spreadArgType);
1.445 + Name array = names[argIndex];
1.446 + names[nameCursor++] = new Name(Lazy.NF_checkSpreadArgument, array, spreadArgCount);
1.447 + for (int j = 0; j < spreadArgCount; i++, j++) {
1.448 + indexes[i] = nameCursor;
1.449 + names[nameCursor++] = new Name(aload, array, j);
1.450 + }
1.451 + } else if (i < indexes.length) {
1.452 + indexes[i] = argIndex;
1.453 + }
1.454 + }
1.455 + assert(nameCursor == names.length-1); // leave room for the final call
1.456 +
1.457 + // Build argument array for the call.
1.458 + Name[] targetArgs = new Name[targetType.parameterCount()];
1.459 + for (int i = 0; i < targetType.parameterCount(); i++) {
1.460 + int idx = indexes[i];
1.461 + targetArgs[i] = names[idx];
1.462 + }
1.463 + names[names.length - 1] = new Name(target, (Object[]) targetArgs);
1.464 +
1.465 + LambdaForm form = new LambdaForm("spread", lambdaType.parameterCount(), names);
1.466 + return SimpleMethodHandle.make(srcType, form);
1.467 + }
1.468 +
1.469 + static void checkSpreadArgument(Object av, int n) {
1.470 + if (av == null) {
1.471 + if (n == 0) return;
1.472 + } else if (av instanceof Object[]) {
1.473 + int len = ((Object[])av).length;
1.474 + if (len == n) return;
1.475 + } else {
1.476 + int len = java.lang.reflect.Array.getLength(av);
1.477 + if (len == n) return;
1.478 + }
1.479 + // fall through to error:
1.480 + throw newIllegalArgumentException("array is not of length "+n);
1.481 + }
1.482 +
1.483 + /**
1.484 + * Pre-initialized NamedFunctions for bootstrapping purposes.
1.485 + * Factored in an inner class to delay initialization until first usage.
1.486 + */
1.487 + private static class Lazy {
1.488 + static final NamedFunction NF_checkSpreadArgument;
1.489 + static {
1.490 + try {
1.491 + NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class
1.492 + .getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
1.493 + NF_checkSpreadArgument.resolve();
1.494 + } catch (ReflectiveOperationException ex) {
1.495 + throw newInternalError(ex);
1.496 + }
1.497 + }
1.498 + }
1.499 +
1.500 + /** Factory method: Collect or filter selected argument(s). */
1.501 + static MethodHandle makeCollectArguments(MethodHandle target,
1.502 + MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) {
1.503 + MethodType targetType = target.type(); // (a..., c, [b...])=>r
1.504 + MethodType collectorType = collector.type(); // (b...)=>c
1.505 + int collectArgCount = collectorType.parameterCount();
1.506 + Class<?> collectValType = collectorType.returnType();
1.507 + int collectValCount = (collectValType == void.class ? 0 : 1);
1.508 + MethodType srcType = targetType // (a..., [b...])=>r
1.509 + .dropParameterTypes(collectArgPos, collectArgPos+collectValCount);
1.510 + if (!retainOriginalArgs) { // (a..., b...)=>r
1.511 + srcType = srcType.insertParameterTypes(collectArgPos, collectorType.parameterList());
1.512 + }
1.513 + // in arglist: [0: ...keep1 | cpos: collect... | cpos+cacount: keep2... ]
1.514 + // out arglist: [0: ...keep1 | cpos: collectVal? | cpos+cvcount: keep2... ]
1.515 + // out(retain): [0: ...keep1 | cpos: cV? coll... | cpos+cvc+cac: keep2... ]
1.516 +
1.517 + // Now build a LambdaForm.
1.518 + MethodType lambdaType = srcType.invokerType();
1.519 + Name[] names = arguments(2, lambdaType);
1.520 + final int collectNamePos = names.length - 2;
1.521 + final int targetNamePos = names.length - 1;
1.522 +
1.523 + Name[] collectorArgs = Arrays.copyOfRange(names, 1 + collectArgPos, 1 + collectArgPos + collectArgCount);
1.524 + names[collectNamePos] = new Name(collector, (Object[]) collectorArgs);
1.525 +
1.526 + // Build argument array for the target.
1.527 + // Incoming LF args to copy are: [ (mh) headArgs collectArgs tailArgs ].
1.528 + // Output argument array is [ headArgs (collectVal)? (collectArgs)? tailArgs ].
1.529 + Name[] targetArgs = new Name[targetType.parameterCount()];
1.530 + int inputArgPos = 1; // incoming LF args to copy to target
1.531 + int targetArgPos = 0; // fill pointer for targetArgs
1.532 + int chunk = collectArgPos; // |headArgs|
1.533 + System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk);
1.534 + inputArgPos += chunk;
1.535 + targetArgPos += chunk;
1.536 + if (collectValType != void.class) {
1.537 + targetArgs[targetArgPos++] = names[collectNamePos];
1.538 + }
1.539 + chunk = collectArgCount;
1.540 + if (retainOriginalArgs) {
1.541 + System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk);
1.542 + targetArgPos += chunk; // optionally pass on the collected chunk
1.543 + }
1.544 + inputArgPos += chunk;
1.545 + chunk = targetArgs.length - targetArgPos; // all the rest
1.546 + System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk);
1.547 + assert(inputArgPos + chunk == collectNamePos); // use of rest of input args also
1.548 + names[targetNamePos] = new Name(target, (Object[]) targetArgs);
1.549 +
1.550 + LambdaForm form = new LambdaForm("collect", lambdaType.parameterCount(), names);
1.551 + return SimpleMethodHandle.make(srcType, form);
1.552 + }
1.553 +
1.554 + static
1.555 + MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) {
1.556 + return testResult ? target : fallback;
1.557 + }
1.558 +
1.559 + static MethodHandle SELECT_ALTERNATIVE;
1.560 + static MethodHandle selectAlternative() {
1.561 + if (SELECT_ALTERNATIVE != null) return SELECT_ALTERNATIVE;
1.562 + try {
1.563 + SELECT_ALTERNATIVE
1.564 + = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "selectAlternative",
1.565 + MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class));
1.566 + } catch (ReflectiveOperationException ex) {
1.567 + throw new RuntimeException(ex);
1.568 + }
1.569 + return SELECT_ALTERNATIVE;
1.570 + }
1.571 +
1.572 + static
1.573 + MethodHandle makeGuardWithTest(MethodHandle test,
1.574 + MethodHandle target,
1.575 + MethodHandle fallback) {
1.576 + MethodType basicType = target.type().basicType();
1.577 + MethodHandle invokeBasic = MethodHandles.basicInvoker(basicType);
1.578 + int arity = basicType.parameterCount();
1.579 + int extraNames = 3;
1.580 + MethodType lambdaType = basicType.invokerType();
1.581 + Name[] names = arguments(extraNames, lambdaType);
1.582 +
1.583 + Object[] testArgs = Arrays.copyOfRange(names, 1, 1 + arity, Object[].class);
1.584 + Object[] targetArgs = Arrays.copyOfRange(names, 0, 1 + arity, Object[].class);
1.585 +
1.586 + // call test
1.587 + names[arity + 1] = new Name(test, testArgs);
1.588 +
1.589 + // call selectAlternative
1.590 + Object[] selectArgs = { names[arity + 1], target, fallback };
1.591 + names[arity + 2] = new Name(MethodHandleImpl.selectAlternative(), selectArgs);
1.592 + targetArgs[0] = names[arity + 2];
1.593 +
1.594 + // call target or fallback
1.595 + names[arity + 3] = new Name(new NamedFunction(invokeBasic), targetArgs);
1.596 +
1.597 + LambdaForm form = new LambdaForm("guard", lambdaType.parameterCount(), names);
1.598 + return SimpleMethodHandle.make(target.type(), form);
1.599 + }
1.600 +
1.601 + private static class GuardWithCatch {
1.602 + private final MethodHandle target;
1.603 + private final Class<? extends Throwable> exType;
1.604 + private final MethodHandle catcher;
1.605 + // FIXME: Build the control flow out of foldArguments.
1.606 + GuardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
1.607 + this.target = target;
1.608 + this.exType = exType;
1.609 + this.catcher = catcher;
1.610 + }
1.611 + @LambdaForm.Hidden
1.612 + private Object invoke_V(Object... av) throws Throwable {
1.613 + try {
1.614 + return target.invokeExact(av);
1.615 + } catch (Throwable t) {
1.616 + if (!exType.isInstance(t)) throw t;
1.617 + return catcher.invokeExact(t, av);
1.618 + }
1.619 + }
1.620 + @LambdaForm.Hidden
1.621 + private Object invoke_L0() throws Throwable {
1.622 + try {
1.623 + return target.invokeExact();
1.624 + } catch (Throwable t) {
1.625 + if (!exType.isInstance(t)) throw t;
1.626 + return catcher.invokeExact(t);
1.627 + }
1.628 + }
1.629 + @LambdaForm.Hidden
1.630 + private Object invoke_L1(Object a0) throws Throwable {
1.631 + try {
1.632 + return target.invokeExact(a0);
1.633 + } catch (Throwable t) {
1.634 + if (!exType.isInstance(t)) throw t;
1.635 + return catcher.invokeExact(t, a0);
1.636 + }
1.637 + }
1.638 + @LambdaForm.Hidden
1.639 + private Object invoke_L2(Object a0, Object a1) throws Throwable {
1.640 + try {
1.641 + return target.invokeExact(a0, a1);
1.642 + } catch (Throwable t) {
1.643 + if (!exType.isInstance(t)) throw t;
1.644 + return catcher.invokeExact(t, a0, a1);
1.645 + }
1.646 + }
1.647 + @LambdaForm.Hidden
1.648 + private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
1.649 + try {
1.650 + return target.invokeExact(a0, a1, a2);
1.651 + } catch (Throwable t) {
1.652 + if (!exType.isInstance(t)) throw t;
1.653 + return catcher.invokeExact(t, a0, a1, a2);
1.654 + }
1.655 + }
1.656 + @LambdaForm.Hidden
1.657 + private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
1.658 + try {
1.659 + return target.invokeExact(a0, a1, a2, a3);
1.660 + } catch (Throwable t) {
1.661 + if (!exType.isInstance(t)) throw t;
1.662 + return catcher.invokeExact(t, a0, a1, a2, a3);
1.663 + }
1.664 + }
1.665 + @LambdaForm.Hidden
1.666 + private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
1.667 + try {
1.668 + return target.invokeExact(a0, a1, a2, a3, a4);
1.669 + } catch (Throwable t) {
1.670 + if (!exType.isInstance(t)) throw t;
1.671 + return catcher.invokeExact(t, a0, a1, a2, a3, a4);
1.672 + }
1.673 + }
1.674 + @LambdaForm.Hidden
1.675 + private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
1.676 + try {
1.677 + return target.invokeExact(a0, a1, a2, a3, a4, a5);
1.678 + } catch (Throwable t) {
1.679 + if (!exType.isInstance(t)) throw t;
1.680 + return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5);
1.681 + }
1.682 + }
1.683 + @LambdaForm.Hidden
1.684 + private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
1.685 + try {
1.686 + return target.invokeExact(a0, a1, a2, a3, a4, a5, a6);
1.687 + } catch (Throwable t) {
1.688 + if (!exType.isInstance(t)) throw t;
1.689 + return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6);
1.690 + }
1.691 + }
1.692 + @LambdaForm.Hidden
1.693 + private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
1.694 + try {
1.695 + return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
1.696 + } catch (Throwable t) {
1.697 + if (!exType.isInstance(t)) throw t;
1.698 + return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6, a7);
1.699 + }
1.700 + }
1.701 + static MethodHandle[] makeInvokes() {
1.702 + ArrayList<MethodHandle> invokes = new ArrayList<>();
1.703 + MethodHandles.Lookup lookup = IMPL_LOOKUP;
1.704 + for (;;) {
1.705 + int nargs = invokes.size();
1.706 + String name = "invoke_L"+nargs;
1.707 + MethodHandle invoke = null;
1.708 + try {
1.709 + invoke = lookup.findVirtual(GuardWithCatch.class, name, MethodType.genericMethodType(nargs));
1.710 + } catch (ReflectiveOperationException ex) {
1.711 + }
1.712 + if (invoke == null) break;
1.713 + invokes.add(invoke);
1.714 + }
1.715 + assert(invokes.size() == 9); // current number of methods
1.716 + return invokes.toArray(new MethodHandle[0]);
1.717 + };
1.718 + static final MethodHandle[] INVOKES = makeInvokes();
1.719 + // For testing use this:
1.720 + //static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2);
1.721 + static final MethodHandle VARARGS_INVOKE;
1.722 + static {
1.723 + try {
1.724 + VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(GuardWithCatch.class, "invoke_V", MethodType.genericMethodType(0, true));
1.725 + } catch (ReflectiveOperationException ex) {
1.726 + throw uncaughtException(ex);
1.727 + }
1.728 + }
1.729 + }
1.730 +
1.731 +
1.732 + static
1.733 + MethodHandle makeGuardWithCatch(MethodHandle target,
1.734 + Class<? extends Throwable> exType,
1.735 + MethodHandle catcher) {
1.736 + MethodType type = target.type();
1.737 + MethodType ctype = catcher.type();
1.738 + int nargs = type.parameterCount();
1.739 + if (nargs < GuardWithCatch.INVOKES.length) {
1.740 + MethodType gtype = type.generic();
1.741 + MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
1.742 + // Note: convertArguments(...2) avoids interface casts present in convertArguments(...0)
1.743 + MethodHandle gtarget = makePairwiseConvert(target, gtype, 2);
1.744 + MethodHandle gcatcher = makePairwiseConvert(catcher, gcatchType, 2);
1.745 + GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher);
1.746 + if (gtarget == null || gcatcher == null) throw new InternalError();
1.747 + MethodHandle ginvoker = GuardWithCatch.INVOKES[nargs].bindReceiver(gguard);
1.748 + return makePairwiseConvert(ginvoker, type, 2);
1.749 + } else {
1.750 + target = target.asType(type.changeReturnType(Object.class));
1.751 + MethodHandle gtarget = makeSpreadArguments(target, Object[].class, 0, nargs);
1.752 + MethodType catcherType = ctype.changeParameterType(0, Throwable.class)
1.753 + .changeReturnType(Object.class);
1.754 + catcher = catcher.asType(catcherType);
1.755 + MethodHandle gcatcher = makeSpreadArguments(catcher, Object[].class, 1, nargs);
1.756 + GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher);
1.757 + if (gtarget == null || gcatcher == null) throw new InternalError();
1.758 + MethodHandle ginvoker = GuardWithCatch.VARARGS_INVOKE.bindReceiver(gguard);
1.759 + MethodHandle gcollect = makeCollectArguments(ginvoker, ValueConversions.varargsArray(nargs), 0, false);
1.760 + return makePairwiseConvert(gcollect, type, 2);
1.761 + }
1.762 + }
1.763 +
1.764 + static
1.765 + MethodHandle throwException(MethodType type) {
1.766 + assert(Throwable.class.isAssignableFrom(type.parameterType(0)));
1.767 + int arity = type.parameterCount();
1.768 + if (arity > 1) {
1.769 + return throwException(type.dropParameterTypes(1, arity)).dropArguments(type, 1, arity-1);
1.770 + }
1.771 + return makePairwiseConvert(throwException(), type, 2);
1.772 + }
1.773 +
1.774 + static MethodHandle THROW_EXCEPTION;
1.775 + static MethodHandle throwException() {
1.776 + MethodHandle mh = THROW_EXCEPTION;
1.777 + if (mh != null) return mh;
1.778 + try {
1.779 + mh
1.780 + = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException",
1.781 + MethodType.methodType(Empty.class, Throwable.class));
1.782 + } catch (ReflectiveOperationException ex) {
1.783 + throw new RuntimeException(ex);
1.784 + }
1.785 + THROW_EXCEPTION = mh;
1.786 + return mh;
1.787 + }
1.788 + static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
1.789 +
1.790 + static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2];
1.791 + static MethodHandle fakeMethodHandleInvoke(MemberName method) {
1.792 + int idx;
1.793 + assert(method.isMethodHandleInvoke());
1.794 + switch (method.getName()) {
1.795 + case "invoke": idx = 0; break;
1.796 + case "invokeExact": idx = 1; break;
1.797 + default: throw new InternalError(method.getName());
1.798 + }
1.799 + MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE[idx];
1.800 + if (mh != null) return mh;
1.801 + MethodType type = MethodType.methodType(Object.class, UnsupportedOperationException.class,
1.802 + MethodHandle.class, Object[].class);
1.803 + mh = throwException(type);
1.804 + mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle"));
1.805 + if (!method.getInvocationType().equals(mh.type()))
1.806 + throw new InternalError(method.toString());
1.807 + mh = mh.withInternalMemberName(method);
1.808 + mh = mh.asVarargsCollector(Object[].class);
1.809 + assert(method.isVarargs());
1.810 + FAKE_METHOD_HANDLE_INVOKE[idx] = mh;
1.811 + return mh;
1.812 + }
1.813 +
1.814 + /**
1.815 + * Create an alias for the method handle which, when called,
1.816 + * appears to be called from the same class loader and protection domain
1.817 + * as hostClass.
1.818 + * This is an expensive no-op unless the method which is called
1.819 + * is sensitive to its caller. A small number of system methods
1.820 + * are in this category, including Class.forName and Method.invoke.
1.821 + */
1.822 + static
1.823 + MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) {
1.824 + return BindCaller.bindCaller(mh, hostClass);
1.825 + }
1.826 +
1.827 + // Put the whole mess into its own nested class.
1.828 + // That way we can lazily load the code and set up the constants.
1.829 + private static class BindCaller {
1.830 + static
1.831 + MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) {
1.832 + // Do not use this function to inject calls into system classes.
1.833 + if (hostClass == null
1.834 + || (hostClass.isArray() ||
1.835 + hostClass.isPrimitive() ||
1.836 + hostClass.getName().startsWith("java.") ||
1.837 + hostClass.getName().startsWith("sun."))) {
1.838 + throw new InternalError(); // does not happen, and should not anyway
1.839 + }
1.840 + // For simplicity, convert mh to a varargs-like method.
1.841 + MethodHandle vamh = prepareForInvoker(mh);
1.842 + // Cache the result of makeInjectedInvoker once per argument class.
1.843 + MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass);
1.844 + return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName(), hostClass);
1.845 + }
1.846 +
1.847 + private static MethodHandle makeInjectedInvoker(Class<?> hostClass) {
1.848 + Class<?> bcc = UNSAFE.defineAnonymousClass(hostClass, T_BYTES, null);
1.849 + if (hostClass.getClassLoader() != bcc.getClassLoader())
1.850 + throw new InternalError(hostClass.getName()+" (CL)");
1.851 + try {
1.852 + if (hostClass.getProtectionDomain() != bcc.getProtectionDomain())
1.853 + throw new InternalError(hostClass.getName()+" (PD)");
1.854 + } catch (SecurityException ex) {
1.855 + // Self-check was blocked by security manager. This is OK.
1.856 + // In fact the whole try body could be turned into an assertion.
1.857 + }
1.858 + try {
1.859 + MethodHandle init = IMPL_LOOKUP.findStatic(bcc, "init", MethodType.methodType(void.class));
1.860 + init.invokeExact(); // force initialization of the class
1.861 + } catch (Throwable ex) {
1.862 + throw uncaughtException(ex);
1.863 + }
1.864 + MethodHandle bccInvoker;
1.865 + try {
1.866 + MethodType invokerMT = MethodType.methodType(Object.class, MethodHandle.class, Object[].class);
1.867 + bccInvoker = IMPL_LOOKUP.findStatic(bcc, "invoke_V", invokerMT);
1.868 + } catch (ReflectiveOperationException ex) {
1.869 + throw uncaughtException(ex);
1.870 + }
1.871 + // Test the invoker, to ensure that it really injects into the right place.
1.872 + try {
1.873 + MethodHandle vamh = prepareForInvoker(MH_checkCallerClass);
1.874 + Object ok = bccInvoker.invokeExact(vamh, new Object[]{hostClass, bcc});
1.875 + } catch (Throwable ex) {
1.876 + throw new InternalError(ex);
1.877 + }
1.878 + return bccInvoker;
1.879 + }
1.880 + private static ClassValue<MethodHandle> CV_makeInjectedInvoker = new ClassValue<MethodHandle>() {
1.881 + @Override protected MethodHandle computeValue(Class<?> hostClass) {
1.882 + return makeInjectedInvoker(hostClass);
1.883 + }
1.884 + };
1.885 +
1.886 + // Adapt mh so that it can be called directly from an injected invoker:
1.887 + private static MethodHandle prepareForInvoker(MethodHandle mh) {
1.888 + mh = mh.asFixedArity();
1.889 + MethodType mt = mh.type();
1.890 + int arity = mt.parameterCount();
1.891 + MethodHandle vamh = mh.asType(mt.generic());
1.892 + vamh.internalForm().compileToBytecode(); // eliminate LFI stack frames
1.893 + vamh = vamh.asSpreader(Object[].class, arity);
1.894 + vamh.internalForm().compileToBytecode(); // eliminate LFI stack frames
1.895 + return vamh;
1.896 + }
1.897 +
1.898 + // Undo the adapter effect of prepareForInvoker:
1.899 + private static MethodHandle restoreToType(MethodHandle vamh, MethodType type,
1.900 + MemberName member,
1.901 + Class<?> hostClass) {
1.902 + MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount());
1.903 + mh = mh.asType(type);
1.904 + mh = new WrappedMember(mh, type, member, hostClass);
1.905 + return mh;
1.906 + }
1.907 +
1.908 + private static final MethodHandle MH_checkCallerClass;
1.909 + static {
1.910 + final Class<?> THIS_CLASS = BindCaller.class;
1.911 + assert(checkCallerClass(THIS_CLASS, THIS_CLASS));
1.912 + try {
1.913 + MH_checkCallerClass = IMPL_LOOKUP
1.914 + .findStatic(THIS_CLASS, "checkCallerClass",
1.915 + MethodType.methodType(boolean.class, Class.class, Class.class));
1.916 + assert((boolean) MH_checkCallerClass.invokeExact(THIS_CLASS, THIS_CLASS));
1.917 + } catch (Throwable ex) {
1.918 + throw new InternalError(ex);
1.919 + }
1.920 + }
1.921 +
1.922 + @CallerSensitive
1.923 + private static boolean checkCallerClass(Class<?> expected, Class<?> expected2) {
1.924 + // This method is called via MH_checkCallerClass and so it's
1.925 + // correct to ask for the immediate caller here.
1.926 + Class<?> actual = Reflection.getCallerClass();
1.927 + if (actual != expected && actual != expected2)
1.928 + throw new InternalError("found "+actual.getName()+", expected "+expected.getName()
1.929 + +(expected == expected2 ? "" : ", or else "+expected2.getName()));
1.930 + return true;
1.931 + }
1.932 +
1.933 + private static final byte[] T_BYTES;
1.934 + static {
1.935 + final Object[] values = {null};
1.936 + AccessController.doPrivileged(new PrivilegedAction<Void>() {
1.937 + public Void run() {
1.938 + try {
1.939 + Class<T> tClass = T.class;
1.940 + String tName = tClass.getName();
1.941 + String tResource = tName.substring(tName.lastIndexOf('.')+1)+".class";
1.942 + java.net.URLConnection uconn = tClass.getResource(tResource).openConnection();
1.943 + int len = uconn.getContentLength();
1.944 + byte[] bytes = new byte[len];
1.945 + try (java.io.InputStream str = uconn.getInputStream()) {
1.946 + int nr = str.read(bytes);
1.947 + if (nr != len) throw new java.io.IOException(tResource);
1.948 + }
1.949 + values[0] = bytes;
1.950 + } catch (java.io.IOException ex) {
1.951 + throw new InternalError(ex);
1.952 + }
1.953 + return null;
1.954 + }
1.955 + });
1.956 + T_BYTES = (byte[]) values[0];
1.957 + }
1.958 +
1.959 + // The following class is used as a template for Unsafe.defineAnonymousClass:
1.960 + private static class T {
1.961 + static void init() { } // side effect: initializes this class
1.962 + static Object invoke_V(MethodHandle vamh, Object[] args) throws Throwable {
1.963 + return vamh.invokeExact(args);
1.964 + }
1.965 + }
1.966 + }
1.967 +
1.968 +
1.969 + /** This subclass allows a wrapped method handle to be re-associated with an arbitrary member name. */
1.970 + static class WrappedMember extends MethodHandle {
1.971 + private final MethodHandle target;
1.972 + private final MemberName member;
1.973 + private final Class<?> callerClass;
1.974 +
1.975 + private WrappedMember(MethodHandle target, MethodType type, MemberName member, Class<?> callerClass) {
1.976 + super(type, reinvokerForm(target));
1.977 + this.target = target;
1.978 + this.member = member;
1.979 + this.callerClass = callerClass;
1.980 + }
1.981 +
1.982 + @Override
1.983 + MethodHandle reinvokerTarget() {
1.984 + return target;
1.985 + }
1.986 + @Override
1.987 + public MethodHandle asTypeUncached(MethodType newType) {
1.988 + // This MH is an alias for target, except for the MemberName
1.989 + // Drop the MemberName if there is any conversion.
1.990 + return asTypeCache = target.asType(newType);
1.991 + }
1.992 + @Override
1.993 + MemberName internalMemberName() {
1.994 + return member;
1.995 + }
1.996 + @Override
1.997 + Class<?> internalCallerClass() {
1.998 + return callerClass;
1.999 + }
1.1000 + @Override
1.1001 + boolean isInvokeSpecial() {
1.1002 + return target.isInvokeSpecial();
1.1003 + }
1.1004 + @Override
1.1005 + MethodHandle viewAsType(MethodType newType) {
1.1006 + return new WrappedMember(target, newType, member, callerClass);
1.1007 + }
1.1008 + }
1.1009 +
1.1010 + static MethodHandle makeWrappedMember(MethodHandle target, MemberName member) {
1.1011 + if (member.equals(target.internalMemberName()))
1.1012 + return target;
1.1013 + return new WrappedMember(target, target.type(), member, null);
1.1014 + }
1.1015 +
1.1016 +}