From 9199c1747e59a4cfcc5c701186de09b2fef94e6b Mon Sep 17 00:00:00 2001 From: jrose Date: Fri, 18 Mar 2011 00:03:24 -0700 Subject: [PATCH] 6839872: remove implementation inheritance from JSR 292 APIs Summary: move everything into a single package; remove all multi-package machinery Reviewed-by: twisti, forax --- .../dyn/AdapterMethodHandle.java | 129 ++--- .../{sun => java}/dyn/BoundMethodHandle.java | 50 +- src/share/classes/java/dyn/CallSite.java | 113 +++- src/share/classes/java/dyn/ClassValue.java | 2 - .../{sun => java}/dyn/DirectMethodHandle.java | 9 +- .../{sun => java}/dyn/FilterGeneric.java | 18 +- .../{sun => java}/dyn/FilterOneArgument.java | 16 +- .../{sun => java}/dyn/FromGeneric.java | 31 +- src/share/classes/java/dyn/InvokeDynamic.java | 2 +- .../{sun => java}/dyn/InvokeGeneric.java | 32 +- .../classes/{sun => java}/dyn/Invokers.java | 26 +- src/share/classes/java/dyn/Linkage.java | 14 +- .../classes/{sun => java}/dyn/MemberName.java | 65 +-- src/share/classes/java/dyn/MethodHandle.java | 75 ++- .../{sun => java}/dyn/MethodHandleImpl.java | 370 ++++--------- .../dyn/MethodHandleNatives.java | 67 +-- .../classes/java/dyn/MethodHandleStatics.java | 92 ++++ src/share/classes/java/dyn/MethodHandles.java | 118 ++-- src/share/classes/java/dyn/MethodType.java | 74 +-- .../classes/java/dyn/MethodTypeForm.java | 449 ++++++++++++++- .../classes/java/dyn/MutableCallSite.java | 2 - .../{sun => java}/dyn/SpreadGeneric.java | 24 +- .../classes/{sun => java}/dyn/ToGeneric.java | 43 +- .../classes/java/dyn/VolatileCallSite.java | 2 - .../java/dyn/WrongMethodTypeException.java | 2 +- src/share/classes/sun/dyn/Access.java | 109 ---- src/share/classes/sun/dyn/CallSiteImpl.java | 141 ----- src/share/classes/sun/dyn/MethodTypeImpl.java | 516 ------------------ .../sun/dyn/util/ValueConversions.java | 72 +-- .../classes/sun/dyn/util/VerifyAccess.java | 3 - test/java/dyn/6987555/Test6987555.java | 177 ++++++ test/java/dyn/6991596/Test6991596.java | 465 ++++++++++++++++ test/java/dyn/MethodTypeTest.java | 13 - 33 files changed, 1758 insertions(+), 1563 deletions(-) rename src/share/classes/{sun => java}/dyn/AdapterMethodHandle.java (89%) rename src/share/classes/{sun => java}/dyn/BoundMethodHandle.java (81%) rename src/share/classes/{sun => java}/dyn/DirectMethodHandle.java (91%) rename src/share/classes/{sun => java}/dyn/FilterGeneric.java (99%) rename src/share/classes/{sun => java}/dyn/FilterOneArgument.java (86%) rename src/share/classes/{sun => java}/dyn/FromGeneric.java (97%) rename src/share/classes/{sun => java}/dyn/InvokeGeneric.java (86%) rename src/share/classes/{sun => java}/dyn/Invokers.java (87%) rename src/share/classes/{sun => java}/dyn/MemberName.java (93%) rename src/share/classes/{sun => java}/dyn/MethodHandleImpl.java (78%) rename src/share/classes/{sun => java}/dyn/MethodHandleNatives.java (91%) create mode 100644 src/share/classes/java/dyn/MethodHandleStatics.java rename src/share/classes/{sun => java}/dyn/SpreadGeneric.java (98%) rename src/share/classes/{sun => java}/dyn/ToGeneric.java (98%) delete mode 100644 src/share/classes/sun/dyn/Access.java delete mode 100644 src/share/classes/sun/dyn/CallSiteImpl.java delete mode 100644 src/share/classes/sun/dyn/MethodTypeImpl.java create mode 100644 test/java/dyn/6987555/Test6987555.java create mode 100644 test/java/dyn/6991596/Test6991596.java diff --git a/src/share/classes/sun/dyn/AdapterMethodHandle.java b/src/share/classes/java/dyn/AdapterMethodHandle.java similarity index 89% rename from src/share/classes/sun/dyn/AdapterMethodHandle.java rename to src/share/classes/java/dyn/AdapterMethodHandle.java index 676907c91..98d5c32c4 100644 --- a/src/share/classes/sun/dyn/AdapterMethodHandle.java +++ b/src/share/classes/java/dyn/AdapterMethodHandle.java @@ -23,20 +23,19 @@ * questions. */ -package sun.dyn; +package java.dyn; import sun.dyn.util.VerifyType; import sun.dyn.util.Wrapper; -import java.dyn.*; import java.util.Arrays; -import static sun.dyn.MethodHandleNatives.Constants.*; -import static sun.dyn.MemberName.newIllegalArgumentException; +import static java.dyn.MethodHandleNatives.Constants.*; +import static java.dyn.MethodHandleStatics.*; /** * This method handle performs simple conversion or checking of a single argument. * @author jrose */ -public class AdapterMethodHandle extends BoundMethodHandle { +class AdapterMethodHandle extends BoundMethodHandle { //MethodHandle vmtarget; // next AMH or BMH in chain or final DMH //Object argument; // parameter to the conversion if needed @@ -48,25 +47,21 @@ public class AdapterMethodHandle extends BoundMethodHandle { long conv, Object convArg) { super(newType, convArg, newType.parameterSlotDepth(1+convArgPos(conv))); this.conversion = convCode(conv); - if (MethodHandleNatives.JVM_SUPPORT) { - // JVM might update VM-specific bits of conversion (ignore) - MethodHandleNatives.init(this, target, convArgPos(conv)); - } + // JVM might update VM-specific bits of conversion (ignore) + MethodHandleNatives.init(this, target, convArgPos(conv)); } private AdapterMethodHandle(MethodHandle target, MethodType newType, long conv) { this(target, newType, conv, null); } - private static final Access IMPL_TOKEN = Access.getToken(); - // TO DO: When adapting another MH with a null conversion, clone // the target and change its type, instead of adding another layer. /** Can a JVM-level adapter directly implement the proposed * argument conversions, as if by MethodHandles.convertArguments? */ - public static boolean canPairwiseConvert(MethodType newType, MethodType oldType) { + static boolean canPairwiseConvert(MethodType newType, MethodType oldType) { // same number of args, of course int len = newType.parameterCount(); if (len != oldType.parameterCount()) @@ -92,7 +87,7 @@ public class AdapterMethodHandle extends BoundMethodHandle { /** Can a JVM-level adapter directly implement the proposed * argument conversion, as if by MethodHandles.convertArguments? */ - public static boolean canConvertArgument(Class src, Class dst) { + static boolean canConvertArgument(Class src, Class dst) { // ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes, // so we don't need to repeat so much decision making. if (VerifyType.isNullConversion(src, dst)) { @@ -118,16 +113,13 @@ public class AdapterMethodHandle extends BoundMethodHandle { * the JVM supports ricochet adapters). * The argument conversions allowed are casting, unboxing, * integral widening or narrowing, and floating point widening or narrowing. - * @param token access check * @param newType required call type * @param target original method handle * @return an adapter to the original handle with the desired new type, * or the original target if the types are already identical * or null if the adaptation cannot be made */ - public static MethodHandle makePairwiseConvert(Access token, - MethodType newType, MethodHandle target) { - Access.check(token); + static MethodHandle makePairwiseConvert(MethodType newType, MethodHandle target) { MethodType oldType = target.type(); if (newType == oldType) return target; @@ -170,9 +162,9 @@ public class AdapterMethodHandle extends BoundMethodHandle { // It parallels canConvertArgument() above. if (src.isPrimitive()) { if (dst.isPrimitive()) { - adapter = makePrimCast(token, midType, adapter, i, dst); + adapter = makePrimCast(midType, adapter, i, dst); } else { - adapter = makeBoxArgument(token, midType, adapter, i, dst); + adapter = makeBoxArgument(midType, adapter, i, dst); } } else { if (dst.isPrimitive()) { @@ -182,13 +174,13 @@ public class AdapterMethodHandle extends BoundMethodHandle { // conversions supported by reflect.Method.invoke. // Those conversions require a big nest of if/then/else logic, // which we prefer to make a user responsibility. - adapter = makeUnboxArgument(token, midType, adapter, i, dst); + adapter = makeUnboxArgument(midType, adapter, i, dst); } else { // Simple reference conversion. // Note: Do not check for a class hierarchy relation // between src and dst. In all cases a 'null' argument // will pass the cast conversion. - adapter = makeCheckCast(token, midType, adapter, i, dst); + adapter = makeCheckCast(midType, adapter, i, dst); } } assert(adapter != null); @@ -196,7 +188,7 @@ public class AdapterMethodHandle extends BoundMethodHandle { } if (adapter.type() != newType) { // Only trivial conversions remain. - adapter = makeRetypeOnly(IMPL_TOKEN, newType, adapter); + adapter = makeRetypeOnly(newType, adapter); assert(adapter != null); // Actually, that's because there were no non-trivial ones: assert(lastConv == -1); @@ -208,7 +200,6 @@ public class AdapterMethodHandle extends BoundMethodHandle { /** * Create a JVM-level adapter method handle to permute the arguments * of the given method. - * @param token access check * @param newType required call type * @param target original method handle * @param argumentMap for each target argument, position of its source in newType @@ -218,8 +209,7 @@ public class AdapterMethodHandle extends BoundMethodHandle { * @throws IllegalArgumentException if the adaptation cannot be made * directly by a JVM-level adapter, without help from Java code */ - public static MethodHandle makePermutation(Access token, - MethodType newType, MethodHandle target, + static MethodHandle makePermutation(MethodType newType, MethodHandle target, int[] argumentMap) { MethodType oldType = target.type(); boolean nullPermutation = true; @@ -234,7 +224,7 @@ public class AdapterMethodHandle extends BoundMethodHandle { if (argumentMap.length != oldType.parameterCount()) throw newIllegalArgumentException("bad permutation: "+Arrays.toString(argumentMap)); if (nullPermutation) { - MethodHandle res = makePairwiseConvert(token, newType, target); + MethodHandle res = makePairwiseConvert(newType, target); // well, that was easy if (res == null) throw newIllegalArgumentException("cannot convert pairwise: "+newType); @@ -435,7 +425,7 @@ public class AdapterMethodHandle extends BoundMethodHandle { } /** Can a retyping adapter (alone) validly convert the target to newType? */ - public static boolean canRetypeOnly(MethodType newType, MethodType targetType) { + static boolean canRetypeOnly(MethodType newType, MethodType targetType) { return canRetype(newType, targetType, false); } /** Can a retyping adapter (alone) convert the target to newType? @@ -444,7 +434,7 @@ public class AdapterMethodHandle extends BoundMethodHandle { * reference conversions on return. This last feature requires that the * caller be trusted, and perform explicit cast conversions on return values. */ - public static boolean canRetypeRaw(MethodType newType, MethodType targetType) { + static boolean canRetypeRaw(MethodType newType, MethodType targetType) { return canRetype(newType, targetType, true); } static boolean canRetype(MethodType newType, MethodType targetType, boolean raw) { @@ -459,17 +449,13 @@ public class AdapterMethodHandle extends BoundMethodHandle { * Allows unchecked argument conversions pairwise, if they are safe. * Returns null if not possible. */ - public static MethodHandle makeRetypeOnly(Access token, - MethodType newType, MethodHandle target) { - return makeRetype(token, newType, target, false); + static MethodHandle makeRetypeOnly(MethodType newType, MethodHandle target) { + return makeRetype(newType, target, false); } - public static MethodHandle makeRetypeRaw(Access token, - MethodType newType, MethodHandle target) { - return makeRetype(token, newType, target, true); + static MethodHandle makeRetypeRaw(MethodType newType, MethodHandle target) { + return makeRetype(newType, target, true); } - static MethodHandle makeRetype(Access token, - MethodType newType, MethodHandle target, boolean raw) { - Access.check(token); + static MethodHandle makeRetype(MethodType newType, MethodHandle target, boolean raw) { MethodType oldType = target.type(); if (oldType == newType) return target; if (!canRetype(newType, oldType, raw)) @@ -478,9 +464,7 @@ public class AdapterMethodHandle extends BoundMethodHandle { return new AdapterMethodHandle(target, newType, makeConv(raw ? OP_RETYPE_RAW : OP_RETYPE_ONLY)); } - static MethodHandle makeVarargsCollector(Access token, - MethodHandle target, Class arrayType) { - Access.check(token); + static MethodHandle makeVarargsCollector(MethodHandle target, Class arrayType) { return new AsVarargsCollector(target, arrayType); } @@ -526,6 +510,7 @@ public class AdapterMethodHandle extends BoundMethodHandle { return collector.asType(newType); } + @Override public MethodHandle asVarargsCollector(Class arrayType) { MethodType type = this.type(); if (type.parameterType(type.parameterCount()-1) == arrayType) @@ -537,7 +522,7 @@ public class AdapterMethodHandle extends BoundMethodHandle { /** Can a checkcast adapter validly convert the target to newType? * The JVM supports all kind of reference casts, even silly ones. */ - public static boolean canCheckCast(MethodType newType, MethodType targetType, + static boolean canCheckCast(MethodType newType, MethodType targetType, int arg, Class castType) { if (!convOpSupported(OP_CHECK_CAST)) return false; Class src = newType.parameterType(arg); @@ -549,7 +534,7 @@ public class AdapterMethodHandle extends BoundMethodHandle { return (diff == arg+1); // arg is sole non-trivial diff } /** Can an primitive conversion adapter validly convert src to dst? */ - public static boolean canCheckCast(Class src, Class dst) { + static boolean canCheckCast(Class src, Class dst) { return (!src.isPrimitive() && !dst.isPrimitive()); } @@ -558,10 +543,8 @@ public class AdapterMethodHandle extends BoundMethodHandle { * with a null conversion to the corresponding target parameter. * Return null if this cannot be done. */ - public static MethodHandle makeCheckCast(Access token, - MethodType newType, MethodHandle target, + static MethodHandle makeCheckCast(MethodType newType, MethodHandle target, int arg, Class castType) { - Access.check(token); if (!canCheckCast(newType, target.type(), arg, castType)) return null; long conv = makeConv(OP_CHECK_CAST, arg, T_OBJECT, T_OBJECT); @@ -572,7 +555,7 @@ public class AdapterMethodHandle extends BoundMethodHandle { * The JVM currently supports all conversions except those between * floating and integral types. */ - public static boolean canPrimCast(MethodType newType, MethodType targetType, + static boolean canPrimCast(MethodType newType, MethodType targetType, int arg, Class convType) { if (!convOpSupported(OP_PRIM_TO_PRIM)) return false; Class src = newType.parameterType(arg); @@ -584,7 +567,7 @@ public class AdapterMethodHandle extends BoundMethodHandle { return (diff == arg+1); // arg is sole non-trivial diff } /** Can an primitive conversion adapter validly convert src to dst? */ - public static boolean canPrimCast(Class src, Class dst) { + static boolean canPrimCast(Class src, Class dst) { if (src == dst || !src.isPrimitive() || !dst.isPrimitive()) { return false; } else if (Wrapper.forPrimitiveType(dst).isFloating()) { @@ -604,10 +587,8 @@ public class AdapterMethodHandle extends BoundMethodHandle { * with a null conversion to the corresponding target parameter. * Return null if this cannot be done. */ - public static MethodHandle makePrimCast(Access token, - MethodType newType, MethodHandle target, + static MethodHandle makePrimCast(MethodType newType, MethodHandle target, int arg, Class convType) { - Access.check(token); MethodType oldType = target.type(); if (!canPrimCast(newType, oldType, arg, convType)) return null; @@ -620,7 +601,7 @@ public class AdapterMethodHandle extends BoundMethodHandle { * The JVM currently supports all kinds of casting and unboxing. * The convType is the unboxed type; it can be either a primitive or wrapper. */ - public static boolean canUnboxArgument(MethodType newType, MethodType targetType, + static boolean canUnboxArgument(MethodType newType, MethodType targetType, int arg, Class convType) { if (!convOpSupported(OP_REF_TO_PRIM)) return false; Class src = newType.parameterType(arg); @@ -635,15 +616,14 @@ public class AdapterMethodHandle extends BoundMethodHandle { return (diff == arg+1); // arg is sole non-trivial diff } /** Can an primitive unboxing adapter validly convert src to dst? */ - public static boolean canUnboxArgument(Class src, Class dst) { + static boolean canUnboxArgument(Class src, Class dst) { return (!src.isPrimitive() && Wrapper.asPrimitiveType(dst).isPrimitive()); } /** Factory method: Unbox the given argument. * Return null if this cannot be done. */ - public static MethodHandle makeUnboxArgument(Access token, - MethodType newType, MethodHandle target, + static MethodHandle makeUnboxArgument(MethodType newType, MethodHandle target, int arg, Class convType) { MethodType oldType = target.type(); Class src = newType.parameterType(arg); @@ -659,11 +639,11 @@ public class AdapterMethodHandle extends BoundMethodHandle { MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType); if (castDone == newType) return adapter; - return makeCheckCast(token, newType, adapter, arg, boxType); + return makeCheckCast(newType, adapter, arg, boxType); } /** Can an primitive boxing adapter validly convert src to dst? */ - public static boolean canBoxArgument(Class src, Class dst) { + static boolean canBoxArgument(Class src, Class dst) { if (!convOpSupported(OP_PRIM_TO_REF)) return false; throw new UnsupportedOperationException("NYI"); } @@ -671,15 +651,14 @@ public class AdapterMethodHandle extends BoundMethodHandle { /** Factory method: Unbox the given argument. * Return null if this cannot be done. */ - public static MethodHandle makeBoxArgument(Access token, - MethodType newType, MethodHandle target, + static MethodHandle makeBoxArgument(MethodType newType, MethodHandle target, int arg, Class convType) { // this is difficult to do in the JVM because it must GC return null; } /** Can an adapter simply drop arguments to convert the target to newType? */ - public static boolean canDropArguments(MethodType newType, MethodType targetType, + static boolean canDropArguments(MethodType newType, MethodType targetType, int dropArgPos, int dropArgCount) { if (dropArgCount == 0) return canRetypeOnly(newType, targetType); @@ -706,12 +685,10 @@ public class AdapterMethodHandle extends BoundMethodHandle { * Allow unchecked retyping of remaining arguments, pairwise. * Return null if this is not possible. */ - public static MethodHandle makeDropArguments(Access token, - MethodType newType, MethodHandle target, + static MethodHandle makeDropArguments(MethodType newType, MethodHandle target, int dropArgPos, int dropArgCount) { - Access.check(token); if (dropArgCount == 0) - return makeRetypeOnly(IMPL_TOKEN, newType, target); + return makeRetypeOnly(newType, target); if (!canDropArguments(newType, target.type(), dropArgPos, dropArgCount)) return null; // in arglist: [0: ...keep1 | dpos: drop... | dpos+dcount: keep2... ] @@ -727,7 +704,7 @@ public class AdapterMethodHandle extends BoundMethodHandle { } /** Can an adapter duplicate an argument to convert the target to newType? */ - public static boolean canDupArguments(MethodType newType, MethodType targetType, + static boolean canDupArguments(MethodType newType, MethodType targetType, int dupArgPos, int dupArgCount) { if (!convOpSupported(OP_DUP_ARGS)) return false; if (diffReturnTypes(newType, targetType, false) != 0) @@ -749,10 +726,8 @@ public class AdapterMethodHandle extends BoundMethodHandle { /** Factory method: Duplicate the selected argument. * Return null if this is not possible. */ - public static MethodHandle makeDupArguments(Access token, - MethodType newType, MethodHandle target, + static MethodHandle makeDupArguments(MethodType newType, MethodHandle target, int dupArgPos, int dupArgCount) { - Access.check(token); if (!canDupArguments(newType, target.type(), dupArgPos, dupArgCount)) return null; if (dupArgCount == 0) @@ -769,7 +744,7 @@ public class AdapterMethodHandle extends BoundMethodHandle { } /** Can an adapter swap two arguments to convert the target to newType? */ - public static boolean canSwapArguments(MethodType newType, MethodType targetType, + static boolean canSwapArguments(MethodType newType, MethodType targetType, int swapArg1, int swapArg2) { if (!convOpSupported(OP_SWAP_ARGS)) return false; if (diffReturnTypes(newType, targetType, false) != 0) @@ -796,10 +771,8 @@ public class AdapterMethodHandle extends BoundMethodHandle { /** Factory method: Swap the selected arguments. * Return null if this is not possible. */ - public static MethodHandle makeSwapArguments(Access token, - MethodType newType, MethodHandle target, + static MethodHandle makeSwapArguments(MethodType newType, MethodHandle target, int swapArg1, int swapArg2) { - Access.check(token); if (swapArg1 == swapArg2) return target; if (swapArg1 > swapArg2) { int t = swapArg1; swapArg1 = swapArg2; swapArg2 = t; } @@ -829,7 +802,7 @@ public class AdapterMethodHandle extends BoundMethodHandle { final static int MAX_ARG_ROTATION = 1; /** Can an adapter rotate arguments to convert the target to newType? */ - public static boolean canRotateArguments(MethodType newType, MethodType targetType, + static boolean canRotateArguments(MethodType newType, MethodType targetType, int firstArg, int argCount, int rotateBy) { if (!convOpSupported(OP_ROT_ARGS)) return false; if (argCount <= 2) return false; // must be a swap, not a rotate @@ -861,10 +834,8 @@ public class AdapterMethodHandle extends BoundMethodHandle { /** Factory method: Rotate the selected argument range. * Return null if this is not possible. */ - public static MethodHandle makeRotateArguments(Access token, - MethodType newType, MethodHandle target, + static MethodHandle makeRotateArguments(MethodType newType, MethodHandle target, int firstArg, int argCount, int rotateBy) { - Access.check(token); rotateBy = positiveRotation(argCount, rotateBy); if (!canRotateArguments(newType, target.type(), firstArg, argCount, rotateBy)) return null; @@ -904,7 +875,7 @@ public class AdapterMethodHandle extends BoundMethodHandle { } /** Can an adapter spread an argument to convert the target to newType? */ - public static boolean canSpreadArguments(MethodType newType, MethodType targetType, + static boolean canSpreadArguments(MethodType newType, MethodType targetType, Class spreadArgType, int spreadArgPos, int spreadArgCount) { if (!convOpSupported(OP_SPREAD_ARGS)) return false; if (diffReturnTypes(newType, targetType, false) != 0) @@ -937,10 +908,8 @@ public class AdapterMethodHandle extends BoundMethodHandle { /** Factory method: Spread selected argument. */ - public static MethodHandle makeSpreadArguments(Access token, - MethodType newType, MethodHandle target, + static MethodHandle makeSpreadArguments(MethodType newType, MethodHandle target, Class spreadArgType, int spreadArgPos, int spreadArgCount) { - Access.check(token); MethodType targetType = target.type(); if (!canSpreadArguments(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount)) return null; @@ -962,7 +931,7 @@ public class AdapterMethodHandle extends BoundMethodHandle { @Override public String toString() { - return MethodHandleImpl.getNameString(IMPL_TOKEN, nonAdapter((MethodHandle)vmtarget), this); + return getNameString(nonAdapter((MethodHandle)vmtarget), this); } private static MethodHandle nonAdapter(MethodHandle mh) { diff --git a/src/share/classes/sun/dyn/BoundMethodHandle.java b/src/share/classes/java/dyn/BoundMethodHandle.java similarity index 81% rename from src/share/classes/sun/dyn/BoundMethodHandle.java rename to src/share/classes/java/dyn/BoundMethodHandle.java index 0fab63f7c..40b56cb00 100644 --- a/src/share/classes/sun/dyn/BoundMethodHandle.java +++ b/src/share/classes/java/dyn/BoundMethodHandle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,15 +23,11 @@ * questions. */ -package sun.dyn; +package java.dyn; import sun.dyn.util.VerifyType; import sun.dyn.util.Wrapper; -import java.dyn.*; -import java.util.List; -import sun.dyn.MethodHandleNatives.Constants; -import static sun.dyn.MethodHandleImpl.IMPL_LOOKUP; -import static sun.dyn.MemberName.newIllegalArgumentException; +import static java.dyn.MethodHandleStatics.*; /** * The flavor of method handle which emulates an invoke instruction @@ -39,37 +35,29 @@ import static sun.dyn.MemberName.newIllegalArgumentException; * when the handle is created, not when it is invoked. * @author jrose */ -public class BoundMethodHandle extends MethodHandle { +class BoundMethodHandle extends MethodHandle { //MethodHandle vmtarget; // next BMH or final DMH or methodOop private final Object argument; // argument to insert private final int vmargslot; // position at which it is inserted - private static final Access IMPL_TOKEN = Access.getToken(); - private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(IMPL_TOKEN); - // Constructors in this class *must* be package scoped or private. /** Bind a direct MH to its receiver (or first ref. argument). * The JVM will pre-dispatch the MH if it is not already static. */ - BoundMethodHandle(DirectMethodHandle mh, Object argument) { - super(Access.TOKEN, mh.type().dropParameterTypes(0, 1)); + /*non-public*/ BoundMethodHandle(DirectMethodHandle mh, Object argument) { + super(mh.type().dropParameterTypes(0, 1)); // check the type now, once for all: this.argument = checkReferenceArgument(argument, mh, 0); this.vmargslot = this.type().parameterSlotCount(); - if (MethodHandleNatives.JVM_SUPPORT) { - this.vmtarget = null; // maybe updated by JVM - MethodHandleNatives.init(this, mh, 0); - } else { - this.vmtarget = mh; - } + initTarget(mh, 0); } /** Insert an argument into an arbitrary method handle. * If argnum is zero, inserts the first argument, etc. * The argument type must be a reference. */ - BoundMethodHandle(MethodHandle mh, Object argument, int argnum) { + /*non-public*/ BoundMethodHandle(MethodHandle mh, Object argument, int argnum) { this(mh.type().dropParameterTypes(argnum, argnum+1), mh, argument, argnum); } @@ -77,8 +65,8 @@ public class BoundMethodHandle extends MethodHandle { /** Insert an argument into an arbitrary method handle. * If argnum is zero, inserts the first argument, etc. */ - BoundMethodHandle(MethodType type, MethodHandle mh, Object argument, int argnum) { - super(Access.TOKEN, type); + /*non-public*/ BoundMethodHandle(MethodType type, MethodHandle mh, Object argument, int argnum) { + super(type); if (mh.type().parameterType(argnum).isPrimitive()) this.argument = bindPrimitiveArgument(argument, mh, argnum); else { @@ -89,18 +77,14 @@ public class BoundMethodHandle extends MethodHandle { } private void initTarget(MethodHandle mh, int argnum) { - if (MethodHandleNatives.JVM_SUPPORT) { - this.vmtarget = null; // maybe updated by JVM - MethodHandleNatives.init(this, mh, argnum); - } else { - this.vmtarget = mh; - } + //this.vmtarget = mh; // maybe updated by JVM + MethodHandleNatives.init(this, mh, argnum); } /** For the AdapterMethodHandle subclass. */ - BoundMethodHandle(MethodType type, Object argument, int vmargslot) { - super(Access.TOKEN, type); + /*non-public*/ BoundMethodHandle(MethodType type, Object argument, int vmargslot) { + super(type); this.argument = argument; this.vmargslot = vmargslot; assert(this instanceof AdapterMethodHandle); @@ -112,8 +96,8 @@ public class BoundMethodHandle extends MethodHandle { * same as {@code entryPoint}, except that the first argument * type will be dropped. */ - protected BoundMethodHandle(Access token, MethodHandle entryPoint) { - super(token, entryPoint.type().dropParameterTypes(0, 1)); + /*non-public*/ BoundMethodHandle(MethodHandle entryPoint) { + super(entryPoint.type().dropParameterTypes(0, 1)); this.argument = this; // kludge; get rid of this.vmargslot = this.type().parameterSlotDepth(0); initTarget(entryPoint, 0); @@ -172,7 +156,7 @@ public class BoundMethodHandle extends MethodHandle { @Override public String toString() { - return MethodHandleImpl.addTypeString(baseName(), this); + return addTypeString(baseName(), this); } /** Component of toString() before the type string. */ diff --git a/src/share/classes/java/dyn/CallSite.java b/src/share/classes/java/dyn/CallSite.java index 42af08a72..e78922625 100644 --- a/src/share/classes/java/dyn/CallSite.java +++ b/src/share/classes/java/dyn/CallSite.java @@ -25,10 +25,10 @@ package java.dyn; -import sun.dyn.*; import sun.dyn.empty.Empty; import sun.misc.Unsafe; -import java.util.Collection; +import static java.dyn.MethodHandleStatics.*; +import static java.dyn.MethodHandles.Lookup.IMPL_LOOKUP; /** * A {@code CallSite} is a holder for a variable {@link MethodHandle}, @@ -85,7 +85,6 @@ private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String nam */ abstract public class CallSite { - private static final Access IMPL_TOKEN = Access.getToken(); static { MethodHandleImpl.initStatics(); } // Fields used only by the JVM. Do not use or change. @@ -111,7 +110,7 @@ public class CallSite { */ /*package-private*/ CallSite(MethodType type) { - target = MethodHandles.invokers(type).uninitializedCallSite(); + target = type.invokers().uninitializedCallSite(); } /** @@ -218,7 +217,7 @@ public class CallSite { public abstract MethodHandle dynamicInvoker(); /*non-public*/ MethodHandle makeDynamicInvoker() { - MethodHandle getTarget = MethodHandleImpl.bindReceiver(IMPL_TOKEN, GET_TARGET, this); + MethodHandle getTarget = MethodHandleImpl.bindReceiver(GET_TARGET, this); MethodHandle invoker = MethodHandles.exactInvoker(this.type()); return MethodHandles.foldArguments(invoker, getTarget); } @@ -226,7 +225,7 @@ public class CallSite { private static final MethodHandle GET_TARGET; static { try { - GET_TARGET = MethodHandles.Lookup.IMPL_LOOKUP. + GET_TARGET = IMPL_LOOKUP. findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class)); } catch (ReflectiveOperationException ignore) { throw new InternalError(); @@ -252,7 +251,6 @@ public class CallSite { /*package-private*/ void setTargetNormal(MethodHandle newTarget) { target = newTarget; - //CallSiteImpl.setCallSiteTarget(IMPL_TOKEN, this, newTarget); } /*package-private*/ MethodHandle getTargetVolatile() { @@ -261,6 +259,105 @@ public class CallSite { /*package-private*/ void setTargetVolatile(MethodHandle newTarget) { unsafe.putObjectVolatile(this, TARGET_OFFSET, newTarget); - //CallSiteImpl.setCallSiteTarget(IMPL_TOKEN, this, newTarget); + } + + // 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: + MemberName callerMethod, int callerBCI) { + Class callerClass = callerMethod.getDeclaringClass(); + Object caller; + if (bootstrapMethod.type().parameterType(0) == Class.class && TRANSITIONAL_BEFORE_PFD) + caller = callerClass; // remove for PFD + else + caller = IMPL_LOOKUP.in(callerClass); + if (bootstrapMethod == null && TRANSITIONAL_BEFORE_PFD) { + // If there is no bootstrap method, throw IncompatibleClassChangeError. + // This is a valid generic error type for resolution (JLS 12.3.3). + throw new IncompatibleClassChangeError + ("Class "+callerClass.getName()+" has not declared a bootstrap method for invokedynamic"); + } + CallSite site; + try { + Object binding; + info = maybeReBox(info); + if (info == null) { + binding = bootstrapMethod.invokeGeneric(caller, name, type); + } else if (!info.getClass().isArray()) { + binding = bootstrapMethod.invokeGeneric(caller, name, type, info); + } else { + Object[] argv = (Object[]) info; + maybeReBoxElements(argv); + if (3 + argv.length > 255) + throw new InvokeDynamicBootstrapError("too many bootstrap method arguments"); + MethodType bsmType = bootstrapMethod.type(); + if (bsmType.parameterCount() == 4 && bsmType.parameterType(3) == Object[].class) + binding = bootstrapMethod.invokeGeneric(caller, name, type, argv); + else + binding = MethodHandles.spreadInvoker(bsmType, 3) + .invokeGeneric(bootstrapMethod, caller, name, type, argv); + } + //System.out.println("BSM for "+name+type+" => "+binding); + if (binding instanceof CallSite) { + site = (CallSite) binding; + } else if (binding instanceof MethodHandle && TRANSITIONAL_BEFORE_PFD) { + // Transitional! + MethodHandle target = (MethodHandle) binding; + site = new ConstantCallSite(target); + } else { + throw new ClassCastException("bootstrap method failed to produce a CallSite"); + } + if (TRANSITIONAL_BEFORE_PFD) + PRIVATE_INITIALIZE_CALL_SITE.invokeExact(site, name, type, + callerMethod, callerBCI); + assert(site.getTarget() != null); + assert(site.getTarget().type().equals(type)); + } catch (Throwable ex) { + InvokeDynamicBootstrapError bex; + if (ex instanceof InvokeDynamicBootstrapError) + bex = (InvokeDynamicBootstrapError) ex; + else + bex = new InvokeDynamicBootstrapError("call site initialization exception", ex); + throw bex; + } + return site; + } + + private static final boolean TRANSITIONAL_BEFORE_PFD = true; // FIXME: remove for PFD + // booby trap to force removal after package rename: + static { if (TRANSITIONAL_BEFORE_PFD) assert(CallSite.class.getName().startsWith("java.dyn.")); } + + 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]); + } + } + + // This method is private in CallSite because it touches private fields in CallSite. + // These private fields (vmmethod, vmindex) are specific to the JVM. + private static final MethodHandle PRIVATE_INITIALIZE_CALL_SITE; + static { + try { + PRIVATE_INITIALIZE_CALL_SITE = + !TRANSITIONAL_BEFORE_PFD ? null : + IMPL_LOOKUP.findVirtual(CallSite.class, "initializeFromJVM", + MethodType.methodType(void.class, + String.class, MethodType.class, + MemberName.class, int.class)); + } catch (ReflectiveOperationException ex) { + throw uncaughtException(ex); + } } } diff --git a/src/share/classes/java/dyn/ClassValue.java b/src/share/classes/java/dyn/ClassValue.java index 597dd951e..776ecb6c2 100644 --- a/src/share/classes/java/dyn/ClassValue.java +++ b/src/share/classes/java/dyn/ClassValue.java @@ -27,8 +27,6 @@ package java.dyn; import java.util.WeakHashMap; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import java.lang.reflect.UndeclaredThrowableException; /** * Lazily associate a computed value with (potentially) every type. diff --git a/src/share/classes/sun/dyn/DirectMethodHandle.java b/src/share/classes/java/dyn/DirectMethodHandle.java similarity index 91% rename from src/share/classes/sun/dyn/DirectMethodHandle.java rename to src/share/classes/java/dyn/DirectMethodHandle.java index b43f353bb..e400fb6f5 100644 --- a/src/share/classes/sun/dyn/DirectMethodHandle.java +++ b/src/share/classes/java/dyn/DirectMethodHandle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,10 +23,9 @@ * questions. */ -package sun.dyn; +package java.dyn; -import java.dyn.*; -import static sun.dyn.MethodHandleNatives.Constants.*; +import static java.dyn.MethodHandleNatives.Constants.*; /** * The flavor of method handle which emulates invokespecial or invokestatic. @@ -39,7 +38,7 @@ class DirectMethodHandle extends MethodHandle { // Constructors in this class *must* be package scoped or private. DirectMethodHandle(MethodType mtype, MemberName m, boolean doDispatch, Class lookupClass) { - super(Access.TOKEN, mtype); + super(mtype); assert(m.isMethod() || !doDispatch && m.isConstructor()); if (!m.isResolved()) diff --git a/src/share/classes/sun/dyn/FilterGeneric.java b/src/share/classes/java/dyn/FilterGeneric.java similarity index 99% rename from src/share/classes/sun/dyn/FilterGeneric.java rename to src/share/classes/java/dyn/FilterGeneric.java index e77d742a1..a469561b0 100644 --- a/src/share/classes/sun/dyn/FilterGeneric.java +++ b/src/share/classes/java/dyn/FilterGeneric.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,11 +23,11 @@ * questions. */ -package sun.dyn; +package java.dyn; -import java.dyn.*; import java.lang.reflect.*; -import static sun.dyn.MemberName.newIllegalArgumentException; +import static java.dyn.MethodHandleStatics.*; +import static java.dyn.MethodHandles.Lookup.IMPL_LOOKUP; /** * These adapters apply arbitrary conversions to arguments @@ -123,7 +123,7 @@ class FilterGeneric { MethodType entryType = entryType(kind, pos, filterType, targetType); if (entryType.generic() != entryType) throw newIllegalArgumentException("must be generic: "+entryType); - MethodTypeImpl form = MethodTypeImpl.of(entryType); + MethodTypeForm form = entryType.form(); FilterGeneric filterGen = form.filterGeneric; if (filterGen == null) form.filterGeneric = filterGen = new FilterGeneric(entryType); @@ -186,7 +186,7 @@ class FilterGeneric { // see if it has the required invoke method MethodHandle entryPoint = null; try { - entryPoint = MethodHandleImpl.IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls); + entryPoint = IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls); } catch (ReflectiveOperationException ex) { } if (entryPoint == null) continue; @@ -231,7 +231,7 @@ class FilterGeneric { @Override public String toString() { - return MethodHandleImpl.addTypeString(target, this); + return addTypeString(target, this); } protected boolean isPrototype() { return target == null; } @@ -246,7 +246,7 @@ class FilterGeneric { protected Adapter(MethodHandle entryPoint, MethodHandle filter, MethodHandle target) { - super(Access.TOKEN, entryPoint); + super(entryPoint); this.filter = filter; this.target = target; } @@ -256,7 +256,7 @@ class FilterGeneric { MethodHandle filter, MethodHandle target); // { return new ThisType(entryPoint, filter, target); } - static private final String CLASS_PREFIX; // "sun.dyn.FilterGeneric$" + static private final String CLASS_PREFIX; // "java.dyn.FilterGeneric$" static { String aname = Adapter.class.getName(); String sname = Adapter.class.getSimpleName(); diff --git a/src/share/classes/sun/dyn/FilterOneArgument.java b/src/share/classes/java/dyn/FilterOneArgument.java similarity index 86% rename from src/share/classes/sun/dyn/FilterOneArgument.java rename to src/share/classes/java/dyn/FilterOneArgument.java index 86c722f3c..2f76bbf8e 100644 --- a/src/share/classes/sun/dyn/FilterOneArgument.java +++ b/src/share/classes/java/dyn/FilterOneArgument.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,10 +23,10 @@ * questions. */ -package sun.dyn; +package java.dyn; -import java.dyn.*; -import static sun.dyn.MemberName.uncaughtException; +import static java.dyn.MethodHandleStatics.*; +import static java.dyn.MethodHandles.Lookup.IMPL_LOOKUP; /** * Unary function composition, useful for many small plumbing jobs. @@ -36,7 +36,7 @@ import static sun.dyn.MemberName.uncaughtException; * final method type is the responsibility of a JVM-level adapter. * @author jrose */ -public class FilterOneArgument extends BoundMethodHandle { +class FilterOneArgument extends BoundMethodHandle { protected final MethodHandle filter; // Object -> Object protected final MethodHandle target; // Object -> Object @@ -54,15 +54,15 @@ public class FilterOneArgument extends BoundMethodHandle { static { try { INVOKE = - MethodHandleImpl.IMPL_LOOKUP.findVirtual(FilterOneArgument.class, "invoke", - MethodType.genericMethodType(1)); + IMPL_LOOKUP.findVirtual(FilterOneArgument.class, "invoke", + MethodType.genericMethodType(1)); } catch (ReflectiveOperationException ex) { throw uncaughtException(ex); } } protected FilterOneArgument(MethodHandle filter, MethodHandle target) { - super(Access.TOKEN, INVOKE); + super(INVOKE); this.filter = filter; this.target = target; } diff --git a/src/share/classes/sun/dyn/FromGeneric.java b/src/share/classes/java/dyn/FromGeneric.java similarity index 97% rename from src/share/classes/sun/dyn/FromGeneric.java rename to src/share/classes/java/dyn/FromGeneric.java index b996a6b3e..67cb70d23 100644 --- a/src/share/classes/sun/dyn/FromGeneric.java +++ b/src/share/classes/java/dyn/FromGeneric.java @@ -23,12 +23,13 @@ * questions. */ -package sun.dyn; +package java.dyn; -import java.dyn.*; +import sun.dyn.util.ValueConversions; +import sun.dyn.util.Wrapper; import java.lang.reflect.*; -import sun.dyn.util.*; -import static sun.dyn.MethodTypeImpl.invokers; +import static java.dyn.MethodHandleStatics.*; +import static java.dyn.MethodHandles.Lookup.IMPL_LOOKUP; /** * Adapters which mediate between incoming calls which are generic @@ -82,8 +83,8 @@ class FromGeneric { } // outgoing primitive arguments will be wrapped; unwrap them - MethodType primsAsObj = MethodTypeImpl.of(targetType).primArgsAsBoxes(); - MethodType objArgsRawRet = MethodTypeImpl.of(primsAsObj).primsAsInts(); + MethodType primsAsObj = targetType.form().primArgsAsBoxes(); + MethodType objArgsRawRet = primsAsObj.form().primsAsInts(); if (objArgsRawRet != targetType) ad = findAdapter(internalType0 = objArgsRawRet); if (ad == null) { @@ -129,16 +130,16 @@ class FromGeneric { MethodType targetType, MethodType internalType) { // All the adapters we have here have reference-untyped internal calls. assert(internalType == internalType.erase()); - MethodHandle invoker = invokers(targetType).exactInvoker(); + MethodHandle invoker = targetType.invokers().exactInvoker(); // cast all narrow reference types, unbox all primitive arguments: MethodType fixArgsType = internalType.changeReturnType(targetType.returnType()); - MethodHandle fixArgs = AdapterMethodHandle.convertArguments(Access.TOKEN, + MethodHandle fixArgs = MethodHandleImpl.convertArguments( invoker, Invokers.invokerType(fixArgsType), invoker.type(), null); if (fixArgs == null) throw new InternalError("bad fixArgs"); // reinterpret the calling sequence as raw: - MethodHandle retyper = AdapterMethodHandle.makeRetypeRaw(Access.TOKEN, + MethodHandle retyper = AdapterMethodHandle.makeRetypeRaw( Invokers.invokerType(internalType), fixArgs); if (retyper == null) throw new InternalError("bad retyper"); @@ -171,7 +172,7 @@ class FromGeneric { /** Return the adapter information for this type's erasure. */ static FromGeneric of(MethodType type) { - MethodTypeImpl form = MethodTypeImpl.of(type); + MethodTypeForm form = type.form(); FromGeneric fromGen = form.fromGeneric; if (fromGen == null) form.fromGeneric = fromGen = new FromGeneric(form.erasedType()); @@ -185,7 +186,7 @@ class FromGeneric { /* Create an adapter that handles spreading calls for the given type. */ static Adapter findAdapter(MethodType internalType) { MethodType entryType = internalType.generic(); - MethodTypeImpl form = MethodTypeImpl.of(internalType); + MethodTypeForm form = internalType.form(); Class rtype = internalType.returnType(); int argc = form.parameterCount(); int lac = form.longPrimitiveParameterCount(); @@ -203,7 +204,7 @@ class FromGeneric { // see if it has the required invoke method MethodHandle entryPoint = null; try { - entryPoint = MethodHandleImpl.IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls); + entryPoint = IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls); } catch (ReflectiveOperationException ex) { } if (entryPoint == null) continue; @@ -257,7 +258,7 @@ class FromGeneric { @Override public String toString() { - return MethodHandleImpl.addTypeString(target, this); + return addTypeString(target, this); } protected boolean isPrototype() { return target == null; } @@ -272,7 +273,7 @@ class FromGeneric { protected Adapter(MethodHandle entryPoint, MethodHandle invoker, MethodHandle convert, MethodHandle target) { - super(Access.TOKEN, entryPoint); + super(entryPoint); this.invoker = invoker; this.convert = convert; this.target = target; @@ -290,7 +291,7 @@ class FromGeneric { protected Object convert_F(float result) throws Throwable { return convert.invokeExact(result); } protected Object convert_D(double result) throws Throwable { return convert.invokeExact(result); } - static private final String CLASS_PREFIX; // "sun.dyn.FromGeneric$" + static private final String CLASS_PREFIX; // "java.dyn.FromGeneric$" static { String aname = Adapter.class.getName(); String sname = Adapter.class.getSimpleName(); diff --git a/src/share/classes/java/dyn/InvokeDynamic.java b/src/share/classes/java/dyn/InvokeDynamic.java index 9c3ede1ee..dfe3ff380 100644 --- a/src/share/classes/java/dyn/InvokeDynamic.java +++ b/src/share/classes/java/dyn/InvokeDynamic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/share/classes/sun/dyn/InvokeGeneric.java b/src/share/classes/java/dyn/InvokeGeneric.java similarity index 86% rename from src/share/classes/sun/dyn/InvokeGeneric.java rename to src/share/classes/java/dyn/InvokeGeneric.java index 0d1a5defc..4b14fffe5 100644 --- a/src/share/classes/sun/dyn/InvokeGeneric.java +++ b/src/share/classes/java/dyn/InvokeGeneric.java @@ -23,15 +23,13 @@ * questions. */ -package sun.dyn; +package java.dyn; -import java.dyn.*; -import java.lang.reflect.*; import sun.dyn.util.*; -import static sun.dyn.MethodTypeImpl.invokers; +import static java.dyn.MethodHandles.Lookup.IMPL_LOOKUP; /** - * Adapters which manage MethodHanndle.invokeGeneric calls. + * Adapters which manage MethodHandle.invokeGeneric calls. * The JVM calls one of these when the exact type match fails. * @author jrose */ @@ -44,7 +42,8 @@ class InvokeGeneric { /** Compute and cache information for this adapter, so that it can * call out to targets of the erasure-family of the given erased type. */ - private InvokeGeneric(MethodType erasedCallerType) throws ReflectiveOperationException { + /*non-public*/ InvokeGeneric(MethodType erasedCallerType) throws ReflectiveOperationException { + assert(erasedCallerType.equals(erasedCallerType.erase())); this.erasedCallerType = erasedCallerType; this.initialInvoker = makeInitialInvoker(); assert initialInvoker.type().equals(erasedCallerType @@ -53,22 +52,13 @@ class InvokeGeneric { } private static MethodHandles.Lookup lookup() { - return MethodHandleImpl.IMPL_LOOKUP; + return IMPL_LOOKUP; } /** Return the adapter information for this type's erasure. */ - static MethodHandle genericInvokerOf(MethodType type) { - MethodTypeImpl form = MethodTypeImpl.of(type); - MethodHandle genericInvoker = form.genericInvoker; - if (genericInvoker == null) { - try { - InvokeGeneric gen = new InvokeGeneric(form.erasedType()); - form.genericInvoker = genericInvoker = gen.initialInvoker; - } catch (ReflectiveOperationException ex) { - throw new RuntimeException(ex); - } - } - return genericInvoker; + /*non-public*/ static MethodHandle genericInvokerOf(MethodType erasedCallerType) throws ReflectiveOperationException { + InvokeGeneric gen = new InvokeGeneric(erasedCallerType); + return gen.initialInvoker; } private MethodHandle makeInitialInvoker() throws ReflectiveOperationException { @@ -88,7 +78,7 @@ class InvokeGeneric { private MethodHandle makePostDispatchInvoker() { // Take (MH'; MT, MH; A...) and run MH'(MT, MH; A...). MethodType invokerType = erasedCallerType.insertParameterTypes(0, EXTRA_ARGS); - return invokers(invokerType).exactInvoker(); + return invokerType.invokers().exactInvoker(); } private MethodHandle dropDispatchArguments(MethodHandle targetInvoker) { assert(targetInvoker.type().parameterType(0) == MethodHandle.class); @@ -112,7 +102,7 @@ class InvokeGeneric { if (USE_AS_TYPE_PATH || target.isVarargsCollector()) { MethodHandle newTarget = target.asType(callerType); targetType = callerType; - Invokers invokers = MethodTypeImpl.invokers(Access.TOKEN, targetType); + Invokers invokers = targetType.invokers(); MethodHandle invoker = invokers.erasedInvokerWithDrops; if (invoker == null) { invokers.erasedInvokerWithDrops = invoker = diff --git a/src/share/classes/sun/dyn/Invokers.java b/src/share/classes/java/dyn/Invokers.java similarity index 87% rename from src/share/classes/sun/dyn/Invokers.java rename to src/share/classes/java/dyn/Invokers.java index 55eef1911..4a7fcbe3a 100644 --- a/src/share/classes/sun/dyn/Invokers.java +++ b/src/share/classes/java/dyn/Invokers.java @@ -23,16 +23,16 @@ * questions. */ -package sun.dyn; +package java.dyn; -import java.dyn.*; import sun.dyn.empty.Empty; +import static java.dyn.MethodHandles.Lookup.IMPL_LOOKUP; /** * Construction and caching of often-used invokers. * @author jrose */ -public class Invokers { +class Invokers { // exact type (sans leading taget MH) for the outgoing call private final MethodType targetType; @@ -60,15 +60,15 @@ public class Invokers { this.spreadInvokers = new MethodHandle[targetType.parameterCount()+1]; } - public static MethodType invokerType(MethodType targetType) { + /*non-public*/ static MethodType invokerType(MethodType targetType) { return targetType.insertParameterTypes(0, MethodHandle.class); } - public MethodHandle exactInvoker() { + /*non-public*/ MethodHandle exactInvoker() { MethodHandle invoker = exactInvoker; if (invoker != null) return invoker; try { - invoker = MethodHandleImpl.IMPL_LOOKUP.findVirtual(MethodHandle.class, "invokeExact", targetType); + invoker = IMPL_LOOKUP.findVirtual(MethodHandle.class, "invokeExact", targetType); } catch (ReflectiveOperationException ex) { throw new InternalError("JVM cannot find invoker for "+targetType); } @@ -77,7 +77,7 @@ public class Invokers { return invoker; } - public MethodHandle genericInvoker() { + /*non-public*/ MethodHandle genericInvoker() { MethodHandle invoker1 = exactInvoker(); MethodHandle invoker = genericInvoker; if (invoker != null) return invoker; @@ -87,7 +87,7 @@ public class Invokers { return invoker; } - public MethodHandle erasedInvoker() { + /*non-public*/ MethodHandle erasedInvoker() { MethodHandle invoker1 = exactInvoker(); MethodHandle invoker = erasedInvoker; if (invoker != null) return invoker; @@ -100,7 +100,7 @@ public class Invokers { return invoker; } - public MethodHandle spreadInvoker(int objectArgCount) { + /*non-public*/ MethodHandle spreadInvoker(int objectArgCount) { MethodHandle vaInvoker = spreadInvokers[objectArgCount]; if (vaInvoker != null) return vaInvoker; MethodHandle gInvoker = genericInvoker(); @@ -111,12 +111,12 @@ public class Invokers { private static MethodHandle THROW_UCS = null; - public MethodHandle uninitializedCallSite() { + /*non-public*/ MethodHandle uninitializedCallSite() { MethodHandle invoker = uninitializedCallSite; if (invoker != null) return invoker; if (targetType.parameterCount() > 0) { MethodType type0 = targetType.dropParameterTypes(0, targetType.parameterCount()); - Invokers invokers0 = MethodTypeImpl.invokers(type0); + Invokers invokers0 = type0.invokers(); invoker = MethodHandles.dropArguments(invokers0.uninitializedCallSite(), 0, targetType.parameterList()); assert(invoker.type().equals(targetType)); @@ -125,14 +125,14 @@ public class Invokers { } if (THROW_UCS == null) { try { - THROW_UCS = MethodHandleImpl.IMPL_LOOKUP + THROW_UCS = IMPL_LOOKUP .findStatic(CallSite.class, "uninitializedCallSite", MethodType.methodType(Empty.class)); } catch (ReflectiveOperationException ex) { throw new RuntimeException(ex); } } - invoker = AdapterMethodHandle.makeRetypeRaw(Access.TOKEN, targetType, THROW_UCS); + invoker = AdapterMethodHandle.makeRetypeRaw(targetType, THROW_UCS); assert(invoker.type().equals(targetType)); uninitializedCallSite = invoker; return invoker; diff --git a/src/share/classes/java/dyn/Linkage.java b/src/share/classes/java/dyn/Linkage.java index 4ddda0a19..d23bdf550 100644 --- a/src/share/classes/java/dyn/Linkage.java +++ b/src/share/classes/java/dyn/Linkage.java @@ -25,13 +25,9 @@ package java.dyn; -import java.dyn.MethodHandles.Lookup; -import java.util.WeakHashMap; -import sun.dyn.Access; -import sun.dyn.MethodHandleImpl; import sun.dyn.util.VerifyAccess; +import java.dyn.MethodHandles.Lookup; import sun.reflect.Reflection; -import static sun.dyn.MemberName.newIllegalArgumentException; /** * CLASS WILL BE REMOVED FOR PFD: @@ -41,8 +37,6 @@ import static sun.dyn.MemberName.newIllegalArgumentException; * @deprecated This class will be removed in the Public Final Draft. */ public class Linkage { - private static final Access IMPL_TOKEN = Access.getToken(); - private Linkage() {} // do not instantiate /** @@ -56,7 +50,7 @@ public class Linkage { Class callc = Reflection.getCallerClass(2); if (callc != null && !VerifyAccess.isSamePackage(callerClass, callc)) throw new IllegalArgumentException("cannot set bootstrap method on "+callerClass); - MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod); + MethodHandleImpl.registerBootstrap(callerClass, bootstrapMethod); } /** @@ -84,14 +78,14 @@ public class Linkage { private static void registerBootstrapMethodLookup(Class callerClass, Class runtime, String name) { - Lookup lookup = new Lookup(IMPL_TOKEN, callerClass); + Lookup lookup = new Lookup(callerClass); MethodHandle bootstrapMethod; try { bootstrapMethod = lookup.findStatic(runtime, name, BOOTSTRAP_METHOD_TYPE); } catch (ReflectiveOperationException ex) { throw new IllegalArgumentException("no such bootstrap method in "+runtime+": "+name, ex); } - MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod); + MethodHandleImpl.registerBootstrap(callerClass, bootstrapMethod); } private static final MethodType BOOTSTRAP_METHOD_TYPE diff --git a/src/share/classes/sun/dyn/MemberName.java b/src/share/classes/java/dyn/MemberName.java similarity index 93% rename from src/share/classes/sun/dyn/MemberName.java rename to src/share/classes/java/dyn/MemberName.java index 5e98b85ca..8032cecc3 100644 --- a/src/share/classes/sun/dyn/MemberName.java +++ b/src/share/classes/java/dyn/MemberName.java @@ -23,10 +23,9 @@ * questions. */ -package sun.dyn; +package java.dyn; import sun.dyn.util.BytecodeDescriptor; -import java.dyn.*; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -37,7 +36,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; -import static sun.dyn.MethodHandleNatives.Constants.*; +import static java.dyn.MethodHandleNatives.Constants.*; +import static java.dyn.MethodHandleStatics.*; /** * A {@code MemberName} is a compact symbolic datum which fully characterizes @@ -66,7 +66,7 @@ import static sun.dyn.MethodHandleNatives.Constants.*; * and those seven fields omit much of the information in Method. * @author jrose */ -public final class MemberName implements Member, Cloneable { +/*non-public*/ final class MemberName implements Member, Cloneable { private Class clazz; // class in which the method is defined private String name; // may be null if not yet materialized private Object type; // may be null if not yet materialized @@ -435,7 +435,7 @@ public final class MemberName implements Member, Cloneable { /** Query whether this member name is resolved to a non-static, non-final method. */ public boolean hasReceiverTypeDispatch() { - return (isMethod() && getVMIndex(Access.TOKEN) >= 0); + return (isMethod() && getVMIndex() >= 0); } /** Produce a string form of this member name. @@ -490,59 +490,38 @@ public final class MemberName implements Member, Cloneable { // Queries to the JVM: /** Document? */ - public int getVMIndex(Access token) { - Access.check(token); + /*non-public*/ int getVMIndex() { if (!isResolved()) - throw newIllegalStateException("not resolved"); + throw newIllegalStateException("not resolved", this); return vmindex; } -// public Object getVMTarget(Access token) { -// Access.check(token); +// /*non-public*/ Object getVMTarget() { // if (!isResolved()) -// throw newIllegalStateException("not resolved"); +// throw newIllegalStateException("not resolved", this); // return vmtarget; // } - private RuntimeException newIllegalStateException(String message) { - return new IllegalStateException(message+": "+this); - } - // handy shared exception makers (they simplify the common case code) - public static RuntimeException newIllegalArgumentException(String message) { - return new IllegalArgumentException(message); - } - public static IllegalAccessException newNoAccessException(MemberName name, Object from) { - return newNoAccessException("cannot access", name, from); - } - public static IllegalAccessException newNoAccessException(String message, - MemberName name, Object from) { - message += ": " + name; + public IllegalAccessException makeAccessException(String message, Object from) { + message = message + ": "+ toString(); if (from != null) message += ", from " + from; return new IllegalAccessException(message); } - public static ReflectiveOperationException newNoAccessException(MemberName name) { - if (name.isResolved()) - return new IllegalAccessException(name.toString()); - else if (name.isConstructor()) - return new NoSuchMethodException(name.toString()); - else if (name.isMethod()) - return new NoSuchMethodException(name.toString()); + public ReflectiveOperationException makeAccessException(String message) { + message = message + ": "+ toString(); + if (isResolved()) + return new IllegalAccessException(message); + else if (isConstructor()) + return new NoSuchMethodException(message); + else if (isMethod()) + return new NoSuchMethodException(message); else - return new NoSuchFieldException(name.toString()); - } - public static Error uncaughtException(Exception ex) { - Error err = new InternalError("uncaught exception"); - err.initCause(ex); - return err; + return new NoSuchFieldException(message); } /** Actually making a query requires an access check. */ - public static Factory getFactory(Access token) { - Access.check(token); + /*non-public*/ static Factory getFactory() { return Factory.INSTANCE; } - public static Factory getFactory() { - return getFactory(Access.getToken()); - } /** A factory type for resolving member names with the help of the VM. * TBD: Define access-safe public constructors for this factory. */ @@ -662,7 +641,7 @@ public final class MemberName implements Member, Cloneable { MemberName result = resolveOrNull(m, searchSupers, lookupClass); if (result != null) return result; - ReflectiveOperationException ex = newNoAccessException(m); + ReflectiveOperationException ex = m.makeAccessException("no access"); if (ex instanceof IllegalAccessException) throw (IllegalAccessException) ex; throw nsmClass.cast(ex); } diff --git a/src/share/classes/java/dyn/MethodHandle.java b/src/share/classes/java/dyn/MethodHandle.java index b78b40248..8a261374b 100644 --- a/src/share/classes/java/dyn/MethodHandle.java +++ b/src/share/classes/java/dyn/MethodHandle.java @@ -25,13 +25,8 @@ package java.dyn; -//import sun.dyn.*; -import sun.dyn.Access; -import sun.dyn.MethodHandleImpl; - -import static java.dyn.MethodHandles.invokers; // package-private API -import static sun.dyn.MemberName.newIllegalArgumentException; // utility +import static java.dyn.MethodHandleStatics.*; /** * A method handle is a typed, directly executable reference to an underlying method, @@ -436,12 +431,35 @@ mh.invokeExact(System.out, "Hello, world."); * @see MethodHandles * @author John Rose, JSR 292 EG */ -public abstract class MethodHandle - // Note: This is an implementation inheritance hack, and will be removed - // with a JVM change which moves the required hidden state onto this class. - extends MethodHandleImpl -{ - private static Access IMPL_TOKEN = Access.getToken(); +public abstract class MethodHandle { + // { JVM internals: + + private byte vmentry; // adapter stub or method entry point + //private int vmslots; // optionally, hoist type.form.vmslots + /*non-public*/ Object vmtarget; // VM-specific, class-specific target value + + // TO DO: vmtarget should be invisible to Java, since the JVM puts internal + // managed pointers into it. Making it visible exposes it to debuggers, + // which can cause errors when they treat the pointer as an Object. + + // These two dummy fields are present to force 'I' and 'J' signatures + // into this class's constant pool, so they can be transferred + // to vmentry when this class is loaded. + static final int INT_FIELD = 0; + static final long LONG_FIELD = 0; + + // vmentry (a void* field) is used *only* by the JVM. + // The JVM adjusts its type to int or long depending on system wordsize. + // Since it is statically typed as neither int nor long, it is impossible + // to use this field from Java bytecode. (Please don't try to, either.) + + // The vmentry is an assembly-language stub which is jumped to + // immediately after the method type is verified. + // For a direct MH, this stub loads the vmtarget's entry point + // and jumps to it. + + // } End of JVM internals. + static { MethodHandleImpl.initStatics(); } // interface MethodHandle @@ -467,37 +485,16 @@ public abstract class MethodHandle } /** - * CONSTRUCTOR WILL BE REMOVED FOR PFD: - * Temporary constructor in early versions of the Reference Implementation. - * Method handle inheritance (if any) will be contained completely within + * Package-private constructor for the method handle implementation hierarchy. + * Method handle inheritance will be contained completely within * the {@code java.dyn} package. */ - // The constructor for MethodHandle may only be called by privileged code. - // Subclasses may be in other packages, but must possess - // a token which they obtained from MH with a security check. - // @param token non-null object which proves access permission // @param type type (permanently assigned) of the new method handle - protected MethodHandle(Access token, MethodType type) { - super(token); - Access.check(token); - this.type = type; - } - - private void initType(MethodType type) { + /*non-public*/ MethodHandle(MethodType type) { type.getClass(); // elicit NPE - if (this.type != null) throw new InternalError(); this.type = type; } - static { - // This hack allows the implementation package special access to - // the internals of MethodHandle. In particular, the MTImpl has all sorts - // of cached information useful to the implementation code. - MethodHandleImpl.setMethodHandleFriend(IMPL_TOKEN, new MethodHandleImpl.MethodHandleFriend() { - public void initType(MethodHandle mh, MethodType type) { mh.initType(type); } - }); - } - /** * Invoke the method handle, allowing any caller type descriptor, but requiring an exact type match. * The type descriptor at the call site of {@code invokeExact} must @@ -608,7 +605,7 @@ public abstract class MethodHandle return asType(MethodType.genericMethodType(argc)).invokeWithArguments(arguments); } if (argc <= 10) { - MethodHandle invoker = invokers(type).genericInvoker(); + MethodHandle invoker = type.invokers().genericInvoker(); switch (argc) { case 0: return invoker.invokeExact(this); case 1: return invoker.invokeExact(this, @@ -647,7 +644,7 @@ public abstract class MethodHandle } // more than ten arguments get boxed in a varargs list: - MethodHandle invoker = invokers(type).spreadInvoker(0); + MethodHandle invoker = type.invokers().spreadInvoker(0); return invoker.invokeExact(this, arguments); } /** Equivalent to {@code invokeWithArguments(arguments.toArray())}. */ @@ -1004,6 +1001,6 @@ assert(failed); */ @Override public String toString() { - return MethodHandleImpl.getNameString(IMPL_TOKEN, this); + return getNameString(this); } } diff --git a/src/share/classes/sun/dyn/MethodHandleImpl.java b/src/share/classes/java/dyn/MethodHandleImpl.java similarity index 78% rename from src/share/classes/sun/dyn/MethodHandleImpl.java rename to src/share/classes/java/dyn/MethodHandleImpl.java index eab492354..51701cd3b 100644 --- a/src/share/classes/sun/dyn/MethodHandleImpl.java +++ b/src/share/classes/java/dyn/MethodHandleImpl.java @@ -23,134 +23,34 @@ * questions. */ -package sun.dyn; +package java.dyn; -import java.dyn.*; -import java.dyn.MethodHandles.Lookup; -import java.util.logging.Level; -import java.util.logging.Logger; import sun.dyn.util.VerifyType; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import sun.dyn.empty.Empty; import sun.dyn.util.ValueConversions; import sun.dyn.util.Wrapper; import sun.misc.Unsafe; -import static sun.dyn.MemberName.newIllegalArgumentException; -import static sun.dyn.MemberName.newNoAccessException; -import static sun.dyn.MemberName.uncaughtException; +import static java.dyn.MethodHandleStatics.*; +import static java.dyn.MethodHandles.Lookup.IMPL_LOOKUP; /** - * Base class for method handles, containing JVM-specific fields and logic. - * TO DO: It should not be a base class. + * Trusted implementation code for MethodHandle. * @author jrose */ -public abstract class MethodHandleImpl { - - // Fields which really belong in MethodHandle: - private byte vmentry; // adapter stub or method entry point - //private int vmslots; // optionally, hoist type.form.vmslots - protected Object vmtarget; // VM-specific, class-specific target value - //MethodType type; // defined in MethodHandle - - // TO DO: vmtarget should be invisible to Java, since the JVM puts internal - // managed pointers into it. Making it visible exposes it to debuggers, - // which can cause errors when they treat the pointer as an Object. - - // These two dummy fields are present to force 'I' and 'J' signatures - // into this class's constant pool, so they can be transferred - // to vmentry when this class is loaded. - static final int INT_FIELD = 0; - static final long LONG_FIELD = 0; - - /** Access methods for the internals of MethodHandle, supplied to - * MethodHandleImpl as a trusted agent. - */ - static public interface MethodHandleFriend { - void initType(MethodHandle mh, MethodType type); - } - public static void setMethodHandleFriend(Access token, MethodHandleFriend am) { - Access.check(token); - if (METHOD_HANDLE_FRIEND != null) - throw new InternalError(); // just once - METHOD_HANDLE_FRIEND = am; - } - static private MethodHandleFriend METHOD_HANDLE_FRIEND; - - // NOT public - static void initType(MethodHandle mh, MethodType type) { - METHOD_HANDLE_FRIEND.initType(mh, type); - } - - // type is defined in java.dyn.MethodHandle, which is platform-independent - - // vmentry (a void* field) is used *only* by by the JVM. - // The JVM adjusts its type to int or long depending on system wordsize. - // Since it is statically typed as neither int nor long, it is impossible - // to use this field from Java bytecode. (Please don't try to, either.) - - // The vmentry is an assembly-language stub which is jumped to - // immediately after the method type is verified. - // For a direct MH, this stub loads the vmtarget's entry point - // and jumps to it. - - /** - * VM-based method handles must have a security token. - * This security token can only be obtained by trusted code. - * Do not create method handles directly; use factory methods. - */ - public MethodHandleImpl(Access token) { - Access.check(token); - } - - /** Initialize the method type form to participate in JVM calls. - * This is done once for each erased type. - */ - public static void init(Access token, MethodType self) { - Access.check(token); - if (MethodHandleNatives.JVM_SUPPORT) - MethodHandleNatives.init(self); - } - +/*non-public*/ abstract class MethodHandleImpl { /// Factory methods to create method handles: private static final MemberName.Factory LOOKUP = MemberName.Factory.INSTANCE; - static private Lookup IMPL_LOOKUP_INIT; - - public static void initLookup(Access token, Lookup lookup) { - Access.check(token); - if (IMPL_LOOKUP_INIT != null) - throw new InternalError(); - IMPL_LOOKUP_INIT = lookup; - } - - public static Lookup getLookup(Access token) { - Access.check(token); - return IMPL_LOOKUP; - } - - static { - if (!MethodHandleNatives.JVM_SUPPORT) // force init of native API - throw new InternalError("No JVM support for JSR 292"); - // Force initialization of Lookup, so it calls us back as initLookup: - MethodHandles.publicLookup(); - if (IMPL_LOOKUP_INIT == null) - throw new InternalError(); - } - - public static void initStatics() { + static void initStatics() { // Trigger preceding sequence. } - /** Shared secret with MethodHandles.Lookup, a copy of Lookup.IMPL_LOOKUP. */ - static final Lookup IMPL_LOOKUP = IMPL_LOOKUP_INIT; - - /** Look up a given method. * Callable only from java.dyn and related packages. *

@@ -170,10 +70,9 @@ public abstract class MethodHandleImpl { * @return a direct handle to the matching method * @throws IllegalAccessException if the given method cannot be accessed by the lookup class */ - public static - MethodHandle findMethod(Access token, MemberName method, + static + MethodHandle findMethod(MemberName method, boolean doDispatch, Class lookupClass) throws IllegalAccessException { - Access.check(token); // only trusted calls MethodType mtype = method.getMethodType(); if (!method.isStatic()) { // adjust the advertised receiver type to be exactly the one requested @@ -183,7 +82,7 @@ public abstract class MethodHandleImpl { } DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, lookupClass); if (!mh.isValid()) - throw newNoAccessException(method, lookupClass); + throw method.makeAccessException("no access", lookupClass); assert(mh.type() == mtype); if (!method.isVarargs()) return mh; @@ -191,13 +90,12 @@ public abstract class MethodHandleImpl { return mh.asVarargsCollector(mtype.parameterType(mtype.parameterCount()-1)); } - public static - MethodHandle makeAllocator(Access token, MethodHandle rawConstructor) { - Access.check(token); + static + MethodHandle makeAllocator(MethodHandle rawConstructor) { MethodType rawConType = rawConstructor.type(); // Wrap the raw (unsafe) constructor with the allocation of a suitable object. MethodHandle allocator - = AllocateObject.make(token, rawConType.parameterType(0), rawConstructor); + = AllocateObject.make(rawConType.parameterType(0), rawConstructor); assert(allocator.type() .equals(rawConType.dropParameterTypes(0, 1).changeReturnType(rawConType.parameterType(0)))); return allocator; @@ -211,13 +109,11 @@ public abstract class MethodHandleImpl { private AllocateObject(MethodHandle invoker, Class allocateClass, MethodHandle rawConstructor) { - super(Access.TOKEN, invoker); + super(invoker); this.allocateClass = allocateClass; this.rawConstructor = rawConstructor; } - static MethodHandle make(Access token, - Class allocateClass, MethodHandle rawConstructor) { - Access.check(token); + static MethodHandle make(Class allocateClass, MethodHandle rawConstructor) { MethodType rawConType = rawConstructor.type(); assert(rawConType.parameterType(0) == allocateClass); MethodType newType = rawConType.dropParameterTypes(0, 1).changeReturnType(allocateClass); @@ -225,18 +121,18 @@ public abstract class MethodHandleImpl { if (nargs < INVOKES.length) { MethodHandle invoke = INVOKES[nargs]; MethodType conType = CON_TYPES[nargs]; - MethodHandle gcon = convertArguments(token, rawConstructor, conType, rawConType, null); + MethodHandle gcon = convertArguments(rawConstructor, conType, rawConType, null); if (gcon == null) return null; MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon); assert(galloc.type() == newType.generic()); - return convertArguments(token, galloc, newType, galloc.type(), null); + return convertArguments(galloc, newType, galloc.type(), null); } else { MethodHandle invoke = VARARGS_INVOKE; MethodType conType = CON_TYPES[nargs]; - MethodHandle gcon = spreadArguments(token, rawConstructor, conType, 1); + MethodHandle gcon = spreadArguments(rawConstructor, conType, 1); if (gcon == null) return null; MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon); - return collectArguments(token, galloc, newType, 1, null); + return collectArguments(galloc, newType, 1, null); } } @Override @@ -338,20 +234,16 @@ public abstract class MethodHandleImpl { } } - public static - MethodHandle accessField(Access token, - MemberName member, boolean isSetter, + static + MethodHandle accessField(MemberName member, boolean isSetter, Class lookupClass) { - Access.check(token); // Use sun. misc.Unsafe to dig up the dirt on the field. - MethodHandle mh = new FieldAccessor(token, member, isSetter); + MethodHandle mh = new FieldAccessor(member, isSetter); return mh; } - public static - MethodHandle accessArrayElement(Access token, - Class arrayClass, boolean isSetter) { - Access.check(token); + static + MethodHandle accessArrayElement(Class arrayClass, boolean isSetter) { if (!arrayClass.isArray()) throw newIllegalArgumentException("not an array: "+arrayClass); Class elemClass = arrayClass.getComponentType(); @@ -379,12 +271,13 @@ public abstract class MethodHandleImpl { final long offset; final String name; - public FieldAccessor(Access token, MemberName field, boolean isSetter) { - super(Access.TOKEN, fhandle(field.getDeclaringClass(), field.getFieldType(), isSetter, field.isStatic())); - this.offset = (long) field.getVMIndex(token); + FieldAccessor(MemberName field, boolean isSetter) { + super(fhandle(field.getDeclaringClass(), field.getFieldType(), isSetter, field.isStatic())); + this.offset = (long) field.getVMIndex(); this.name = field.getName(); this.base = staticBase(field); } + @Override public String toString() { return addTypeString(name, this); } int getFieldI(C obj) { return unsafe.getInt(obj, offset); } @@ -560,10 +453,8 @@ public abstract class MethodHandleImpl { * @param receiver Receiver (or first static method argument) to pre-bind. * @return a BoundMethodHandle for the given DirectMethodHandle, or null if it does not exist */ - public static - MethodHandle bindReceiver(Access token, - MethodHandle target, Object receiver) { - Access.check(token); + static + MethodHandle bindReceiver(MethodHandle target, Object receiver) { if (target instanceof AdapterMethodHandle && ((AdapterMethodHandle)target).conversionOp() == MethodHandleNatives.Constants.OP_RETYPE_ONLY ) { @@ -574,7 +465,7 @@ public abstract class MethodHandleImpl { dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) { MethodHandle bmh = new BoundMethodHandle(dmh, receiver, 0); MethodType newType = target.type().dropParameterTypes(0, 1); - return convertArguments(token, bmh, newType, bmh.type(), null); + return convertArguments(bmh, newType, bmh.type(), null); } } } @@ -590,19 +481,15 @@ public abstract class MethodHandleImpl { * @param receiver Argument (which can be a boxed primitive) to pre-bind. * @return a suitable BoundMethodHandle */ - public static - MethodHandle bindArgument(Access token, - MethodHandle target, int argnum, Object receiver) { - Access.check(token); + static + MethodHandle bindArgument(MethodHandle target, int argnum, Object receiver) { return new BoundMethodHandle(target, receiver, argnum); } - public static MethodHandle convertArguments(Access token, - MethodHandle target, + static MethodHandle convertArguments(MethodHandle target, MethodType newType, MethodType oldType, int[] permutationOrNull) { - Access.check(token); assert(oldType.parameterCount() == target.type().parameterCount()); if (permutationOrNull != null) { int outargs = oldType.parameterCount(), inargs = newType.parameterCount(); @@ -613,7 +500,7 @@ public abstract class MethodHandleImpl { for (int i = 0; i < outargs; i++) callTypeArgs[i] = newType.parameterType(permutationOrNull[i]); MethodType callType = MethodType.methodType(oldType.returnType(), callTypeArgs); - target = convertArguments(token, target, callType, oldType, null); + target = convertArguments(target, callType, oldType, null); assert(target != null); oldType = target.type(); List goal = new ArrayList(); // i*TOKEN @@ -710,7 +597,7 @@ public abstract class MethodHandleImpl { Collections.rotate(ptypes.subList(rotBeg, rotEnd+1), -rotBy); MethodType rotType = MethodType.methodType(oldType.returnType(), ptypes); MethodHandle nextTarget - = AdapterMethodHandle.makeRotateArguments(token, rotType, target, + = AdapterMethodHandle.makeRotateArguments(rotType, target, rotBeg, rotSpan.size(), rotBy); if (nextTarget != null) { //System.out.println("Rot: "+rotSpan+" by "+rotBy); @@ -733,7 +620,7 @@ public abstract class MethodHandleImpl { int j = state.indexOf(arg); Collections.swap(ptypes, i, j); MethodType swapType = MethodType.methodType(oldType.returnType(), ptypes); - target = AdapterMethodHandle.makeSwapArguments(token, swapType, target, i, j); + target = AdapterMethodHandle.makeSwapArguments(swapType, target, i, j); if (target == null) throw newIllegalArgumentException("cannot swap"); assert(target.type() == swapType); oldType = swapType; @@ -760,7 +647,7 @@ public abstract class MethodHandleImpl { List> ptypes = oldType.parameterList(); ptypes = ptypes.subList(0, ptypes.size() - dupArgCount); MethodType dupType = MethodType.methodType(oldType.returnType(), ptypes); - target = AdapterMethodHandle.makeDupArguments(token, dupType, target, dupArgPos, dupArgCount); + target = AdapterMethodHandle.makeDupArguments(dupType, target, dupArgPos, dupArgCount); if (target == null) throw newIllegalArgumentException("cannot dup"); oldType = target.type(); @@ -778,7 +665,7 @@ public abstract class MethodHandleImpl { List> dropTypes = newType.parameterList() .subList(dropArgPos, dropArgPos + dropArgCount); MethodType dropType = oldType.insertParameterTypes(dropArgPos, dropTypes); - target = AdapterMethodHandle.makeDropArguments(token, dropType, target, dropArgPos, dropArgCount); + target = AdapterMethodHandle.makeDropArguments(dropType, target, dropArgPos, dropArgCount); if (target == null) throw newIllegalArgumentException("cannot drop"); oldType = target.type(); } @@ -787,7 +674,7 @@ public abstract class MethodHandleImpl { return target; if (oldType.parameterCount() != newType.parameterCount()) throw newIllegalArgumentException("mismatched parameter count"); - MethodHandle res = AdapterMethodHandle.makePairwiseConvert(token, newType, target); + MethodHandle res = AdapterMethodHandle.makePairwiseConvert(newType, target); if (res != null) return res; int argc = oldType.parameterCount(); @@ -797,26 +684,24 @@ public abstract class MethodHandleImpl { // then back to the desired types. We might have to use Java-based // method handles to do this. MethodType objType = MethodType.genericMethodType(argc); - MethodHandle objTarget = AdapterMethodHandle.makePairwiseConvert(token, objType, target); + MethodHandle objTarget = AdapterMethodHandle.makePairwiseConvert(objType, target); if (objTarget == null) objTarget = FromGeneric.make(target); - res = AdapterMethodHandle.makePairwiseConvert(token, newType, objTarget); + res = AdapterMethodHandle.makePairwiseConvert(newType, objTarget); if (res != null) return res; return ToGeneric.make(newType, objTarget); } - public static MethodHandle spreadArguments(Access token, - MethodHandle target, + static MethodHandle spreadArguments(MethodHandle target, MethodType newType, int spreadArg) { - Access.check(token); // TO DO: maybe allow the restarg to be Object and implicitly cast to Object[] MethodType oldType = target.type(); // spread the last argument of newType to oldType int spreadCount = oldType.parameterCount() - spreadArg; Class spreadArgType = Object[].class; - MethodHandle res = AdapterMethodHandle.makeSpreadArguments(token, newType, target, spreadArgType, spreadArg, spreadCount); + MethodHandle res = AdapterMethodHandle.makeSpreadArguments(newType, target, spreadArgType, spreadArg, spreadCount); if (res != null) return res; // try an intermediate adapter @@ -829,20 +714,19 @@ public abstract class MethodHandleImpl { ptypes[spreadArg + i] = VerifyType.spreadArgElementType(spreadType, i); MethodType midType = MethodType.methodType(newType.returnType(), ptypes); // after spreading, some arguments may need further conversion - MethodHandle target2 = convertArguments(token, target, midType, oldType, null); + MethodHandle target2 = convertArguments(target, midType, oldType, null); if (target2 == null) throw new UnsupportedOperationException("NYI: convert "+midType+" =calls=> "+oldType); - res = AdapterMethodHandle.makeSpreadArguments(token, newType, target2, spreadArgType, spreadArg, spreadCount); + res = AdapterMethodHandle.makeSpreadArguments(newType, target2, spreadArgType, spreadArg, spreadCount); if (res != null) return res; res = SpreadGeneric.make(target2, spreadCount); if (res != null) - res = convertArguments(token, res, newType, res.type(), null); + res = convertArguments(res, newType, res.type(), null); return res; } - public static MethodHandle collectArguments(Access token, - MethodHandle target, + static MethodHandle collectArguments(MethodHandle target, MethodType newType, int collectArg, MethodHandle collector) { @@ -856,29 +740,27 @@ public abstract class MethodHandleImpl { // oldType // (a..., b...)=>r assert(newType.parameterCount() == collectArg + colType.parameterCount()); assert(oldType.parameterCount() == collectArg + 1); - MethodHandle gtarget = convertArguments(token, target, oldType.generic(), oldType, null); - MethodHandle gcollector = convertArguments(token, collector, colType.generic(), colType, null); + MethodHandle gtarget = convertArguments(target, oldType.generic(), oldType, null); + MethodHandle gcollector = convertArguments(collector, colType.generic(), colType, null); if (gtarget == null || gcollector == null) return null; MethodHandle gresult = FilterGeneric.makeArgumentCollector(gcollector, gtarget); - MethodHandle result = convertArguments(token, gresult, newType, gresult.type(), null); + MethodHandle result = convertArguments(gresult, newType, gresult.type(), null); return result; } - public static MethodHandle filterArgument(Access token, - MethodHandle target, + static MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) { - Access.check(token); MethodType ttype = target.type(), gttype = ttype.generic(); if (ttype != gttype) { - target = convertArguments(token, target, gttype, ttype, null); + target = convertArguments(target, gttype, ttype, null); ttype = gttype; } MethodType ftype = filter.type(), gftype = ftype.generic(); if (ftype.parameterCount() != 1) throw new InternalError(); if (ftype != gftype) { - filter = convertArguments(token, filter, gftype, ftype, null); + filter = convertArguments(filter, gftype, ftype, null); ftype = gftype; } if (ftype == ttype) { @@ -888,27 +770,24 @@ public abstract class MethodHandleImpl { return FilterGeneric.makeArgumentFilter(pos, filter, target); } - public static MethodHandle foldArguments(Access token, - MethodHandle target, + static MethodHandle foldArguments(MethodHandle target, MethodType newType, MethodHandle combiner) { - Access.check(token); MethodType oldType = target.type(); MethodType ctype = combiner.type(); - MethodHandle gtarget = convertArguments(token, target, oldType.generic(), oldType, null); - MethodHandle gcombiner = convertArguments(token, combiner, ctype.generic(), ctype, null); + MethodHandle gtarget = convertArguments(target, oldType.generic(), oldType, null); + MethodHandle gcombiner = convertArguments(combiner, ctype.generic(), ctype, null); if (gtarget == null || gcombiner == null) return null; MethodHandle gresult = FilterGeneric.makeArgumentFolder(gcombiner, gtarget); - MethodHandle result = convertArguments(token, gresult, newType, gresult.type(), null); + MethodHandle result = convertArguments(gresult, newType, gresult.type(), null); return result; } - public static - MethodHandle dropArguments(Access token, MethodHandle target, + static + MethodHandle dropArguments(MethodHandle target, MethodType newType, int argnum) { - Access.check(token); int drops = newType.parameterCount() - target.type().parameterCount(); - MethodHandle res = AdapterMethodHandle.makeDropArguments(token, newType, target, argnum, drops); + MethodHandle res = AdapterMethodHandle.makeDropArguments(newType, target, argnum, drops); if (res != null) return res; throw new UnsupportedOperationException("NYI"); @@ -918,36 +797,34 @@ public abstract class MethodHandleImpl { private final MethodHandle test, target, fallback; private GuardWithTest(MethodHandle invoker, MethodHandle test, MethodHandle target, MethodHandle fallback) { - super(Access.TOKEN, invoker); + super(invoker); this.test = test; this.target = target; this.fallback = fallback; } - static MethodHandle make(Access token, - MethodHandle test, MethodHandle target, MethodHandle fallback) { - Access.check(token); + static MethodHandle make(MethodHandle test, MethodHandle target, MethodHandle fallback) { MethodType type = target.type(); int nargs = type.parameterCount(); if (nargs < INVOKES.length) { MethodHandle invoke = INVOKES[nargs]; MethodType gtype = type.generic(); assert(invoke.type().dropParameterTypes(0,1) == gtype); - MethodHandle gtest = convertArguments(token, test, gtype.changeReturnType(boolean.class), test.type(), null); - MethodHandle gtarget = convertArguments(token, target, gtype, type, null); - MethodHandle gfallback = convertArguments(token, fallback, gtype, type, null); + MethodHandle gtest = convertArguments(test, gtype.changeReturnType(boolean.class), test.type(), null); + MethodHandle gtarget = convertArguments(target, gtype, type, null); + MethodHandle gfallback = convertArguments(fallback, gtype, type, null); if (gtest == null || gtarget == null || gfallback == null) return null; MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback); - return convertArguments(token, gguard, type, gtype, null); + return convertArguments(gguard, type, gtype, null); } else { MethodHandle invoke = VARARGS_INVOKE; MethodType gtype = MethodType.genericMethodType(1); assert(invoke.type().dropParameterTypes(0,1) == gtype); - MethodHandle gtest = spreadArguments(token, test, gtype.changeReturnType(boolean.class), 0); - MethodHandle gtarget = spreadArguments(token, target, gtype, 0); - MethodHandle gfallback = spreadArguments(token, fallback, gtype, 0); + MethodHandle gtest = spreadArguments(test, gtype.changeReturnType(boolean.class), 0); + MethodHandle gtarget = spreadArguments(target, gtype, 0); + MethodHandle gfallback = spreadArguments(fallback, gtype, 0); MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback); if (gtest == null || gtarget == null || gfallback == null) return null; - return collectArguments(token, gguard, type, 0, null); + return collectArguments(gguard, type, 0, null); } } @Override @@ -1034,24 +911,23 @@ public abstract class MethodHandleImpl { } } - public static - MethodHandle makeGuardWithTest(Access token, - MethodHandle test, + static + MethodHandle makeGuardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback) { - return GuardWithTest.make(token, test, target, fallback); + return GuardWithTest.make(test, target, fallback); } private static class GuardWithCatch extends BoundMethodHandle { private final MethodHandle target; private final Class exType; private final MethodHandle catcher; - public GuardWithCatch(MethodHandle target, Class exType, MethodHandle catcher) { + GuardWithCatch(MethodHandle target, Class exType, MethodHandle catcher) { this(INVOKES[target.type().parameterCount()], target, exType, catcher); } - public GuardWithCatch(MethodHandle invoker, - MethodHandle target, Class exType, MethodHandle catcher) { - super(Access.TOKEN, invoker); + GuardWithCatch(MethodHandle invoker, + MethodHandle target, Class exType, MethodHandle catcher) { + super(invoker); this.target = target; this.exType = exType; this.catcher = catcher; @@ -1171,42 +1047,40 @@ public abstract class MethodHandleImpl { } - public static - MethodHandle makeGuardWithCatch(Access token, - MethodHandle target, + static + MethodHandle makeGuardWithCatch(MethodHandle target, Class exType, MethodHandle catcher) { - Access.check(token); MethodType type = target.type(); MethodType ctype = catcher.type(); int nargs = type.parameterCount(); if (nargs < GuardWithCatch.INVOKES.length) { MethodType gtype = type.generic(); MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class); - MethodHandle gtarget = convertArguments(token, target, gtype, type, null); - MethodHandle gcatcher = convertArguments(token, catcher, gcatchType, ctype, null); + MethodHandle gtarget = convertArguments(target, gtype, type, null); + MethodHandle gcatcher = convertArguments(catcher, gcatchType, ctype, null); MethodHandle gguard = new GuardWithCatch(gtarget, exType, gcatcher); if (gtarget == null || gcatcher == null || gguard == null) return null; - return convertArguments(token, gguard, type, gtype, null); + return convertArguments(gguard, type, gtype, null); } else { MethodType gtype = MethodType.genericMethodType(0, true); MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class); - MethodHandle gtarget = spreadArguments(token, target, gtype, 0); - MethodHandle gcatcher = spreadArguments(token, catcher, gcatchType, 1); + MethodHandle gtarget = spreadArguments(target, gtype, 0); + MethodHandle gcatcher = spreadArguments(catcher, gcatchType, 1); MethodHandle gguard = new GuardWithCatch(GuardWithCatch.VARARGS_INVOKE, gtarget, exType, gcatcher); if (gtarget == null || gcatcher == null || gguard == null) return null; - return collectArguments(token, gguard, type, 0, null); + return collectArguments(gguard, type, 0, null); } } - public static - MethodHandle throwException(Access token, MethodType type) { - Access.check(token); - return AdapterMethodHandle.makeRetypeRaw(token, type, THROW_EXCEPTION); + static + MethodHandle throwException(MethodType type) { + return AdapterMethodHandle.makeRetypeRaw(type, throwException()); } - static final MethodHandle THROW_EXCEPTION; - static { + static MethodHandle THROW_EXCEPTION; + static MethodHandle throwException() { + if (THROW_EXCEPTION != null) return THROW_EXCEPTION; try { THROW_EXCEPTION = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException", @@ -1214,71 +1088,19 @@ public abstract class MethodHandleImpl { } catch (ReflectiveOperationException ex) { throw new RuntimeException(ex); } + return THROW_EXCEPTION; } static Empty throwException(T t) throws T { throw t; } - public static String getNameString(Access token, MethodHandle target, Object type) { - Access.check(token); - if (!(type instanceof MethodType)) { - if (type == null) - type = target.type(); - else if (type instanceof MethodHandle) - type = ((MethodHandle)type).type(); - } - MemberName name = null; - if (target != null) - name = MethodHandleNatives.getMethodName(target); - if (name == null) - return "invoke" + type; - return name.getName() + type; - } - - public static String getNameString(Access token, MethodHandle target) { - return getNameString(token, target, null); - } - - 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(); - } - - static void checkSpreadArgument(Object av, int n) { - if (av == null ? n != 0 : ((Object[])av).length != n) - throw newIllegalArgumentException("Array is not of length "+n); - } - - static void raiseException(int code, Object actual, Object required) { - String message; - // disregard the identity of the actual object, if it is not a class: - if (!(actual instanceof Class) && !(actual instanceof MethodType)) - actual = actual.getClass(); - if (actual != null) - message = "required "+required+" but encountered "+actual; - else - message = "required "+required; - switch (code) { - case 192: // checkcast - throw new ClassCastException(message); - default: - throw new InternalError("unexpected code "+code+": "+message); - } - } - // Linkage support: - public static void registerBootstrap(Access token, Class callerClass, MethodHandle bootstrapMethod) { - Access.check(token); + static void registerBootstrap(Class callerClass, MethodHandle bootstrapMethod) { MethodHandleNatives.registerBootstrap(callerClass, bootstrapMethod); } - public static MethodHandle getBootstrap(Access token, Class callerClass) { - Access.check(token); + static MethodHandle getBootstrap(Class callerClass) { return MethodHandleNatives.getBootstrap(callerClass); } - public static MethodHandle asVarargsCollector(Access token, MethodHandle target, Class arrayType) { - Access.check(token); - return AdapterMethodHandle.makeVarargsCollector(token, target, arrayType); + static MethodHandle asVarargsCollector(MethodHandle target, Class arrayType) { + return AdapterMethodHandle.makeVarargsCollector(target, arrayType); } } diff --git a/src/share/classes/sun/dyn/MethodHandleNatives.java b/src/share/classes/java/dyn/MethodHandleNatives.java similarity index 91% rename from src/share/classes/sun/dyn/MethodHandleNatives.java rename to src/share/classes/java/dyn/MethodHandleNatives.java index 5f1076bff..ccf957d22 100644 --- a/src/share/classes/sun/dyn/MethodHandleNatives.java +++ b/src/share/classes/java/dyn/MethodHandleNatives.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,14 +23,13 @@ * questions. */ -package sun.dyn; +package java.dyn; -import java.dyn.*; import java.dyn.MethodHandles.Lookup; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; -import static sun.dyn.MethodHandleNatives.Constants.*; -import static sun.dyn.MethodHandleImpl.IMPL_LOOKUP; +import static java.dyn.MethodHandleNatives.Constants.*; +import static java.dyn.MethodHandles.Lookup.IMPL_LOOKUP; /** * The JVM interface for the method handles package is all here. @@ -81,14 +80,12 @@ class MethodHandleNatives { * This routine is for debugging and reflection. */ static MemberName getMethodName(MethodHandle self) { - if (!JVM_SUPPORT) return null; return (MemberName) getTarget(self, ETF_METHOD_NAME); } /** Fetch the reflective version of the handled method, if available. */ static AccessibleObject getTargetMethod(MethodHandle self) { - if (!JVM_SUPPORT) return null; return (AccessibleObject) getTarget(self, ETF_REFLECT_METHOD); } @@ -97,7 +94,6 @@ class MethodHandleNatives { * If it is chained to another method handle, return that handle. */ static Object getTargetInfo(MethodHandle self) { - if (!JVM_SUPPORT) return null; return getTarget(self, ETF_HANDLE_OR_METHOD_NAME); } @@ -111,11 +107,6 @@ class MethodHandleNatives { */ static native int getConstant(int which); - /** True iff this HotSpot JVM has built-in support for method handles. - * If false, some test cases might run, but functionality will be missing. - */ - public static final boolean JVM_SUPPORT; - /** Java copy of MethodHandlePushLimit in range 2..255. */ static final int JVM_PUSH_LIMIT; /** JVM stack motion (in words) after one slot is pushed, usually -1. @@ -127,31 +118,24 @@ class MethodHandleNatives { private static native void registerNatives(); static { - boolean JVM_SUPPORT_; int JVM_PUSH_LIMIT_; int JVM_STACK_MOVE_UNIT_; int CONV_OP_IMPLEMENTED_MASK_; try { registerNatives(); - JVM_SUPPORT_ = true; JVM_PUSH_LIMIT_ = getConstant(Constants.GC_JVM_PUSH_LIMIT); JVM_STACK_MOVE_UNIT_ = getConstant(Constants.GC_JVM_STACK_MOVE_UNIT); CONV_OP_IMPLEMENTED_MASK_ = getConstant(Constants.GC_CONV_OP_IMPLEMENTED_MASK); //sun.reflect.Reflection.registerMethodsToFilter(MethodHandleImpl.class, "init"); } catch (UnsatisfiedLinkError ee) { // ignore; if we use init() methods later we'll see linkage errors - JVM_SUPPORT_ = false; JVM_PUSH_LIMIT_ = 3; // arbitrary JVM_STACK_MOVE_UNIT_ = -1; // arbitrary CONV_OP_IMPLEMENTED_MASK_ = 0; - //System.out.println("Warning: Running with JVM_SUPPORT=false"); - //System.out.println(ee); - JVM_SUPPORT = JVM_SUPPORT_; JVM_PUSH_LIMIT = JVM_PUSH_LIMIT_; JVM_STACK_MOVE_UNIT = JVM_STACK_MOVE_UNIT_; throw ee; // just die; hopeless to try to run with an older JVM } - JVM_SUPPORT = JVM_SUPPORT_; JVM_PUSH_LIMIT = JVM_PUSH_LIMIT_; JVM_STACK_MOVE_UNIT = JVM_STACK_MOVE_UNIT_; if (CONV_OP_IMPLEMENTED_MASK_ == 0) @@ -191,7 +175,7 @@ class MethodHandleNatives { // AdapterMethodHandle /** Conversions recognized by the JVM. - * They must align with the constants in sun.dyn_AdapterMethodHandle, + * They must align with the constants in java.dyn_AdapterMethodHandle, * in the JVM file hotspot/src/share/vm/classfile/javaClasses.hpp. */ static final int @@ -292,7 +276,7 @@ class MethodHandleNatives { return true; } static { - if (JVM_SUPPORT) verifyConstants(); + verifyConstants(); } // Up-calls from the JVM. @@ -305,28 +289,47 @@ class MethodHandleNatives { String name, MethodType type, Object info, MemberName callerMethod, int callerBCI) { - return CallSiteImpl.makeSite(bootstrapMethod, name, type, info, callerMethod, callerBCI); + return CallSite.makeSite(bootstrapMethod, name, type, info, callerMethod, callerBCI); + } + + /** + * Called by the JVM to check the length of a spread array. + */ + static void checkSpreadArgument(Object av, int n) { + MethodHandleStatics.checkSpreadArgument(av, n); } /** * The JVM wants a pointer to a MethodType. Oblige it by finding or creating one. */ static MethodType findMethodHandleType(Class rtype, Class[] ptypes) { - MethodType.genericMethodType(0); // trigger initialization - return MethodTypeImpl.makeImpl(Access.TOKEN, rtype, ptypes, true); + return MethodType.makeImpl(rtype, ptypes, true); } /** * The JVM wants to use a MethodType with invokeGeneric. Give the runtime fair warning. */ static void notifyGenericMethodType(MethodType type) { - try { - // Trigger adapter creation. - InvokeGeneric.genericInvokerOf(type); - } catch (Exception ex) { - Error err = new InternalError("Exception while resolving invokeGeneric"); - err.initCause(ex); - throw err; + type.form().notifyGenericMethodType(); + } + + /** + * The JVM wants to raise an exception. Here's the path. + */ + static void raiseException(int code, Object actual, Object required) { + String message; + // disregard the identity of the actual object, if it is not a class: + if (!(actual instanceof Class) && !(actual instanceof MethodType)) + actual = actual.getClass(); + if (actual != null) + message = "required "+required+" but encountered "+actual; + else + message = "required "+required; + switch (code) { + case 192: // checkcast + throw new ClassCastException(message); + default: + throw new InternalError("unexpected code "+code+": "+message); } } diff --git a/src/share/classes/java/dyn/MethodHandleStatics.java b/src/share/classes/java/dyn/MethodHandleStatics.java new file mode 100644 index 000000000..4ed38dd9b --- /dev/null +++ b/src/share/classes/java/dyn/MethodHandleStatics.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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.dyn; + +/** + * This class consists exclusively of static names internal to the + * method handle implementation. + * Usage: {@code import static java.dyn.MethodHandleStatics.*} + * @author John Rose, JSR 292 EG + */ +/*non-public*/ class MethodHandleStatics { + + private MethodHandleStatics() { } // do not instantiate + + /*non-public*/ static String getNameString(MethodHandle target, MethodType type) { + if (type == null) + type = target.type(); + MemberName name = null; + if (target != null) + name = MethodHandleNatives.getMethodName(target); + 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(); + } + + static void checkSpreadArgument(Object av, int n) { + if (av == null ? n != 0 : ((Object[])av).length != n) + throw newIllegalArgumentException("Array is not of length "+n); + } + + // handy shared exception makers (they simplify the common case code) + /*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 Error uncaughtException(Exception ex) { + Error err = new InternalError("uncaught exception"); + err.initCause(ex); + return err; + } + private static String message(String message, Object obj) { + if (obj != null) message = message + ": " + obj; + return message; + } +} diff --git a/src/share/classes/java/dyn/MethodHandles.java b/src/share/classes/java/dyn/MethodHandles.java index 3bc9bd4a3..2f4993bbe 100644 --- a/src/share/classes/java/dyn/MethodHandles.java +++ b/src/share/classes/java/dyn/MethodHandles.java @@ -26,9 +26,6 @@ package java.dyn; import java.lang.reflect.*; -import sun.dyn.Access; -import sun.dyn.MemberName; -import sun.dyn.MethodHandleImpl; import sun.dyn.WrapperInstance; import sun.dyn.util.ValueConversions; import sun.dyn.util.VerifyAccess; @@ -36,11 +33,8 @@ import sun.dyn.util.Wrapper; import java.util.List; import java.util.ArrayList; import java.util.Arrays; -import sun.dyn.Invokers; -import sun.dyn.MethodTypeImpl; import sun.reflect.Reflection; -import static sun.dyn.MemberName.newIllegalArgumentException; -import static sun.dyn.MemberName.newNoAccessException; +import static java.dyn.MethodHandleStatics.*; /** * This class consists exclusively of static methods that operate on or return @@ -58,8 +52,7 @@ public class MethodHandles { private MethodHandles() { } // do not instantiate - private static final Access IMPL_TOKEN = Access.getToken(); - private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(IMPL_TOKEN); + private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(); static { MethodHandleImpl.initStatics(); } // See IMPL_LOOKUP below. @@ -410,9 +403,8 @@ public class MethodHandles { checkUnprivilegedlookupClass(lookupClass); } - Lookup(Access token, Class lookupClass) { + Lookup(Class lookupClass) { this(lookupClass, ALL_MODES); - Access.check(token); } private Lookup(Class lookupClass, int allowedModes) { @@ -471,7 +463,7 @@ public class MethodHandles { } // Make sure outer class is initialized first. - static { IMPL_TOKEN.getClass(); } + static { IMPL_NAMES.getClass(); } /** Version of lookup which is trusted minimally. * It can only be used to create method handles to @@ -481,11 +473,10 @@ public class MethodHandles { /** Package-private version of lookup which is trusted. */ static final Lookup IMPL_LOOKUP = new Lookup(Object.class, TRUSTED); - static { MethodHandleImpl.initLookup(IMPL_TOKEN, IMPL_LOOKUP); } private static void checkUnprivilegedlookupClass(Class lookupClass) { String name = lookupClass.getName(); - if (name.startsWith("java.dyn.") || name.startsWith("sun.dyn.")) + if (name.startsWith("java.dyn.")) throw newIllegalArgumentException("illegal lookupClass: "+lookupClass); } @@ -577,7 +568,7 @@ public class MethodHandles { MethodHandle findStatic(Class refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { MemberName method = resolveOrFail(refc, name, type, true); checkMethod(refc, method, true); - return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClassOrNull()); + return MethodHandleImpl.findMethod(method, false, lookupClassOrNull()); } /** @@ -618,7 +609,7 @@ public class MethodHandles { public MethodHandle findVirtual(Class refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { MemberName method = resolveOrFail(refc, name, type, false); checkMethod(refc, method, false); - MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull()); + MethodHandle mh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull()); return restrictProtectedReceiver(method, mh); } @@ -651,8 +642,8 @@ public class MethodHandles { MemberName ctor = resolveOrFail(refc, name, type, false, false, lookupClassOrNull()); assert(ctor.isConstructor()); checkAccess(refc, ctor); - MethodHandle rawMH = MethodHandleImpl.findMethod(IMPL_TOKEN, ctor, false, lookupClassOrNull()); - MethodHandle allocMH = MethodHandleImpl.makeAllocator(IMPL_TOKEN, rawMH); + MethodHandle rawMH = MethodHandleImpl.findMethod(ctor, false, lookupClassOrNull()); + MethodHandle allocMH = MethodHandleImpl.makeAllocator(rawMH); return fixVarargs(allocMH, rawMH); } @@ -708,7 +699,7 @@ public class MethodHandles { checkSpecialCaller(specialCaller); MemberName method = resolveOrFail(refc, name, type, false, false, specialCaller); checkMethod(refc, method, false); - MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, specialCaller); + MethodHandle mh = MethodHandleImpl.findMethod(method, false, specialCaller); return restrictReceiver(method, mh, specialCaller); } @@ -839,10 +830,10 @@ return mh1; Class refc = receiver.getClass(); // may get NPE MemberName method = resolveOrFail(refc, name, type, false); checkMethod(refc, method, false); - MethodHandle dmh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull()); - MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, dmh, receiver); + MethodHandle dmh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull()); + MethodHandle bmh = MethodHandleImpl.bindReceiver(dmh, receiver); if (bmh == null) - throw newNoAccessException(method, this); + throw method.makeAccessException("no access", this); if (dmh.type().parameterCount() == 0) return dmh; // bound the trailing parameter; no varargs possible return fixVarargs(bmh, dmh); @@ -871,7 +862,7 @@ return mh1; MemberName method = new MemberName(m); assert(method.isMethod()); if (!m.isAccessible()) checkMethod(method.getDeclaringClass(), method, method.isStatic()); - MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull()); + MethodHandle mh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull()); if (!m.isAccessible()) mh = restrictProtectedReceiver(method, mh); return mh; } @@ -901,7 +892,7 @@ return mh1; assert(method.isMethod()); // ignore m.isAccessible: this is a new kind of access checkMethod(m.getDeclaringClass(), method, false); - MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClassOrNull()); + MethodHandle mh = MethodHandleImpl.findMethod(method, false, lookupClassOrNull()); return restrictReceiver(method, mh, specialCaller); } @@ -928,8 +919,8 @@ return mh1; MemberName ctor = new MemberName(c); assert(ctor.isConstructor()); if (!c.isAccessible()) checkAccess(c.getDeclaringClass(), ctor); - MethodHandle rawCtor = MethodHandleImpl.findMethod(IMPL_TOKEN, ctor, false, lookupClassOrNull()); - MethodHandle allocator = MethodHandleImpl.makeAllocator(IMPL_TOKEN, rawCtor); + MethodHandle rawCtor = MethodHandleImpl.findMethod(ctor, false, lookupClassOrNull()); + MethodHandle allocator = MethodHandleImpl.makeAllocator(rawCtor); return fixVarargs(allocator, rawCtor); } @@ -999,7 +990,7 @@ return mh1; void checkSymbolicClass(Class refc) throws IllegalAccessException { Class caller = lookupClassOrNull(); if (caller != null && !VerifyAccess.isClassAccessible(refc, caller)) - throw newNoAccessException("symbolic reference class is not public", new MemberName(refc), this); + throw new MemberName(refc).makeAccessException("symbolic reference class is not public", this); } void checkMethod(Class refc, MemberName m, boolean wantStatic) throws IllegalAccessException { @@ -1012,7 +1003,7 @@ return mh1; message = wantStatic ? "expected a static method" : "expected a non-static method"; else { checkAccess(refc, m); return; } - throw newNoAccessException(message, m, this); + throw m.makeAccessException(message, this); } void checkAccess(Class refc, MemberName m) throws IllegalAccessException { @@ -1030,7 +1021,7 @@ return mh1; && VerifyAccess.isSamePackage(m.getDeclaringClass(), lookupClass())) // Protected members can also be checked as if they were package-private. return; - throw newNoAccessException(accessFailedMessage(refc, m), m, this); + throw m.makeAccessException(accessFailedMessage(refc, m), this); } String accessFailedMessage(Class refc, MemberName m) { @@ -1064,8 +1055,8 @@ return mh1; || (specialCaller != lookupClass() && !(ALLOW_NESTMATE_ACCESS && VerifyAccess.isSamePackageMember(specialCaller, lookupClass())))) - throw newNoAccessException("no private access for invokespecial", - new MemberName(specialCaller), this); + throw new MemberName(specialCaller). + makeAccessException("no private access for invokespecial", this); } MethodHandle restrictProtectedReceiver(MemberName method, MethodHandle mh) throws IllegalAccessException { @@ -1084,12 +1075,12 @@ return mh1; assert(!method.isStatic()); Class defc = method.getDeclaringClass(); // receiver type of mh is too wide if (defc.isInterface() || !defc.isAssignableFrom(caller)) { - throw newNoAccessException("caller class must be a subclass below the method", method, caller); + throw method.makeAccessException("caller class must be a subclass below the method", caller); } MethodType rawType = mh.type(); if (rawType.parameterType(0) == caller) return mh; MethodType narrowType = rawType.changeParameterType(0, caller); - MethodHandle narrowMH = MethodHandleImpl.convertArguments(IMPL_TOKEN, mh, narrowType, rawType, null); + MethodHandle narrowMH = MethodHandleImpl.convertArguments(mh, narrowType, rawType, null); return fixVarargs(narrowMH, mh); } @@ -1097,10 +1088,9 @@ return mh1; boolean isStatic, boolean isSetter) throws NoSuchFieldException, IllegalAccessException { MemberName field = resolveOrFail(refc, name, type, isStatic); if (isStatic != field.isStatic()) - throw newNoAccessException(isStatic - ? "expected a static field" - : "expected a non-static field", - field, this); + throw field.makeAccessException(isStatic + ? "expected a static field" + : "expected a non-static field", this); return makeAccessor(refc, field, false, isSetter); } @@ -1108,9 +1098,9 @@ return mh1; boolean trusted, boolean isSetter) throws IllegalAccessException { assert(field.isField()); if (trusted) - return MethodHandleImpl.accessField(IMPL_TOKEN, field, isSetter, lookupClassOrNull()); + return MethodHandleImpl.accessField(field, isSetter, lookupClassOrNull()); checkAccess(refc, field); - MethodHandle mh = MethodHandleImpl.accessField(IMPL_TOKEN, field, isSetter, lookupClassOrNull()); + MethodHandle mh = MethodHandleImpl.accessField(field, isSetter, lookupClassOrNull()); return restrictProtectedReceiver(field, mh); } } @@ -1127,7 +1117,7 @@ return mh1; */ public static MethodHandle arrayElementGetter(Class arrayClass) throws IllegalArgumentException { - return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, false); + return MethodHandleImpl.accessArrayElement(arrayClass, false); } /** @@ -1141,7 +1131,7 @@ return mh1; */ public static MethodHandle arrayElementSetter(Class arrayClass) throws IllegalArgumentException { - return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, true); + return MethodHandleImpl.accessArrayElement(arrayClass, true); } /// method handle invocation (reflective style) @@ -1191,7 +1181,7 @@ return invoker; MethodHandle spreadInvoker(MethodType type, int objectArgCount) { if (objectArgCount < 0 || objectArgCount > type.parameterCount()) throw new IllegalArgumentException("bad argument count "+objectArgCount); - return invokers(type).spreadInvoker(objectArgCount); + return type.invokers().spreadInvoker(objectArgCount); } /** @@ -1231,7 +1221,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeExact", type) */ static public MethodHandle exactInvoker(MethodType type) { - return invokers(type).exactInvoker(); + return type.invokers().exactInvoker(); } /** @@ -1258,11 +1248,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeGeneric", type) */ static public MethodHandle genericInvoker(MethodType type) { - return invokers(type).genericInvoker(); - } - - static Invokers invokers(MethodType type) { - return MethodTypeImpl.invokers(IMPL_TOKEN, type); + return type.invokers().genericInvoker(); } /** @@ -1387,7 +1373,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeGeneric", type) return target; MethodHandle res = null; try { - res = MethodHandleImpl.convertArguments(IMPL_TOKEN, target, + res = MethodHandleImpl.convertArguments(target, newType, oldType, null); } catch (IllegalArgumentException ex) { } @@ -1531,7 +1517,7 @@ assert((int)twice.invokeExact(21) == 42); MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder) { MethodType oldType = target.type(); checkReorder(reorder, newType, oldType); - return MethodHandleImpl.convertArguments(IMPL_TOKEN, target, + return MethodHandleImpl.convertArguments(target, newType, oldType, reorder); } @@ -1574,7 +1560,7 @@ assert((int)twice.invokeExact(21) == 42); int numSpread = (outargs - spreadPos); MethodHandle res = null; if (spreadPos >= 0 && numSpread >= 0) { - res = MethodHandleImpl.spreadArguments(IMPL_TOKEN, target, newType, spreadPos); + res = MethodHandleImpl.spreadArguments(target, newType, spreadPos); } if (res == null) { throw newIllegalArgumentException("cannot spread "+newType+" to " +oldType); @@ -1607,7 +1593,7 @@ assert((int)twice.invokeExact(21) == 42); int numCollect = (inargs - collectPos); if (collectPos < 0 || numCollect < 0) throw newIllegalArgumentException("wrong number of arguments"); - MethodHandle res = MethodHandleImpl.collectArguments(IMPL_TOKEN, target, newType, collectPos, null); + MethodHandle res = MethodHandleImpl.collectArguments(target, newType, collectPos, null); if (res == null) { throw newIllegalArgumentException("cannot collect from "+newType+" to " +oldType); } @@ -1654,7 +1640,13 @@ assert((int)twice.invokeExact(21) == 42); MethodHandle identity(Class type) { if (type == void.class) throw newIllegalArgumentException("void type"); - return ValueConversions.identity(type); + else if (type == Object.class) + return ValueConversions.identity(); + else if (type.isPrimitive()) + return ValueConversions.identity(Wrapper.forPrimitiveType(type)); + else + return AdapterMethodHandle.makeRetypeRaw( + MethodType.methodType(type, type), ValueConversions.identity()); } /** @@ -1701,14 +1693,14 @@ assert((int)twice.invokeExact(21) == 42); value = checkValue(valueType, value); if (pos == 0 && !valueType.isPrimitive()) { // At least for now, make bound method handles a special case. - MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, result, value); + MethodHandle bmh = MethodHandleImpl.bindReceiver(result, value); if (bmh != null) { result = bmh; continue; } // else fall through to general adapter machinery } - result = MethodHandleImpl.bindArgument(IMPL_TOKEN, result, pos, value); + result = MethodHandleImpl.bindArgument(result, pos, value); } return result; } @@ -1762,7 +1754,7 @@ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z")); new ArrayList>(oldType.parameterList()); ptypes.addAll(pos, valueTypes); MethodType newType = MethodType.methodType(oldType.returnType(), ptypes); - return MethodHandleImpl.dropArguments(IMPL_TOKEN, target, newType, pos); + return MethodHandleImpl.dropArguments(target, newType, pos); } /** @@ -1855,11 +1847,11 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY || filterType.returnType() != targetType.parameterType(curPos)) throw newIllegalArgumentException("target and filter types do not match"); adapterType = adapterType.changeParameterType(curPos, filterType.parameterType(0)); - adapter = MethodHandleImpl.filterArgument(IMPL_TOKEN, adapter, curPos, filter); + adapter = MethodHandleImpl.filterArgument(adapter, curPos, filter); } MethodType midType = adapter.type(); if (midType != adapterType) - adapter = MethodHandleImpl.convertArguments(IMPL_TOKEN, adapter, adapterType, midType, null); + adapter = MethodHandleImpl.convertArguments(adapter, adapterType, midType, null); return adapter; } @@ -1966,7 +1958,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2 if (!ok) throw misMatchedTypes("target and combiner types", targetType, combinerType); MethodType newType = targetType.dropParameterTypes(0, 1); - return MethodHandleImpl.foldArguments(IMPL_TOKEN, target, newType, combiner); + return MethodHandleImpl.foldArguments(target, newType, combiner); } /** @@ -2021,7 +2013,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2 test = dropArguments(test, gpc, targs.subList(gpc, tpc)); gtype = test.type(); } - return MethodHandleImpl.makeGuardWithTest(IMPL_TOKEN, test, target, fallback); + return MethodHandleImpl.makeGuardWithTest(test, target, fallback); } static RuntimeException misMatchedTypes(String what, MethodType t1, MethodType t2) { @@ -2092,7 +2084,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2 handler = dropArguments(handler, hpc, hargs.subList(hpc, tpc)); htype = handler.type(); } - return MethodHandleImpl.makeGuardWithCatch(IMPL_TOKEN, target, exType, handler); + return MethodHandleImpl.makeGuardWithCatch(target, exType, handler); } /** @@ -2107,7 +2099,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2 */ public static MethodHandle throwException(Class returnType, Class exType) { - return MethodHandleImpl.throwException(IMPL_TOKEN, MethodType.methodType(returnType, exType)); + return MethodHandleImpl.throwException(MethodType.methodType(returnType, exType)); } /** @@ -2334,6 +2326,6 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2 /*non-public*/ static MethodHandle asVarargsCollector(MethodHandle target, Class arrayType) { - return MethodHandleImpl.asVarargsCollector(IMPL_TOKEN, target, arrayType); + return MethodHandleImpl.asVarargsCollector(target, arrayType); } } diff --git a/src/share/classes/java/dyn/MethodType.java b/src/share/classes/java/dyn/MethodType.java index a7baf7c63..be496c42a 100644 --- a/src/share/classes/java/dyn/MethodType.java +++ b/src/share/classes/java/dyn/MethodType.java @@ -29,12 +29,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; -import sun.dyn.Access; -import sun.dyn.Invokers; -import sun.dyn.MethodHandleImpl; -import sun.dyn.MethodTypeImpl; import sun.dyn.util.BytecodeDescriptor; -import static sun.dyn.MemberName.newIllegalArgumentException; +import static java.dyn.MethodHandleStatics.*; /** * A method type represents the arguments and return type accepted and @@ -96,34 +92,6 @@ class MethodType implements java.io.Serializable { private MethodType wrapAlt; // alternative wrapped/unwrapped version private Invokers invokers; // cache of handy higher-order adapters - private static final Access IMPL_TOKEN = Access.getToken(); - - // share a cache with a friend in this package - Invokers getInvokers() { return invokers; } - void setInvokers(Invokers inv) { invokers = inv; } - - static { - // This hack allows the implementation package special access to - // the internals of MethodType. In particular, the MTImpl has all sorts - // of cached information useful to the implementation code. - MethodTypeImpl.setMethodTypeFriend(IMPL_TOKEN, new MethodTypeImpl.MethodTypeFriend() { - public Class[] ptypes(MethodType mt) { return mt.ptypes; } - public MethodTypeImpl form(MethodType mt) { return mt.form; } - public void setForm(MethodType mt, MethodTypeImpl form) { - assert(mt.form == null); - mt.form = (MethodTypeForm) form; - } - public MethodType makeImpl(Class rtype, Class[] ptypes, boolean trusted) { - return MethodType.makeImpl(rtype, ptypes, trusted); - } - public MethodTypeImpl newMethodTypeForm(MethodType mt) { - return new MethodTypeForm(mt); - } - public Invokers getInvokers(MethodType mt) { return mt.invokers; } - public void setInvokers(MethodType mt, Invokers inv) { mt.invokers = inv; } - }); - } - /** * Check the given parameters for validity and store them into the final fields. */ @@ -134,6 +102,10 @@ class MethodType implements java.io.Serializable { this.ptypes = ptypes; } + /*trusted*/ MethodTypeForm form() { return form; } + /*trusted*/ Class rtype() { return rtype; } + /*trusted*/ Class[] ptypes() { return ptypes; } + private static void checkRtype(Class rtype) { rtype.equals(rtype); // null check } @@ -253,7 +225,7 @@ class MethodType implements java.io.Serializable { * @param trusted whether the ptypes can be used without cloning * @return the unique method type of the desired structure */ - private static + /*trusted*/ static MethodType makeImpl(Class rtype, Class[] ptypes, boolean trusted) { if (ptypes == null || ptypes.length == 0) { ptypes = NO_PTYPES; trusted = true; @@ -269,7 +241,12 @@ class MethodType implements java.io.Serializable { // defensively copy the array passed in by the user mt1 = new MethodType(rtype, ptypes.clone()); // promote the object to the Real Thing, and reprobe - MethodTypeImpl.initForm(IMPL_TOKEN, mt1); + MethodTypeForm form = MethodTypeForm.findForm(mt1); + mt1.form = form; + if (form.erasedType == mt1) { + // This is a principal (erased) type; show it to the JVM. + MethodHandleNatives.init(mt1); + } synchronized (internTable) { mt0 = internTable.get(mt1); if (mt0 != null) @@ -279,12 +256,6 @@ class MethodType implements java.io.Serializable { return mt1; } - // Entry point from JVM. TODO: Change the name & signature. - private static MethodType makeImpl(Class rtype, Class[] ptypes, - boolean ignore1, boolean ignore2) { - return makeImpl(rtype, ptypes, true); - } - private static final MethodType[] objectOnlyTypes = new MethodType[20]; /** @@ -535,7 +506,7 @@ class MethodType implements java.io.Serializable { MethodType wt = pt.wrapAlt; if (wt == null) { // fill in lazily - wt = MethodTypeImpl.canonicalize(pt, MethodTypeImpl.WRAP, MethodTypeImpl.WRAP); + wt = MethodTypeForm.canonicalize(pt, MethodTypeForm.WRAP, MethodTypeForm.WRAP); assert(wt != null); pt.wrapAlt = wt; } @@ -547,7 +518,7 @@ class MethodType implements java.io.Serializable { MethodType uwt = wt.wrapAlt; if (uwt == null) { // fill in lazily - uwt = MethodTypeImpl.canonicalize(wt, MethodTypeImpl.UNWRAP, MethodTypeImpl.UNWRAP); + uwt = MethodTypeForm.canonicalize(wt, MethodTypeForm.UNWRAP, MethodTypeForm.UNWRAP); if (uwt == null) uwt = wt; // type has no wrappers or prims at all wt.wrapAlt = uwt; @@ -666,12 +637,18 @@ class MethodType implements java.io.Serializable { * This method is included for the benfit of applications that must * generate bytecodes that process method handles and invokedynamic. * @return the number of JVM stack slots for this type's parameters - * @deprecated Will be removed for PFD. */ - public int parameterSlotCount() { + /*non-public*/ int parameterSlotCount() { return form.parameterSlotCount(); } + /*non-public*/ Invokers invokers() { + Invokers inv = invokers; + if (inv != null) return inv; + invokers = inv = new Invokers(this); + return inv; + } + /** 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 @@ -694,9 +671,8 @@ class MethodType implements java.io.Serializable { * @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()} - * @deprecated Will be removed for PFD. */ - public int parameterSlotDepth(int num) { + /*non-public*/ int parameterSlotDepth(int num) { if (num < 0 || num > ptypes.length) parameterType(num); // force a range check return form.parameterToArgSlot(num-1); @@ -710,9 +686,9 @@ class MethodType implements java.io.Serializable { * This method is included for the benfit 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 - * @deprecated Will be removed for PFD. + * Will be removed for PFD. */ - public int returnSlotCount() { + /*non-public*/ int returnSlotCount() { return form.returnSlotCount(); } diff --git a/src/share/classes/java/dyn/MethodTypeForm.java b/src/share/classes/java/dyn/MethodTypeForm.java index 35c59a45c..217d2f220 100644 --- a/src/share/classes/java/dyn/MethodTypeForm.java +++ b/src/share/classes/java/dyn/MethodTypeForm.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,15 +25,452 @@ package java.dyn; +import sun.dyn.util.Wrapper; +import static java.dyn.MethodHandleStatics.*; + /** - * TO DO: Temporary shim; remove after refactoring effects are complete in JVM. + * Shared information for a group of method types, which differ + * only by reference types, and therefore share a common erasure + * and wrapping. + *

+ * For an empirical discussion of the structure of method types, + * see + * the thread "Avoiding Boxing" on jvm-languages. + * 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 */ -import sun.dyn.MethodTypeImpl; +class MethodTypeForm { + final int[] argToSlotTable, slotToArgTable; + final long argCounts; // packed slot & value counts + final long primCounts; // packed prim & double counts + final int vmslots; // total number of parameter slots + final MethodType erasedType; // the canonical erasure + + /*lazy*/ MethodType primsAsBoxes; // replace prims by wrappers + /*lazy*/ MethodType primArgsAsBoxes; // wrap args only; make raw return + /*lazy*/ MethodType primsAsInts; // replace prims by int/long + /*lazy*/ MethodType primsAsLongs; // replace prims by long + /*lazy*/ MethodType primsAtEnd; // reorder primitives to the end + + // Cached adapter information: + /*lazy*/ ToGeneric toGeneric; // convert cs. with prims to w/o + /*lazy*/ FromGeneric fromGeneric; // convert cs. w/o prims to with + /*lazy*/ SpreadGeneric[] spreadGeneric; // expand one argument to many + /*lazy*/ FilterGeneric filterGeneric; // convert argument(s) on the fly + /*lazy*/ MethodHandle genericInvoker; // hook for invokeGeneric + + public MethodType erasedType() { + return erasedType; + } + + 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; + for (int i = 0; i < epts.length; i++) { + Class pt = epts[i]; + if (pt != Object.class) { + assert(pt.isPrimitive()); + ++pac; + if (hasTwoArgSlots(pt)) ++lac; + } + } + pslotCount += lac; // #slots = #args + #longs + Class rt = erasedType.returnType(); + if (rt != Object.class) { + ++prc; // even void.class counts as a prim here + if (hasTwoArgSlots(rt)) ++lrc; + // adjust #slots, #args + if (rt == void.class) + rtypeCount = rslotCount = 0; + else + rslotCount += lrc; + } + 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]; + if (hasTwoArgSlots(pt)) --slot; + --slot; + slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note + argToSlotTab[1+i] = slot; + } + assert(slot == 0); // filled the table + } + this.primCounts = pack(lrc, prc, lac, pac); + this.argCounts = pack(rslotCount, rtypeCount, pslotCount, ptypeCount); + if (slotToArgTab == null) { + 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.argToSlotTable = argToSlotTab; + this.slotToArgTable = slotToArgTab; + + if (pslotCount >= 256) throw newIllegalArgumentException("too many arguments"); + + // send a few bits down to the JVM: + this.vmslots = parameterSlotCount(); + + // short circuit some no-op canonicalizations: + if (!hasPrimitives()) { + primsAsBoxes = erasedType; + primArgsAsBoxes = erasedType; + primsAsInts = erasedType; + primsAsLongs = erasedType; + primsAtEnd = erasedType; + } + } + + /** Turn all primitive types to corresponding wrapper types. + */ + public MethodType primsAsBoxes() { + MethodType ct = primsAsBoxes; + if (ct != null) return ct; + MethodType t = erasedType; + ct = canonicalize(erasedType, WRAP, WRAP); + if (ct == null) ct = t; // no prims to box + return primsAsBoxes = ct; + } + + /** Turn all primitive argument types to corresponding wrapper types. + * Subword and void return types are promoted to int. + */ + public MethodType primArgsAsBoxes() { + MethodType ct = primArgsAsBoxes; + if (ct != null) return ct; + MethodType t = erasedType; + ct = canonicalize(erasedType, RAW_RETURN, WRAP); + if (ct == null) ct = t; // no prims to box + return primArgsAsBoxes = ct; + } + + /** Turn all primitive types to either int or long. + * Floating point return types are not changed, because + * they may require special calling sequences. + * A void return value is turned to int. + */ + public MethodType primsAsInts() { + MethodType ct = primsAsInts; + if (ct != null) return ct; + MethodType t = erasedType; + ct = canonicalize(t, RAW_RETURN, INTS); + if (ct == null) ct = t; // no prims to int-ify + return primsAsInts = ct; + } + + /** Turn all primitive types to either int or long. + * Floating point return types are not changed, because + * they may require special calling sequences. + * A void return value is turned to int. + */ + public MethodType primsAsLongs() { + MethodType ct = primsAsLongs; + if (ct != null) return ct; + MethodType t = erasedType; + ct = canonicalize(t, RAW_RETURN, LONGS); + if (ct == null) ct = t; // no prims to int-ify + return primsAsLongs = ct; + } + + /** Stably sort parameters into 3 buckets: ref, int, long. */ + public MethodType primsAtEnd() { + MethodType ct = primsAtEnd; + if (ct != null) return ct; + MethodType t = erasedType; + + int pac = primitiveParameterCount(); + if (pac == 0) + return primsAtEnd = t; + + int argc = parameterCount(); + int lac = longPrimitiveParameterCount(); + if (pac == argc && (lac == 0 || lac == argc)) + return primsAtEnd = t; + + // known to have a mix of 2 or 3 of ref, int, long + int[] reorder = primsAtEndOrder(t); + ct = reorderParameters(t, reorder, null); + //System.out.println("t="+t+" / reorder="+java.util.Arrays.toString(reorder)+" => "+ct); + return primsAtEnd = ct; + } + + /** Compute a new ordering of parameters so that all references + * are before all ints or longs, and all ints are before all longs. + * For this ordering, doubles count as longs, and all other primitive + * values count as ints. + * As a special case, if the parameters are already in the specified + * order, this method returns a null reference, rather than an array + * specifying a null permutation. + *

+ * For example, the type {@code (int,boolean,int,Object,String)void} + * produces the order {@code {3,4,0,1,2}}, the type + * {@code (long,int,String)void} produces {@code {2,1,2}}, and + * the type {@code (Object,int)Object} produces {@code null}. + */ + public static int[] primsAtEndOrder(MethodType mt) { + MethodTypeForm form = mt.form(); + if (form.primsAtEnd == form.erasedType) + // quick check shows no reordering is necessary + return null; + + int argc = form.parameterCount(); + int[] paramOrder = new int[argc]; + + // 3-way bucket sort: + int pac = form.primitiveParameterCount(); + int lac = form.longPrimitiveParameterCount(); + int rfill = 0, ifill = argc - pac, lfill = argc - lac; + + Class[] ptypes = mt.ptypes(); + boolean changed = false; + for (int i = 0; i < ptypes.length; i++) { + Class pt = ptypes[i]; + int ord; + if (!pt.isPrimitive()) ord = rfill++; + else if (!hasTwoArgSlots(pt)) ord = ifill++; + else ord = lfill++; + if (ord != i) changed = true; + assert(paramOrder[ord] == 0); + paramOrder[ord] = i; + } + assert(rfill == argc - pac && ifill == argc - lac && lfill == argc); + if (!changed) { + form.primsAtEnd = form.erasedType; + return null; + } + return paramOrder; + } -class MethodTypeForm extends MethodTypeImpl { + /** Put the existing parameters of mt into a new order, given by newParamOrder. + * The third argument is logically appended to mt.parameterArray, + * so that elements of newParamOrder can index either pre-existing or + * new parameter types. + */ + public static MethodType reorderParameters(MethodType mt, int[] newParamOrder, Class[] moreParams) { + if (newParamOrder == null) return mt; // no-op reordering + Class[] ptypes = mt.ptypes(); + Class[] ntypes = new Class[newParamOrder.length]; + int maxParam = ptypes.length + (moreParams == null ? 0 : moreParams.length); + boolean changed = (ntypes.length != ptypes.length); + for (int i = 0; i < newParamOrder.length; i++) { + int param = newParamOrder[i]; + if (param != i) changed = true; + Class nt; + if (param < ptypes.length) nt = ptypes[param]; + else if (param == maxParam) nt = mt.returnType(); + else nt = moreParams[param - ptypes.length]; + ntypes[i] = nt; + } + if (!changed) return mt; + return MethodType.makeImpl(mt.returnType(), ntypes, true); + } + + private static boolean hasTwoArgSlots(Class type) { + return type == long.class || type == double.class; + } + + 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)); + } - MethodTypeForm(MethodType erasedType) { - super(erasedType); + 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.canonicalizes(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[] canonicalizes(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 != null) { + if (cs == null) + cs = ts.clone(); + cs[i] = c; + } + } + return cs; + } + + /*non-public*/ void notifyGenericMethodType() { + if (genericInvoker != null) return; + try { + // Trigger adapter creation. + genericInvoker = InvokeGeneric.genericInvokerOf(erasedType); + } catch (Exception ex) { + Error err = new InternalError("Exception while resolving invokeGeneric"); + err.initCause(ex); + throw err; + } + } + + @Override + public String toString() { + return "Form"+erasedType; + } + } diff --git a/src/share/classes/java/dyn/MutableCallSite.java b/src/share/classes/java/dyn/MutableCallSite.java index 95df7a6a6..c2326c8af 100644 --- a/src/share/classes/java/dyn/MutableCallSite.java +++ b/src/share/classes/java/dyn/MutableCallSite.java @@ -25,8 +25,6 @@ package java.dyn; -import sun.dyn.*; -import sun.dyn.empty.Empty; import java.util.concurrent.atomic.AtomicInteger; /** diff --git a/src/share/classes/sun/dyn/SpreadGeneric.java b/src/share/classes/java/dyn/SpreadGeneric.java similarity index 98% rename from src/share/classes/sun/dyn/SpreadGeneric.java rename to src/share/classes/java/dyn/SpreadGeneric.java index 4c6a0800b..b1e6c9f44 100644 --- a/src/share/classes/sun/dyn/SpreadGeneric.java +++ b/src/share/classes/java/dyn/SpreadGeneric.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,14 +23,14 @@ * questions. */ -package sun.dyn; +package java.dyn; -import java.dyn.*; +import sun.dyn.util.ValueConversions; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; -import sun.dyn.util.ValueConversions; -import static sun.dyn.MemberName.newIllegalArgumentException; +import static java.dyn.MethodHandleStatics.*; +import static java.dyn.MethodHandles.Lookup.IMPL_LOOKUP; /** * Generic spread adapter. @@ -110,7 +110,7 @@ class SpreadGeneric { static SpreadGeneric of(MethodType targetType, int spreadCount) { if (targetType != targetType.generic()) throw new UnsupportedOperationException("NYI type="+targetType); - MethodTypeImpl form = MethodTypeImpl.of(targetType); + MethodTypeForm form = targetType.form(); int outcount = form.parameterCount(); assert(spreadCount <= outcount); SpreadGeneric[] spreadGens = form.spreadGeneric; @@ -129,7 +129,7 @@ class SpreadGeneric { // This mini-api is called from an Adapter to manage the spread. /** A check/coercion that happens once before any selections. */ protected Object check(Object av, int n) { - MethodHandleImpl.checkSpreadArgument(av, n); + checkSpreadArgument(av, n); return av; } @@ -166,7 +166,7 @@ class SpreadGeneric { // see if it has the required invoke method MethodHandle entryPoint = null; try { - entryPoint = MethodHandleImpl.IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls); + entryPoint = IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls); } catch (ReflectiveOperationException ex) { } if (entryPoint == null) continue; @@ -221,21 +221,21 @@ class SpreadGeneric { @Override public String toString() { - return MethodHandleImpl.addTypeString(target, this); + return addTypeString(target, this); } static final MethodHandle NO_ENTRY = ValueConversions.identity(); protected boolean isPrototype() { return target == null; } protected Adapter(SpreadGeneric outer) { - super(Access.TOKEN, NO_ENTRY); + super(NO_ENTRY); this.outer = outer; this.target = null; assert(isPrototype()); } protected Adapter(SpreadGeneric outer, MethodHandle target) { - super(Access.TOKEN, outer.entryPoint); + super(outer.entryPoint); this.outer = outer; this.target = target; } @@ -251,7 +251,7 @@ class SpreadGeneric { return outer.select(av, n); } - static private final String CLASS_PREFIX; // "sun.dyn.SpreadGeneric$" + static private final String CLASS_PREFIX; // "java.dyn.SpreadGeneric$" static { String aname = Adapter.class.getName(); String sname = Adapter.class.getSimpleName(); diff --git a/src/share/classes/sun/dyn/ToGeneric.java b/src/share/classes/java/dyn/ToGeneric.java similarity index 98% rename from src/share/classes/sun/dyn/ToGeneric.java rename to src/share/classes/java/dyn/ToGeneric.java index 38db3fea4..3414e1a31 100644 --- a/src/share/classes/sun/dyn/ToGeneric.java +++ b/src/share/classes/java/dyn/ToGeneric.java @@ -23,15 +23,14 @@ * questions. */ -package sun.dyn; +package java.dyn; -import java.dyn.*; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import sun.dyn.util.ValueConversions; import sun.dyn.util.Wrapper; -import static sun.dyn.MemberName.newIllegalArgumentException; -import static sun.dyn.MethodTypeImpl.invokers; +import static java.dyn.MethodHandleStatics.*; +import static java.dyn.MethodHandles.Lookup.IMPL_LOOKUP; /** * Adapters which mediate between incoming calls which are not generic @@ -73,7 +72,7 @@ class ToGeneric { assert(entryType.erase() == entryType); // for now // incoming call will first "forget" all reference types except Object this.entryType = entryType; - MethodHandle invoker0 = invokers(entryType.generic()).exactInvoker(); + MethodHandle invoker0 = entryType.generic().invokers().exactInvoker(); MethodType rawEntryTypeInit; Adapter ad = findAdapter(rawEntryTypeInit = entryType); if (ad != null) { @@ -89,15 +88,15 @@ class ToGeneric { } // next, it will reorder primitives after references - MethodType primsAtEnd = MethodTypeImpl.of(entryType).primsAtEnd(); + MethodType primsAtEnd = entryType.form().primsAtEnd(); // at the same time, it will "forget" all primitive types except int/long - this.primsAtEndOrder = MethodTypeImpl.primsAtEndOrder(entryType); + this.primsAtEndOrder = MethodTypeForm.primsAtEndOrder(entryType); if (primsAtEndOrder != null) { // reordering is required; build on top of a simpler ToGeneric ToGeneric va2 = ToGeneric.of(primsAtEnd); this.adapter = va2.adapter; if (true) throw new UnsupportedOperationException("NYI: primitive parameters must follow references; entryType = "+entryType); - this.entryPoint = MethodHandleImpl.convertArguments(Access.TOKEN, + this.entryPoint = MethodHandleImpl.convertArguments( va2.entryPoint, primsAtEnd, entryType, primsAtEndOrder); // example: for entryType of (int,Object,Object), the reordered // type is (Object,Object,int) and the order is {1,2,0}, @@ -107,7 +106,7 @@ class ToGeneric { // after any needed argument reordering, it will reinterpret // primitive arguments according to their "raw" types int/long - MethodType intsAtEnd = MethodTypeImpl.of(primsAtEnd).primsAsInts(); + MethodType intsAtEnd = primsAtEnd.form().primsAsInts(); ad = findAdapter(rawEntryTypeInit = intsAtEnd); MethodHandle rawEntryPoint; if (ad != null) { @@ -116,7 +115,7 @@ class ToGeneric { // Perhaps the adapter is available only for longs. // If so, we can use it, but there will have to be a little // more stack motion on each call. - MethodType longsAtEnd = MethodTypeImpl.of(primsAtEnd).primsAsLongs(); + MethodType longsAtEnd = primsAtEnd.form().primsAsLongs(); ad = findAdapter(rawEntryTypeInit = longsAtEnd); if (ad != null) { MethodType eptWithLongs = longsAtEnd.insertParameterTypes(0, ad.getClass()); @@ -128,7 +127,7 @@ class ToGeneric { assert(midType.parameterType(i) == long.class); assert(eptWithInts.parameterType(i) == int.class); MethodType nextType = midType.changeParameterType(i, int.class); - rawEntryPoint = MethodHandle.convertArguments(Access.TOKEN, + rawEntryPoint = MethodHandleImpl.convertArguments( rawEntryPoint, nextType, midType, null); midType = nextType; } @@ -143,7 +142,7 @@ class ToGeneric { } MethodType tepType = entryType.insertParameterTypes(0, ad.getClass()); this.entryPoint = - AdapterMethodHandle.makeRetypeRaw(Access.TOKEN, tepType, rawEntryPoint); + AdapterMethodHandle.makeRetypeRaw(tepType, rawEntryPoint); if (this.entryPoint == null) throw new UnsupportedOperationException("cannot retype to "+entryType +" from "+rawEntryPoint.type().dropParameterTypes(0, 1)); @@ -168,7 +167,7 @@ class ToGeneric { assert(src.isPrimitive() && dst.isPrimitive()); if (filteredInvoker == null) { filteredInvoker = - AdapterMethodHandle.makeCheckCast(Access.TOKEN, + AdapterMethodHandle.makeCheckCast( invoker.type().generic(), invoker, 0, MethodHandle.class); if (filteredInvoker == null) throw new UnsupportedOperationException("NYI"); } @@ -177,7 +176,7 @@ class ToGeneric { if (filteredInvoker == null) throw new InternalError(); } if (filteredInvoker == null) return invoker; - return AdapterMethodHandle.makeRetypeOnly(Access.TOKEN, invoker.type(), filteredInvoker); + return AdapterMethodHandle.makeRetypeOnly(invoker.type(), filteredInvoker); } /** @@ -227,7 +226,7 @@ class ToGeneric { // retype erased reference arguments (the cast makes it safe to do this) MethodType tepType = type.insertParameterTypes(0, adapter.getClass()); MethodHandle typedEntryPoint = - AdapterMethodHandle.makeRetypeRaw(Access.TOKEN, tepType, entryPoint); + AdapterMethodHandle.makeRetypeRaw(tepType, entryPoint); return adapter.makeInstance(typedEntryPoint, invoker, convert, genericTarget); } @@ -248,7 +247,7 @@ class ToGeneric { /** Return the adapter information for this type's erasure. */ static ToGeneric of(MethodType type) { - MethodTypeImpl form = MethodTypeImpl.of(type); + MethodTypeForm form = type.form(); ToGeneric toGen = form.toGeneric; if (toGen == null) form.toGeneric = toGen = new ToGeneric(form.erasedType()); @@ -262,7 +261,7 @@ class ToGeneric { /* Create an adapter for the given incoming call type. */ static Adapter findAdapter(MethodType entryPointType) { - MethodTypeImpl form = MethodTypeImpl.of(entryPointType); + MethodTypeForm form = entryPointType.form(); Class rtype = entryPointType.returnType(); int argc = form.parameterCount(); int lac = form.longPrimitiveParameterCount(); @@ -283,7 +282,7 @@ class ToGeneric { for (String iname : inames) { MethodHandle entryPoint = null; try { - entryPoint = MethodHandleImpl.IMPL_LOOKUP. + entryPoint = IMPL_LOOKUP. findSpecial(acls, iname, entryPointType, acls); } catch (ReflectiveOperationException ex) { } @@ -338,13 +337,13 @@ class ToGeneric { @Override public String toString() { - return target == null ? "prototype:"+convert : MethodHandleImpl.addTypeString(target, this); + return target == null ? "prototype:"+convert : addTypeString(target, this); } protected boolean isPrototype() { return target == null; } /* Prototype constructor. */ protected Adapter(MethodHandle entryPoint) { - super(Access.TOKEN, entryPoint); + super(entryPoint); this.invoker = null; this.convert = entryPoint; this.target = null; @@ -356,7 +355,7 @@ class ToGeneric { } protected Adapter(MethodHandle entryPoint, MethodHandle invoker, MethodHandle convert, MethodHandle target) { - super(Access.TOKEN, entryPoint); + super(entryPoint); this.invoker = invoker; this.convert = convert; this.target = target; @@ -396,7 +395,7 @@ class ToGeneric { protected float return_F(Object res) throws Throwable { return (float) convert.invokeExact(res); } protected double return_D(Object res) throws Throwable { return (double)convert.invokeExact(res); } - static private final String CLASS_PREFIX; // "sun.dyn.ToGeneric$" + static private final String CLASS_PREFIX; // "java.dyn.ToGeneric$" static { String aname = Adapter.class.getName(); String sname = Adapter.class.getSimpleName(); diff --git a/src/share/classes/java/dyn/VolatileCallSite.java b/src/share/classes/java/dyn/VolatileCallSite.java index 616813ce2..75e99e3a6 100644 --- a/src/share/classes/java/dyn/VolatileCallSite.java +++ b/src/share/classes/java/dyn/VolatileCallSite.java @@ -25,8 +25,6 @@ package java.dyn; -import java.util.List; - /** * 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 diff --git a/src/share/classes/java/dyn/WrongMethodTypeException.java b/src/share/classes/java/dyn/WrongMethodTypeException.java index 2455432e8..eac122324 100644 --- a/src/share/classes/java/dyn/WrongMethodTypeException.java +++ b/src/share/classes/java/dyn/WrongMethodTypeException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/share/classes/sun/dyn/Access.java b/src/share/classes/sun/dyn/Access.java deleted file mode 100644 index 931303b03..000000000 --- a/src/share/classes/sun/dyn/Access.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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 sun.dyn; - -import sun.reflect.Reflection; - -/** - * Access control to this package. - * Classes in other packages can attempt to acquire the access token, - * but will fail if they are not recognized as friends. - * Certain methods in this package, although public, require a non-null - * access token in order to proceed; they act like package-private methods. - * @author jrose - */ - -public class Access { - - private Access() { } - - /** - * The heart of this pattern: The list of classes which are - * permitted to acquire the access token, and become honorary - * members of this package. - */ - private static final String[] FRIENDS = { - "java.dyn.", "sun.dyn." - }; - - /** - * The following object is NOT public. That's the point of the pattern. - * It is package-private, so that any member of this package - * can acquire the access token, and give it away to trusted friends. - */ - static final Access TOKEN = new Access(); - - /** - * @return Access.TOKEN, if the caller is a friend of this package - */ - public static Access getToken() { - Class callc = Reflection.getCallerClass(2); - if (isFriend(callc)) - return TOKEN; - else - throw new IllegalAccessError("bad caller: " + callc); - } - - /** Is the given name the name of a class which could be our friend? */ - public static boolean isFriendName(String name) { - for (String friend : FRIENDS) { - if (name.startsWith(friend)) - return true; - } - return false; - } - - /** Is the given class a friend? True if {@link #isFriendName}, - * and the given class also shares a class loader with us. - */ - public static boolean isFriend(Class c) { - return isFriendName(c.getName()) && c.getClassLoader() == CLASS_LOADER; - } - - private static final ClassLoader CLASS_LOADER = Access.class.getClassLoader(); - - /** - * Throw an IllegalAccessError if the caller does not possess - * the Access.TOKEN. - * @param must be Access.TOKEN - */ - public static void check(Access token) { - if (token == null) - fail(); - // else it must be the unique Access.TOKEN - assert(token == Access.TOKEN); - } - private static void fail() { - final int CALLER_DEPTH = 3; - // 0: Reflection.getCC, 1: this.fail, 2: Access.*, 3: caller - Class callc = Reflection.getCallerClass(CALLER_DEPTH); - throw new IllegalAccessError("bad caller: " + callc); - } - - static { - //sun.reflect.Reflection.registerMethodsToFilter(MH.class, "getToken"); - } -} diff --git a/src/share/classes/sun/dyn/CallSiteImpl.java b/src/share/classes/sun/dyn/CallSiteImpl.java deleted file mode 100644 index 703788ff4..000000000 --- a/src/share/classes/sun/dyn/CallSiteImpl.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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 sun.dyn; - -import java.dyn.*; -import static sun.dyn.MemberName.uncaughtException; - -/** - * Parts of CallSite known to the JVM. - * @author jrose - */ -public class CallSiteImpl { - // 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: - MemberName callerMethod, int callerBCI) { - Class callerClass = callerMethod.getDeclaringClass(); - Object caller; - if (bootstrapMethod.type().parameterType(0) == Class.class && TRANSITIONAL_BEFORE_PFD) - caller = callerClass; // remove for PFD - else - caller = MethodHandleImpl.IMPL_LOOKUP.in(callerClass); - if (bootstrapMethod == null && TRANSITIONAL_BEFORE_PFD) { - // If there is no bootstrap method, throw IncompatibleClassChangeError. - // This is a valid generic error type for resolution (JLS 12.3.3). - throw new IncompatibleClassChangeError - ("Class "+callerClass.getName()+" has not declared a bootstrap method for invokedynamic"); - } - CallSite site; - try { - Object binding; - info = maybeReBox(info); - if (info == null) { - binding = bootstrapMethod.invokeGeneric(caller, name, type); - } else if (!info.getClass().isArray()) { - binding = bootstrapMethod.invokeGeneric(caller, name, type, info); - } else { - Object[] argv = (Object[]) info; - if (3 + argv.length > 255) - new InvokeDynamicBootstrapError("too many bootstrap method arguments"); - MethodType bsmType = bootstrapMethod.type(); - if (bsmType.parameterCount() == 4 && bsmType.parameterType(3) == Object[].class) - binding = bootstrapMethod.invokeGeneric(caller, name, type, argv); - else - binding = MethodHandles.spreadInvoker(bsmType, 3) - .invokeGeneric(bootstrapMethod, caller, name, type, argv); - } - //System.out.println("BSM for "+name+type+" => "+binding); - if (binding instanceof CallSite) { - site = (CallSite) binding; - } else if (binding instanceof MethodHandle && TRANSITIONAL_BEFORE_PFD) { - // Transitional! - MethodHandle target = (MethodHandle) binding; - site = new ConstantCallSite(target); - } else { - throw new ClassCastException("bootstrap method failed to produce a CallSite"); - } - if (TRANSITIONAL_BEFORE_PFD) - PRIVATE_INITIALIZE_CALL_SITE.invokeExact(site, name, type, - callerMethod, callerBCI); - assert(site.getTarget() != null); - assert(site.getTarget().type().equals(type)); - } catch (Throwable ex) { - InvokeDynamicBootstrapError bex; - if (ex instanceof InvokeDynamicBootstrapError) - bex = (InvokeDynamicBootstrapError) ex; - else - bex = new InvokeDynamicBootstrapError("call site initialization exception", ex); - throw bex; - } - return site; - } - - private static boolean TRANSITIONAL_BEFORE_PFD = true; // FIXME: remove for PFD - - 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; - } else if (x instanceof Object[]) { - Object[] xa = (Object[]) x; - for (int i = 0; i < xa.length; i++) { - if (xa[i] instanceof Integer) - xa[i] = maybeReBox(xa[i]); - } - return xa; - } else { - return x; - } - } - - // This method is private in CallSite because it touches private fields in CallSite. - // These private fields (vmmethod, vmindex) are specific to the JVM. - private static final MethodHandle PRIVATE_INITIALIZE_CALL_SITE; - static { - try { - PRIVATE_INITIALIZE_CALL_SITE = - !TRANSITIONAL_BEFORE_PFD ? null : - MethodHandleImpl.IMPL_LOOKUP.findVirtual(CallSite.class, "initializeFromJVM", - MethodType.methodType(void.class, - String.class, MethodType.class, - MemberName.class, int.class)); - } catch (ReflectiveOperationException ex) { - throw uncaughtException(ex); - } - } - - public static void setCallSiteTarget(Access token, CallSite site, MethodHandle target) { - Access.check(token); - MethodHandleNatives.setCallSiteTarget(site, target); - } -} diff --git a/src/share/classes/sun/dyn/MethodTypeImpl.java b/src/share/classes/sun/dyn/MethodTypeImpl.java deleted file mode 100644 index 700ed307f..000000000 --- a/src/share/classes/sun/dyn/MethodTypeImpl.java +++ /dev/null @@ -1,516 +0,0 @@ -/* - * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.dyn; - -import java.dyn.*; -import sun.dyn.util.Wrapper; -import static sun.dyn.MemberName.newIllegalArgumentException; - -/** - * Shared information for a group of method types, which differ - * only by reference types, and therefore share a common erasure - * and wrapping. - *

- * For an empirical discussion of the structure of method types, - * see - * the thread "Avoiding Boxing" on jvm-languages. - * 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 - */ -public class MethodTypeImpl { - final int[] argToSlotTable, slotToArgTable; - final long argCounts; // packed slot & value counts - final long primCounts; // packed prim & double counts - final int vmslots; // total number of parameter slots - final MethodType erasedType; // the canonical erasure - - /*lazy*/ MethodType primsAsBoxes; // replace prims by wrappers - /*lazy*/ MethodType primArgsAsBoxes; // wrap args only; make raw return - /*lazy*/ MethodType primsAsInts; // replace prims by int/long - /*lazy*/ MethodType primsAsLongs; // replace prims by long - /*lazy*/ MethodType primsAtEnd; // reorder primitives to the end - - // Cached adapter information: - /*lazy*/ ToGeneric toGeneric; // convert cs. with prims to w/o - /*lazy*/ FromGeneric fromGeneric; // convert cs. w/o prims to with - /*lazy*/ SpreadGeneric[] spreadGeneric; // expand one argument to many - /*lazy*/ FilterGeneric filterGeneric; // convert argument(s) on the fly - /*lazy*/ MethodHandle genericInvoker; // hook for invokeGeneric - - public MethodType erasedType() { - return erasedType; - } - - public static MethodTypeImpl of(MethodType type) { - return METHOD_TYPE_FRIEND.form(type); - } - - /** Access methods for the internals of MethodType, supplied to - * MethodTypeImpl as a trusted agent. - */ - static public interface MethodTypeFriend { - Class[] ptypes(MethodType mt); - MethodTypeImpl form(MethodType mt); - void setForm(MethodType mt, MethodTypeImpl form); - MethodType makeImpl(Class rtype, Class[] ptypes, boolean trusted); - MethodTypeImpl newMethodTypeForm(MethodType mt); - Invokers getInvokers(MethodType mt); - void setInvokers(MethodType mt, Invokers inv); - } - public static void setMethodTypeFriend(Access token, MethodTypeFriend am) { - Access.check(token); - if (METHOD_TYPE_FRIEND != null) - throw new InternalError(); // just once - METHOD_TYPE_FRIEND = am; - } - static private MethodTypeFriend METHOD_TYPE_FRIEND; - - static MethodType makeImpl(Access token, Class rtype, Class[] ptypes, boolean trusted) { - Access.check(token); - return METHOD_TYPE_FRIEND.makeImpl(rtype, ptypes, trusted); - } - - protected MethodTypeImpl(MethodType erasedType) { - this.erasedType = erasedType; - - Class[] ptypes = METHOD_TYPE_FRIEND.ptypes(erasedType); - 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; - for (int i = 0; i < epts.length; i++) { - Class pt = epts[i]; - if (pt != Object.class) { - assert(pt.isPrimitive()); - ++pac; - if (hasTwoArgSlots(pt)) ++lac; - } - } - pslotCount += lac; // #slots = #args + #longs - Class rt = erasedType.returnType(); - if (rt != Object.class) { - ++prc; // even void.class counts as a prim here - if (hasTwoArgSlots(rt)) ++lrc; - // adjust #slots, #args - if (rt == void.class) - rtypeCount = rslotCount = 0; - else - rslotCount += lrc; - } - 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]; - if (hasTwoArgSlots(pt)) --slot; - --slot; - slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note - argToSlotTab[1+i] = slot; - } - assert(slot == 0); // filled the table - } - this.primCounts = pack(lrc, prc, lac, pac); - this.argCounts = pack(rslotCount, rtypeCount, pslotCount, ptypeCount); - if (slotToArgTab == null) { - 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.argToSlotTable = argToSlotTab; - this.slotToArgTable = slotToArgTab; - - if (pslotCount >= 256) throw newIllegalArgumentException("too many arguments"); - - // send a few bits down to the JVM: - this.vmslots = parameterSlotCount(); - - // short circuit some no-op canonicalizations: - if (!hasPrimitives()) { - primsAsBoxes = erasedType; - primArgsAsBoxes = erasedType; - primsAsInts = erasedType; - primsAsLongs = erasedType; - primsAtEnd = erasedType; - } - } - - /** Turn all primitive types to corresponding wrapper types. - */ - public MethodType primsAsBoxes() { - MethodType ct = primsAsBoxes; - if (ct != null) return ct; - MethodType t = erasedType; - ct = canonicalize(erasedType, WRAP, WRAP); - if (ct == null) ct = t; // no prims to box - return primsAsBoxes = ct; - } - - /** Turn all primitive argument types to corresponding wrapper types. - * Subword and void return types are promoted to int. - */ - public MethodType primArgsAsBoxes() { - MethodType ct = primArgsAsBoxes; - if (ct != null) return ct; - MethodType t = erasedType; - ct = canonicalize(erasedType, RAW_RETURN, WRAP); - if (ct == null) ct = t; // no prims to box - return primArgsAsBoxes = ct; - } - - /** Turn all primitive types to either int or long. - * Floating point return types are not changed, because - * they may require special calling sequences. - * A void return value is turned to int. - */ - public MethodType primsAsInts() { - MethodType ct = primsAsInts; - if (ct != null) return ct; - MethodType t = erasedType; - ct = canonicalize(t, RAW_RETURN, INTS); - if (ct == null) ct = t; // no prims to int-ify - return primsAsInts = ct; - } - - /** Turn all primitive types to either int or long. - * Floating point return types are not changed, because - * they may require special calling sequences. - * A void return value is turned to int. - */ - public MethodType primsAsLongs() { - MethodType ct = primsAsLongs; - if (ct != null) return ct; - MethodType t = erasedType; - ct = canonicalize(t, RAW_RETURN, LONGS); - if (ct == null) ct = t; // no prims to int-ify - return primsAsLongs = ct; - } - - /** Stably sort parameters into 3 buckets: ref, int, long. */ - public MethodType primsAtEnd() { - MethodType ct = primsAtEnd; - if (ct != null) return ct; - MethodType t = erasedType; - - int pac = primitiveParameterCount(); - if (pac == 0) - return primsAtEnd = t; - - int argc = parameterCount(); - int lac = longPrimitiveParameterCount(); - if (pac == argc && (lac == 0 || lac == argc)) - return primsAtEnd = t; - - // known to have a mix of 2 or 3 of ref, int, long - int[] reorder = primsAtEndOrder(t); - ct = reorderParameters(t, reorder, null); - //System.out.println("t="+t+" / reorder="+java.util.Arrays.toString(reorder)+" => "+ct); - return primsAtEnd = ct; - } - - /** Compute a new ordering of parameters so that all references - * are before all ints or longs, and all ints are before all longs. - * For this ordering, doubles count as longs, and all other primitive - * values count as ints. - * As a special case, if the parameters are already in the specified - * order, this method returns a null reference, rather than an array - * specifying a null permutation. - *

- * For example, the type {@code (int,boolean,int,Object,String)void} - * produces the order {@code {3,4,0,1,2}}, the type - * {@code (long,int,String)void} produces {@code {2,1,2}}, and - * the type {@code (Object,int)Object} produces {@code null}. - */ - public static int[] primsAtEndOrder(MethodType mt) { - MethodTypeImpl form = METHOD_TYPE_FRIEND.form(mt); - if (form.primsAtEnd == form.erasedType) - // quick check shows no reordering is necessary - return null; - - int argc = form.parameterCount(); - int[] paramOrder = new int[argc]; - - // 3-way bucket sort: - int pac = form.primitiveParameterCount(); - int lac = form.longPrimitiveParameterCount(); - int rfill = 0, ifill = argc - pac, lfill = argc - lac; - - Class[] ptypes = METHOD_TYPE_FRIEND.ptypes(mt); - boolean changed = false; - for (int i = 0; i < ptypes.length; i++) { - Class pt = ptypes[i]; - int ord; - if (!pt.isPrimitive()) ord = rfill++; - else if (!hasTwoArgSlots(pt)) ord = ifill++; - else ord = lfill++; - if (ord != i) changed = true; - assert(paramOrder[ord] == 0); - paramOrder[ord] = i; - } - assert(rfill == argc - pac && ifill == argc - lac && lfill == argc); - if (!changed) { - form.primsAtEnd = form.erasedType; - return null; - } - return paramOrder; - } - - /** Put the existing parameters of mt into a new order, given by newParamOrder. - * The third argument is logically appended to mt.parameterArray, - * so that elements of newParamOrder can index either pre-existing or - * new parameter types. - */ - public static MethodType reorderParameters(MethodType mt, int[] newParamOrder, Class[] moreParams) { - if (newParamOrder == null) return mt; // no-op reordering - Class[] ptypes = METHOD_TYPE_FRIEND.ptypes(mt); - Class[] ntypes = new Class[newParamOrder.length]; - int maxParam = ptypes.length + (moreParams == null ? 0 : moreParams.length); - boolean changed = (ntypes.length != ptypes.length); - for (int i = 0; i < newParamOrder.length; i++) { - int param = newParamOrder[i]; - if (param != i) changed = true; - Class nt; - if (param < ptypes.length) nt = ptypes[param]; - else if (param == maxParam) nt = mt.returnType(); - else nt = moreParams[param - ptypes.length]; - ntypes[i] = nt; - } - if (!changed) return mt; - return METHOD_TYPE_FRIEND.makeImpl(mt.returnType(), ntypes, true); - } - - private static boolean hasTwoArgSlots(Class type) { - return type == long.class || type == double.class; - } - - 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; - } - - public static void initForm(Access token, MethodType mt) { - Access.check(token); - MethodTypeImpl form = findForm(mt); - METHOD_TYPE_FRIEND.setForm(mt, form); - if (form.erasedType == mt) { - // This is a principal (erased) type; show it to the JVM. - MethodHandleImpl.init(token, mt); - } - } - - static MethodTypeImpl findForm(MethodType mt) { - MethodType erased = canonicalize(mt, ERASE, ERASE); - if (erased == null) { - // It is already erased. Make a new MethodTypeImpl. - return METHOD_TYPE_FRIEND.newMethodTypeForm(mt); - } else { - // Share the MethodTypeImpl with the erased version. - return METHOD_TYPE_FRIEND.form(erased); - } - } - - /** 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 = METHOD_TYPE_FRIEND.ptypes(mt); - Class[] ptc = MethodTypeImpl.canonicalizes(ptypes, howArgs); - Class rtype = mt.returnType(); - Class rtc = MethodTypeImpl.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 METHOD_TYPE_FRIEND.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[] canonicalizes(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 != null) { - if (cs == null) - cs = ts.clone(); - cs[i] = c; - } - } - return cs; - } - - public static Invokers invokers(Access token, MethodType type) { - Access.check(token); - return invokers(type); - } - /*non-public*/ static Invokers invokers(MethodType type) { - Invokers inv = METHOD_TYPE_FRIEND.getInvokers(type); - if (inv != null) return inv; - inv = new Invokers(type); - METHOD_TYPE_FRIEND.setInvokers(type, inv); - return inv; - } - - @Override - public String toString() { - return "Form"+erasedType; - } - -} diff --git a/src/share/classes/sun/dyn/util/ValueConversions.java b/src/share/classes/sun/dyn/util/ValueConversions.java index 374bd2450..17e3e7a47 100644 --- a/src/share/classes/sun/dyn/util/ValueConversions.java +++ b/src/share/classes/sun/dyn/util/ValueConversions.java @@ -25,20 +25,17 @@ package sun.dyn.util; -import java.dyn.*; +import java.dyn.MethodHandle; +import java.dyn.MethodHandles; import java.dyn.MethodHandles.Lookup; +import java.dyn.MethodType; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumMap; import java.util.List; -import sun.dyn.Access; -import sun.dyn.AdapterMethodHandle; -import sun.dyn.MethodHandleImpl; -import static sun.dyn.MemberName.uncaughtException; public class ValueConversions { - private static final Access IMPL_TOKEN = Access.getToken(); - private static final Lookup IMPL_LOOKUP = MethodHandleImpl.getLookup(IMPL_TOKEN); + private static final Lookup IMPL_LOOKUP = MethodHandles.lookup(); private static EnumMap[] newWrapperCaches(int n) { @SuppressWarnings("unchecked") @@ -157,7 +154,7 @@ public class ValueConversions { mh = null; } } else { - mh = retype(type, unbox(wrap, !exact, raw)); + mh = unbox(wrap, !exact, raw).asType(type); } if (mh != null) { cache.put(wrap, mh); @@ -293,7 +290,7 @@ public class ValueConversions { mh = null; } } else { - mh = retype(type.erase(), box(wrap, !exact, raw)); + mh = box(wrap, !exact, raw).asType(type.erase()); } if (mh != null) { cache.put(wrap, mh); @@ -412,7 +409,7 @@ public class ValueConversions { mh = null; } } else { - mh = retype(IDENTITY.type(), rebox(wrap, !exact)); + mh = rebox(wrap, !exact).asType(IDENTITY.type()); } if (mh != null) { cache.put(wrap, mh); @@ -504,8 +501,8 @@ public class ValueConversions { // use the raw method Wrapper rawWrap = wrap.rawPrimitive(); - if (rawWrap != wrap) { - mh = retype(type, zeroConstantFunction(rawWrap)); + if (mh == null && rawWrap != wrap) { + mh = MethodHandles.explicitCastArguments(zeroConstantFunction(rawWrap), type); } if (mh != null) { cache.put(wrap, mh); @@ -552,6 +549,22 @@ public class ValueConversions { return x; } + static byte identity(byte x) { + return x; + } + + static short identity(short x) { + return x; + } + + static boolean identity(boolean x) { + return x; + } + + static char identity(char x) { + return x; + } + /** * Identity function on longs. * @param x an arbitrary long value @@ -561,6 +574,14 @@ public class ValueConversions { return x; } + static float identity(float x) { + return x; + } + + static double identity(double x) { + return x; + } + /** * Identity function, with reference cast. * @param t an arbitrary reference type @@ -590,7 +611,9 @@ public class ValueConversions { IGNORE = IMPL_LOOKUP.findStatic(ValueConversions.class, "ignore", ignoreType); EMPTY = IMPL_LOOKUP.findStatic(ValueConversions.class, "empty", ignoreType.dropParameterTypes(0, 1)); } catch (Exception ex) { - throw uncaughtException(ex); + Error err = new InternalError("uncaught exception"); + err.initCause(ex); + throw err; } } @@ -622,7 +645,8 @@ public class ValueConversions { mh = MethodHandles.insertArguments(CAST_REFERENCE, 0, type); if (exact) { MethodType xmt = MethodType.methodType(type, Object.class); - mh = AdapterMethodHandle.makeRetypeRaw(IMPL_TOKEN, xmt, mh); + mh = MethodHandles.explicitCastArguments(mh, xmt); + //mh = AdapterMethodHandle.makeRetypeRaw(IMPL_TOKEN, xmt, mh); } if (cache != null) cache.put(wrap, mh); @@ -634,15 +658,11 @@ public class ValueConversions { } public static MethodHandle identity(Class type) { - if (type == Object.class) - return IDENTITY; - else if (!type.isPrimitive()) - return retype(MethodType.methodType(type, type), IDENTITY); - else - return identity(Wrapper.forPrimitiveType(type)); + // This stuff has been moved into MethodHandles: + return MethodHandles.identity(type); } - static MethodHandle identity(Wrapper wrap) { + public static MethodHandle identity(Wrapper wrap) { EnumMap cache = CONSTANT_FUNCTIONS[1]; MethodHandle mh = cache.get(wrap); if (mh != null) { @@ -665,12 +685,6 @@ public class ValueConversions { return mh; } - // use a raw conversion - if (wrap.isSingleWord() && wrap != Wrapper.INT) { - mh = retype(type, identity(Wrapper.INT)); - } else if (wrap.isDoubleWord() && wrap != Wrapper.LONG) { - mh = retype(type, identity(Wrapper.LONG)); - } if (mh != null) { cache.put(wrap, mh); return mh; @@ -678,10 +692,6 @@ public class ValueConversions { throw new IllegalArgumentException("cannot find identity for " + wrap); } - private static MethodHandle retype(MethodType type, MethodHandle mh) { - return AdapterMethodHandle.makeRetypeRaw(IMPL_TOKEN, type, mh); - } - private static final Object[] NO_ARGS_ARRAY = {}; private static Object[] makeArray(Object... args) { return args; } private static Object[] array() { return NO_ARGS_ARRAY; } diff --git a/src/share/classes/sun/dyn/util/VerifyAccess.java b/src/share/classes/sun/dyn/util/VerifyAccess.java index 1114bad26..4b87d15ef 100644 --- a/src/share/classes/sun/dyn/util/VerifyAccess.java +++ b/src/share/classes/sun/dyn/util/VerifyAccess.java @@ -26,9 +26,6 @@ package sun.dyn.util; import java.lang.reflect.Modifier; -import sun.dyn.MemberName; -import sun.dyn.MethodHandleImpl; -import sun.dyn.empty.Empty; import static java.lang.reflect.Modifier.*; /** diff --git a/test/java/dyn/6987555/Test6987555.java b/test/java/dyn/6987555/Test6987555.java new file mode 100644 index 000000000..a438fee8d --- /dev/null +++ b/test/java/dyn/6987555/Test6987555.java @@ -0,0 +1,177 @@ +/* + * 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. + * + * 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. + * + */ + +/** + * @test + * @bug 6987555 + * @summary JSR 292 unboxing to a boolean value fails on big-endian SPARC + * + * @run main/othervm -Xint -ea -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles -XX:+EnableInvokeDynamic -XX:+UnlockDiagnosticVMOptions -XX:+VerifyMethodHandles Test6987555 + */ + +import java.dyn.*; + +public class Test6987555 { + private static final Class CLASS = Test6987555.class; + private static final String NAME = "foo"; + private static final boolean DEBUG = false; + + public static void main(String[] args) throws Throwable { + testboolean(); + testbyte(); + testchar(); + testshort(); + testint(); + } + + // boolean + static void testboolean() throws Throwable { + doboolean(false); + doboolean(true); + } + static void doboolean(boolean x) throws Throwable { + if (DEBUG) System.out.println("boolean=" + x); + MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(boolean.class, boolean.class)); + MethodHandle mh2 = mh1.asType(MethodType.methodType(boolean.class, Boolean.class)); + boolean a = (boolean) mh1.invokeExact(x); + boolean b = (boolean) mh2.invokeExact(Boolean.valueOf(x)); + assert a == b : a + " != " + b; + } + + // byte + static void testbyte() throws Throwable { + byte[] a = new byte[] { + Byte.MIN_VALUE, + Byte.MIN_VALUE + 1, + -0x0F, + -1, + 0, + 1, + 0x0F, + Byte.MAX_VALUE - 1, + Byte.MAX_VALUE + }; + for (int i = 0; i < a.length; i++) { + dobyte(a[i]); + } + } + static void dobyte(byte x) throws Throwable { + if (DEBUG) System.out.println("byte=" + x); + MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(byte.class, byte.class)); + MethodHandle mh2 = mh1.asType(MethodType.methodType(byte.class, Byte.class)); + byte a = (byte) mh1.invokeExact(x); + byte b = (byte) mh2.invokeExact(Byte.valueOf(x)); + assert a == b : a + " != " + b; + } + + // char + static void testchar() throws Throwable { + char[] a = new char[] { + Character.MIN_VALUE, + Character.MIN_VALUE + 1, + 0x000F, + 0x00FF, + 0x0FFF, + Character.MAX_VALUE - 1, + Character.MAX_VALUE + }; + for (int i = 0; i < a.length; i++) { + dochar(a[i]); + } + } + static void dochar(char x) throws Throwable { + if (DEBUG) System.out.println("char=" + x); + MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(char.class, char.class)); + MethodHandle mh2 = mh1.asType(MethodType.methodType(char.class, Character.class)); + char a = (char) mh1.invokeExact(x); + char b = (char) mh2.invokeExact(Character.valueOf(x)); + assert a == b : a + " != " + b; + } + + // short + static void testshort() throws Throwable { + short[] a = new short[] { + Short.MIN_VALUE, + Short.MIN_VALUE + 1, + -0x0FFF, + -0x00FF, + -0x000F, + -1, + 0, + 1, + 0x000F, + 0x00FF, + 0x0FFF, + Short.MAX_VALUE - 1, + Short.MAX_VALUE + }; + for (int i = 0; i < a.length; i++) { + doshort(a[i]); + } + } + static void doshort(short x) throws Throwable { + if (DEBUG) System.out.println("short=" + x); + MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(short.class, short.class)); + MethodHandle mh2 = mh1.asType(MethodType.methodType(short.class, Short.class)); + short a = (short) mh1.invokeExact(x); + short b = (short) mh2.invokeExact(Short.valueOf(x)); + assert a == b : a + " != " + b; + } + + // int + static void testint() throws Throwable { + int[] a = new int[] { + Integer.MIN_VALUE, + Integer.MIN_VALUE + 1, + -0x00000FFF, + -0x000000FF, + -0x0000000F, + -1, + 0, + 1, + 0x0000000F, + 0x000000FF, + 0x00000FFF, + Integer.MAX_VALUE - 1, + Integer.MAX_VALUE + }; + for (int i = 0; i < a.length; i++) { + doint(a[i]); + } + } + static void doint(int x) throws Throwable { + if (DEBUG) System.out.println("int=" + x); + MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(int.class, int.class)); + MethodHandle mh2 = mh1.asType(MethodType.methodType(int.class, Integer.class)); + int a = (int) mh1.invokeExact(x); + int b = (int) mh2.invokeExact(Integer.valueOf(x)); + assert a == b : a + " != " + b; + } + + public static boolean foo(boolean i) { return i; } + public static byte foo(byte i) { return i; } + public static char foo(char i) { return i; } + public static short foo(short i) { return i; } + public static int foo(int i) { return i; } +} diff --git a/test/java/dyn/6991596/Test6991596.java b/test/java/dyn/6991596/Test6991596.java new file mode 100644 index 000000000..14b85bcda --- /dev/null +++ b/test/java/dyn/6991596/Test6991596.java @@ -0,0 +1,465 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + * + */ + +/** + * @test + * @bug 6991596 + * @summary JSR 292 unimplemented adapter_opt_i2i and adapter_opt_l2i on SPARC + * + * @run main/othervm -ea -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles -XX:+EnableInvokeDynamic -XX:+UnlockDiagnosticVMOptions -XX:+VerifyMethodHandles Test6991596 + */ + +import java.dyn.*; + +public class Test6991596 { + private static final Class CLASS = Test6991596.class; + private static final String NAME = "foo"; + private static final boolean DEBUG = System.getProperty("DEBUG", "false").equals("true"); + + public static void main(String[] args) throws Throwable { + testboolean(); + testbyte(); + testchar(); + testshort(); + testint(); + testlong(); + } + + // Helpers to get various methods. + static MethodHandle getmh1(Class ret, Class arg) throws ReflectiveOperationException { + return MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(ret, arg)); + } + static MethodHandle getmh2(MethodHandle mh1, Class ret, Class arg) { + return MethodHandles.convertArguments(mh1, MethodType.methodType(ret, arg)); + } + static MethodHandle getmh3(MethodHandle mh1, Class ret, Class arg) { + return MethodHandles.convertArguments(mh1, MethodType.methodType(ret, arg)); + } + + // test adapter_opt_i2i + static void testboolean() throws Throwable { + boolean[] a = new boolean[] { + true, + false + }; + for (int i = 0; i < a.length; i++) { + doboolean(a[i]); + } + } + static void doboolean(boolean x) throws Throwable { + if (DEBUG) System.out.println("boolean=" + x); + + // boolean + { + MethodHandle mh1 = getmh1( boolean.class, boolean.class); + MethodHandle mh2 = getmh2(mh1, boolean.class, boolean.class); + // TODO add this for all cases when the bugs are fixed. + //MethodHandle mh3 = getmh3(mh1, boolean.class, boolean.class); + boolean a = (boolean) mh1.invokeExact((boolean) x); + boolean b = (boolean) mh2.invokeExact(x); + //boolean c = mh3.invokeExact((boolean) x); + check(x, a, b); + //check(x, c, x); + } + + // byte + { + MethodHandle mh1 = getmh1( byte.class, byte.class ); + MethodHandle mh2 = getmh2(mh1, byte.class, boolean.class); + byte a = (byte) mh1.invokeExact((byte) (x ? 1 : 0)); + byte b = (byte) mh2.invokeExact(x); + check(x, a, b); + } + + // char + { + MethodHandle mh1 = getmh1( char.class, char.class); + MethodHandle mh2 = getmh2(mh1, char.class, boolean.class); + char a = (char) mh1.invokeExact((char) (x ? 1 : 0)); + char b = (char) mh2.invokeExact(x); + check(x, a, b); + } + + // short + { + MethodHandle mh1 = getmh1( short.class, short.class); + MethodHandle mh2 = getmh2(mh1, short.class, boolean.class); + short a = (short) mh1.invokeExact((short) (x ? 1 : 0)); + short b = (short) mh2.invokeExact(x); + check(x, a, b); + } + } + + static void testbyte() throws Throwable { + byte[] a = new byte[] { + Byte.MIN_VALUE, + Byte.MIN_VALUE + 1, + -0x0F, + -1, + 0, + 1, + 0x0F, + Byte.MAX_VALUE - 1, + Byte.MAX_VALUE + }; + for (int i = 0; i < a.length; i++) { + dobyte(a[i]); + } + } + static void dobyte(byte x) throws Throwable { + if (DEBUG) System.out.println("byte=" + x); + + // boolean + { + MethodHandle mh1 = getmh1( boolean.class, boolean.class); + MethodHandle mh2 = getmh2(mh1, boolean.class, byte.class); + boolean a = (boolean) mh1.invokeExact((x & 1) == 1); + boolean b = (boolean) mh2.invokeExact(x); + check(x, a, b); + } + + // byte + { + MethodHandle mh1 = getmh1( byte.class, byte.class); + MethodHandle mh2 = getmh2(mh1, byte.class, byte.class); + byte a = (byte) mh1.invokeExact((byte) x); + byte b = (byte) mh2.invokeExact(x); + check(x, a, b); + } + + // char + { + MethodHandle mh1 = getmh1( char.class, char.class); + MethodHandle mh2 = getmh2(mh1, char.class, byte.class); + char a = (char) mh1.invokeExact((char) x); + char b = (char) mh2.invokeExact(x); + check(x, a, b); + } + + // short + { + MethodHandle mh1 = getmh1( short.class, short.class); + MethodHandle mh2 = getmh2(mh1, short.class, byte.class); + short a = (short) mh1.invokeExact((short) x); + short b = (short) mh2.invokeExact(x); + check(x, a, b); + } + } + + static void testchar() throws Throwable { + char[] a = new char[] { + Character.MIN_VALUE, + Character.MIN_VALUE + 1, + 0x000F, + 0x00FF, + 0x0FFF, + Character.MAX_VALUE - 1, + Character.MAX_VALUE + }; + for (int i = 0; i < a.length; i++) { + dochar(a[i]); + } + } + static void dochar(char x) throws Throwable { + if (DEBUG) System.out.println("char=" + x); + + // boolean + { + MethodHandle mh1 = getmh1( boolean.class, boolean.class); + MethodHandle mh2 = getmh2(mh1, boolean.class, char.class); + boolean a = (boolean) mh1.invokeExact((x & 1) == 1); + boolean b = (boolean) mh2.invokeExact(x); + check(x, a, b); + } + + // byte + { + MethodHandle mh1 = getmh1( byte.class, byte.class); + MethodHandle mh2 = getmh2(mh1, byte.class, char.class); + byte a = (byte) mh1.invokeExact((byte) x); + byte b = (byte) mh2.invokeExact(x); + check(x, a, b); + } + + // char + { + MethodHandle mh1 = getmh1( char.class, char.class); + MethodHandle mh2 = getmh2(mh1, char.class, char.class); + char a = (char) mh1.invokeExact((char) x); + char b = (char) mh2.invokeExact(x); + check(x, a, b); + } + + // short + { + MethodHandle mh1 = getmh1( short.class, short.class); + MethodHandle mh2 = getmh2(mh1, short.class, char.class); + short a = (short) mh1.invokeExact((short) x); + short b = (short) mh2.invokeExact(x); + check(x, a, b); + } + } + + static void testshort() throws Throwable { + short[] a = new short[] { + Short.MIN_VALUE, + Short.MIN_VALUE + 1, + -0x0FFF, + -0x00FF, + -0x000F, + -1, + 0, + 1, + 0x000F, + 0x00FF, + 0x0FFF, + Short.MAX_VALUE - 1, + Short.MAX_VALUE + }; + for (int i = 0; i < a.length; i++) { + doshort(a[i]); + } + } + static void doshort(short x) throws Throwable { + if (DEBUG) System.out.println("short=" + x); + + // boolean + { + MethodHandle mh1 = getmh1( boolean.class, boolean.class); + MethodHandle mh2 = getmh2(mh1, boolean.class, short.class); + boolean a = (boolean) mh1.invokeExact((x & 1) == 1); + boolean b = (boolean) mh2.invokeExact(x); + check(x, a, b); + } + + // byte + { + MethodHandle mh1 = getmh1( byte.class, byte.class); + MethodHandle mh2 = getmh2(mh1, byte.class, short.class); + byte a = (byte) mh1.invokeExact((byte) x); + byte b = (byte) mh2.invokeExact(x); + check(x, a, b); + } + + // char + { + MethodHandle mh1 = getmh1( char.class, char.class); + MethodHandle mh2 = getmh2(mh1, char.class, short.class); + char a = (char) mh1.invokeExact((char) x); + char b = (char) mh2.invokeExact(x); + check(x, a, b); + } + + // short + { + MethodHandle mh1 = getmh1( short.class, short.class); + MethodHandle mh2 = getmh2(mh1, short.class, short.class); + short a = (short) mh1.invokeExact((short) x); + short b = (short) mh2.invokeExact(x); + check(x, a, b); + } + } + + static void testint() throws Throwable { + int[] a = new int[] { + Integer.MIN_VALUE, + Integer.MIN_VALUE + 1, + -0x0FFFFFFF, + -0x00FFFFFF, + -0x000FFFFF, + -0x0000FFFF, + -0x00000FFF, + -0x000000FF, + -0x0000000F, + -1, + 0, + 1, + 0x0000000F, + 0x000000FF, + 0x00000FFF, + 0x0000FFFF, + 0x000FFFFF, + 0x00FFFFFF, + 0x0FFFFFFF, + Integer.MAX_VALUE - 1, + Integer.MAX_VALUE + }; + for (int i = 0; i < a.length; i++) { + doint(a[i]); + } + } + static void doint(int x) throws Throwable { + if (DEBUG) System.out.println("int=" + x); + + // boolean + { + MethodHandle mh1 = getmh1( boolean.class, boolean.class); + MethodHandle mh2 = getmh2(mh1, boolean.class, int.class); + boolean a = (boolean) mh1.invokeExact((x & 1) == 1); + boolean b = (boolean) mh2.invokeExact(x); + check(x, a, b); + } + + // byte + { + MethodHandle mh1 = getmh1( byte.class, byte.class); + MethodHandle mh2 = getmh2(mh1, byte.class, int.class); + byte a = (byte) mh1.invokeExact((byte) x); + byte b = (byte) mh2.invokeExact(x); + check(x, a, b); + } + + // char + { + MethodHandle mh1 = getmh1( char.class, char.class); + MethodHandle mh2 = getmh2(mh1, char.class, int.class); + char a = (char) mh1.invokeExact((char) x); + char b = (char) mh2.invokeExact(x); + check(x, a, b); + } + + // short + { + MethodHandle mh1 = getmh1( short.class, short.class); + MethodHandle mh2 = getmh2(mh1, short.class, int.class); + short a = (short) mh1.invokeExact((short) x); + short b = (short) mh2.invokeExact(x); + assert a == b : a + " != " + b; + check(x, a, b); + } + + // int + { + MethodHandle mh1 = getmh1( int.class, int.class); + MethodHandle mh2 = getmh2(mh1, int.class, int.class); + int a = (int) mh1.invokeExact((int) x); + int b = (int) mh2.invokeExact(x); + check(x, a, b); + } + } + + // test adapter_opt_l2i + static void testlong() throws Throwable { + long[] a = new long[] { + Long.MIN_VALUE, + Long.MIN_VALUE + 1, + -0x000000000FFFFFFFL, + -0x0000000000FFFFFFL, + -0x00000000000FFFFFL, + -0x000000000000FFFFL, + -0x0000000000000FFFL, + -0x00000000000000FFL, + -0x000000000000000FL, + -1L, + 0L, + 1L, + 0x000000000000000FL, + 0x00000000000000FFL, + 0x0000000000000FFFL, + 0x0000000000000FFFL, + 0x000000000000FFFFL, + 0x00000000000FFFFFL, + 0x0000000000FFFFFFL, + 0x000000000FFFFFFFL, + Long.MAX_VALUE - 1, + Long.MAX_VALUE + }; + for (int i = 0; i < a.length; i++) { + dolong(a[i]); + } + } + static void dolong(long x) throws Throwable { + if (DEBUG) System.out.println("long=" + x); + + // boolean + { + MethodHandle mh1 = getmh1( boolean.class, boolean.class); + MethodHandle mh2 = getmh2(mh1, boolean.class, long.class); + boolean a = (boolean) mh1.invokeExact((x & 1L) == 1L); + boolean b = (boolean) mh2.invokeExact(x); + check(x, a, b); + } + + // byte + { + MethodHandle mh1 = getmh1( byte.class, byte.class); + MethodHandle mh2 = getmh2(mh1, byte.class, long.class); + byte a = (byte) mh1.invokeExact((byte) x); + byte b = (byte) mh2.invokeExact(x); + check(x, a, b); + } + + // char + { + MethodHandle mh1 = getmh1( char.class, char.class); + MethodHandle mh2 = getmh2(mh1, char.class, long.class); + char a = (char) mh1.invokeExact((char) x); + char b = (char) mh2.invokeExact(x); + check(x, a, b); + } + + // short + { + MethodHandle mh1 = getmh1( short.class, short.class); + MethodHandle mh2 = getmh2(mh1, short.class, long.class); + short a = (short) mh1.invokeExact((short) x); + short b = (short) mh2.invokeExact(x); + check(x, a, b); + } + + // int + { + MethodHandle mh1 = getmh1( int.class, int.class); + MethodHandle mh2 = getmh2(mh1, int.class, long.class); + int a = (int) mh1.invokeExact((int) x); + int b = (int) mh2.invokeExact(x); + check(x, a, b); + } + } + + static void check(boolean x, boolean e, boolean a) { p(z2h(x), z2h(e), z2h(a)); assert e == a : z2h(x) + ": " + z2h(e) + " != " + z2h(a); } + static void check(boolean x, byte e, byte a) { p(z2h(x), i2h(e), i2h(a)); assert e == a : z2h(x) + ": " + i2h(e) + " != " + i2h(a); } + static void check(boolean x, int e, int a) { p(z2h(x), i2h(e), i2h(a)); assert e == a : z2h(x) + ": " + i2h(e) + " != " + i2h(a); } + + static void check(int x, boolean e, boolean a) { p(i2h(x), z2h(e), z2h(a)); assert e == a : i2h(x) + ": " + z2h(e) + " != " + z2h(a); } + static void check(int x, byte e, byte a) { p(i2h(x), i2h(e), i2h(a)); assert e == a : i2h(x) + ": " + i2h(e) + " != " + i2h(a); } + static void check(int x, int e, int a) { p(i2h(x), i2h(e), i2h(a)); assert e == a : i2h(x) + ": " + i2h(e) + " != " + i2h(a); } + + static void check(long x, boolean e, boolean a) { p(l2h(x), z2h(e), z2h(a)); assert e == a : l2h(x) + ": " + z2h(e) + " != " + z2h(a); } + static void check(long x, byte e, byte a) { p(l2h(x), i2h(e), i2h(a)); assert e == a : l2h(x) + ": " + i2h(e) + " != " + i2h(a); } + static void check(long x, int e, int a) { p(l2h(x), i2h(e), i2h(a)); assert e == a : l2h(x) + ": " + i2h(e) + " != " + i2h(a); } + + static void p(String x, String e, String a) { if (DEBUG) System.out.println(x + ": expected: " + e + ", actual: " + a); } + + static String z2h(boolean x) { return x ? "1" : "0"; } + static String i2h(int x) { return Integer.toHexString(x); } + static String l2h(long x) { return Long.toHexString(x); } + + // to int + public static boolean foo(boolean i) { return i; } + public static byte foo(byte i) { return i; } + public static char foo(char i) { return i; } + public static short foo(short i) { return i; } + public static int foo(int i) { return i; } +} diff --git a/test/java/dyn/MethodTypeTest.java b/test/java/dyn/MethodTypeTest.java index caadaa04a..1be9e9a1a 100644 --- a/test/java/dyn/MethodTypeTest.java +++ b/test/java/dyn/MethodTypeTest.java @@ -31,7 +31,6 @@ package test.java.dyn; -import sun.dyn.MemberName; import java.dyn.MethodType; import java.lang.reflect.Method; @@ -163,18 +162,6 @@ public class MethodTypeTest { assertSame(expResult, result); } - /** - * Test of make method, of class MethodType. - */ - @Test - public void testMake_Method() { - System.out.println("make (via MemberName.getMethodType)"); - MethodType expResult = MethodType.methodType(int.class, String.class); - MemberName name = new MemberName(compareTo); - MethodType result = name.getMethodType(); - assertSame(expResult, result); - } - /** * Test of make method, of class MethodType. */ -- GitLab