1.1 --- a/make/docs/CORE_PKGS.gmk Tue May 05 09:09:24 2009 -0700
1.2 +++ b/make/docs/CORE_PKGS.gmk Tue May 05 23:12:47 2009 -0700
1.3 @@ -1,5 +1,5 @@
1.4 #
1.5 -# Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved.
1.6 +# Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved.
1.7 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1.8 #
1.9 # This code is free software; you can redistribute it and/or modify it
1.10 @@ -55,6 +55,7 @@
1.11 # This is a list of regular expressions. So foo.* matches "foo" and "foo.bar".
1.12 #
1.13 ACTIVE_JSR_PKGS= \
1.14 + java.dyn \
1.15 java.sql \
1.16 javax.activation \
1.17 javax.annotation.* \
2.1 --- a/make/java/Makefile Tue May 05 09:09:24 2009 -0700
2.2 +++ b/make/java/Makefile Tue May 05 23:12:47 2009 -0700
2.3 @@ -1,5 +1,5 @@
2.4 #
2.5 -# Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved.
2.6 +# Copyright 1995-2009 Sun Microsystems, Inc. All Rights Reserved.
2.7 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
2.8 #
2.9 # This code is free software; you can redistribute it and/or modify it
2.10 @@ -39,7 +39,7 @@
2.11 # Others
2.12 # Note: java_crw_demo java_hprof_demo are demos but must be delivered built in sdk
2.13 SUBDIRS += security npt java_crw_demo java_hprof_demo \
2.14 - math awt util text applet net nio \
2.15 + math awt util text applet net nio dyn \
2.16 sql rmi jar beans logging management instrument
2.17
2.18
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/make/java/dyn/Makefile Tue May 05 23:12:47 2009 -0700
3.3 @@ -0,0 +1,44 @@
3.4 +#
3.5 +# Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
3.6 +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3.7 +#
3.8 +# This code is free software; you can redistribute it and/or modify it
3.9 +# under the terms of the GNU General Public License version 2 only, as
3.10 +# published by the Free Software Foundation. Sun designates this
3.11 +# particular file as subject to the "Classpath" exception as provided
3.12 +# by Sun in the LICENSE file that accompanied this code.
3.13 +#
3.14 +# This code is distributed in the hope that it will be useful, but WITHOUT
3.15 +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
3.16 +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
3.17 +# version 2 for more details (a copy is included in the LICENSE file that
3.18 +# accompanied this code).
3.19 +#
3.20 +# You should have received a copy of the GNU General Public License version
3.21 +# 2 along with this work; if not, write to the Free Software Foundation,
3.22 +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
3.23 +#
3.24 +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
3.25 +# CA 95054 USA or visit www.sun.com if you need additional information or
3.26 +# have any questions.
3.27 +#
3.28 +
3.29 +BUILDDIR = ../..
3.30 +
3.31 +PACKAGE = java.dyn
3.32 +PRODUCT = java
3.33 +include $(BUILDDIR)/common/Defs.gmk
3.34 +
3.35 +AUTO_FILES_JAVA_DIRS = java/dyn sun/dyn
3.36 +
3.37 +# The sources built here use new language syntax to generate
3.38 +# method handle calls. Let's be sure we are using that format.
3.39 +#LANGUAGE_VERSION = -source 7
3.40 +#CLASS_VERSION = -target 7
3.41 +
3.42 +# Actually, it will be less disruptive to compile with the same
3.43 +# -target option as the rest of the system, and just turn on
3.44 +# the specific compiler option we need here:
3.45 +OTHER_JAVACFLAGS = -XDinvokedynamic
3.46 +
3.47 +include $(BUILDDIR)/common/Classes.gmk
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/src/share/classes/java/dyn/CallSite.java Tue May 05 23:12:47 2009 -0700
4.3 @@ -0,0 +1,201 @@
4.4 +/*
4.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
4.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4.7 + *
4.8 + * This code is free software; you can redistribute it and/or modify it
4.9 + * under the terms of the GNU General Public License version 2 only, as
4.10 + * published by the Free Software Foundation. Sun designates this
4.11 + * particular file as subject to the "Classpath" exception as provided
4.12 + * by Sun in the LICENSE file that accompanied this code.
4.13 + *
4.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
4.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
4.17 + * version 2 for more details (a copy is included in the LICENSE file that
4.18 + * accompanied this code).
4.19 + *
4.20 + * You should have received a copy of the GNU General Public License version
4.21 + * 2 along with this work; if not, write to the Free Software Foundation,
4.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
4.23 + *
4.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
4.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
4.26 + * have any questions.
4.27 + */
4.28 +
4.29 +package java.dyn;
4.30 +
4.31 +import sun.dyn.util.BytecodeName;
4.32 +
4.33 +/**
4.34 + * An <code>invokedynamic</code> call site, as reified to the bootstrap method.
4.35 + * Every instance of a call site corresponds to a distinct instance
4.36 + * of the <code>invokedynamic</code> instruction.
4.37 + * Call sites have state, one reference word, called the <code>target</code>,
4.38 + * and typed as a {@link MethodHandle}. When this state is null (as it is
4.39 + * initially) the call site is in the unlinked state. Otherwise, it is said
4.40 + * to be linked to its target.
4.41 + * <p>
4.42 + * When an unlinked call site is executed, a bootstrap routine is called
4.43 + * to finish the execution of the call site, and optionally to link
4.44 + * the call site.
4.45 + * <p>
4.46 + * @author John Rose, JSR 292 EG
4.47 + */
4.48 +public class CallSite {
4.49 + // Fields used only by the JVM. Do not use or change.
4.50 + private Object vmmethod;
4.51 + int callerMID, callerBCI; // supplied by the JVM
4.52 +
4.53 + MethodHandle target;
4.54 + final Object caller; // usually a class
4.55 + final String name;
4.56 + final MethodType type;
4.57 +
4.58 + public CallSite(Object caller, String name, MethodType type) {
4.59 + this.caller = caller;
4.60 + this.name = name;
4.61 + this.type = type;
4.62 + }
4.63 +
4.64 + private static void privateInitializeCallSite(CallSite site, int callerMID, int callerBCI) {
4.65 + site.callerMID = callerMID;
4.66 + site.callerBCI = callerBCI;
4.67 + if (site.target == null)
4.68 + site.setTarget(site.initialTarget());
4.69 + }
4.70 +
4.71 + /**
4.72 + * Just after a call site is created by a bootstrap method handle,
4.73 + * if the target has not been initialized by the factory method itself,
4.74 + * the method {@code initialTarget} is called to produce an initial
4.75 + * non-null target. (Live call sites must never have null targets.)
4.76 + * <p>
4.77 + * If the bootstrap method itself does not initialize the call site,
4.78 + * this method must be overridden, because it just raises an
4.79 + * {@code InvokeDynamicBootstrapError}.
4.80 + */
4.81 + protected MethodHandle initialTarget() {
4.82 + throw new InvokeDynamicBootstrapError("target must be initialized before call site is linked: "+this);
4.83 + }
4.84 +
4.85 + /**
4.86 + * Report the current linkage state of the call site. (This is mutable.)
4.87 + * The value is null if and only if the call site is currently unlinked.
4.88 + * When a linked call site is invoked, the target method is used directly.
4.89 + * When an unlinked call site is invoked, its bootstrap method receives
4.90 + * the call, as if via {@link Linkage#bootstrapInvokeDynamic}.
4.91 + * <p>
4.92 + * The interactions of {@code getTarget} with memory are the same
4.93 + * as of a read from an ordinary variable, such as an array element or a
4.94 + * non-volatile, non-final field.
4.95 + * <p>
4.96 + * In particular, the current thread may choose to reuse the result
4.97 + * of a previous read of the target from memory, and may fail to see
4.98 + * a recent update to the target by another thread.
4.99 + * @return the current linkage state of the call site
4.100 + * @see #setTarget
4.101 + */
4.102 + public MethodHandle getTarget() {
4.103 + return target;
4.104 + }
4.105 +
4.106 + /**
4.107 + * Link or relink the call site, by setting its target method.
4.108 + * <p>
4.109 + * The interactions of {@code setTarget} with memory are the same
4.110 + * as of a write to an ordinary variable, such as an array element or a
4.111 + * non-volatile, non-final field.
4.112 + * <p>
4.113 + * In particular, unrelated threads may fail to see the updated target
4.114 + * until they perform a read from memory.
4.115 + * Stronger guarantees can be created by putting appropriate operations
4.116 + * into the bootstrap method and/or the target methods used
4.117 + * at any given call site.
4.118 + * @param target the new target, or null if it is to be unlinked
4.119 + * @throws WrongMethodTypeException if the new target is not null
4.120 + * and has a method type that differs from the call site's {@link #type}
4.121 + */
4.122 + public void setTarget(MethodHandle target) {
4.123 + checkTarget(target);
4.124 + this.target = target;
4.125 + }
4.126 +
4.127 + protected void checkTarget(MethodHandle target) {
4.128 + if (!canSetTarget(target))
4.129 + throw new WrongMethodTypeException(String.valueOf(target));
4.130 + }
4.131 +
4.132 + protected boolean canSetTarget(MethodHandle target) {
4.133 + return (target != null && target.type() == type());
4.134 + }
4.135 +
4.136 + /**
4.137 + * Report the class containing the call site.
4.138 + * This is immutable static context.
4.139 + * @return class containing the call site
4.140 + */
4.141 + public Class<?> callerClass() {
4.142 + return (Class) caller;
4.143 + }
4.144 +
4.145 + /**
4.146 + * Report the method name specified in the {@code invokedynamic} instruction.
4.147 + * This is immutable static context.
4.148 + * <p>
4.149 + * Note that the name is a JVM bytecode name, and as such can be any
4.150 + * non-empty string, as long as it does not contain certain "dangerous"
4.151 + * characters such as slash {@code '/'} and dot {@code '.'}.
4.152 + * See the Java Virtual Machine specification for more details.
4.153 + * <p>
4.154 + * Application such as a language runtimes may need to encode
4.155 + * arbitrary program element names and other configuration information
4.156 + * into the name. A standard convention for doing this is
4.157 + * <a href="http://blogs.sun.com/jrose/entry/symbolic_freedom_in_the_vm">specified here</a>.
4.158 + * @return method name specified by the call site
4.159 + */
4.160 + public String name() {
4.161 + return name;
4.162 + }
4.163 +
4.164 + /**
4.165 + * Report the method name specified in the {@code invokedynamic} instruction,
4.166 + * as a series of components, individually demangled according to
4.167 + * the standard convention
4.168 + * <a href="http://blogs.sun.com/jrose/entry/symbolic_freedom_in_the_vm">specified here</a>.
4.169 + * <p>
4.170 + * Non-empty runs of characters between dangerous characters are demangled.
4.171 + * Each component is either a completely arbitrary demangled string,
4.172 + * or else a character constant for a punctuation character, typically ':'.
4.173 + * (In principle, the character can be any dangerous character that the
4.174 + * JVM lets through in a method name, such as '$' or ']'.
4.175 + * Runtime implementors are encouraged to use colon ':' for building
4.176 + * structured names.)
4.177 + * <p>
4.178 + * In the common case where the name contains no dangerous characters,
4.179 + * the result is an array whose only element array is the demangled
4.180 + * name at the call site. Such a demangled name can be any sequence
4.181 + * of any number of any unicode characters.
4.182 + * @return method name components specified by the call site
4.183 + */
4.184 + public Object[] nameComponents() {
4.185 + return BytecodeName.parseBytecodeName(name);
4.186 + }
4.187 +
4.188 + /**
4.189 + * Report the resolved result and parameter types of this call site,
4.190 + * which are derived from its bytecode-level invocation descriptor.
4.191 + * The types are packaged into a {@link MethodType}.
4.192 + * Any linked target of this call site must be exactly this method type.
4.193 + * This is immutable static context.
4.194 + * @return method type specified by the call site
4.195 + */
4.196 + public MethodType type() {
4.197 + return type;
4.198 + }
4.199 +
4.200 + @Override
4.201 + public String toString() {
4.202 + return "CallSite#"+hashCode()+"["+name+type+" => "+target+"]";
4.203 + }
4.204 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/src/share/classes/java/dyn/InvokeDynamic.java Tue May 05 23:12:47 2009 -0700
5.3 @@ -0,0 +1,39 @@
5.4 +/*
5.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5.7 + *
5.8 + * This code is free software; you can redistribute it and/or modify it
5.9 + * under the terms of the GNU General Public License version 2 only, as
5.10 + * published by the Free Software Foundation. Sun designates this
5.11 + * particular file as subject to the "Classpath" exception as provided
5.12 + * by Sun in the LICENSE file that accompanied this code.
5.13 + *
5.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
5.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
5.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5.17 + * version 2 for more details (a copy is included in the LICENSE file that
5.18 + * accompanied this code).
5.19 + *
5.20 + * You should have received a copy of the GNU General Public License version
5.21 + * 2 along with this work; if not, write to the Free Software Foundation,
5.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
5.23 + *
5.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
5.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
5.26 + * have any questions.
5.27 + */
5.28 +
5.29 +package java.dyn;
5.30 +
5.31 +/**
5.32 + * Syntactic marker interface to request javac to emit an {@code invokedynamic} instruction.
5.33 + * <p>
5.34 + * This type has no particular meaning as a class or interface supertype, and can never be instantiated.
5.35 + * Logically, it denotes a source of all dynamically typed methods.
5.36 + * @author John Rose, JSR 292 EG
5.37 + */
5.38 +public final class InvokeDynamic {
5.39 + private InvokeDynamic() { throw new InternalError(); } // do not instantiate
5.40 +
5.41 + // no statically defined static methods
5.42 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java Tue May 05 23:12:47 2009 -0700
6.3 @@ -0,0 +1,55 @@
6.4 +/*
6.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
6.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6.7 + *
6.8 + * This code is free software; you can redistribute it and/or modify it
6.9 + * under the terms of the GNU General Public License version 2 only, as
6.10 + * published by the Free Software Foundation. Sun designates this
6.11 + * particular file as subject to the "Classpath" exception as provided
6.12 + * by Sun in the LICENSE file that accompanied this code.
6.13 + *
6.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
6.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
6.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
6.17 + * version 2 for more details (a copy is included in the LICENSE file that
6.18 + * accompanied this code).
6.19 + *
6.20 + * You should have received a copy of the GNU General Public License version
6.21 + * 2 along with this work; if not, write to the Free Software Foundation,
6.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
6.23 + *
6.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
6.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
6.26 + * have any questions.
6.27 + */
6.28 +
6.29 +package java.dyn;
6.30 +
6.31 +/**
6.32 + * Thrown to indicate that an {@code invokedynamic} instruction has
6.33 + * failed to find its bootstrap method, or the bootstrap method has
6.34 + * failed to provide a call site with a non-null target.
6.35 + * <p>
6.36 + * The boostrap method must have been declared during a class's initialization
6.37 + * by a call to {@link Linkage#registerBootstrapMethod}.
6.38 + *
6.39 + * @author John Rose, JSR 292 EG
6.40 + */
6.41 +public class InvokeDynamicBootstrapError extends LinkageError {
6.42 + /**
6.43 + * Constructs a {@code InvokeDynamicBootstrapError} with no detail message.
6.44 + */
6.45 + public InvokeDynamicBootstrapError() {
6.46 + super();
6.47 + }
6.48 +
6.49 + /**
6.50 + * Constructs a {@code InvokeDynamicBootstrapError} with the specified
6.51 + * detail message.
6.52 + *
6.53 + * @param s the detail message.
6.54 + */
6.55 + public InvokeDynamicBootstrapError(String s) {
6.56 + super(s);
6.57 + }
6.58 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/src/share/classes/java/dyn/JavaMethodHandle.java Tue May 05 23:12:47 2009 -0700
7.3 @@ -0,0 +1,83 @@
7.4 +/*
7.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
7.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7.7 + *
7.8 + * This code is free software; you can redistribute it and/or modify it
7.9 + * under the terms of the GNU General Public License version 2 only, as
7.10 + * published by the Free Software Foundation. Sun designates this
7.11 + * particular file as subject to the "Classpath" exception as provided
7.12 + * by Sun in the LICENSE file that accompanied this code.
7.13 + *
7.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
7.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
7.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
7.17 + * version 2 for more details (a copy is included in the LICENSE file that
7.18 + * accompanied this code).
7.19 + *
7.20 + * You should have received a copy of the GNU General Public License version
7.21 + * 2 along with this work; if not, write to the Free Software Foundation,
7.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
7.23 + *
7.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
7.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
7.26 + * have any questions.
7.27 + */
7.28 +
7.29 +package java.dyn;
7.30 +
7.31 +/**
7.32 + * A Java method handle extends the basic method handle type with additional
7.33 + * programmer defined methods and fields.
7.34 + * Its behavior as a method handle is determined at instance creation time,
7.35 + * by providing the new instance with an "entry point" method handle
7.36 + * to handle calls. This entry point must accept a leading argument
7.37 + * whose type is the Java method handle itself or a supertype, and the
7.38 + * entry point is always called with the Java method handle itself as
7.39 + * the first argument. This is similar to ordinary virtual methods, which also
7.40 + * accept the receiver object {@code this} as an implicit leading argument.
7.41 + * The {@code MethodType} of the Java method handle is the same as that
7.42 + * of the entry point method handle, with the leading parameter type
7.43 + * omitted.
7.44 + * <p>
7.45 + * Here is an example of usage:
7.46 + * <p><blockquote><pre>
7.47 + * class Greeter extends JavaMethodHandle {
7.48 + * public void run() { System.out.println("hello, "+greetee); }
7.49 + * private final String greetee;
7.50 + * Greeter(String greetee) {
7.51 + * super(RUN);
7.52 + * this.greetee = greetee;
7.53 + * }
7.54 + * // the entry point function is computed once:
7.55 + * private static final MethodHandle RUN
7.56 + * = MethodHandles.findVirtual(MyMethodHandle.class, "run",
7.57 + * MethodType.make(void.class));
7.58 + * }
7.59 + * Greeter greeter = new Greeter("world");
7.60 + * greeter.run(); // prints "hello, world"
7.61 + * MethodHandle mh = greeter;
7.62 + * mh.invoke(); // also prints "hello, world"
7.63 + * </pre></blockquote>
7.64 + * <p>
7.65 + * In this example, the method {@code run} provides the entry point.
7.66 + * The entry point need not be a constant value; it may be independently
7.67 + * computed in each call to the constructor. The entry point does not
7.68 + * even need to be a method on the Java method handle class, though
7.69 + * that is the typical case.
7.70 + * @see MethodHandle
7.71 + * @author John Rose, JSR 292 EG
7.72 + */
7.73 +public abstract class JavaMethodHandle
7.74 + // Note: This is an implementation inheritance hack, and will be removed
7.75 + // with a JVM change which moves the required hidden behavior onto this class.
7.76 + extends sun.dyn.BoundMethodHandle
7.77 +{
7.78 + /**
7.79 + * When creating a, pass in {@code entryPoint}, any method handle which
7.80 + * can take the current object
7.81 + * @param entryPoint
7.82 + */
7.83 + protected JavaMethodHandle(MethodHandle entryPoint) {
7.84 + super(entryPoint, 0);
7.85 + }
7.86 +}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/src/share/classes/java/dyn/Linkage.java Tue May 05 23:12:47 2009 -0700
8.3 @@ -0,0 +1,199 @@
8.4 +/*
8.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
8.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8.7 + *
8.8 + * This code is free software; you can redistribute it and/or modify it
8.9 + * under the terms of the GNU General Public License version 2 only, as
8.10 + * published by the Free Software Foundation. Sun designates this
8.11 + * particular file as subject to the "Classpath" exception as provided
8.12 + * by Sun in the LICENSE file that accompanied this code.
8.13 + *
8.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
8.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
8.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
8.17 + * version 2 for more details (a copy is included in the LICENSE file that
8.18 + * accompanied this code).
8.19 + *
8.20 + * You should have received a copy of the GNU General Public License version
8.21 + * 2 along with this work; if not, write to the Free Software Foundation,
8.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
8.23 + *
8.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
8.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
8.26 + * have any questions.
8.27 + */
8.28 +
8.29 +package java.dyn;
8.30 +
8.31 +import java.util.WeakHashMap;
8.32 +import sun.reflect.Reflection;
8.33 +import static sun.dyn.util.VerifyAccess.checkBootstrapPrivilege;
8.34 +
8.35 +/**
8.36 + * Static methods which control the linkage of invokedynamic call sites.
8.37 + * @author John Rose, JSR 292 EG
8.38 + */
8.39 +public class Linkage {
8.40 + private Linkage() {} // do not instantiate
8.41 +
8.42 + /**
8.43 + * Register a bootstrap method for use for a given caller class.
8.44 + * The method handle must be of a type equivalent to {@link Linkage#makeCallSite}.
8.45 + * <p>
8.46 + * The operation will fail with an exception if any of the following conditions hold:
8.47 + * <ul>
8.48 + * <li>The caller of this method is in a different package than the {@code callerClass},
8.49 + * and there is a security manager, and its {@code checkPermission} call throws
8.50 + * when passed {@link LinkagePermission}("registerBootstrapMethod",callerClass).
8.51 + * <li>The given class already has a bootstrap method, either from an embedded
8.52 + * {@code BootstrapInvokeDynamic} classfile attribute, or from a previous
8.53 + * call to this method.
8.54 + * <li>The given class is already fully initialized.
8.55 + * <li>The given class is in the process of initialization, in another thread.
8.56 + * </ul>
8.57 + * Because of these rules, a class may install its own bootstrap method in
8.58 + * a static initializer.
8.59 + */
8.60 + public static
8.61 + void registerBootstrapMethod(Class callerClass, MethodHandle mh) {
8.62 + Class callc = Reflection.getCallerClass(2);
8.63 + checkBootstrapPrivilege(callc, callerClass, "registerBootstrapMethod");
8.64 + checkBSM(mh);
8.65 + synchronized (bootstrapMethods) {
8.66 + if (bootstrapMethods.containsKey(callerClass))
8.67 + throw new IllegalStateException("bootstrap method already declared in "+callerClass);
8.68 + bootstrapMethods.put(callerClass, mh);
8.69 + }
8.70 + }
8.71 +
8.72 + static void checkBSM(MethodHandle mh) {
8.73 + if (mh == null) throw new IllegalArgumentException("null bootstrap method");
8.74 + if (mh.type() == OLD_BOOTSTRAP_METHOD_TYPE) // FIXME: delete at EDR/PFD
8.75 + throw new WrongMethodTypeException("bootstrap method must be a CallSite factory");
8.76 + if (mh.type() != BOOTSTRAP_METHOD_TYPE)
8.77 + throw new WrongMethodTypeException(mh.toString());
8.78 + }
8.79 +
8.80 + /**
8.81 + * Simplified version of registerBootstrapMethod for self-registration,
8.82 + * to be called from a static initializer.
8.83 + * Finds a static method of type (CallSite, Object[]) -> Object in the
8.84 + * given class, and installs it on the caller.
8.85 + * @throws IllegalArgumentException if there is no such method
8.86 + */
8.87 + public static
8.88 + void registerBootstrapMethod(Class<?> runtime, String name) {
8.89 + Class callc = Reflection.getCallerClass(2);
8.90 + MethodHandle bootstrapMethod =
8.91 + MethodHandles.findStaticFrom(callc, runtime, name, BOOTSTRAP_METHOD_TYPE);
8.92 + // FIXME: exception processing wrong here
8.93 + checkBSM(bootstrapMethod);
8.94 + Linkage.registerBootstrapMethod(callc, bootstrapMethod);
8.95 + }
8.96 +
8.97 + /**
8.98 + * Simplified version of registerBootstrapMethod for self-registration,
8.99 + * to be called from a static initializer.
8.100 + * Finds a static method of type (CallSite, Object[]) -> Object in the
8.101 + * caller's class, and installs it on the caller.
8.102 + * @throws IllegalArgumentException if there is no such method
8.103 + */
8.104 + public static
8.105 + void registerBootstrapMethod(String name) {
8.106 + Class callc = Reflection.getCallerClass(2);
8.107 + MethodHandle bootstrapMethod =
8.108 + MethodHandles.findStaticFrom(callc, callc, name, BOOTSTRAP_METHOD_TYPE);
8.109 + // FIXME: exception processing wrong here
8.110 + checkBSM(bootstrapMethod);
8.111 + Linkage.registerBootstrapMethod(callc, bootstrapMethod);
8.112 + }
8.113 +
8.114 + /**
8.115 + * Report the bootstrap method registered for a given class.
8.116 + * Returns null if the class has never yet registered a bootstrap method,
8.117 + * or if the class has explicitly registered a null bootstrap method.
8.118 + * Only callers privileged to set the bootstrap method may inquire
8.119 + * about it, because a bootstrap method is potentially a back-door entry
8.120 + * point into its class.
8.121 + */
8.122 + public static
8.123 + MethodHandle getBootstrapMethod(Class callerClass) {
8.124 + Class callc = Reflection.getCallerClass(2);
8.125 + checkBootstrapPrivilege(callc, callerClass, "registerBootstrapMethod");
8.126 + synchronized (bootstrapMethods) {
8.127 + return bootstrapMethods.get(callerClass);
8.128 + }
8.129 + }
8.130 +
8.131 + /** The type of any bootstrap method is a three-argument method
8.132 + * {@code (Class<?>, String, MethodType)} returning a {@code CallSite}.
8.133 + */
8.134 + public static final MethodType BOOTSTRAP_METHOD_TYPE
8.135 + = MethodType.make(CallSite.class,
8.136 + Class.class, String.class, MethodType.class);
8.137 +
8.138 + private static final MethodType OLD_BOOTSTRAP_METHOD_TYPE
8.139 + = MethodType.make(Object.class,
8.140 + CallSite.class, Object[].class);
8.141 +
8.142 + private static final WeakHashMap<Class, MethodHandle> bootstrapMethods =
8.143 + new WeakHashMap<Class, MethodHandle>();
8.144 +
8.145 + /**
8.146 + * Invalidate all <code>invokedynamic</code> call sites everywhere.
8.147 + * <p>
8.148 + * When this method returns, every <code>invokedynamic</code> instruction
8.149 + * will invoke its bootstrap method on next call.
8.150 + * <p>
8.151 + * It is unspecified whether call sites already known to the Java
8.152 + * code will continue to be associated with <code>invokedynamic</code>
8.153 + * instructions. If any call site is still so associated, its
8.154 + * {@link CallSite#getTarget()} method is guaranteed to return null
8.155 + * the invalidation operation completes.
8.156 + * <p>
8.157 + * Invalidation operations are likely to be slow. Use them sparingly.
8.158 + */
8.159 + public static
8.160 + Object invalidateAll() {
8.161 + SecurityManager security = System.getSecurityManager();
8.162 + if (security != null) {
8.163 + security.checkPermission(new LinkagePermission("invalidateAll"));
8.164 + }
8.165 + throw new UnsupportedOperationException("NYI");
8.166 + }
8.167 +
8.168 + /**
8.169 + * Invalidate all <code>invokedynamic</code> call sites associated
8.170 + * with the given class.
8.171 + * (These are exactly those sites which report the given class
8.172 + * via the {@link CallSite#callerClass()} method.)
8.173 + * <p>
8.174 + * When this method returns, every matching <code>invokedynamic</code>
8.175 + * instruction will invoke its bootstrap method on next call.
8.176 + * <p>
8.177 + * For additional semantics of call site invalidation,
8.178 + * see {@link #invalidateAll()}.
8.179 + */
8.180 + public static
8.181 + Object invalidateCallerClass(Class<?> callerClass) {
8.182 + SecurityManager security = System.getSecurityManager();
8.183 + if (security != null) {
8.184 + security.checkPermission(new LinkagePermission("invalidateAll", callerClass));
8.185 + }
8.186 + throw new UnsupportedOperationException("NYI");
8.187 + }
8.188 +
8.189 + private static Object doNotBootstrap(CallSite site, Object... arguments) {
8.190 + throw new UnsupportedOperationException("call site must not have null target: "+site);
8.191 + }
8.192 +
8.193 + private static final MethodHandle DO_NOT_BOOTSTRAP =
8.194 + MethodHandles.Lookup.IMPL_LOOKUP.findStatic(Linkage.class, "doNotBootstrap",
8.195 + OLD_BOOTSTRAP_METHOD_TYPE);
8.196 +
8.197 + // Up-call from the JVM. Obsolete. FIXME: Delete from VM then from here.
8.198 + static
8.199 + MethodHandle findBootstrapMethod(Class callerClass, Class searchBootstrapClass) {
8.200 + return DO_NOT_BOOTSTRAP;
8.201 + }
8.202 +}
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/src/share/classes/java/dyn/LinkagePermission.java Tue May 05 23:12:47 2009 -0700
9.3 @@ -0,0 +1,111 @@
9.4 +/*
9.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
9.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
9.7 + *
9.8 + * This code is free software; you can redistribute it and/or modify it
9.9 + * under the terms of the GNU General Public License version 2 only, as
9.10 + * published by the Free Software Foundation. Sun designates this
9.11 + * particular file as subject to the "Classpath" exception as provided
9.12 + * by Sun in the LICENSE file that accompanied this code.
9.13 + *
9.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
9.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
9.17 + * version 2 for more details (a copy is included in the LICENSE file that
9.18 + * accompanied this code).
9.19 + *
9.20 + * You should have received a copy of the GNU General Public License version
9.21 + * 2 along with this work; if not, write to the Free Software Foundation,
9.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
9.23 + *
9.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
9.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
9.26 + * have any questions.
9.27 + */
9.28 +
9.29 +package java.dyn;
9.30 +
9.31 +import java.security.*;
9.32 +import java.util.Enumeration;
9.33 +import java.util.Hashtable;
9.34 +import java.util.StringTokenizer;
9.35 +
9.36 +/**
9.37 + * This class is for runtime permissions. A RuntimePermission
9.38 + * contains a name (also referred to as a "target name") but
9.39 + * no actions list; you either have the named permission
9.40 + * or you don't.
9.41 + *
9.42 + * <P>
9.43 + * The target name is the name of the runtime permission (see below). The
9.44 + * naming convention follows the hierarchical property naming convention.
9.45 + * Also, an asterisk
9.46 + * may appear at the end of the name, following a ".", or by itself, to
9.47 + * signify a wildcard match. For example: "loadLibrary.*" or "*" is valid,
9.48 + * "*loadLibrary" or "a*b" is not valid.
9.49 + * <P>
9.50 + * The following table lists all the possible RuntimePermission target names,
9.51 + * and for each provides a description of what the permission allows
9.52 + * and a discussion of the risks of granting code the permission.
9.53 + * <P>
9.54 + *
9.55 + * <table border=1 cellpadding=5 summary="permission target name,
9.56 + * what the target allows,and associated risks">
9.57 + * <tr>
9.58 + * <th>Permission Target Name</th>
9.59 + * <th>What the Permission Allows</th>
9.60 + * <th>Risks of Allowing this Permission</th>
9.61 + * </tr>
9.62 + *
9.63 + * <tr>
9.64 + * <td>registerBootstrapMethod.{class name}</td>
9.65 + * <td>Specifying a bootstrap method for invokedynamic, within a class of the given name</td>
9.66 + * <td>An attacker could attempt to attach a bootstrap method to a class which
9.67 + * has just been loaded, thus gaining control of its invokedynamic calls.</td>
9.68 + * </tr>
9.69 + *
9.70 + * <tr>
9.71 + * <td>invalidateAll</td>
9.72 + * <td>Force the relinking of invokedynamic call sites everywhere.</td>
9.73 + * <td>This could allow an attacker to slow down the system, or perhaps surface timing bugs in a dynamic language implementations, by forcing redundant relinking operations.</td>
9.74 + * </tr>
9.75 + *
9.76 + *
9.77 + * <tr>
9.78 + * <td>invalidateCallerClass.{class name}</td>
9.79 + * <td>Force the relinking of invokedynamic call sites in the given class.</td>
9.80 + * <td>See {@code invalidateAll}.</td>
9.81 + * </tr>
9.82 + * </table>
9.83 + *
9.84 + * @see java.security.BasicPermission
9.85 + * @see java.lang.SecurityManager
9.86 + *
9.87 + * @author John Rose, JSR 292 EG
9.88 + */
9.89 +
9.90 +public final class LinkagePermission extends BasicPermission {
9.91 + /**
9.92 + * Create a new LinkagePermission with the given name.
9.93 + * The name is the symbolic name of the LinkagePermission, such as
9.94 + * "registerBootstrapMethod", "invalidateClass.*", etc. An asterisk
9.95 + * may appear at the end of the name, following a ".", or by itself, to
9.96 + * signify a wildcard match.
9.97 + *
9.98 + * @param name the name of the LinkagePermission
9.99 + */
9.100 + public LinkagePermission(String name) {
9.101 + super(name);
9.102 + }
9.103 +
9.104 + /**
9.105 + * Create a new LinkagePermission with the given name on the given class.
9.106 + * Equivalent to {@code LinkagePermission(name+"."+clazz.getName())}.
9.107 + *
9.108 + * @param name the name of the LinkagePermission
9.109 + * @param clazz the class affected by the permission
9.110 + */
9.111 + public LinkagePermission(String name, Class<?> clazz) {
9.112 + super(name + "." + clazz.getName());
9.113 + }
9.114 +}
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/src/share/classes/java/dyn/MethodHandle.java Tue May 05 23:12:47 2009 -0700
10.3 @@ -0,0 +1,135 @@
10.4 +/*
10.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
10.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
10.7 + *
10.8 + * This code is free software; you can redistribute it and/or modify it
10.9 + * under the terms of the GNU General Public License version 2 only, as
10.10 + * published by the Free Software Foundation. Sun designates this
10.11 + * particular file as subject to the "Classpath" exception as provided
10.12 + * by Sun in the LICENSE file that accompanied this code.
10.13 + *
10.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
10.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
10.17 + * version 2 for more details (a copy is included in the LICENSE file that
10.18 + * accompanied this code).
10.19 + *
10.20 + * You should have received a copy of the GNU General Public License version
10.21 + * 2 along with this work; if not, write to the Free Software Foundation,
10.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
10.23 + *
10.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
10.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
10.26 + * have any questions.
10.27 + */
10.28 +
10.29 +package java.dyn;
10.30 +
10.31 +//import sun.dyn.*;
10.32 +
10.33 +import sun.dyn.Access;
10.34 +import sun.dyn.MethodHandleImpl;
10.35 +
10.36 +/**
10.37 + * A method handle is a typed reference to the entry point of a method.
10.38 + * <p>
10.39 + * Method handles are strongly typed according to signature.
10.40 + * They are not distinguished by method name or enclosing class.
10.41 + * A method handle must be invoked under a signature which exactly matches
10.42 + * the method handle's own type.
10.43 + * <p>
10.44 + * Every method handle confesses its type via the <code>type</code> accessor.
10.45 + * The structure of this type is a series of classes, one of which is
10.46 + * the return type of the method (or <code>void.class</code> if none).
10.47 + * <p>
10.48 + * Every method handle appears as an object containing a method named
10.49 + * <code>invoke</code>, whose signature exactly matches
10.50 + * the method handle's type.
10.51 + * A normal Java method call (using the <code>invokevirtual</code> instruction)
10.52 + * can invoke this method from Java source code (if language support is present).
10.53 + * <p>
10.54 + * Every call to a method handle specifies an intended method type,
10.55 + * which must exactly match the type of the method handle.
10.56 + * (The type is specified in the <code>invokevirtual</code> instruction,
10.57 + * via a {@code CONSTANT_NameAndType} constant pool entry.)
10.58 + * The call looks within the receiver object for a method
10.59 + * named <code>invoke</code> of the intended method type.
10.60 + * The call fails with a {@link WrongMethodTypeException}
10.61 + * if the method does not exist, even if there is an <code>invoke</code>
10.62 + * method of a closely similar signature.
10.63 + * <p>
10.64 + * A method handle is an unrestricted capability to call a method.
10.65 + * A method handle can be formed on a non-public method by a class
10.66 + * that has access to that method; the resulting handle can be used
10.67 + * in any place by any caller who receives a reference to it. Thus, access
10.68 + * checking is performed when the method handle is created, not
10.69 + * (as in reflection) every time it is called. Handles to non-public
10.70 + * methods, or in non-public classes, should generally be kept secret.
10.71 + * They should not be passed to untrusted code.
10.72 + * <p>
10.73 + * Bytecode in an extended JVM can directly call a method handle's
10.74 + * <code>invoke</code> from an <code>invokevirtual</code> instruction.
10.75 + * The receiver class type must be <code>MethodHandle</code> and the method name
10.76 + * must be <code>invoke</code>. The signature of the invocation
10.77 + * (after resolving symbolic type names) must exactly match the method type
10.78 + * of the target method.
10.79 + * <p>
10.80 + * Bytecode in an extended JVM can directly obtain a method handle
10.81 + * for any accessible method from a <code>ldc</code> instruction
10.82 + * which refers to a <code>CONSTANT_Methodref</code> or
10.83 + * <code>CONSTANT_InterfaceMethodref</code> constant pool entry.
10.84 + * <p>
10.85 + * All JVMs can also use a reflective API called <code>MethodHandles</code>
10.86 + * for creating and calling method handles.
10.87 + * <p>
10.88 + * A method reference may refer either to a static or non-static method.
10.89 + * In the non-static case, the method handle type includes an explicit
10.90 + * receiver argument, prepended before any other arguments.
10.91 + * In the method handle's type, the initial receiver argument is typed
10.92 + * according to the class under which the method was initially requested.
10.93 + * (E.g., if a non-static method handle is obtained via <code>ldc</code>,
10.94 + * the type of the receiver is the class named in the constant pool entry.)
10.95 + * <p>
10.96 + * When a method handle to a virtual method is invoked, the method is
10.97 + * always looked up in the receiver (that is, the first argument).
10.98 + * <p>
10.99 + * A non-virtual method handles to a specific virtual method implementation
10.100 + * can also be created. These do not perform virtual lookup based on
10.101 + * receiver type. Such a method handle simulates the effect of
10.102 + * an <code>invokespecial</code> instruction to the same method.
10.103 + *
10.104 + * @see MethodType
10.105 + * @see MethodHandles
10.106 + * @author John Rose, JSR 292 EG
10.107 + */
10.108 +public abstract class MethodHandle
10.109 + // Note: This is an implementation inheritance hack, and will be removed
10.110 + // with a JVM change which moves the required hidden state onto this class.
10.111 + extends MethodHandleImpl
10.112 +{
10.113 + // interface MethodHandle<T extends MethodType<R,A...>>
10.114 + // { T type(); <R,A...> public R invoke(A...); }
10.115 +
10.116 + final private MethodType type;
10.117 +
10.118 + /**
10.119 + * Report the type of this method handle.
10.120 + * Every invocation of this method handle must exactly match this type.
10.121 + * @return the method handle type
10.122 + */
10.123 + public MethodType type() {
10.124 + return type;
10.125 + }
10.126 +
10.127 + /**
10.128 + * The constructor for MethodHandle may only be called by privileged code.
10.129 + * Subclasses may be in other packages, but must possess
10.130 + * a token which they obtained from MH with a security check.
10.131 + * @param token non-null object which proves access permission
10.132 + * @param type type (permanently assigned) of the new method handle
10.133 + */
10.134 + protected MethodHandle(Access token, MethodType type) {
10.135 + super(token);
10.136 + this.type = type;
10.137 + }
10.138 +}
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/src/share/classes/java/dyn/MethodHandles.java Tue May 05 23:12:47 2009 -0700
11.3 @@ -0,0 +1,1092 @@
11.4 +/*
11.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
11.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
11.7 + *
11.8 + * This code is free software; you can redistribute it and/or modify it
11.9 + * under the terms of the GNU General Public License version 2 only, as
11.10 + * published by the Free Software Foundation. Sun designates this
11.11 + * particular file as subject to the "Classpath" exception as provided
11.12 + * by Sun in the LICENSE file that accompanied this code.
11.13 + *
11.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
11.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11.17 + * version 2 for more details (a copy is included in the LICENSE file that
11.18 + * accompanied this code).
11.19 + *
11.20 + * You should have received a copy of the GNU General Public License version
11.21 + * 2 along with this work; if not, write to the Free Software Foundation,
11.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
11.23 + *
11.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
11.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
11.26 + * have any questions.
11.27 + */
11.28 +
11.29 +package java.dyn;
11.30 +
11.31 +import java.lang.reflect.Constructor;
11.32 +import sun.dyn.Access;
11.33 +import sun.dyn.MemberName;
11.34 +import sun.dyn.MethodHandleImpl;
11.35 +import sun.dyn.util.VerifyAccess;
11.36 +import sun.dyn.util.Wrapper;
11.37 +import java.lang.reflect.Field;
11.38 +import java.lang.reflect.Method;
11.39 +import java.lang.reflect.Modifier;
11.40 +import java.util.ArrayList;
11.41 +import java.util.Arrays;
11.42 +import sun.dyn.Invokers;
11.43 +import sun.dyn.MethodTypeImpl;
11.44 +import sun.reflect.Reflection;
11.45 +import static sun.dyn.MemberName.newIllegalArgumentException;
11.46 +import static sun.dyn.MemberName.newNoAccessException;
11.47 +
11.48 +/**
11.49 + * Fundamental operations and utilities for MethodHandle.
11.50 + * <p>
11.51 + * <em>API Note:</em> The matching of method types in this API cannot
11.52 + * be completely checked by Java's generic type system for three reasons:
11.53 + * <ol>
11.54 + * <li>Method types range over all possible arities,
11.55 + * from no arguments to an arbitrary number of arguments.
11.56 + * Generics are not variadic, and so cannot represent this.</li>
11.57 + * <li>Method types can specify arguments of primitive types,
11.58 + * which Java generic types cannot range over.</li>
11.59 + * <li>Method types can optionally specify varargs (ellipsis).</li>
11.60 + * </ol>
11.61 + * @author John Rose, JSR 292 EG
11.62 + */
11.63 +public class MethodHandles {
11.64 +
11.65 + private MethodHandles() { } // do not instantiate
11.66 +
11.67 + private static final Access IMPL_TOKEN = Access.getToken();
11.68 + private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(IMPL_TOKEN);
11.69 + static { MethodHandleImpl.initStatics(); }
11.70 + // See IMPL_LOOKUP below.
11.71 +
11.72 + //// Method handle creation from ordinary methods.
11.73 +
11.74 + public static Lookup lookup() {
11.75 + return new Lookup();
11.76 + }
11.77 +
11.78 + /**
11.79 + * A factory object for creating method handles, when the creation
11.80 + * requires access checking. Method handles do not perform
11.81 + * access checks when they are called; this is a major difference
11.82 + * from reflective {@link Method}, which performs access checking
11.83 + * against every caller, on every call. Method handle access
11.84 + * restrictions are enforced when a method handle is created.
11.85 + * The caller class against which those restrictions are enforced
11.86 + * is known as the "lookup class". {@link Lookup} embodies an
11.87 + * authenticated lookup class, and can be used to create any number
11.88 + * of access-checked method handles, all checked against a single
11.89 + * lookup class.
11.90 + * <p>
11.91 + * A class which needs to create method handles will call
11.92 + * {@code MethodHandles.lookup()} to create a factory for itself.
11.93 + * It may then use this factory to create method handles on
11.94 + * all of its methods, including private ones.
11.95 + * It may also delegate the lookup (e.g., to a metaobject protocol)
11.96 + * by passing the {@code Lookup} object to other code.
11.97 + * If this other code creates method handles, they will be access
11.98 + * checked against the original lookup class, and not with any higher
11.99 + * privileges.
11.100 + * <p>
11.101 + * Note that access checks only apply to named and reflected methods.
11.102 + * Other method handle creation methods, such as {@link #convertArguments},
11.103 + * do not require any access checks, and can be done independently
11.104 + * of any lookup class.
11.105 + * <p>
11.106 + * <em>A note about error conditions:<em> A lookup can fail, because
11.107 + * the containing class is not accessible to the lookup class, or
11.108 + * because the desired class member is missing, or because the
11.109 + * desired class member is not accessible to the lookup class.
11.110 + * It can also fail if a security manager is installed and refuses
11.111 + * access. In any of these cases, an exception will be
11.112 + * thrown from the attempted lookup.
11.113 + * In general, the conditions under which a method handle may be
11.114 + * created for a method M are exactly as restrictive as the conditions
11.115 + * under which the lookup class could have compiled a call to M.
11.116 + */
11.117 + public static final
11.118 + class Lookup {
11.119 + private final Class<?> lookupClass;
11.120 +
11.121 + /** Which class is performing the lookup? It is this class against
11.122 + * which checks are performed for visibility and access permissions.
11.123 + * <p>
11.124 + * This value is null if and only if this lookup is {@link #PUBLIC_LOOKUP}.
11.125 + */
11.126 + public Class<?> lookupClass() {
11.127 + return lookupClass;
11.128 + }
11.129 +
11.130 + /** Embody the current class (the lookupClass) as a lookup class
11.131 + * for method handle creation.
11.132 + * Must be called by from a method in this package,
11.133 + * which in turn is called by a method not in this package.
11.134 + * Also, don't make it private, lest javac interpose
11.135 + * an access$N method.
11.136 + */
11.137 + Lookup() {
11.138 + Class caller = getCallerClassAtEntryPoint();
11.139 + // make sure we haven't accidentally picked up this class:
11.140 + checkUnprivilegedlookupClass(caller);
11.141 + this.lookupClass = caller;
11.142 + }
11.143 +
11.144 + private Lookup(Class<?> lookupClass) {
11.145 + this.lookupClass = lookupClass;
11.146 + }
11.147 +
11.148 + /** Version of lookup which is trusted minimally.
11.149 + * It can only be used to create method handles to
11.150 + * publicly accessible members.
11.151 + */
11.152 + public static final Lookup PUBLIC_LOOKUP = new Lookup(null);
11.153 +
11.154 + /** Package-private version of lookup which is trusted. */
11.155 + static final Lookup IMPL_LOOKUP = new Lookup(Access.class);
11.156 + static { MethodHandleImpl.initLookup(IMPL_TOKEN, IMPL_LOOKUP); }
11.157 +
11.158 + private static void checkUnprivilegedlookupClass(Class<?> lookupClass) {
11.159 + if (lookupClass == null ||
11.160 + lookupClass == Access.class ||
11.161 + lookupClass.getName().startsWith("java.dyn."))
11.162 + throw newIllegalArgumentException("illegal lookupClass: "+lookupClass);
11.163 + }
11.164 +
11.165 + @Override
11.166 + public String toString() {
11.167 + if (lookupClass == null)
11.168 + return "public";
11.169 + return lookupClass.getName();
11.170 + }
11.171 +
11.172 + // call this from an entry point method in Lookup with extraFrames=0.
11.173 + private static Class<?> getCallerClassAtEntryPoint() {
11.174 + final int CALLER_DEPTH = 4;
11.175 + // 0: Reflection.getCC, 1: getCallerClassAtEntryPoint,
11.176 + // 2: Lookup.<init>, 3: MethodHandles.*, 4: caller
11.177 + // Note: This should be the only use of getCallerClass in this file.
11.178 + return Reflection.getCallerClass(CALLER_DEPTH);
11.179 + }
11.180 +
11.181 + /**
11.182 + * Produce a method handle for a static method.
11.183 + * The type of the method handle will be that of the method.
11.184 + * The method and all its argument types must be accessible to the lookup class.
11.185 + * If the method's class has not yet been initialized, that is done
11.186 + * immediately, before the method handle is returned.
11.187 + * @param defc the class from which the method is accessed
11.188 + * @param name the name of the method
11.189 + * @param type the type of the method
11.190 + * @return the desired method handle
11.191 + * @exception SecurityException <em>TBD</em>
11.192 + * @exception NoAccessException if the method does not exist or access checking fails
11.193 + */
11.194 + public
11.195 + MethodHandle findStatic(Class<?> defc, String name, MethodType type) throws NoAccessException {
11.196 + MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type, Modifier.STATIC), true, lookupClass);
11.197 + checkStatic(true, method, lookupClass);
11.198 + //throw NoSuchMethodException
11.199 + return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClass);
11.200 + }
11.201 +
11.202 + /**
11.203 + * Produce a method handle for a virtual method.
11.204 + * The type of the method handle will be that of the method,
11.205 + * with the receiver type ({@code defc}) prepended.
11.206 + * The method and all its argument types must be accessible to the lookup class.
11.207 + * <p>
11.208 + * When called, the handle will treat the first argument as a receiver
11.209 + * and dispatch on the receiver's type to determine which method
11.210 + * implementation to enter.
11.211 + * (The dispatching action is identical with that performed by an
11.212 + * {@code invokevirtual} or {@code invokeinterface} instruction.)
11.213 + * @param defc the class or interface from which the method is accessed
11.214 + * @param name the name of the method
11.215 + * @param type the type of the method, with the receiver argument omitted
11.216 + * @return the desired method handle
11.217 + * @exception SecurityException <em>TBD</em>
11.218 + * @exception NoAccessException if the method does not exist or access checking fails
11.219 + */
11.220 + public MethodHandle findVirtual(Class<?> defc, String name, MethodType type) throws NoAccessException {
11.221 + MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type), true, lookupClass);
11.222 + checkStatic(false, method, lookupClass);
11.223 + return MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClass);
11.224 + }
11.225 +
11.226 + /**
11.227 + * Produce an early-bound method handle for a virtual method,
11.228 + * or a handle for a constructor, as if called from an {@code invokespecial}
11.229 + * instruction from {@code caller}.
11.230 + * The type of the method handle will be that of the method or constructor,
11.231 + * with a suitably restricted receiver type (such as {@code caller}) prepended.
11.232 + * The method or constructor and all its argument types must be accessible
11.233 + * to the caller.
11.234 + * <p>
11.235 + * When called, the handle will treat the first argument as a receiver,
11.236 + * but will not dispatch on the receiver's type.
11.237 + * (This direct invocation action is identical with that performed by an
11.238 + * {@code invokespecial} instruction.)
11.239 + * <p>
11.240 + * If the explicitly specified caller class is not identical with the
11.241 + * lookup class, a security check TBD is performed.
11.242 + * @param defc the class or interface from which the method is accessed
11.243 + * @param name the name of the method, or "<init>" for a constructor
11.244 + * @param type the type of the method, with the receiver argument omitted
11.245 + * @param specialCaller the proposed calling class to perform the {@code invokespecial}
11.246 + * @return the desired method handle
11.247 + * @exception SecurityException <em>TBD</em>
11.248 + * @exception NoAccessException if the method does not exist or access checking fails
11.249 + */
11.250 + public MethodHandle findSpecial(Class<?> defc, String name, MethodType type,
11.251 + Class<?> specialCaller) throws NoAccessException {
11.252 + checkSpecialCaller(specialCaller, lookupClass);
11.253 + MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type), false, specialCaller);
11.254 + checkStatic(false, method, lookupClass);
11.255 + if (name.equals("<init>")) {
11.256 + if (defc != specialCaller)
11.257 + throw newNoAccessException("constructor must be local to lookup class", method, lookupClass);
11.258 + } else if (defc.isInterface() || !defc.isAssignableFrom(specialCaller)) {
11.259 + throw newNoAccessException("method must be in a superclass of lookup class", method, lookupClass);
11.260 + }
11.261 + return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, specialCaller);
11.262 + }
11.263 +
11.264 + /**
11.265 + * Produce an early-bound method handle for a non-static method.
11.266 + * The receiver must have a supertype {@code defc} in which a method
11.267 + * of the given name and type is accessible to the lookup class.
11.268 + * The method and all its argument types must be accessible to the lookup class.
11.269 + * The type of the method handle will be that of the method.
11.270 + * The given receiver will be bound into the method handle.
11.271 + * <p>
11.272 + * Equivalent to the following expression:
11.273 + * <code>
11.274 + * {@link #insertArgument}({@link #findVirtual}(defc, name, type), receiver)
11.275 + * </code>
11.276 + * @param receiver the object from which the method is accessed
11.277 + * @param name the name of the method
11.278 + * @param type the type of the method, with the receiver argument omitted
11.279 + * @return the desired method handle
11.280 + * @exception SecurityException <em>TBD</em>
11.281 + * @exception NoAccessException if the method does not exist or access checking fails
11.282 + */
11.283 + public MethodHandle bind(Object receiver, String name, MethodType type) throws NoAccessException {
11.284 + Class<? extends Object> rcvc = receiver.getClass(); // may get NPE
11.285 + MemberName reference = new MemberName(rcvc, name, type);
11.286 + MemberName method = IMPL_NAMES.resolveOrFail(reference, true, lookupClass);
11.287 + checkStatic(false, method, lookupClass);
11.288 + MethodHandle dmh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClass);
11.289 + MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, dmh, receiver);
11.290 + if (bmh == null)
11.291 + throw newNoAccessException(method, lookupClass);
11.292 + return bmh;
11.293 + }
11.294 +
11.295 + /**
11.296 + * Make a direct method handle to <i>m</i>, if the lookup class has permission.
11.297 + * If <i>m</i> is non-static, the receiver argument is treated as an initial argument.
11.298 + * If <i>m</i> is virtual, overriding is respected on every call.
11.299 + * Unlike the Core Reflection API, exceptions are <em>not</em> wrapped.
11.300 + * The type of the method handle will be that of the method,
11.301 + * with the receiver type prepended (but only if it is non-static).
11.302 + * If the method's {@code accessible} flag is not set,
11.303 + * access checking is performed immediately on behalf of the lookup class.
11.304 + * If <i>m</i> is not public, do not share the resulting handle with untrusted parties.
11.305 + * @param m the reflected method
11.306 + * @return a method handle which can invoke the reflected method
11.307 + * @exception NoAccessException if access checking fails
11.308 + */
11.309 + public MethodHandle unreflect(Method m) throws NoAccessException {
11.310 + return unreflectImpl(new MemberName(m), m.isAccessible(), true, lookupClass);
11.311 + }
11.312 +
11.313 + /**
11.314 + * Produce a method handle for a reflected method.
11.315 + * It will bypass checks for overriding methods on the receiver,
11.316 + * as if by the {@code invokespecial} instruction.
11.317 + * The type of the method handle will be that of the method,
11.318 + * with the receiver type prepended.
11.319 + * If the method's {@code accessible} flag is not set,
11.320 + * access checking is performed immediately on behalf of the lookup class,
11.321 + * as if {@code invokespecial} instruction were being linked.
11.322 + * @param m the reflected method
11.323 + * @return a method handle which can invoke the reflected method
11.324 + * @exception NoAccessException if access checking fails
11.325 + */
11.326 + public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws NoAccessException {
11.327 + checkSpecialCaller(specialCaller, lookupClass);
11.328 + MemberName mname = new MemberName(m);
11.329 + checkStatic(false, mname, lookupClass);
11.330 + return unreflectImpl(mname, m.isAccessible(), false, specialCaller);
11.331 + }
11.332 +
11.333 + /**
11.334 + * Produce a method handle for a reflected constructor.
11.335 + * The type of the method handle will be that of the constructor.
11.336 + * The method handle will perform a {@code newInstance} operation,
11.337 + * creating a new instance of the constructor's class on the
11.338 + * arguments passed to the method handle.
11.339 + * <p>
11.340 + * If the constructor's {@code accessible} flag is not set,
11.341 + * access checking is performed immediately on behalf of the lookup class,
11.342 + * as if {@code invokespecial} instruction were being linked.
11.343 + * @param ctor the reflected constructor
11.344 + * @return a method handle which can invoke the reflected constructor
11.345 + * @exception NoAccessException if access checking fails
11.346 + */
11.347 + public MethodHandle unreflectConstructor(Constructor ctor) throws NoAccessException {
11.348 + MemberName m = new MemberName(ctor);
11.349 + return unreflectImpl(m, ctor.isAccessible(), false, lookupClass);
11.350 + }
11.351 +
11.352 + /**
11.353 + * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
11.354 + * Produce a method handle giving read access to a reflected field.
11.355 + * The type of the method handle will have a return type of the field's
11.356 + * value type. Its sole argument will be the field's containing class
11.357 + * (but only if it is non-static).
11.358 + * If the method's {@code accessible} flag is not set,
11.359 + * access checking is performed immediately on behalf of the lookup class.
11.360 + * @param f the reflected field
11.361 + * @return a method handle which can load values from the reflected field
11.362 + * @exception NoAccessException if access checking fails
11.363 + */
11.364 + public MethodHandle unreflectGetter(Field f) throws NoAccessException {
11.365 + return MethodHandleImpl.accessField(IMPL_TOKEN, new MemberName(f), false, lookupClass);
11.366 + }
11.367 +
11.368 + /**
11.369 + * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
11.370 + * Produce a method handle giving write access to a reflected field.
11.371 + * The type of the method handle will have a void return type.
11.372 + * Its last argument will be the field's value type.
11.373 + * Its other argument will be the field's containing class
11.374 + * (but only if it is non-static).
11.375 + * If the method's {@code accessible} flag is not set,
11.376 + * access checking is performed immediately on behalf of the lookup class.
11.377 + * @param f the reflected field
11.378 + * @return a method handle which can store values into the reflected field
11.379 + * @exception NoAccessException if access checking fails
11.380 + */
11.381 + public MethodHandle unreflectSetter(Field f) throws NoAccessException {
11.382 + return MethodHandleImpl.accessField(IMPL_TOKEN, new MemberName(f), true, lookupClass);
11.383 + }
11.384 +
11.385 + }
11.386 +
11.387 + static /*must not be public*/
11.388 + MethodHandle findStaticFrom(Class<?> lookupClass,
11.389 + Class<?> defc, String name, MethodType type) throws NoAccessException {
11.390 + MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type, Modifier.STATIC), true, lookupClass);
11.391 + checkStatic(true, method, lookupClass);
11.392 + return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClass);
11.393 + }
11.394 +
11.395 + static void checkStatic(boolean wantStatic, MemberName m, Class<?> lookupClass) {
11.396 + if (wantStatic != m.isStatic()) {
11.397 + String message = wantStatic ? "expected a static method" : "expected a non-static method";
11.398 + throw newNoAccessException(message, m, lookupClass);
11.399 + }
11.400 + }
11.401 +
11.402 + static void checkSpecialCaller(Class<?> specialCaller, Class<?> lookupClass) {
11.403 + if (lookupClass == Lookup.IMPL_LOOKUP.lookupClass())
11.404 + return; // privileged action
11.405 + if (lookupClass == null || // public-only access
11.406 + !VerifyAccess.isSamePackageMember(specialCaller, lookupClass))
11.407 + throw newNoAccessException("no private access", new MemberName(specialCaller), lookupClass);
11.408 + }
11.409 +
11.410 + // Helper for creating handles on reflected methods and constructors.
11.411 + static MethodHandle unreflectImpl(MemberName m, boolean isAccessible,
11.412 + boolean doDispatch, Class<?> lookupClass) {
11.413 + MethodType mtype = m.getInvocationType();
11.414 + Class<?> defc = m.getDeclaringClass();
11.415 + int mods = m.getModifiers();
11.416 + if (m.isStatic()) {
11.417 + if (!isAccessible &&
11.418 + VerifyAccess.isAccessible(defc, mods, false, lookupClass) == null)
11.419 + throw newNoAccessException(m, lookupClass);
11.420 + } else {
11.421 + Class<?> constraint;
11.422 + if (isAccessible) {
11.423 + // abbreviated access check for "unlocked" method
11.424 + constraint = doDispatch ? defc : lookupClass;
11.425 + } else {
11.426 + constraint = VerifyAccess.isAccessible(defc, mods, doDispatch, lookupClass);
11.427 + }
11.428 + if (constraint != defc && !constraint.isAssignableFrom(defc)) {
11.429 + if (!defc.isAssignableFrom(constraint))
11.430 + throw newNoAccessException("receiver must be in caller class", m, lookupClass);
11.431 + mtype = mtype.changeParameterType(0, constraint);
11.432 + }
11.433 + }
11.434 + return MethodHandleImpl.findMethod(IMPL_TOKEN, m, doDispatch, lookupClass);
11.435 + }
11.436 +
11.437 + /**
11.438 + * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
11.439 + * Produce a method handle giving read access to elements of an array.
11.440 + * The type of the method handle will have a return type of the array's
11.441 + * element type. Its first argument will be the array type,
11.442 + * and the second will be {@code int}.
11.443 + * @param arrayClass an array type
11.444 + * @return a method handle which can load values from the given array type
11.445 + * @throws IllegalArgumentException if arrayClass is not an array type
11.446 + */
11.447 + public static
11.448 + MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentException {
11.449 + return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, false);
11.450 + }
11.451 +
11.452 + /**
11.453 + * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
11.454 + * Produce a method handle giving write access to elements of an array.
11.455 + * The type of the method handle will have a void return type.
11.456 + * Its last argument will be the array's element type.
11.457 + * The first and second arguments will be the array type and int.
11.458 + * @return a method handle which can store values into the array type
11.459 + * @throws IllegalArgumentException if arrayClass is not an array type
11.460 + */
11.461 + public static
11.462 + MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException {
11.463 + return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, true);
11.464 + }
11.465 +
11.466 +
11.467 + /// method handle invocation (reflective style)
11.468 +
11.469 + /**
11.470 + * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
11.471 + * Call the {@code invoke} method of a given method handle,
11.472 + * with arguments that exactly match the parameter types of the method handle.
11.473 + * The length of the arguments array must equal the parameter count
11.474 + * of the target's type.
11.475 + * The arguments array is spread into separate arguments, and
11.476 + * basic reference and unboxing conversions are applied.
11.477 + * <p>
11.478 + * In order to match the type of the target, the following argument
11.479 + * conversions are applied as necessary:
11.480 + * <ul>
11.481 + * <li>reference casting
11.482 + * <li>unboxing
11.483 + * </ul>
11.484 + * The following conversions are not applied:
11.485 + * <ul>
11.486 + * <li>primitive conversions (e.g., {@code byte} to {@code int}
11.487 + * <li>varargs conversions other than the initial spread
11.488 + * <li>any application-specific conversions (e.g., string to number)
11.489 + * </ul>
11.490 + * The result returned by the call is boxed if it is a primitive,
11.491 + * or forced to null if the return type is void.
11.492 + * <p>
11.493 + * This call is a convenience method for the following code:
11.494 + * <pre>
11.495 + * MethodHandle invoker = MethodHandles.genericInvoker(target.type(), 0, true);
11.496 + * Object result = invoker.invoke(arguments);
11.497 + * </pre>
11.498 + * @param target the method handle to invoke
11.499 + * @param arguments the arguments to pass to the target
11.500 + * @return the result returned by the target
11.501 + */
11.502 + public static
11.503 + Object invoke(MethodHandle target, Object... arguments) {
11.504 + int argc = arguments == null ? 0 : arguments.length;
11.505 + MethodType type = target.type();
11.506 + if (argc <= 4) {
11.507 + MethodHandle invoker = invokers(type).genericInvoker();
11.508 + switch (argc) {
11.509 + case 0: return invoker.<Object>invoke(target);
11.510 + case 1: return invoker.<Object>invoke(target,
11.511 + arguments[0]);
11.512 + case 2: return invoker.<Object>invoke(target,
11.513 + arguments[0], arguments[1]);
11.514 + case 3: return invoker.<Object>invoke(target,
11.515 + arguments[0], arguments[1], arguments[2]);
11.516 + case 4: return invoker.<Object>invoke(target,
11.517 + arguments[0], arguments[1], arguments[2], arguments[3]);
11.518 + }
11.519 + }
11.520 + MethodHandle invoker = invokers(type).varargsInvoker();
11.521 + return invoker.<Object>invoke(target, arguments);
11.522 + }
11.523 +
11.524 + public static
11.525 + Object invoke_0(MethodHandle target) {
11.526 + MethodHandle invoker = invokers(target.type()).genericInvoker();
11.527 + return invoker.<Object>invoke(target);
11.528 + }
11.529 + public static
11.530 + Object invoke_1(MethodHandle target, Object a0) {
11.531 + MethodHandle invoker = invokers(target.type()).genericInvoker();
11.532 + return invoker.<Object>invoke(target, a0);
11.533 + }
11.534 + public static
11.535 + Object invoke_2(MethodHandle target, Object a0, Object a1) {
11.536 + MethodHandle invoker = invokers(target.type()).genericInvoker();
11.537 + return invoker.<Object>invoke(target, a0, a1);
11.538 + }
11.539 + public static
11.540 + Object invoke_3(MethodHandle target, Object a0, Object a1, Object a2) {
11.541 + MethodHandle invoker = invokers(target.type()).genericInvoker();
11.542 + return invoker.<Object>invoke(target, a0, a1, a2);
11.543 + }
11.544 + public static
11.545 + Object invoke_4(MethodHandle target, Object a0, Object a1, Object a2, Object a3) {
11.546 + MethodHandle invoker = invokers(target.type()).genericInvoker();
11.547 + return invoker.<Object>invoke(target, a0, a1, a2, a3);
11.548 + }
11.549 +
11.550 + /**
11.551 + * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
11.552 + * Give a method handle which will invoke any method handle of the
11.553 + * given type on a standard set of {@code Object} type arguments.
11.554 + * The the resulting invoker will be a method handle with the following
11.555 + * arguments:
11.556 + * <ul>
11.557 + * <li>a single {@code MethodHandle} target
11.558 + * <li>zero or more {@code Object} values
11.559 + * <li>an optional {@code Object[]} array containing more arguments
11.560 + * </ul>
11.561 + * The invoker will spread the varargs array (if present), apply
11.562 + * reference casts as necessary, and unbox primitive arguments.
11.563 + * The return value of the invoker will be an {@code Object} reference,
11.564 + * boxing a primitive value if the original type returns a primitive,
11.565 + * and always null if the original type returns void.
11.566 + * <p>
11.567 + * This is a convenience method equivalent to the following code:
11.568 + * <pre>
11.569 + * MethodHandle invoker = exactInvoker(type);
11.570 + * MethodType genericType = MethodType.makeGeneric(objectArgCount, varargs);
11.571 + * genericType = genericType.insertParameterType(0, MethodHandle.class);
11.572 + * if (!varargs)
11.573 + * return convertArguments(invoker, genericType);
11.574 + * else
11.575 + * return spreadArguments(invoker, genericType);
11.576 + * </pre>
11.577 + * @param type the desired target type
11.578 + * @param objectArgCount number of fixed (non-varargs) {@code Object} arguments
11.579 + * @param varargs if true, the invoker will accept a final {@code Object[]} argument
11.580 + * @return a method handle suitable for invoking any method handle of the given type
11.581 + */
11.582 + static public
11.583 + MethodHandle genericInvoker(MethodType type, int objectArgCount, boolean varargs) {
11.584 + return invokers(type).genericInvoker();
11.585 + }
11.586 +
11.587 + /**
11.588 + * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
11.589 + * Give a method handle which will take a invoke any method handle of the
11.590 + * given type. The resulting invoker will have a type which is
11.591 + * exactly equal to the desired type, except that it will accept
11.592 + * an additional leading argument of type {@code MethodHandle}.
11.593 + * <p>
11.594 + * This is a convenience method equivalent to the following code:
11.595 + * <pre>
11.596 + * MethodHandles.lookup().findVirtual(MethodHandle.class, "invoke", type);
11.597 + * </pre>
11.598 + * @param type the desired target type
11.599 + * @return a method handle suitable for invoking any method handle of the given type
11.600 + */
11.601 + static public
11.602 + MethodHandle exactInvoker(MethodType type) {
11.603 + return invokers(type).exactInvoker();
11.604 + }
11.605 +
11.606 + static private Invokers invokers(MethodType type) {
11.607 + return MethodTypeImpl.invokers(IMPL_TOKEN, type);
11.608 + }
11.609 +
11.610 + /**
11.611 + * <em>WORK IN PROGRESS:</em>
11.612 + * Perform value checking, exactly as if for an adapted method handle.
11.613 + * It is assumed that the given value is either null, of type T0,
11.614 + * or (if T0 is primitive) of the wrapper type corresponding to T0.
11.615 + * The following checks and conversions are made:
11.616 + * <ul>
11.617 + * <li>If T0 and T1 are references, then a cast to T1 is applied.
11.618 + * (The types do not need to be related in any particular way.)
11.619 + * <li>If T0 and T1 are primitives, then a widening or narrowing
11.620 + * conversion is applied, if one exists.
11.621 + * <li>If T0 is a primitive and T1 a reference, and
11.622 + * T0 has a wrapper type TW, a boxing conversion to TW is applied,
11.623 + * possibly followed by a reference conversion.
11.624 + * T1 must be TW or a supertype.
11.625 + * <li>If T0 is a reference and T1 a primitive, and
11.626 + * T1 has a wrapper type TW, an unboxing conversion is applied,
11.627 + * possibly preceded by a reference conversion.
11.628 + * T0 must be TW or a supertype.
11.629 + * <li>If T1 is void, the return value is discarded
11.630 + * <li>If T0 is void and T1 a reference, a null value is introduced.
11.631 + * <li>If T0 is void and T1 a primitive, a zero value is introduced.
11.632 + * </ul>
11.633 + * If the value is discarded, null will be returned.
11.634 + * @param valueType
11.635 + * @param value
11.636 + * @return the value, converted if necessary
11.637 + * @throws java.lang.ClassCastException if a cast fails
11.638 + */
11.639 + static
11.640 + <T0, T1> T1 checkValue(Class<T0> t0, Class<T1> t1, Object value)
11.641 + throws ClassCastException
11.642 + {
11.643 + if (t0 == t1) {
11.644 + // no conversion needed; just reassert the same type
11.645 + if (t0.isPrimitive())
11.646 + return Wrapper.asPrimitiveType(t1).cast(value);
11.647 + else
11.648 + return Wrapper.OBJECT.cast(value, t1);
11.649 + }
11.650 + boolean prim0 = t0.isPrimitive(), prim1 = t1.isPrimitive();
11.651 + if (!prim0) {
11.652 + // check contract with caller
11.653 + Wrapper.OBJECT.cast(value, t0);
11.654 + if (!prim1) {
11.655 + return Wrapper.OBJECT.cast(value, t1);
11.656 + }
11.657 + // convert reference to primitive by unboxing
11.658 + Wrapper w1 = Wrapper.forPrimitiveType(t1);
11.659 + return w1.cast(value, t1);
11.660 + }
11.661 + // check contract with caller:
11.662 + Wrapper.asWrapperType(t0).cast(value);
11.663 + Wrapper w1 = Wrapper.forPrimitiveType(t1);
11.664 + return w1.cast(value, t1);
11.665 + }
11.666 +
11.667 + static
11.668 + Object checkValue(Class<?> T1, Object value)
11.669 + throws ClassCastException
11.670 + {
11.671 + Class<?> T0;
11.672 + if (value == null)
11.673 + T0 = Object.class;
11.674 + else
11.675 + T0 = value.getClass();
11.676 + return checkValue(T0, T1, value);
11.677 + }
11.678 +
11.679 + /// method handle modification (creation from other method handles)
11.680 +
11.681 + /**
11.682 + * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
11.683 + * Produce a method handle which adapts the type of the
11.684 + * given method handle to a new type, by pairwise argument conversion,
11.685 + * and/or varargs conversion.
11.686 + * The original type and new type must have the same number of
11.687 + * arguments, or else one or both them the must be varargs types.
11.688 + * The resulting method handle is guaranteed to confess a type
11.689 + * which is equal to the desired new type, with any varargs property erased.
11.690 + * <p>
11.691 + * If the original type and new type are equal, returns target.
11.692 + * <p>
11.693 + * The following conversions are applied as needed both to
11.694 + * arguments and return types. Let T0 and T1 be the differing
11.695 + * new and old parameter types (or old and new return types)
11.696 + * for corresponding values passed by the new and old method types.
11.697 + * <p>
11.698 + * If an ordinary (non-varargs) parameter of the new type is
11.699 + * to be boxed in a varargs parameter of the old type of type T1[],
11.700 + * then T1 is the element type of the varargs array.
11.701 + * Otherwise, if a varargs parameter of the new type of type T0[]
11.702 + * is to be spread into one or more outgoing old type parameters,
11.703 + * then T0 is the element type of the
11.704 + * If the new type is varargs and the old type is not, the varargs
11.705 + * argument will be checked and must be a non-null array of exactly
11.706 + * the right length. If there are no parameters in the old type
11.707 + * corresponding to the new varargs parameter, the varargs argument
11.708 + * is also allowed to be null.
11.709 + * <p>
11.710 + * Given those types T0, T1, one of the following conversions is applied
11.711 + * if possible:
11.712 + * <ul>
11.713 + * <li>If T0 and T1 are references, then a cast to T2 is applied,
11.714 + * where T2 is Object if T1 is an interface, else T1.
11.715 + * (The types do not need to be related in any particular way.
11.716 + * The treatment of interfaces follows the usage of the bytecode verifier.)
11.717 + * <li>If T0 and T1 are primitives, then a Java casting
11.718 + * conversion (JLS 5.5) is applied, if one exists.
11.719 + * <li>If T0 and T1 are primitives and one is boolean,
11.720 + * the boolean is treated as a one-bit unsigned integer.
11.721 + * (This treatment follows the usage of the bytecode verifier.)
11.722 + * A conversion from another primitive type behaves as if
11.723 + * it first converts to byte, and then masks all but the low bit.
11.724 + * <li>If T0 is a primitive and T1 a reference, a boxing
11.725 + * conversion is applied if one exists, possibly followed by
11.726 + * an reference conversion to a superclass.
11.727 + * T1 must be a wrapper class or a supertype of one.
11.728 + * If T1 is a wrapper class, T0 is converted if necessary
11.729 + * to T1's primitive type by one of the preceding conversions.
11.730 + * Otherwise, T0 is boxed, and its wrapper converted to T1.
11.731 + * <li>If T0 is a reference and T1 a primitive, an unboxing
11.732 + * conversion is applied if one exists, possibly preceded by
11.733 + * a reference conversion to a wrapper class.
11.734 + * T0 must be a wrapper class or a supertype of one.
11.735 + * If T0 is a wrapper class, its primitive value is converted
11.736 + * if necessary to T1 by one of the preceding conversions.
11.737 + * Otherwise, T0 is converted directly to the wrapper type for T1,
11.738 + * which is then unboxed.
11.739 + * <li>If T1 is void, any returned value is discarded
11.740 + * <li>If T0 is void and T1 a reference, a null value is introduced.
11.741 + * <li>If T0 is void and T1 a primitive, a zero value is introduced.
11.742 + * </ul>
11.743 + * @param target the method handle to invoke after arguments are retyped
11.744 + * @param newType the expected type of the new method handle
11.745 + * @return a method handle which delegates to {@code target} after performing
11.746 + * any necessary argument conversions, and arranges for any
11.747 + * necessary return value conversions
11.748 + * @throws WrongMethodTypeException if the conversion cannot be made
11.749 + */
11.750 + public static
11.751 + MethodHandle convertArguments(MethodHandle target, MethodType newType) {
11.752 + MethodType oldType = target.type();
11.753 + if (oldType.equals(newType))
11.754 + return target;
11.755 + MethodHandle res = MethodHandleImpl.convertArguments(IMPL_TOKEN, target,
11.756 + newType, oldType, null);
11.757 + if (res == null)
11.758 + throw newIllegalArgumentException("cannot convert to "+newType+": "+target);
11.759 + return res;
11.760 + }
11.761 +
11.762 + /**
11.763 + * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
11.764 + * Produce a method handle which adapts the calling sequence of the
11.765 + * given method handle to a new type, by reordering the arguments.
11.766 + * The resulting method handle is guaranteed to confess a type
11.767 + * which is equal to the desired new type.
11.768 + * <p>
11.769 + * The given array controls the reordering.
11.770 + * Call {@code #I} the number of incoming parameters (the value
11.771 + * {@code newType.parameterCount()}, and call {@code #O} the number
11.772 + * of outgoing parameters (the value {@code target.type().parameterCount()}).
11.773 + * Then the length of the reordering array must be {@code #O},
11.774 + * and each element must be a non-negative number less than {@code #I}.
11.775 + * For every {@code N} less than {@code #O}, the {@code N}-th
11.776 + * outgoing argument will be taken from the {@code I}-th incoming
11.777 + * argument, where {@code I} is {@code reorder[N]}.
11.778 + * <p>
11.779 + * The reordering array need not specify an actual permutation.
11.780 + * An incoming argument will be duplicated if its index appears
11.781 + * more than once in the array, and an incoming argument will be dropped
11.782 + * if its index does not appear in the array.
11.783 + * <p>
11.784 + * Pairwise conversions are applied as needed to arguments and return
11.785 + * values, as with {@link #convertArguments}.
11.786 + * @param target the method handle to invoke after arguments are reordered
11.787 + * @param newType the expected type of the new method handle
11.788 + * @param reorder a string which controls the reordering
11.789 + * @return a method handle which delegates to {@code target} after performing
11.790 + * any necessary argument motion and conversions, and arranges for any
11.791 + * necessary return value conversions
11.792 + */
11.793 + public static
11.794 + MethodHandle permuteArguments(MethodHandle target, MethodType newType, int[] reorder) {
11.795 + MethodType oldType = target.type();
11.796 + checkReorder(reorder, newType, oldType);
11.797 + return MethodHandleImpl.convertArguments(IMPL_TOKEN, target,
11.798 + newType, oldType,
11.799 + reorder);
11.800 + }
11.801 +
11.802 + private static void checkReorder(int[] reorder, MethodType newType, MethodType oldType) {
11.803 + if (reorder.length == oldType.parameterCount()) {
11.804 + int limit = newType.parameterCount();
11.805 + boolean bad = false;
11.806 + for (int i : reorder) {
11.807 + if (i < 0 || i >= limit) {
11.808 + bad = true; break;
11.809 + }
11.810 + }
11.811 + if (!bad) return;
11.812 + }
11.813 + throw newIllegalArgumentException("bad reorder array");
11.814 + }
11.815 +
11.816 + /**
11.817 + * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
11.818 + * Produce a method handle which adapts the type of the
11.819 + * given method handle to a new type, by spreading the final argument.
11.820 + * The resulting method handle is guaranteed to confess a type
11.821 + * which is equal to the desired new type.
11.822 + * <p>
11.823 + * The final parameter type of the new type must be an array type T[].
11.824 + * This is the type of what is called the <i>spread</i> argument.
11.825 + * All other arguments of the new type are called <i>ordinary</i> arguments.
11.826 + * <p>
11.827 + * The ordinary arguments of the new type are pairwise converted
11.828 + * to the initial parameter types of the old type, according to the
11.829 + * rules in {@link #convertArguments}.
11.830 + * Any additional arguments in the old type
11.831 + * are converted from the array element type T,
11.832 + * again according to the rules in {@link #convertArguments}.
11.833 + * The return value is converted according likewise.
11.834 + * <p>
11.835 + * The call verifies that the spread argument is in fact an array
11.836 + * of exactly the type length, i.e., the excess number of
11.837 + * arguments in the old type over the ordinary arguments in the new type.
11.838 + * If there are no excess arguments, the spread argument is also
11.839 + * allowed to be null.
11.840 + * @param target the method handle to invoke after the argument is prepended
11.841 + * @param newType the expected type of the new method handle
11.842 + * @return a new method handle which spreads its final argument,
11.843 + * before calling the original method handle
11.844 + */
11.845 + public static
11.846 + MethodHandle spreadArguments(MethodHandle target, MethodType newType) {
11.847 + MethodType oldType = target.type();
11.848 + int inargs = newType.parameterCount();
11.849 + int outargs = oldType.parameterCount();
11.850 + int spreadPos = inargs - 1;
11.851 + int numSpread = (outargs - spreadPos);
11.852 + MethodHandle res = null;
11.853 + if (spreadPos >= 0 && numSpread >= 0) {
11.854 + res = MethodHandleImpl.spreadArguments(IMPL_TOKEN, target, newType, spreadPos);
11.855 + }
11.856 + if (res == null) {
11.857 + throw newIllegalArgumentException("cannot spread "+newType+" to " +oldType);
11.858 + }
11.859 + return res;
11.860 + }
11.861 +
11.862 + /**
11.863 + * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
11.864 + * Produce a method handle which adapts the type of the
11.865 + * given method handle to a new type, by collecting a series of
11.866 + * trailing arguments into an array.
11.867 + * The resulting method handle is guaranteed to confess a type
11.868 + * which is equal to the desired new type.
11.869 + * <p>
11.870 + * This method is inverse to {@link #spreadArguments}.
11.871 + * The final parameter type of the old type must be an array type T[],
11.872 + * which is the type of what is called the <i>spread</i> argument.
11.873 + * The trailing arguments of the new type which correspond to
11.874 + * the spread argument are all converted to type T and collected
11.875 + * into an array before the original method is called.
11.876 + * <p>
11.877 + * ISSUE: Unify this with combineArguments. CollectArguments
11.878 + * is combineArguments with (a) new Object[]{...} as a combiner,
11.879 + * and (b) the combined arguments dropped, in favor of the combined result.
11.880 + * @param target the method handle to invoke after the argument is prepended
11.881 + * @param newType the expected type of the new method handle
11.882 + * @return a new method handle which collects some trailings argument
11.883 + * into an array, before calling the original method handle
11.884 + */
11.885 + public static
11.886 + MethodHandle collectArguments(MethodHandle target, MethodType newType) {
11.887 + MethodType oldType = target.type();
11.888 + int inargs = newType.parameterCount();
11.889 + int outargs = oldType.parameterCount();
11.890 + int collectPos = outargs - 1;
11.891 + int numCollect = (inargs - collectPos);
11.892 + if (collectPos < 0 || numCollect < 0)
11.893 + throw newIllegalArgumentException("wrong number of arguments");
11.894 + return MethodHandleImpl.collectArguments(IMPL_TOKEN, target, newType, collectPos);
11.895 + }
11.896 +
11.897 + /**
11.898 + * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
11.899 + * Produce a method handle which calls the original method handle,
11.900 + * after inserting the given argument at the given position.
11.901 + * The type of the new method handle will drop the corresponding argument
11.902 + * type from the original handle's type.
11.903 + * <p>
11.904 + * The given argument object must match the dropped argument type.
11.905 + * If the dropped argument type is a primitive, the argument object
11.906 + * must be a wrapper, and is unboxed to produce the primitive.
11.907 + * <p>
11.908 + * The <i>pos</i> may range between zero and <i>N</i> (inclusively),
11.909 + * where <i>N</i> is the number of argument types in <i>target</i>,
11.910 + * meaning to insert the new argument as the first or last (respectively),
11.911 + * or somewhere in between.
11.912 + * @param target the method handle to invoke after the argument is inserted
11.913 + * @param pos where to insert the argument (zero for the first)
11.914 + * @param value the argument to insert
11.915 + * @return a new method handle which inserts an additional argument,
11.916 + * before calling the original method handle
11.917 + */
11.918 + public static
11.919 + MethodHandle insertArgument(MethodHandle target, int pos, Object value) {
11.920 + MethodType oldType = target.type();
11.921 + ArrayList<Class<?>> ptypes =
11.922 + new ArrayList<Class<?>>(oldType.parameterList());
11.923 + int outargs = oldType.parameterCount();
11.924 + int inargs = outargs - 1;
11.925 + if (pos < 0 || pos >= outargs)
11.926 + throw newIllegalArgumentException("no argument type to append");
11.927 + Class<?> valueType = ptypes.remove(pos);
11.928 + value = checkValue(valueType, value);
11.929 + if (pos == 0 && !valueType.isPrimitive()) {
11.930 + // At least for now, make bound method handles a special case.
11.931 + // This lets us get by with minimal JVM support, at the expense
11.932 + // of generating signature-specific adapters as Java bytecodes.
11.933 + MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, target, value);
11.934 + if (bmh != null) return bmh;
11.935 + // else fall through to general adapter machinery
11.936 + }
11.937 + return MethodHandleImpl.bindArgument(IMPL_TOKEN, target, pos, value);
11.938 + }
11.939 +
11.940 + /**
11.941 + * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
11.942 + * Produce a method handle which calls the original method handle,
11.943 + * after dropping the given argument(s) at the given position.
11.944 + * The type of the new method handle will insert the given argument
11.945 + * type(s), at that position, into the original handle's type.
11.946 + * <p>
11.947 + * The <i>pos</i> may range between zero and <i>N-1</i>,
11.948 + * where <i>N</i> is the number of argument types in <i>target</i>,
11.949 + * meaning to drop the first or last argument (respectively),
11.950 + * or an argument somewhere in between.
11.951 + * @param target the method handle to invoke after the argument is dropped
11.952 + * @param valueTypes the type(s) of the argument to drop
11.953 + * @param pos which argument to drop (zero for the first)
11.954 + * @return a new method handle which drops an argument of the given type,
11.955 + * before calling the original method handle
11.956 + */
11.957 + public static
11.958 + MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes) {
11.959 + if (valueTypes.length == 0) return target;
11.960 + MethodType oldType = target.type();
11.961 + int outargs = oldType.parameterCount();
11.962 + int inargs = outargs + valueTypes.length;
11.963 + if (pos < 0 || pos >= inargs)
11.964 + throw newIllegalArgumentException("no argument type to remove");
11.965 + ArrayList<Class<?>> ptypes =
11.966 + new ArrayList<Class<?>>(oldType.parameterList());
11.967 + ptypes.addAll(pos, Arrays.asList(valueTypes));
11.968 + MethodType newType = MethodType.make(oldType.returnType(), ptypes);
11.969 + return MethodHandleImpl.dropArguments(IMPL_TOKEN, target, newType, pos);
11.970 + }
11.971 +
11.972 + /**
11.973 + * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
11.974 + * Make a method handle which adapts a target method handle,
11.975 + * by guarding it with a test, a boolean-valued method handle.
11.976 + * If the guard fails, a fallback handle is called instead.
11.977 + * All three method handles must have the same corresponding
11.978 + * argument and return types, except that the return type
11.979 + * of the test must be boolean.
11.980 + * <p> Here is pseudocode for the resulting adapter:
11.981 + * <blockquote><pre>
11.982 + * signature T(A...);
11.983 + * boolean test(A...);
11.984 + * T target(A...);
11.985 + * T fallback(A...);
11.986 + * T adapter(A... a) {
11.987 + * if (test(a...))
11.988 + * return target(a...);
11.989 + * else
11.990 + * return fallback(a...);
11.991 + * }
11.992 + * </pre></blockquote>
11.993 + * @param test method handle used for test, must return boolean
11.994 + * @param target method handle to call if test passes
11.995 + * @param fallback method handle to call if test fails
11.996 + * @return method handle which incorporates the specified if/then/else logic
11.997 + * @throws IllegalArgumentException if {@code test} does not return boolean,
11.998 + * or if all three method types do not match (with the return
11.999 + * type of {@code test} changed to match that of {@code target}).
11.1000 + */
11.1001 + public static
11.1002 + MethodHandle guardWithTest(MethodHandle test,
11.1003 + MethodHandle target,
11.1004 + MethodHandle fallback) {
11.1005 + if (target.type() != fallback.type())
11.1006 + throw newIllegalArgumentException("target and fallback types do not match");
11.1007 + if (target.type().changeReturnType(boolean.class) != test.type())
11.1008 + throw newIllegalArgumentException("target and test types do not match");
11.1009 + /* {
11.1010 + MethodHandle invoke = findVirtual(MethodHandle.class, "invoke", target.type());
11.1011 + static MethodHandle choose(boolean z, MethodHandle t, MethodHandle f) {
11.1012 + return z ? t : f;
11.1013 + }
11.1014 + static MethodHandle compose(MethodHandle f, MethodHandle g) {
11.1015 + Class<?> initargs = g.type().parameterArray();
11.1016 + f = dropArguments(f, 1, initargs); // ignore 2nd copy of args
11.1017 + return combineArguments(f, g);
11.1018 + }
11.1019 + // choose = \z.(z ? target : fallback)
11.1020 + MethodHandle choose = findVirtual(MethodHandles.class, "choose",
11.1021 + MethodType.make(boolean.class, MethodHandle.class, MethodHandle.class));
11.1022 + choose = appendArgument(choose, target);
11.1023 + choose = appendArgument(choose, fallback);
11.1024 + MethodHandle dispatch = compose(choose, test);
11.1025 + // dispatch = \(a...).(test(a...) ? target : fallback)
11.1026 + return combineArguments(invoke, dispatch, 0);
11.1027 + // return \(a...).((test(a...) ? target : fallback).invoke(a...))
11.1028 + } */
11.1029 + return MethodHandleImpl.makeGuardWithTest(IMPL_TOKEN, test, target, fallback);
11.1030 + }
11.1031 +
11.1032 + /**
11.1033 + * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
11.1034 + * Adapt a target method handle {@code target} by first processing
11.1035 + * its arguments, and then calling the target.
11.1036 + * The initial processing is performed by a second method handle, the {@code combiner}.
11.1037 + * After this, control passes to the {@code target}, with the same arguments.
11.1038 + * <p>
11.1039 + * The return value of the {@code combiner} is inserted into the argument list
11.1040 + * for the {@code target} at the indicated position {@code pos}, if it is non-negative.
11.1041 + * Except for this inserted argument (if any), the argument types of
11.1042 + * the target {@code target} and the {@code combiner} must be identical.
11.1043 + * <p>
11.1044 + * (Note that {@link #dropArguments} can be used to remove any arguments
11.1045 + * that either the {@code combiner} or {@code target} does not wish to receive.)
11.1046 + * <p>
11.1047 + * The combiner handle must have the same argument types as the
11.1048 + * target handle, but must return {@link MethodHandle} instead of
11.1049 + * the ultimate return type. The returned method handle, in turn,
11.1050 + * is required to have exactly the given final method type.
11.1051 + * <p> Here is pseudocode for the resulting adapter:
11.1052 + * <blockquote><pre>
11.1053 + * signature V(A[pos]..., B...);
11.1054 + * signature T(A[pos]..., V, B...);
11.1055 + * T target(A... a, V v, B... b);
11.1056 + * V combiner(A..., B...);
11.1057 + * T adapter(A... a, B... b) {
11.1058 + * V v = combiner(a..., b...);
11.1059 + * return target(a..., v, b...);
11.1060 + * }
11.1061 + * </pre></blockquote>
11.1062 + * @param target the method handle to invoke after arguments are combined
11.1063 + * @param pos where the return value of {@code combiner} is to
11.1064 + * be inserted as an argument to {@code target}
11.1065 + * @param combiner method handle to call initially on the incoming arguments
11.1066 + * @return method handle which incorporates the specified dispatch logic
11.1067 + * @throws IllegalArgumentException if {@code combiner} does not itself
11.1068 + * return either void or the {@code pos}-th argument of {@code target},
11.1069 + * or does not have the same argument types as {@code target}
11.1070 + * (minus the inserted argument)
11.1071 + */
11.1072 + public static
11.1073 + MethodHandle combineArguments(MethodHandle target, int pos, MethodHandle combiner) {
11.1074 + MethodType mhType = target.type();
11.1075 + Class<?> combineType = combiner.type().returnType();
11.1076 + MethodType incomingArgs;
11.1077 + if (pos < 0) {
11.1078 + // No inserted argument; target & combiner must have same argument types.
11.1079 + incomingArgs = mhType;
11.1080 + if (!incomingArgs.changeReturnType(combineType).equals(combiner.type()))
11.1081 + throw newIllegalArgumentException("target and combiner types do not match");
11.1082 + } else {
11.1083 + // Inserted argument.
11.1084 + if (pos >= mhType.parameterCount()
11.1085 + || mhType.parameterType(pos) != combineType)
11.1086 + throw newIllegalArgumentException("inserted combiner argument does not match target");
11.1087 + incomingArgs = mhType.dropParameterType(pos);
11.1088 + }
11.1089 + if (!incomingArgs.changeReturnType(combineType).equals(combiner.type())) {
11.1090 + throw newIllegalArgumentException("target and combiner types do not match");
11.1091 + }
11.1092 + return MethodHandleImpl.combineArguments(IMPL_TOKEN, target, combiner, pos);
11.1093 + }
11.1094 +
11.1095 +}
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
12.2 +++ b/src/share/classes/java/dyn/MethodType.java Tue May 05 23:12:47 2009 -0700
12.3 @@ -0,0 +1,575 @@
12.4 +/*
12.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
12.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
12.7 + *
12.8 + * This code is free software; you can redistribute it and/or modify it
12.9 + * under the terms of the GNU General Public License version 2 only, as
12.10 + * published by the Free Software Foundation. Sun designates this
12.11 + * particular file as subject to the "Classpath" exception as provided
12.12 + * by Sun in the LICENSE file that accompanied this code.
12.13 + *
12.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
12.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12.17 + * version 2 for more details (a copy is included in the LICENSE file that
12.18 + * accompanied this code).
12.19 + *
12.20 + * You should have received a copy of the GNU General Public License version
12.21 + * 2 along with this work; if not, write to the Free Software Foundation,
12.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
12.23 + *
12.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
12.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
12.26 + * have any questions.
12.27 + */
12.28 +
12.29 +package java.dyn;
12.30 +
12.31 +import java.util.Arrays;
12.32 +import java.util.Collections;
12.33 +import java.util.HashMap;
12.34 +import java.util.List;
12.35 +import sun.dyn.Access;
12.36 +import sun.dyn.Invokers;
12.37 +import sun.dyn.MethodTypeImpl;
12.38 +import sun.dyn.util.BytecodeSignature;
12.39 +import static sun.dyn.MemberName.newIllegalArgumentException;
12.40 +
12.41 +/**
12.42 + * Run-time token used to match call sites with method handles.
12.43 + * The structure is a return type accompanied by any number of parameter types.
12.44 + * The types (primitive, void, and reference) are represented by Class objects.
12.45 + * All instances of <code>MethodType</code> are immutable.
12.46 + * Two instances are completely interchangeable if they compare equal.
12.47 + * Equality depends exactly on the return and parameter types.
12.48 + * <p>
12.49 + * This type can be created only by factory methods, which manage interning.
12.50 + *
12.51 + * @author John Rose, JSR 292 EG
12.52 + */
12.53 +public final
12.54 +class MethodType {
12.55 + private final Class<?> rtype;
12.56 + private final Class<?>[] ptypes;
12.57 + private MethodTypeForm form; // erased form, plus cached data about primitives
12.58 + private MethodType wrapAlt; // alternative wrapped/unwrapped version
12.59 + private Invokers invokers; // cache of handy higher-order adapters
12.60 +
12.61 + private static final Access IMPL_TOKEN = Access.getToken();
12.62 +
12.63 + // share a cache with a friend in this package
12.64 + Invokers getInvokers() { return invokers; }
12.65 + void setInvokers(Invokers inv) { invokers = inv; }
12.66 +
12.67 + static {
12.68 + // This hack allows the implementation package special access to
12.69 + // the internals of MethodType. In particular, the Form has all sorts
12.70 + // of cached information useful to the implementation code.
12.71 + MethodTypeImpl.setMethodTypeFriend(IMPL_TOKEN, new MethodTypeImpl.MethodTypeFriend() {
12.72 + public Class<?>[] ptypes(MethodType mt) { return mt.ptypes; }
12.73 + public MethodTypeImpl form(MethodType mt) { return mt.form; }
12.74 + public void setForm(MethodType mt, MethodTypeImpl form) {
12.75 + assert(mt.form == null);
12.76 + mt.form = (MethodTypeForm) form;
12.77 + }
12.78 + public MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
12.79 + return MethodType.makeImpl(rtype, ptypes, trusted);
12.80 + }
12.81 + public MethodTypeImpl newMethodTypeForm(MethodType mt) {
12.82 + return new MethodTypeForm(mt);
12.83 + }
12.84 + public Invokers getInvokers(MethodType mt) { return mt.invokers; }
12.85 + public void setInvokers(MethodType mt, Invokers inv) { mt.invokers = inv; }
12.86 + });
12.87 + }
12.88 +
12.89 + private MethodType(Class<?> rtype, Class<?>[] ptypes) {
12.90 + checkRtype(rtype);
12.91 + checkPtypes(ptypes);
12.92 + this.rtype = rtype;
12.93 + this.ptypes = ptypes;
12.94 + }
12.95 +
12.96 + private void checkRtype(Class<?> rtype) {
12.97 + rtype.equals(rtype); // null check
12.98 + }
12.99 + private void checkPtypes(Class<?>[] ptypes) {
12.100 + for (Class<?> ptype : ptypes) {
12.101 + ptype.equals(ptype); // null check
12.102 + if (ptype == void.class)
12.103 + throw newIllegalArgumentException("void parameter: "+this);
12.104 + }
12.105 + }
12.106 +
12.107 + static final HashMap<MethodType,MethodType> internTable
12.108 + = new HashMap<MethodType, MethodType>();
12.109 +
12.110 + static final Class<?>[] NO_PTYPES = {};
12.111 +
12.112 + /** Find or create an instance of the given method type.
12.113 + * @param rtype the return type
12.114 + * @param ptypes the parameter types
12.115 + * @return the interned method type with the given parts
12.116 + * @throws NullPointerException if rtype or any ptype is null
12.117 + * @throws IllegalArgumentException if any of the ptypes is void
12.118 + */
12.119 + public static
12.120 + MethodType make(Class<?> rtype, Class<?>[] ptypes) {
12.121 + return makeImpl(rtype, ptypes, false);
12.122 + }
12.123 +
12.124 + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. */
12.125 + public static
12.126 + MethodType make(Class<?> rtype, List<? extends Class<?>> ptypes) {
12.127 + return makeImpl(rtype, ptypes.toArray(NO_PTYPES), true);
12.128 + }
12.129 +
12.130 + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
12.131 + * The leading parameter type is prepended to the remaining array.
12.132 + */
12.133 + public static
12.134 + MethodType make(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) {
12.135 + Class<?>[] ptypes1 = new Class<?>[1+ptypes.length];
12.136 + ptypes1[0] = ptype0;
12.137 + System.arraycopy(ptypes, 0, ptypes1, 1, ptypes.length);
12.138 + return makeImpl(rtype, ptypes1, true);
12.139 + }
12.140 +
12.141 + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
12.142 + * The resulting method has no parameter types.
12.143 + */
12.144 + public static
12.145 + MethodType make(Class<?> rtype) {
12.146 + return makeImpl(rtype, NO_PTYPES, true);
12.147 + }
12.148 +
12.149 + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
12.150 + * The resulting method has the single given parameter type.
12.151 + */
12.152 + public static
12.153 + MethodType make(Class<?> rtype, Class<?> ptype0) {
12.154 + return makeImpl(rtype, new Class<?>[]{ ptype0 }, true);
12.155 + }
12.156 +
12.157 + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
12.158 + * The resulting method has the same parameter types as {@code ptypes},
12.159 + * and the specified return type.
12.160 + */
12.161 + public static
12.162 + MethodType make(Class<?> rtype, MethodType ptypes) {
12.163 + return makeImpl(rtype, ptypes.ptypes, true);
12.164 + }
12.165 +
12.166 + /**
12.167 + * Sole factory method to find or create an interned method type.
12.168 + * @param rtype desired return type
12.169 + * @param ptypes desired parameter types
12.170 + * @param trusted whether the ptypes can be used without cloning
12.171 + * @return the unique method type of the desired structure
12.172 + */
12.173 + private static
12.174 + MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
12.175 + if (ptypes == null || ptypes.length == 0) {
12.176 + ptypes = NO_PTYPES; trusted = true;
12.177 + }
12.178 + MethodType mt1 = new MethodType(rtype, ptypes);
12.179 + MethodType mt0;
12.180 + synchronized (internTable) {
12.181 + mt0 = internTable.get(mt1);
12.182 + if (mt0 != null)
12.183 + return mt0;
12.184 + }
12.185 + if (!trusted)
12.186 + // defensively copy the array passed in by the user
12.187 + mt1 = new MethodType(rtype, ptypes.clone());
12.188 + // promote the object to the Real Thing, and reprobe
12.189 + MethodTypeImpl.initForm(IMPL_TOKEN, mt1);
12.190 + synchronized (internTable) {
12.191 + mt0 = internTable.get(mt1);
12.192 + if (mt0 != null)
12.193 + return mt0;
12.194 + internTable.put(mt1, mt1);
12.195 + }
12.196 + return mt1;
12.197 + }
12.198 +
12.199 + // Entry point from JVM. TODO: Change the name & signature.
12.200 + private static MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes,
12.201 + boolean ignore1, boolean ignore2) {
12.202 + return makeImpl(rtype, ptypes, true);
12.203 + }
12.204 +
12.205 + private static final MethodType[] objectOnlyTypes = new MethodType[20];
12.206 +
12.207 + /**
12.208 + * Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}.
12.209 + * All parameters and the return type will be Object, except the final varargs parameter if any.
12.210 + * @param objectArgCount number of parameters (excluding the varargs parameter if any)
12.211 + * @param varargs whether there will be a varargs parameter, of type Object[]
12.212 + * @return a totally generic method type, given only its count of parameters and varargs
12.213 + * @see #makeGeneric(int)
12.214 + */
12.215 + public static
12.216 + MethodType makeGeneric(int objectArgCount, boolean varargs) {
12.217 + MethodType mt;
12.218 + int ivarargs = (!varargs ? 0 : 1);
12.219 + int ootIndex = objectArgCount*2 + ivarargs;
12.220 + if (ootIndex < objectOnlyTypes.length) {
12.221 + mt = objectOnlyTypes[ootIndex];
12.222 + if (mt != null) return mt;
12.223 + }
12.224 + Class<?>[] ptypes = new Class<?>[objectArgCount + ivarargs];
12.225 + Arrays.fill(ptypes, Object.class);
12.226 + if (ivarargs != 0) ptypes[objectArgCount] = Object[].class;
12.227 + mt = makeImpl(Object.class, ptypes, true);
12.228 + if (ootIndex < objectOnlyTypes.length) {
12.229 + objectOnlyTypes[ootIndex] = mt; // cache it here also!
12.230 + }
12.231 + return mt;
12.232 + }
12.233 +
12.234 + /**
12.235 + * All parameters and the return type will be Object.
12.236 + * @param objectArgCount number of parameters
12.237 + * @return a totally generic method type, given only its count of parameters
12.238 + * @see #makeGeneric(int, boolean)
12.239 + */
12.240 + public static
12.241 + MethodType makeGeneric(int objectArgCount) {
12.242 + return makeGeneric(objectArgCount, false);
12.243 + }
12.244 +
12.245 + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}.
12.246 + * @param num the index (zero-based) of the parameter type to change
12.247 + * @param nptype a new parameter type to replace the old one with
12.248 + * @return the same type, except with the selected parameter changed
12.249 + */
12.250 + public MethodType changeParameterType(int num, Class<?> nptype) {
12.251 + if (parameterType(num) == nptype) return this;
12.252 + Class<?>[] nptypes = ptypes.clone();
12.253 + nptypes[num] = nptype;
12.254 + return makeImpl(rtype, nptypes, true);
12.255 + }
12.256 +
12.257 + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}.
12.258 + * @param num the position (zero-based) of the inserted parameter type
12.259 + * @param nptype a new parameter type to insert into the parameter list
12.260 + * @return the same type, except with the selected parameter inserted
12.261 + */
12.262 + public MethodType insertParameterType(int num, Class<?> nptype) {
12.263 + int len = ptypes.length;
12.264 + Class<?>[] nptypes = Arrays.copyOfRange(ptypes, 0, len+1);
12.265 + System.arraycopy(nptypes, num, nptypes, num+1, len-num);
12.266 + nptypes[num] = nptype;
12.267 + return makeImpl(rtype, nptypes, true);
12.268 + }
12.269 +
12.270 + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}.
12.271 + * @param num the index (zero-based) of the parameter type to remove
12.272 + * @return the same type, except with the selected parameter removed
12.273 + */
12.274 + public MethodType dropParameterType(int num) {
12.275 + int len = ptypes.length;
12.276 + Class<?>[] nptypes;
12.277 + if (num == 0) {
12.278 + nptypes = Arrays.copyOfRange(ptypes, 1, len);
12.279 + } else {
12.280 + nptypes = Arrays.copyOfRange(ptypes, 0, len-1);
12.281 + System.arraycopy(ptypes, num+1, nptypes, num, (len-1)-num);
12.282 + }
12.283 + return makeImpl(rtype, nptypes, true);
12.284 + }
12.285 +
12.286 + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}.
12.287 + * @param nrtype a return parameter type to replace the old one with
12.288 + * @return the same type, except with the return type change
12.289 + */
12.290 + public MethodType changeReturnType(Class<?> nrtype) {
12.291 + if (returnType() == nrtype) return this;
12.292 + return makeImpl(nrtype, ptypes, true);
12.293 + }
12.294 +
12.295 + /** Convenience method.
12.296 + * Report if this type contains a primitive argument or return value.
12.297 + * @return true if any of the types are primitives
12.298 + */
12.299 + public boolean hasPrimitives() {
12.300 + return form.hasPrimitives();
12.301 + }
12.302 +
12.303 + /** Convenience method.
12.304 + * Report if this type contains a wrapper argument or return value.
12.305 + * Wrappers are types which box primitive values, such as {@link Integer}.
12.306 + * @return true if any of the types are wrappers
12.307 + */
12.308 + public boolean hasWrappers() {
12.309 + return unwrap() != this;
12.310 + }
12.311 +
12.312 + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
12.313 + * Erase all reference types to Object.
12.314 + * @return a version of the original type with all reference types replaced
12.315 + */
12.316 + public MethodType erase() {
12.317 + return form.erasedType();
12.318 + }
12.319 +
12.320 + /** Convenience method for {@link #makeGeneric(int)}.
12.321 + * Convert all types, both reference and primitive, to Object.
12.322 + * @return a version of the original type with all types replaced
12.323 + */
12.324 + public MethodType generic() {
12.325 + return makeGeneric(parameterCount());
12.326 + }
12.327 +
12.328 + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
12.329 + * Convert all primitive types to their corresponding wrapper types.
12.330 + * A {@code void} return type is changed to the type {@code java.lang.Void}.
12.331 + * @return a version of the original type with all primitive types replaced
12.332 + */
12.333 + public MethodType wrap() {
12.334 + return hasPrimitives() ? wrapWithPrims(this) : this;
12.335 + }
12.336 +
12.337 + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
12.338 + * Convert all wrapper types to their corresponding primitive types.
12.339 + * A return type of {@java.lang.Void} is changed to {@code void}.
12.340 + * @return a version of the original type with all wrapper types replaced
12.341 + */
12.342 + public MethodType unwrap() {
12.343 + MethodType noprims = !hasPrimitives() ? this : wrapWithPrims(this);
12.344 + return unwrapWithNoPrims(noprims);
12.345 + }
12.346 +
12.347 + private static MethodType wrapWithPrims(MethodType pt) {
12.348 + assert(pt.hasPrimitives());
12.349 + MethodType wt = pt.wrapAlt;
12.350 + if (wt == null) {
12.351 + // fill in lazily
12.352 + wt = MethodTypeImpl.canonicalize(pt, MethodTypeImpl.WRAP, MethodTypeImpl.WRAP);
12.353 + assert(wt != null);
12.354 + pt.wrapAlt = wt;
12.355 + }
12.356 + return wt;
12.357 + }
12.358 +
12.359 + private static MethodType unwrapWithNoPrims(MethodType wt) {
12.360 + assert(!wt.hasPrimitives());
12.361 + MethodType uwt = wt.wrapAlt;
12.362 + if (uwt == null) {
12.363 + // fill in lazily
12.364 + uwt = MethodTypeImpl.canonicalize(wt, MethodTypeImpl.UNWRAP, MethodTypeImpl.UNWRAP);
12.365 + if (uwt == null)
12.366 + uwt = wt; // type has no wrappers or prims at all
12.367 + wt.wrapAlt = uwt;
12.368 + }
12.369 + return uwt;
12.370 + }
12.371 +
12.372 + /** @param num the index (zero-based) of the desired parameter type
12.373 + * @return the selected parameter type
12.374 + */
12.375 + public Class<?> parameterType(int num) {
12.376 + return ptypes[num];
12.377 + }
12.378 + /** @return the number of parameter types */
12.379 + public int parameterCount() {
12.380 + return ptypes.length;
12.381 + }
12.382 + /** @return the return type */
12.383 + public Class<?> returnType() {
12.384 + return rtype;
12.385 + }
12.386 +
12.387 + /**
12.388 + * Convenience method to present the arguments as a list.
12.389 + * @return the parameter types (as an immutable list)
12.390 + */
12.391 + public List<Class<?>> parameterList() {
12.392 + return Collections.unmodifiableList(Arrays.asList(ptypes));
12.393 + }
12.394 +
12.395 + /**
12.396 + * Convenience method to present the arguments as an array.
12.397 + * @return the parameter types (as a fresh copy if necessary)
12.398 + */
12.399 + public Class<?>[] parameterArray() {
12.400 + return ptypes.clone();
12.401 + }
12.402 +
12.403 + /**
12.404 + * Compares the specified object with this type for equality.
12.405 + * That is, it returns <tt>true</tt> if and only if the specified object
12.406 + * is also a method type with exactly the same parameters and return type.
12.407 + * @param x object to compare
12.408 + * @see Object#equals(Object)
12.409 + */
12.410 + @Override
12.411 + public boolean equals(Object x) {
12.412 + return this == x || x instanceof MethodType && equals((MethodType)x);
12.413 + }
12.414 +
12.415 + private boolean equals(MethodType that) {
12.416 + return this.rtype == that.rtype
12.417 + && Arrays.equals(this.ptypes, that.ptypes);
12.418 + }
12.419 +
12.420 + /**
12.421 + * Returns the hash code value for this method type.
12.422 + * It is defined to be the same as the hashcode of a List
12.423 + * whose elements are the return type followed by the
12.424 + * parameter types.
12.425 + * @return the hash code value for this method type
12.426 + * @see Object#hashCode()
12.427 + * @see #equals(Object)
12.428 + * @see List#hashCode()
12.429 + */
12.430 + @Override
12.431 + public int hashCode() {
12.432 + int hashCode = 31 + rtype.hashCode();
12.433 + for (Class<?> ptype : ptypes)
12.434 + hashCode = 31*hashCode + ptype.hashCode();
12.435 + return hashCode;
12.436 + }
12.437 +
12.438 + /**
12.439 + * The string representation of a method type is a
12.440 + * parenthesis enclosed, comma separated list of type names,
12.441 + * followed immediately by the return type.
12.442 + * <p>
12.443 + * If a type name is array, it the base type followed
12.444 + * by [], rather than the Class.getName of the array type.
12.445 + */
12.446 + @Override
12.447 + public String toString() {
12.448 + StringBuilder sb = new StringBuilder();
12.449 + sb.append("(");
12.450 + for (int i = 0; i < ptypes.length; i++) {
12.451 + if (i > 0) sb.append(",");
12.452 + putName(sb, ptypes[i]);
12.453 + }
12.454 + sb.append(")");
12.455 + putName(sb, rtype);
12.456 + return sb.toString();
12.457 + }
12.458 +
12.459 + static void putName(StringBuilder sb, Class<?> cls) {
12.460 + int brackets = 0;
12.461 + while (cls.isArray()) {
12.462 + cls = cls.getComponentType();
12.463 + brackets++;
12.464 + }
12.465 + String n = cls.getName();
12.466 + /*
12.467 + if (n.startsWith("java.lang.")) {
12.468 + String nb = n.substring("java.lang.".length());
12.469 + if (nb.indexOf('.') < 0) n = nb;
12.470 + } else if (n.indexOf('.') < 0) {
12.471 + n = "."+n; // anonymous package
12.472 + }
12.473 + */
12.474 + sb.append(n);
12.475 + while (brackets > 0) {
12.476 + sb.append("[]");
12.477 + brackets--;
12.478 + }
12.479 + }
12.480 +
12.481 + /// Queries which have to do with the bytecode architecture
12.482 +
12.483 + /** The number of JVM stack slots required to invoke a method
12.484 + * of this type. Note that (for historic reasons) the JVM requires
12.485 + * a second stack slot to pass long and double arguments.
12.486 + * So this method returns {@link #parameterCount()} plus the
12.487 + * number of long and double parameters (if any).
12.488 + * <p>
12.489 + * This method is included for the benfit of applications that must
12.490 + * generate bytecodes that process method handles and invokedynamic.
12.491 + * @return the number of JVM stack slots for this type's parameters
12.492 + */
12.493 + public int parameterSlotCount() {
12.494 + return form.parameterSlotCount();
12.495 + }
12.496 +
12.497 + /** Number of JVM stack slots which carry all parameters after
12.498 + * the given position, which must be in the range of 0 to
12.499 + * {@code parameterCount} inclusive. Successive parameters are
12.500 + * more shallowly stacked, and parameters are indexed in the bytecodes
12.501 + * according to their trailing edge. Thus, to obtain the depth
12.502 + * in the outgoing call stack of parameter {@code N}, obtain
12.503 + * the {@code parameterSlotDepth} of its trailing edge
12.504 + * at position {@code N+1}.
12.505 + * <p>
12.506 + * Parameters of type {@code long} and {@code double} occupy
12.507 + * two stack slots (for historical reasons) and all others occupy one.
12.508 + * Therefore, the number returned is the number of arguments
12.509 + * <em>including</em> and <em>after</em> the given parameter,
12.510 + * <em>plus</em> the number of long or double arguments
12.511 + * at or after after the argument for the given parameter.
12.512 + * <p>
12.513 + * This method is included for the benfit of applications that must
12.514 + * generate bytecodes that process method handles and invokedynamic.
12.515 + * @param num an index (zero-based, inclusive) within the parameter types
12.516 + * @return the index of the (shallowest) JVM stack slot transmitting the
12.517 + * given parameter
12.518 + */
12.519 + public int parameterSlotDepth(int num) {
12.520 + if (num < 0 || num > ptypes.length)
12.521 + parameterType(num); // force a range check
12.522 + return form.parameterToArgSlot(num-1);
12.523 + }
12.524 +
12.525 + /** The number of JVM stack slots required to receive a return value
12.526 + * from a method of this type.
12.527 + * If the {@link #returnType() return type} is void, it will be zero,
12.528 + * else if the return type is long or double, it will be two, else one.
12.529 + * <p>
12.530 + * This method is included for the benfit of applications that must
12.531 + * generate bytecodes that process method handles and invokedynamic.
12.532 + * @return the number of JVM stack slots (0, 1, or 2) for this type's return value
12.533 + */
12.534 + public int returnSlotCount() {
12.535 + return form.returnSlotCount();
12.536 + }
12.537 +
12.538 + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
12.539 + * Find or create an instance (interned) of the given method type.
12.540 + * Any class or interface name embedded in the signature string
12.541 + * will be resolved by calling {@link ClassLoader#loadClass(java.lang.String)}
12.542 + * on the given loader (or if it is null, on the system class loader).
12.543 + * <p>
12.544 + * Note that it is possible to build method types which cannot be
12.545 + * constructed by this method, because their component types are
12.546 + * not all reachable from a common class loader.
12.547 + * <p>
12.548 + * This method is included for the benfit of applications that must
12.549 + * generate bytecodes that process method handles and invokedynamic.
12.550 + * @param bytecodeSignature a bytecode-level signature string "(T...)T"
12.551 + * @param loader the class loader in which to look up the types
12.552 + * @return a method type matching the bytecode-level signature
12.553 + * @throws IllegalArgumentException if the string is not well-formed
12.554 + * @throws TypeNotPresentException if a named type cannot be found
12.555 + */
12.556 + public static MethodType fromBytecodeString(String bytecodeSignature, ClassLoader loader)
12.557 + throws IllegalArgumentException, TypeNotPresentException
12.558 + {
12.559 + List<Class<?>> types = BytecodeSignature.parseMethod(bytecodeSignature, loader);
12.560 + Class<?> rtype = types.remove(types.size() - 1);
12.561 + Class<?>[] ptypes = types.toArray(NO_PTYPES);
12.562 + return makeImpl(rtype, ptypes, true);
12.563 + }
12.564 +
12.565 + /**
12.566 + * Create a bytecode signature representation of the type.
12.567 + * Note that this is not a strict inverse of
12.568 + * <p>
12.569 + * This method is included for the benfit of applications that must
12.570 + * generate bytecodes that process method handles and invokedynamic.
12.571 + * {@link #fromBytecodeString(java.lang.String, java.lang.ClassLoader)},
12.572 + * because the latter requires a suitable class loader argument.
12.573 + * @return the bytecode signature representation
12.574 + */
12.575 + public String toBytecodeString() {
12.576 + return BytecodeSignature.unparse(this);
12.577 + }
12.578 +}
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
13.2 +++ b/src/share/classes/java/dyn/MethodTypeForm.java Tue May 05 23:12:47 2009 -0700
13.3 @@ -0,0 +1,39 @@
13.4 +/*
13.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
13.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
13.7 + *
13.8 + * This code is free software; you can redistribute it and/or modify it
13.9 + * under the terms of the GNU General Public License version 2 only, as
13.10 + * published by the Free Software Foundation. Sun designates this
13.11 + * particular file as subject to the "Classpath" exception as provided
13.12 + * by Sun in the LICENSE file that accompanied this code.
13.13 + *
13.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
13.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13.17 + * version 2 for more details (a copy is included in the LICENSE file that
13.18 + * accompanied this code).
13.19 + *
13.20 + * You should have received a copy of the GNU General Public License version
13.21 + * 2 along with this work; if not, write to the Free Software Foundation,
13.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
13.23 + *
13.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
13.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
13.26 + * have any questions.
13.27 + */
13.28 +
13.29 +package java.dyn;
13.30 +
13.31 +/**
13.32 + * TO DO: Temporary shim; remove after refactoring effects are complete in JVM.
13.33 + * @author John Rose
13.34 + */
13.35 +import sun.dyn.MethodTypeImpl;
13.36 +
13.37 +class MethodTypeForm extends MethodTypeImpl {
13.38 +
13.39 + MethodTypeForm(MethodType erasedType) {
13.40 + super(erasedType);
13.41 + }
13.42 +}
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
14.2 +++ b/src/share/classes/java/dyn/NoAccessException.java Tue May 05 23:12:47 2009 -0700
14.3 @@ -0,0 +1,75 @@
14.4 +/*
14.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
14.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
14.7 + *
14.8 + * This code is free software; you can redistribute it and/or modify it
14.9 + * under the terms of the GNU General Public License version 2 only, as
14.10 + * published by the Free Software Foundation. Sun designates this
14.11 + * particular file as subject to the "Classpath" exception as provided
14.12 + * by Sun in the LICENSE file that accompanied this code.
14.13 + *
14.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
14.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14.17 + * version 2 for more details (a copy is included in the LICENSE file that
14.18 + * accompanied this code).
14.19 + *
14.20 + * You should have received a copy of the GNU General Public License version
14.21 + * 2 along with this work; if not, write to the Free Software Foundation,
14.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
14.23 + *
14.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
14.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
14.26 + * have any questions.
14.27 + */
14.28 +
14.29 +package java.dyn;
14.30 +
14.31 +/**
14.32 + * Thrown to indicate that a caller has attempted to create a method handle
14.33 + * which calls a method to which the caller does not have access.
14.34 + * This unchecked exception is analogous to {@link IllegalAccessException},
14.35 + * which is a checked exception thrown when reflective invocation fails
14.36 + * because of an access check. With method handles, this same access
14.37 + * checking is performed on behalf of the method handle creator,
14.38 + * at the time of creation.
14.39 + * @author John Rose, JSR 292 EG
14.40 + */
14.41 +public class NoAccessException extends RuntimeException {
14.42 + /**
14.43 + * Constructs a {@code NoAccessException} with no detail message.
14.44 + */
14.45 + public NoAccessException() {
14.46 + super();
14.47 + }
14.48 +
14.49 + /**
14.50 + * Constructs a {@code NoAccessException} with the specified
14.51 + * detail message.
14.52 + *
14.53 + * @param s the detail message
14.54 + */
14.55 + public NoAccessException(String s) {
14.56 + super(s);
14.57 + }
14.58 +
14.59 + /**
14.60 + * Constructs a {@code NoAccessException} with the specified cause.
14.61 + *
14.62 + * @param cause the underlying cause of the exception
14.63 + */
14.64 + public NoAccessException(Throwable cause) {
14.65 + super(cause);
14.66 + }
14.67 +
14.68 + /**
14.69 + * Constructs a {@code NoAccessException} with the specified
14.70 + * detail message and cause.
14.71 + *
14.72 + * @param s the detail message
14.73 + * @param cause the underlying cause of the exception
14.74 + */
14.75 + public NoAccessException(String s, Throwable cause) {
14.76 + super(s, cause);
14.77 + }
14.78 +}
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
15.2 +++ b/src/share/classes/java/dyn/WrongMethodTypeException.java Tue May 05 23:12:47 2009 -0700
15.3 @@ -0,0 +1,59 @@
15.4 +/*
15.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
15.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
15.7 + *
15.8 + * This code is free software; you can redistribute it and/or modify it
15.9 + * under the terms of the GNU General Public License version 2 only, as
15.10 + * published by the Free Software Foundation. Sun designates this
15.11 + * particular file as subject to the "Classpath" exception as provided
15.12 + * by Sun in the LICENSE file that accompanied this code.
15.13 + *
15.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
15.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15.17 + * version 2 for more details (a copy is included in the LICENSE file that
15.18 + * accompanied this code).
15.19 + *
15.20 + * You should have received a copy of the GNU General Public License version
15.21 + * 2 along with this work; if not, write to the Free Software Foundation,
15.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
15.23 + *
15.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
15.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
15.26 + * have any questions.
15.27 + */
15.28 +
15.29 +package java.dyn;
15.30 +
15.31 +/**
15.32 + * Thrown to indicate that code has attempted to call a method handle
15.33 + * via the wrong method type. As with the bytecode representation of
15.34 + * normal Java method calls, method handle calls are strongly typed
15.35 + * to a specific signature associated with a call site.
15.36 + * <p>
15.37 + * This exception may also be thrown when two method handles are
15.38 + * composed, and the system detects that their types cannot be
15.39 + * matched up correctly. This amounts to an early evaluation
15.40 + * of the type mismatch, at method handle construction time,
15.41 + * instead of when the mismatched method handle is called.
15.42 + *
15.43 + * @author John Rose, JSR 292 EG
15.44 + */
15.45 +public class WrongMethodTypeException extends RuntimeException {
15.46 + /**
15.47 + * Constructs a {@code WrongMethodTypeException} with no detail message.
15.48 + */
15.49 + public WrongMethodTypeException() {
15.50 + super();
15.51 + }
15.52 +
15.53 + /**
15.54 + * Constructs a {@code WrongMethodTypeException} with the specified
15.55 + * detail message.
15.56 + *
15.57 + * @param s the detail message.
15.58 + */
15.59 + public WrongMethodTypeException(String s) {
15.60 + super(s);
15.61 + }
15.62 +}
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
16.2 +++ b/src/share/classes/java/dyn/package-info.java Tue May 05 23:12:47 2009 -0700
16.3 @@ -0,0 +1,32 @@
16.4 +/*
16.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
16.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
16.7 + *
16.8 + * This code is free software; you can redistribute it and/or modify it
16.9 + * under the terms of the GNU General Public License version 2 only, as
16.10 + * published by the Free Software Foundation. Sun designates this
16.11 + * particular file as subject to the "Classpath" exception as provided
16.12 + * by Sun in the LICENSE file that accompanied this code.
16.13 + *
16.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
16.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16.17 + * version 2 for more details (a copy is included in the LICENSE file that
16.18 + * accompanied this code).
16.19 + *
16.20 + * You should have received a copy of the GNU General Public License version
16.21 + * 2 along with this work; if not, write to the Free Software Foundation,
16.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
16.23 + *
16.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
16.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
16.26 + * have any questions.
16.27 + */
16.28 +
16.29 +/**
16.30 + * This package contains dynamic language support provided directly by
16.31 + * the Java core class libraries and virtual machine.
16.32 + * @author John Rose, JSR 292 EG
16.33 + */
16.34 +
16.35 +package java.dyn;
17.1 --- a/src/share/classes/java/io/Console.java Tue May 05 09:09:24 2009 -0700
17.2 +++ b/src/share/classes/java/io/Console.java Tue May 05 23:12:47 2009 -0700
17.3 @@ -503,20 +503,25 @@
17.4
17.5 // Set up JavaIOAccess in SharedSecrets
17.6 static {
17.7 -
17.8 - // Add a shutdown hook to restore console's echo state should
17.9 - // it be necessary.
17.10 - sun.misc.SharedSecrets.getJavaLangAccess()
17.11 - .registerShutdownHook(0 /* shutdown hook invocation order */,
17.12 - new Runnable() {
17.13 - public void run() {
17.14 - try {
17.15 - if (echoOff) {
17.16 - echo(true);
17.17 - }
17.18 - } catch (IOException x) { }
17.19 - }
17.20 - });
17.21 + try {
17.22 + // Add a shutdown hook to restore console's echo state should
17.23 + // it be necessary.
17.24 + sun.misc.SharedSecrets.getJavaLangAccess()
17.25 + .registerShutdownHook(0 /* shutdown hook invocation order */,
17.26 + false /* only register if shutdown is not in progress */,
17.27 + new Runnable() {
17.28 + public void run() {
17.29 + try {
17.30 + if (echoOff) {
17.31 + echo(true);
17.32 + }
17.33 + } catch (IOException x) { }
17.34 + }
17.35 + });
17.36 + } catch (IllegalStateException e) {
17.37 + // shutdown is already in progress and console is first used
17.38 + // by a shutdown hook
17.39 + }
17.40
17.41 sun.misc.SharedSecrets.setJavaIOAccess(new sun.misc.JavaIOAccess() {
17.42 public Console console() {
18.1 --- a/src/share/classes/java/io/DeleteOnExitHook.java Tue May 05 09:09:24 2009 -0700
18.2 +++ b/src/share/classes/java/io/DeleteOnExitHook.java Tue May 05 23:12:47 2009 -0700
18.3 @@ -34,23 +34,31 @@
18.4 */
18.5
18.6 class DeleteOnExitHook {
18.7 + private static LinkedHashSet<String> files = new LinkedHashSet<String>();
18.8 static {
18.9 - sun.misc.SharedSecrets.getJavaLangAccess()
18.10 - .registerShutdownHook(2 /* Shutdown hook invocation order */,
18.11 - new Runnable() {
18.12 - public void run() {
18.13 - runHooks();
18.14 - }
18.15 - });
18.16 + // DeleteOnExitHook must be the last shutdown hook to be invoked.
18.17 + // Application shutdown hooks may add the first file to the
18.18 + // delete on exit list and cause the DeleteOnExitHook to be
18.19 + // registered during shutdown in progress. So set the
18.20 + // registerShutdownInProgress parameter to true.
18.21 + sun.misc.SharedSecrets.getJavaLangAccess()
18.22 + .registerShutdownHook(2 /* Shutdown hook invocation order */,
18.23 + true /* register even if shutdown in progress */,
18.24 + new Runnable() {
18.25 + public void run() {
18.26 + runHooks();
18.27 + }
18.28 + }
18.29 + );
18.30 }
18.31
18.32 - private static LinkedHashSet<String> files = new LinkedHashSet<String>();
18.33 -
18.34 private DeleteOnExitHook() {}
18.35
18.36 static synchronized void add(String file) {
18.37 - if(files == null)
18.38 + if(files == null) {
18.39 + // DeleteOnExitHook is running. Too late to add a file
18.40 throw new IllegalStateException("Shutdown in progress");
18.41 + }
18.42
18.43 files.add(file);
18.44 }
19.1 --- a/src/share/classes/java/lang/ApplicationShutdownHooks.java Tue May 05 09:09:24 2009 -0700
19.2 +++ b/src/share/classes/java/lang/ApplicationShutdownHooks.java Tue May 05 23:12:47 2009 -0700
19.3 @@ -35,17 +35,26 @@
19.4 */
19.5
19.6 class ApplicationShutdownHooks {
19.7 + /* The set of registered hooks */
19.8 + private static IdentityHashMap<Thread, Thread> hooks;
19.9 static {
19.10 - Shutdown.add(1 /* shutdown hook invocation order */,
19.11 - new Runnable() {
19.12 - public void run() {
19.13 - runHooks();
19.14 + try {
19.15 + Shutdown.add(1 /* shutdown hook invocation order */,
19.16 + false /* not registered if shutdown in progress */,
19.17 + new Runnable() {
19.18 + public void run() {
19.19 + runHooks();
19.20 + }
19.21 }
19.22 - });
19.23 + );
19.24 + hooks = new IdentityHashMap<Thread, Thread>();
19.25 + } catch (IllegalStateException e) {
19.26 + // application shutdown hooks cannot be added if
19.27 + // shutdown is in progress.
19.28 + hooks = null;
19.29 + }
19.30 }
19.31
19.32 - /* The set of registered hooks */
19.33 - private static IdentityHashMap<Thread, Thread> hooks = new IdentityHashMap<Thread, Thread>();
19.34
19.35 private ApplicationShutdownHooks() {}
19.36
20.1 --- a/src/share/classes/java/lang/Shutdown.java Tue May 05 09:09:24 2009 -0700
20.2 +++ b/src/share/classes/java/lang/Shutdown.java Tue May 05 23:12:47 2009 -0700
20.3 @@ -53,6 +53,9 @@
20.4 private static final int MAX_SYSTEM_HOOKS = 10;
20.5 private static final Runnable[] hooks = new Runnable[MAX_SYSTEM_HOOKS];
20.6
20.7 + // the index of the currently running shutdown hook to the hooks array
20.8 + private static int currentRunningHook = 0;
20.9 +
20.10 /* The preceding static fields are protected by this lock */
20.11 private static class Lock { };
20.12 private static Object lock = new Lock();
20.13 @@ -68,17 +71,39 @@
20.14 }
20.15
20.16
20.17 - /* Add a new shutdown hook. Checks the shutdown state and the hook itself,
20.18 + /**
20.19 + * Add a new shutdown hook. Checks the shutdown state and the hook itself,
20.20 * but does not do any security checks.
20.21 + *
20.22 + * The registerShutdownInProgress parameter should be false except
20.23 + * registering the DeleteOnExitHook since the first file may
20.24 + * be added to the delete on exit list by the application shutdown
20.25 + * hooks.
20.26 + *
20.27 + * @params slot the slot in the shutdown hook array, whose element
20.28 + * will be invoked in order during shutdown
20.29 + * @params registerShutdownInProgress true to allow the hook
20.30 + * to be registered even if the shutdown is in progress.
20.31 + * @params hook the hook to be registered
20.32 + *
20.33 + * @throw IllegalStateException
20.34 + * if registerShutdownInProgress is false and shutdown is in progress; or
20.35 + * if registerShutdownInProgress is true and the shutdown process
20.36 + * already passes the given slot
20.37 */
20.38 - static void add(int slot, Runnable hook) {
20.39 + static void add(int slot, boolean registerShutdownInProgress, Runnable hook) {
20.40 synchronized (lock) {
20.41 - if (state > RUNNING)
20.42 - throw new IllegalStateException("Shutdown in progress");
20.43 -
20.44 if (hooks[slot] != null)
20.45 throw new InternalError("Shutdown hook at slot " + slot + " already registered");
20.46
20.47 + if (!registerShutdownInProgress) {
20.48 + if (state > RUNNING)
20.49 + throw new IllegalStateException("Shutdown in progress");
20.50 + } else {
20.51 + if (state > HOOKS || (state == HOOKS && slot <= currentRunningHook))
20.52 + throw new IllegalStateException("Shutdown in progress");
20.53 + }
20.54 +
20.55 hooks[slot] = hook;
20.56 }
20.57 }
20.58 @@ -86,11 +111,15 @@
20.59 /* Run all registered shutdown hooks
20.60 */
20.61 private static void runHooks() {
20.62 - /* We needn't bother acquiring the lock just to read the hooks field,
20.63 - * since the hooks can't be modified once shutdown is in progress
20.64 - */
20.65 - for (Runnable hook : hooks) {
20.66 + for (int i=0; i < MAX_SYSTEM_HOOKS; i++) {
20.67 try {
20.68 + Runnable hook;
20.69 + synchronized (lock) {
20.70 + // acquire the lock to make sure the hook registered during
20.71 + // shutdown is visible here.
20.72 + currentRunningHook = i;
20.73 + hook = hooks[i];
20.74 + }
20.75 if (hook != null) hook.run();
20.76 } catch(Throwable t) {
20.77 if (t instanceof ThreadDeath) {
21.1 --- a/src/share/classes/java/lang/System.java Tue May 05 09:09:24 2009 -0700
21.2 +++ b/src/share/classes/java/lang/System.java Tue May 05 23:12:47 2009 -0700
21.3 @@ -1171,8 +1171,8 @@
21.4 public void blockedOn(Thread t, Interruptible b) {
21.5 t.blockedOn(b);
21.6 }
21.7 - public void registerShutdownHook(int slot, Runnable r) {
21.8 - Shutdown.add(slot, r);
21.9 + public void registerShutdownHook(int slot, boolean registerShutdownInProgress, Runnable hook) {
21.10 + Shutdown.add(slot, registerShutdownInProgress, hook);
21.11 }
21.12 });
21.13 }
22.1 --- a/src/share/classes/java/util/zip/ZipFile.java Tue May 05 09:09:24 2009 -0700
22.2 +++ b/src/share/classes/java/util/zip/ZipFile.java Tue May 05 23:12:47 2009 -0700
22.3 @@ -154,7 +154,7 @@
22.4 * @param file the ZIP file to be opened for reading
22.5 * @param mode the mode in which the file is to be opened
22.6 * @param charset
22.7 - * the {@link java.nio.charset.Charset {@code charset}} to
22.8 + * the {@linkplain java.nio.charset.Charset charset} to
22.9 * be used to decode the ZIP entry name and comment that are not
22.10 * encoded by using UTF-8 encoding (indicated by entry's general
22.11 * purpose flag).
22.12 @@ -206,7 +206,7 @@
22.13 *
22.14 * @param name the name of the zip file
22.15 * @param charset
22.16 - * the {@link java.nio.charset.Charset {@code charset}} to
22.17 + * the {@linkplain java.nio.charset.Charset charset} to
22.18 * be used to decode the ZIP entry name and comment that are not
22.19 * encoded by using UTF-8 encoding (indicated by entry's general
22.20 * purpose flag).
22.21 @@ -230,7 +230,7 @@
22.22 * Opens a ZIP file for reading given the specified File object.
22.23 * @param file the ZIP file to be opened for reading
22.24 * @param charset
22.25 - * The {@link java.nio.charset.Charset {@code charset}} to be
22.26 + * The {@linkplain java.nio.charset.Charset charset} to be
22.27 * used to decode the ZIP entry name and comment (ignored if
22.28 * the <a href="package-summary.html#lang_encoding"> language
22.29 * encoding bit</a> of the ZIP entry's general purpose bit
23.1 --- a/src/share/classes/java/util/zip/ZipInputStream.java Tue May 05 09:09:24 2009 -0700
23.2 +++ b/src/share/classes/java/util/zip/ZipInputStream.java Tue May 05 23:12:47 2009 -0700
23.3 @@ -84,7 +84,7 @@
23.4 * @param in the actual input stream
23.5 *
23.6 * @param charset
23.7 - * The {@link java.nio.charset.Charset {@code charset}} to be
23.8 + * The {@linkplain java.nio.charset.Charset charset} to be
23.9 * used to decode the ZIP entry name (ignored if the
23.10 * <a href="package-summary.html#lang_encoding"> language
23.11 * encoding bit</a> of the ZIP entry's general purpose bit
24.1 --- a/src/share/classes/java/util/zip/ZipOutputStream.java Tue May 05 09:09:24 2009 -0700
24.2 +++ b/src/share/classes/java/util/zip/ZipOutputStream.java Tue May 05 23:12:47 2009 -0700
24.3 @@ -108,7 +108,7 @@
24.4 *
24.5 * @param out the actual output stream
24.6 *
24.7 - * @param charset the {@link java.nio.charset.Charset </code>charset<code>}
24.8 + * @param charset the {@linkplain java.nio.charset.Charset charset}
24.9 * to be used to encode the entry names and comments
24.10 *
24.11 * @since 1.7
25.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
25.2 +++ b/src/share/classes/sun/dyn/Access.java Tue May 05 23:12:47 2009 -0700
25.3 @@ -0,0 +1,109 @@
25.4 +/*
25.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
25.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
25.7 + *
25.8 + * This code is free software; you can redistribute it and/or modify it
25.9 + * under the terms of the GNU General Public License version 2 only, as
25.10 + * published by the Free Software Foundation. Sun designates this
25.11 + * particular file as subject to the "Classpath" exception as provided
25.12 + * by Sun in the LICENSE file that accompanied this code.
25.13 + *
25.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
25.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
25.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25.17 + * version 2 for more details (a copy is included in the LICENSE file that
25.18 + * accompanied this code).
25.19 + *
25.20 + * You should have received a copy of the GNU General Public License version
25.21 + * 2 along with this work; if not, write to the Free Software Foundation,
25.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
25.23 + *
25.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
25.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
25.26 + * have any questions.
25.27 + */
25.28 +
25.29 +package sun.dyn;
25.30 +
25.31 +import sun.reflect.Reflection;
25.32 +
25.33 +/**
25.34 + * Access control to this package.
25.35 + * Classes in other packages can attempt to acquire the access token,
25.36 + * but will fail if they are not recognized as friends.
25.37 + * Certain methods in this package, although public, require a non-null
25.38 + * access token in order to proceed; they act like package-private methods.
25.39 + * @author jrose
25.40 + */
25.41 +
25.42 +public class Access {
25.43 +
25.44 + private Access() { }
25.45 +
25.46 + /**
25.47 + * The heart of this pattern: The list of classes which are
25.48 + * permitted to acquire the access token, and become honorary
25.49 + * members of this package.
25.50 + */
25.51 + private static final String[] FRIENDS = {
25.52 + "java.dyn.", "sun.dyn."
25.53 + };
25.54 +
25.55 + /**
25.56 + * The following object is NOT public. That's the point of the pattern.
25.57 + * It is package-private, so that any member of this package
25.58 + * can acquire the access token, and give it away to trusted friends.
25.59 + */
25.60 + static final Access TOKEN = new Access();
25.61 +
25.62 + /**
25.63 + * @return Access.TOKEN, if the caller is a friend of this package
25.64 + */
25.65 + public static Access getToken() {
25.66 + Class<?> callc = Reflection.getCallerClass(2);
25.67 + if (isFriend(callc))
25.68 + return TOKEN;
25.69 + else
25.70 + throw new IllegalAccessError("bad caller: " + callc);
25.71 + }
25.72 +
25.73 + /** Is the given name the name of a class which could be our friend? */
25.74 + public static boolean isFriendName(String name) {
25.75 + for (String friend : FRIENDS) {
25.76 + if (name.startsWith(friend))
25.77 + return true;
25.78 + }
25.79 + return false;
25.80 + }
25.81 +
25.82 + /** Is the given class a friend? True if {@link #isFriendName},
25.83 + * and the given class also shares a class loader with us.
25.84 + */
25.85 + public static boolean isFriend(Class<?> c) {
25.86 + return isFriendName(c.getName()) && c.getClassLoader() == CLASS_LOADER;
25.87 + }
25.88 +
25.89 + private static final ClassLoader CLASS_LOADER = Access.class.getClassLoader();
25.90 +
25.91 + /**
25.92 + * Throw an IllegalAccessError if the caller does not possess
25.93 + * the Access.TOKEN.
25.94 + * @param must be Access.TOKEN
25.95 + */
25.96 + public static void check(Access token) {
25.97 + if (token == null)
25.98 + fail();
25.99 + // else it must be the unique Access.TOKEN
25.100 + assert(token == Access.TOKEN);
25.101 + }
25.102 + private static void fail() {
25.103 + final int CALLER_DEPTH = 3;
25.104 + // 0: Reflection.getCC, 1: this.fail, 2: Access.*, 3: caller
25.105 + Class<?> callc = Reflection.getCallerClass(CALLER_DEPTH);
25.106 + throw new IllegalAccessError("bad caller: " + callc);
25.107 + }
25.108 +
25.109 + static {
25.110 + //sun.reflect.Reflection.registerMethodsToFilter(MH.class, "getToken");
25.111 + }
25.112 +}
26.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
26.2 +++ b/src/share/classes/sun/dyn/AdapterMethodHandle.java Tue May 05 23:12:47 2009 -0700
26.3 @@ -0,0 +1,728 @@
26.4 +/*
26.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
26.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
26.7 + *
26.8 + * This code is free software; you can redistribute it and/or modify it
26.9 + * under the terms of the GNU General Public License version 2 only, as
26.10 + * published by the Free Software Foundation. Sun designates this
26.11 + * particular file as subject to the "Classpath" exception as provided
26.12 + * by Sun in the LICENSE file that accompanied this code.
26.13 + *
26.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
26.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
26.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26.17 + * version 2 for more details (a copy is included in the LICENSE file that
26.18 + * accompanied this code).
26.19 + *
26.20 + * You should have received a copy of the GNU General Public License version
26.21 + * 2 along with this work; if not, write to the Free Software Foundation,
26.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26.23 + *
26.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
26.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
26.26 + * have any questions.
26.27 + */
26.28 +
26.29 +package sun.dyn;
26.30 +
26.31 +import sun.dyn.util.VerifyType;
26.32 +import sun.dyn.util.Wrapper;
26.33 +import java.dyn.*;
26.34 +import java.util.Arrays;
26.35 +import static sun.dyn.MethodHandleNatives.Constants.*;
26.36 +import static sun.dyn.MethodHandleImpl.newIllegalArgumentException;
26.37 +
26.38 +/**
26.39 + * This method handle performs simple conversion or checking of a single argument.
26.40 + * @author jrose
26.41 + */
26.42 +public class AdapterMethodHandle extends BoundMethodHandle {
26.43 +
26.44 + //MethodHandle vmtarget; // next AMH or BMH in chain or final DMH
26.45 + //Object argument; // parameter to the conversion if needed
26.46 + //int vmargslot; // which argument slot is affected
26.47 + private final int conversion; // the type of conversion: RETYPE_ONLY, etc.
26.48 +
26.49 + // Constructors in this class *must* be package scoped or private.
26.50 + private AdapterMethodHandle(MethodHandle target, MethodType newType,
26.51 + long conv, Object convArg) {
26.52 + super(newType, convArg, newType.parameterSlotDepth(1+convArgPos(conv)));
26.53 + this.conversion = convCode(conv);
26.54 + if (MethodHandleNatives.JVM_SUPPORT) {
26.55 + // JVM might update VM-specific bits of conversion (ignore)
26.56 + MethodHandleNatives.init(this, target, convArgPos(conv));
26.57 + }
26.58 + }
26.59 + private AdapterMethodHandle(MethodHandle target, MethodType newType,
26.60 + long conv) {
26.61 + this(target, newType, conv, null);
26.62 + }
26.63 +
26.64 + private static final Access IMPL_TOKEN = Access.getToken();
26.65 +
26.66 + // TO DO: When adapting another MH with a null conversion, clone
26.67 + // the target and change its type, instead of adding another layer.
26.68 +
26.69 + /** Can a JVM-level adapter directly implement the proposed
26.70 + * argument conversions, as if by MethodHandles.convertArguments?
26.71 + */
26.72 + public static boolean canPairwiseConvert(MethodType newType, MethodType oldType) {
26.73 + // same number of args, of course
26.74 + int len = newType.parameterCount();
26.75 + if (len != oldType.parameterCount())
26.76 + return false;
26.77 +
26.78 + // Check return type. (Not much can be done with it.)
26.79 + Class<?> exp = newType.returnType();
26.80 + Class<?> ret = oldType.returnType();
26.81 + if (!VerifyType.isNullConversion(ret, exp))
26.82 + return false;
26.83 +
26.84 + // Check args pairwise.
26.85 + for (int i = 0; i < len; i++) {
26.86 + Class<?> src = newType.parameterType(i); // source type
26.87 + Class<?> dst = oldType.parameterType(i); // destination type
26.88 + if (!canConvertArgument(src, dst))
26.89 + return false;
26.90 + }
26.91 +
26.92 + return true;
26.93 + }
26.94 +
26.95 + /** Can a JVM-level adapter directly implement the proposed
26.96 + * argument conversion, as if by MethodHandles.convertArguments?
26.97 + */
26.98 + public static boolean canConvertArgument(Class<?> src, Class<?> dst) {
26.99 + // ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes,
26.100 + // so we don't need to repeat so much decision making.
26.101 + if (VerifyType.isNullConversion(src, dst)) {
26.102 + return true;
26.103 + } else if (src.isPrimitive()) {
26.104 + if (dst.isPrimitive())
26.105 + return canPrimCast(src, dst);
26.106 + else
26.107 + return canBoxArgument(src, dst);
26.108 + } else {
26.109 + if (dst.isPrimitive())
26.110 + return canUnboxArgument(src, dst);
26.111 + else
26.112 + return true; // any two refs can be interconverted
26.113 + }
26.114 + }
26.115 +
26.116 + /**
26.117 + * Create a JVM-level adapter method handle to conform the given method
26.118 + * handle to the similar newType, using only pairwise argument conversions.
26.119 + * For each argument, convert incoming argument to the exact type needed.
26.120 + * Only null conversions are allowed on the return value (until
26.121 + * the JVM supports ricochet adapters).
26.122 + * The argument conversions allowed are casting, unboxing,
26.123 + * integral widening or narrowing, and floating point widening or narrowing.
26.124 + * @param token access check
26.125 + * @param newType required call type
26.126 + * @param target original method handle
26.127 + * @return an adapter to the original handle with the desired new type,
26.128 + * or the original target if the types are already identical
26.129 + * or null if the adaptation cannot be made
26.130 + */
26.131 + public static MethodHandle makePairwiseConvert(Access token,
26.132 + MethodType newType, MethodHandle target) {
26.133 + Access.check(token);
26.134 + MethodType oldType = target.type();
26.135 + if (newType == oldType) return target;
26.136 +
26.137 + if (!canPairwiseConvert(newType, oldType))
26.138 + return null;
26.139 + // (after this point, it is an assertion error to fail to convert)
26.140 +
26.141 + // Find last non-trivial conversion (if any).
26.142 + int lastConv = newType.parameterCount()-1;
26.143 + while (lastConv >= 0) {
26.144 + Class<?> src = newType.parameterType(lastConv); // source type
26.145 + Class<?> dst = oldType.parameterType(lastConv); // destination type
26.146 + if (VerifyType.isNullConversion(src, dst)) {
26.147 + --lastConv;
26.148 + } else {
26.149 + break;
26.150 + }
26.151 + }
26.152 + // Now build a chain of one or more adapters.
26.153 + MethodHandle adapter = target;
26.154 + MethodType midType = oldType.changeReturnType(newType.returnType());
26.155 + for (int i = 0; i <= lastConv; i++) {
26.156 + Class<?> src = newType.parameterType(i); // source type
26.157 + Class<?> dst = midType.parameterType(i); // destination type
26.158 + if (VerifyType.isNullConversion(src, dst)) {
26.159 + // do nothing: difference is trivial
26.160 + continue;
26.161 + }
26.162 + // Work the current type backward toward the desired caller type:
26.163 + if (i != lastConv) {
26.164 + midType = midType.changeParameterType(i, src);
26.165 + } else {
26.166 + // When doing the last (or only) real conversion,
26.167 + // force all remaining null conversions to happen also.
26.168 + assert(VerifyType.isNullConversion(newType, midType.changeParameterType(i, src)));
26.169 + midType = newType;
26.170 + }
26.171 +
26.172 + // Tricky case analysis follows.
26.173 + // It parallels canConvertArgument() above.
26.174 + if (src.isPrimitive()) {
26.175 + if (dst.isPrimitive()) {
26.176 + adapter = makePrimCast(token, midType, adapter, i, dst);
26.177 + } else {
26.178 + adapter = makeBoxArgument(token, midType, adapter, i, dst);
26.179 + }
26.180 + } else {
26.181 + if (dst.isPrimitive()) {
26.182 + // Caller has boxed a primitive. Unbox it for the target.
26.183 + // The box type must correspond exactly to the primitive type.
26.184 + // This is simpler than the powerful set of widening
26.185 + // conversions supported by reflect.Method.invoke.
26.186 + // Those conversions require a big nest of if/then/else logic,
26.187 + // which we prefer to make a user responsibility.
26.188 + adapter = makeUnboxArgument(token, midType, adapter, i, dst);
26.189 + } else {
26.190 + // Simple reference conversion.
26.191 + // Note: Do not check for a class hierarchy relation
26.192 + // between src and dst. In all cases a 'null' argument
26.193 + // will pass the cast conversion.
26.194 + adapter = makeCheckCast(token, midType, adapter, i, dst);
26.195 + }
26.196 + }
26.197 + assert(adapter != null);
26.198 + assert(adapter.type() == midType);
26.199 + }
26.200 + if (adapter.type() != newType) {
26.201 + // Only trivial conversions remain.
26.202 + adapter = makeRetypeOnly(IMPL_TOKEN, newType, adapter);
26.203 + assert(adapter != null);
26.204 + // Actually, that's because there were no non-trivial ones:
26.205 + assert(lastConv == -1);
26.206 + }
26.207 + assert(adapter.type() == newType);
26.208 + return adapter;
26.209 + }
26.210 +
26.211 + /**
26.212 + * Create a JVM-level adapter method handle to permute the arguments
26.213 + * of the given method.
26.214 + * @param token access check
26.215 + * @param newType required call type
26.216 + * @param target original method handle
26.217 + * @param argumentMap for each target argument, position of its source in newType
26.218 + * @return an adapter to the original handle with the desired new type,
26.219 + * or the original target if the types are already identical
26.220 + * and the permutation is null
26.221 + * @throws IllegalArgumentException if the adaptation cannot be made
26.222 + * directly by a JVM-level adapter, without help from Java code
26.223 + */
26.224 + public static MethodHandle makePermutation(Access token,
26.225 + MethodType newType, MethodHandle target,
26.226 + int[] argumentMap) {
26.227 + MethodType oldType = target.type();
26.228 + boolean nullPermutation = true;
26.229 + for (int i = 0; i < argumentMap.length; i++) {
26.230 + int pos = argumentMap[i];
26.231 + if (pos != i)
26.232 + nullPermutation = false;
26.233 + if (pos < 0 || pos >= newType.parameterCount()) {
26.234 + argumentMap = new int[0]; break;
26.235 + }
26.236 + }
26.237 + if (argumentMap.length != oldType.parameterCount())
26.238 + throw newIllegalArgumentException("bad permutation: "+Arrays.toString(argumentMap));
26.239 + if (nullPermutation) {
26.240 + MethodHandle res = makePairwiseConvert(token, newType, target);
26.241 + // well, that was easy
26.242 + if (res == null)
26.243 + throw newIllegalArgumentException("cannot convert pairwise: "+newType);
26.244 + return res;
26.245 + }
26.246 +
26.247 + // Check return type. (Not much can be done with it.)
26.248 + Class<?> exp = newType.returnType();
26.249 + Class<?> ret = oldType.returnType();
26.250 + if (!VerifyType.isNullConversion(ret, exp))
26.251 + throw newIllegalArgumentException("bad return conversion for "+newType);
26.252 +
26.253 + // See if the argument types match up.
26.254 + for (int i = 0; i < argumentMap.length; i++) {
26.255 + int j = argumentMap[i];
26.256 + Class<?> src = newType.parameterType(j);
26.257 + Class<?> dst = oldType.parameterType(i);
26.258 + if (!VerifyType.isNullConversion(src, dst))
26.259 + throw newIllegalArgumentException("bad argument #"+j+" conversion for "+newType);
26.260 + }
26.261 +
26.262 + // Now figure out a nice mix of SWAP, ROT, DUP, and DROP adapters.
26.263 + // A workable greedy algorithm is as follows:
26.264 + // Drop unused outgoing arguments (right to left: shallowest first).
26.265 + // Duplicate doubly-used outgoing arguments (left to right: deepest first).
26.266 + // Then the remaining problem is a true argument permutation.
26.267 + // Marshal the outgoing arguments as required from left to right.
26.268 + // That is, find the deepest outgoing stack position that does not yet
26.269 + // have the correct argument value, and correct at least that position
26.270 + // by swapping or rotating in the misplaced value (from a shallower place).
26.271 + // If the misplaced value is followed by one or more consecutive values
26.272 + // (also misplaced) issue a rotation which brings as many as possible
26.273 + // into position. Otherwise make progress with either a swap or a
26.274 + // rotation. Prefer the swap as cheaper, but do not use it if it
26.275 + // breaks a slot pair. Prefer the rotation over the swap if it would
26.276 + // preserve more consecutive values shallower than the target position.
26.277 + // When more than one rotation will work (because the required value
26.278 + // is already adjacent to the target position), then use a rotation
26.279 + // which moves the old value in the target position adjacent to
26.280 + // one of its consecutive values. Also, prefer shorter rotation
26.281 + // spans, since they use fewer memory cycles for shuffling.
26.282 +
26.283 + throw new UnsupportedOperationException("NYI");
26.284 + }
26.285 +
26.286 + private static byte basicType(Class<?> type) {
26.287 + if (type == null) return T_VOID;
26.288 + switch (Wrapper.forBasicType(type)) {
26.289 + case BOOLEAN: return T_BOOLEAN;
26.290 + case CHAR: return T_CHAR;
26.291 + case FLOAT: return T_FLOAT;
26.292 + case DOUBLE: return T_DOUBLE;
26.293 + case BYTE: return T_BYTE;
26.294 + case SHORT: return T_SHORT;
26.295 + case INT: return T_INT;
26.296 + case LONG: return T_LONG;
26.297 + case OBJECT: return T_OBJECT;
26.298 + case VOID: return T_VOID;
26.299 + }
26.300 + return 99; // T_ILLEGAL or some such
26.301 + }
26.302 +
26.303 + /** Number of stack slots for the given type.
26.304 + * Two for T_DOUBLE and T_FLOAT, one for the rest.
26.305 + */
26.306 + private static int type2size(int type) {
26.307 + assert(type >= T_BOOLEAN && type <= T_OBJECT);
26.308 + return (type == T_FLOAT || type == T_DOUBLE) ? 2 : 1;
26.309 + }
26.310 +
26.311 + /** Construct an adapter conversion descriptor for a single-argument conversion. */
26.312 + private static long makeConv(int convOp, int argnum, int src, int dest) {
26.313 + assert(src == (src & 0xF));
26.314 + assert(dest == (dest & 0xF));
26.315 + assert(convOp >= OP_CHECK_CAST && convOp <= OP_PRIM_TO_REF);
26.316 + long stackMove = type2size(dest) - type2size(src);
26.317 + return ((long) argnum << 32 |
26.318 + (long) convOp << CONV_OP_SHIFT |
26.319 + (int) src << CONV_SRC_TYPE_SHIFT |
26.320 + (int) dest << CONV_DEST_TYPE_SHIFT |
26.321 + stackMove << CONV_STACK_MOVE_SHIFT
26.322 + );
26.323 + }
26.324 + private static long makeConv(int convOp, int argnum, int stackMove) {
26.325 + assert(convOp >= OP_SWAP_ARGS && convOp <= OP_SPREAD_ARGS);
26.326 + byte src = 0, dest = 0;
26.327 + if (convOp >= OP_COLLECT_ARGS && convOp <= OP_SPREAD_ARGS)
26.328 + src = dest = T_OBJECT;
26.329 + return ((long) argnum << 32 |
26.330 + (long) convOp << CONV_OP_SHIFT |
26.331 + (int) src << CONV_SRC_TYPE_SHIFT |
26.332 + (int) dest << CONV_DEST_TYPE_SHIFT |
26.333 + stackMove << CONV_STACK_MOVE_SHIFT
26.334 + );
26.335 + }
26.336 + private static long makeConv(int convOp) {
26.337 + assert(convOp == OP_RETYPE_ONLY);
26.338 + return (long) convOp << CONV_OP_SHIFT; // stackMove, src, dst, argnum all zero
26.339 + }
26.340 + private static int convCode(long conv) {
26.341 + return (int)conv;
26.342 + }
26.343 + private static int convArgPos(long conv) {
26.344 + return (int)(conv >>> 32);
26.345 + }
26.346 + private static boolean convOpSupported(int convOp) {
26.347 + assert(convOp >= 0 && convOp <= CONV_OP_LIMIT);
26.348 + return ((1<<convOp) & CONV_OP_IMPLEMENTED_MASK) != 0;
26.349 + }
26.350 +
26.351 + /** One of OP_RETYPE_ONLY, etc. */
26.352 + int conversionOp() { return (conversion & CONV_OP_MASK) >> CONV_OP_SHIFT; }
26.353 +
26.354 + @Override
26.355 + public String toString() {
26.356 + return addTypeString(this, "Adapted[" + basicToString(nonAdapter((MethodHandle)vmtarget)) + "]");
26.357 + }
26.358 +
26.359 + private static MethodHandle nonAdapter(MethodHandle mh) {
26.360 + return (MethodHandle)
26.361 + MethodHandleNatives.getTarget(mh, ETF_DIRECT_HANDLE);
26.362 + }
26.363 +
26.364 + /* Return one plus the position of the first non-trivial difference
26.365 + * between the given types. This is not a symmetric operation;
26.366 + * we are considering adapting the targetType to adapterType.
26.367 + * Trivial differences are those which could be ignored by the JVM
26.368 + * without subverting the verifier. Otherwise, adaptable differences
26.369 + * are ones for which we could create an adapter to make the type change.
26.370 + * Return zero if there are no differences (other than trivial ones).
26.371 + * Return 1+N if N is the only adaptable argument difference.
26.372 + * Return the -2-N where N is the first of several adaptable
26.373 + * argument differences.
26.374 + * Return -1 if there there are differences which are not adaptable.
26.375 + */
26.376 + private static int diffTypes(MethodType adapterType,
26.377 + MethodType targetType,
26.378 + boolean raw) {
26.379 + int diff;
26.380 + diff = diffReturnTypes(adapterType, targetType, raw);
26.381 + if (diff != 0) return diff;
26.382 + int nargs = adapterType.parameterCount();
26.383 + if (nargs != targetType.parameterCount())
26.384 + return -1;
26.385 + diff = diffParamTypes(adapterType, 0, targetType, 0, nargs, raw);
26.386 + //System.out.println("diff "+adapterType);
26.387 + //System.out.println(" "+diff+" "+targetType);
26.388 + return diff;
26.389 + }
26.390 + private static int diffReturnTypes(MethodType adapterType,
26.391 + MethodType targetType,
26.392 + boolean raw) {
26.393 + Class<?> src = targetType.returnType();
26.394 + Class<?> dst = adapterType.returnType();
26.395 + if ((!raw
26.396 + ? VerifyType.canPassUnchecked(src, dst)
26.397 + : VerifyType.canPassRaw(src, dst)
26.398 + ) > 0)
26.399 + return 0; // no significant difference
26.400 + if (raw && !src.isPrimitive() && !dst.isPrimitive())
26.401 + return 0; // can force a reference return (very carefully!)
26.402 + //if (false) return 1; // never adaptable!
26.403 + return -1; // some significant difference
26.404 + }
26.405 + private static int diffParamTypes(MethodType adapterType, int tstart,
26.406 + MethodType targetType, int astart,
26.407 + int nargs, boolean raw) {
26.408 + assert(nargs >= 0);
26.409 + int res = 0;
26.410 + for (int i = 0; i < nargs; i++) {
26.411 + Class<?> src = adapterType.parameterType(tstart+i);
26.412 + Class<?> dest = targetType.parameterType(astart+i);
26.413 + if ((!raw
26.414 + ? VerifyType.canPassUnchecked(src, dest)
26.415 + : VerifyType.canPassRaw(src, dest)
26.416 + ) <= 0) {
26.417 + // found a difference; is it the only one so far?
26.418 + if (res != 0)
26.419 + return -1-res; // return -2-i for prev. i
26.420 + res = 1+i;
26.421 + }
26.422 + }
26.423 + return res;
26.424 + }
26.425 +
26.426 + /** Can a retyping adapter (alone) validly convert the target to newType? */
26.427 + public static boolean canRetypeOnly(MethodType newType, MethodType targetType) {
26.428 + return canRetypeOnly(newType, targetType, false);
26.429 + }
26.430 + /** Can a retyping adapter (alone) convert the target to newType?
26.431 + * It is allowed to widen subword types and void to int, to make bitwise
26.432 + * conversions between float/int and double/long, and to perform unchecked
26.433 + * reference conversions on return. This last feature requires that the
26.434 + * caller be trusted, and perform explicit cast conversions on return values.
26.435 + */
26.436 + static boolean canRawRetypeOnly(MethodType newType, MethodType targetType) {
26.437 + return canRetypeOnly(newType, targetType, true);
26.438 + }
26.439 + static boolean canRetypeOnly(MethodType newType, MethodType targetType, boolean raw) {
26.440 + if (!convOpSupported(OP_RETYPE_ONLY)) return false;
26.441 + int diff = diffTypes(newType, targetType, raw);
26.442 + // %%% This assert is too strong. Factor diff into VerifyType and reconcile.
26.443 + assert((diff == 0) == VerifyType.isNullConversion(newType, targetType));
26.444 + return diff == 0;
26.445 + }
26.446 +
26.447 + /** Factory method: Performs no conversions; simply retypes the adapter.
26.448 + * Allows unchecked argument conversions pairwise, if they are safe.
26.449 + * Returns null if not possible.
26.450 + */
26.451 + public static MethodHandle makeRetypeOnly(Access token,
26.452 + MethodType newType, MethodHandle target) {
26.453 + return makeRetypeOnly(token, newType, target, false);
26.454 + }
26.455 + public static MethodHandle makeRawRetypeOnly(Access token,
26.456 + MethodType newType, MethodHandle target) {
26.457 + return makeRetypeOnly(token, newType, target, true);
26.458 + }
26.459 + static MethodHandle makeRetypeOnly(Access token,
26.460 + MethodType newType, MethodHandle target, boolean raw) {
26.461 + Access.check(token);
26.462 + if (!canRetypeOnly(newType, target.type(), raw))
26.463 + return null;
26.464 + // TO DO: clone the target guy, whatever he is, with new type.
26.465 + return new AdapterMethodHandle(target, newType, makeConv(OP_RETYPE_ONLY));
26.466 + }
26.467 +
26.468 + /** Can a checkcast adapter validly convert the target to newType?
26.469 + * The JVM supports all kind of reference casts, even silly ones.
26.470 + */
26.471 + public static boolean canCheckCast(MethodType newType, MethodType targetType,
26.472 + int arg, Class<?> castType) {
26.473 + if (!convOpSupported(OP_CHECK_CAST)) return false;
26.474 + Class<?> src = newType.parameterType(arg);
26.475 + Class<?> dst = targetType.parameterType(arg);
26.476 + if (!canCheckCast(src, castType)
26.477 + || !VerifyType.isNullConversion(castType, dst))
26.478 + return false;
26.479 + int diff = diffTypes(newType, targetType, false);
26.480 + return (diff == arg+1); // arg is sole non-trivial diff
26.481 + }
26.482 + /** Can an primitive conversion adapter validly convert src to dst? */
26.483 + public static boolean canCheckCast(Class<?> src, Class<?> dst) {
26.484 + return (!src.isPrimitive() && !dst.isPrimitive());
26.485 + }
26.486 +
26.487 + /** Factory method: Forces a cast at the given argument.
26.488 + * The castType is the target of the cast, and can be any type
26.489 + * with a null conversion to the corresponding target parameter.
26.490 + * Return null if this cannot be done.
26.491 + */
26.492 + public static MethodHandle makeCheckCast(Access token,
26.493 + MethodType newType, MethodHandle target,
26.494 + int arg, Class<?> castType) {
26.495 + Access.check(token);
26.496 + if (!canCheckCast(newType, target.type(), arg, castType))
26.497 + return null;
26.498 + long conv = makeConv(OP_CHECK_CAST, arg, 0);
26.499 + return new AdapterMethodHandle(target, newType, conv, castType);
26.500 + }
26.501 +
26.502 + /** Can an primitive conversion adapter validly convert the target to newType?
26.503 + * The JVM currently supports all conversions except those between
26.504 + * floating and integral types.
26.505 + */
26.506 + public static boolean canPrimCast(MethodType newType, MethodType targetType,
26.507 + int arg, Class<?> convType) {
26.508 + if (!convOpSupported(OP_PRIM_TO_PRIM)) return false;
26.509 + Class<?> src = newType.parameterType(arg);
26.510 + Class<?> dst = targetType.parameterType(arg);
26.511 + if (!canPrimCast(src, convType)
26.512 + || !VerifyType.isNullConversion(convType, dst))
26.513 + return false;
26.514 + int diff = diffTypes(newType, targetType, false);
26.515 + return (diff == arg+1); // arg is sole non-trivial diff
26.516 + }
26.517 + /** Can an primitive conversion adapter validly convert src to dst? */
26.518 + public static boolean canPrimCast(Class<?> src, Class<?> dst) {
26.519 + if (src == dst || !src.isPrimitive() || !dst.isPrimitive()) {
26.520 + return false;
26.521 + } else if (Wrapper.forPrimitiveType(dst).isFloating()) {
26.522 + // both must be floating types
26.523 + return Wrapper.forPrimitiveType(src).isFloating();
26.524 + } else {
26.525 + // both are integral, and all combinations work fine
26.526 + assert(Wrapper.forPrimitiveType(src).isIntegral() &&
26.527 + Wrapper.forPrimitiveType(dst).isIntegral());
26.528 + return true;
26.529 + }
26.530 + }
26.531 +
26.532 + /** Factory method: Truncate the given argument with zero or sign extension,
26.533 + * and/or convert between single and doubleword versions of integer or float.
26.534 + * The convType is the target of the conversion, and can be any type
26.535 + * with a null conversion to the corresponding target parameter.
26.536 + * Return null if this cannot be done.
26.537 + */
26.538 + public static MethodHandle makePrimCast(Access token,
26.539 + MethodType newType, MethodHandle target,
26.540 + int arg, Class<?> convType) {
26.541 + Access.check(token);
26.542 + MethodType oldType = target.type();
26.543 + Class<?> src = newType.parameterType(arg);
26.544 + Class<?> dst = oldType.parameterType(arg);
26.545 + if (!canPrimCast(newType, oldType, arg, convType))
26.546 + return null;
26.547 + long conv = makeConv(OP_PRIM_TO_PRIM, arg, basicType(src), basicType(convType));
26.548 + return new AdapterMethodHandle(target, newType, conv);
26.549 + }
26.550 +
26.551 + /** Can an unboxing conversion validly convert src to dst?
26.552 + * The JVM currently supports all kinds of casting and unboxing.
26.553 + * The convType is the unboxed type; it can be either a primitive or wrapper.
26.554 + */
26.555 + public static boolean canUnboxArgument(MethodType newType, MethodType targetType,
26.556 + int arg, Class<?> convType) {
26.557 + if (!convOpSupported(OP_REF_TO_PRIM)) return false;
26.558 + Class<?> src = newType.parameterType(arg);
26.559 + Class<?> dst = targetType.parameterType(arg);
26.560 + Class<?> boxType = Wrapper.asWrapperType(convType);
26.561 + convType = Wrapper.asPrimitiveType(convType);
26.562 + if (!canCheckCast(src, boxType)
26.563 + || boxType == convType
26.564 + || !VerifyType.isNullConversion(convType, dst))
26.565 + return false;
26.566 + int diff = diffTypes(newType, targetType, false);
26.567 + return (diff == arg+1); // arg is sole non-trivial diff
26.568 + }
26.569 + /** Can an primitive unboxing adapter validly convert src to dst? */
26.570 + public static boolean canUnboxArgument(Class<?> src, Class<?> dst) {
26.571 + return (!src.isPrimitive() && Wrapper.asPrimitiveType(dst).isPrimitive());
26.572 + }
26.573 +
26.574 + /** Factory method: Unbox the given argument.
26.575 + * Return null if this cannot be done.
26.576 + */
26.577 + public static MethodHandle makeUnboxArgument(Access token,
26.578 + MethodType newType, MethodHandle target,
26.579 + int arg, Class<?> convType) {
26.580 + MethodType oldType = target.type();
26.581 + Class<?> src = newType.parameterType(arg);
26.582 + Class<?> dst = oldType.parameterType(arg);
26.583 + Class<?> boxType = Wrapper.asWrapperType(convType);
26.584 + Class<?> primType = Wrapper.asPrimitiveType(convType);
26.585 + if (!canUnboxArgument(newType, oldType, arg, convType))
26.586 + return null;
26.587 + MethodType castDone = newType;
26.588 + if (!VerifyType.isNullConversion(src, boxType))
26.589 + castDone = newType.changeParameterType(arg, boxType);
26.590 + long conv = makeConv(OP_REF_TO_PRIM, arg, T_OBJECT, basicType(primType));
26.591 + MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType);
26.592 + if (castDone == newType)
26.593 + return adapter;
26.594 + return makeCheckCast(token, newType, adapter, arg, boxType);
26.595 + }
26.596 +
26.597 + /** Can an primitive boxing adapter validly convert src to dst? */
26.598 + public static boolean canBoxArgument(Class<?> src, Class<?> dst) {
26.599 + if (!convOpSupported(OP_PRIM_TO_REF)) return false;
26.600 + throw new UnsupportedOperationException("NYI");
26.601 + }
26.602 +
26.603 + /** Factory method: Unbox the given argument.
26.604 + * Return null if this cannot be done.
26.605 + */
26.606 + public static MethodHandle makeBoxArgument(Access token,
26.607 + MethodType newType, MethodHandle target,
26.608 + int arg, Class<?> convType) {
26.609 + // this is difficult to do in the JVM because it must GC
26.610 + return null;
26.611 + }
26.612 +
26.613 + // TO DO: makeSwapArguments, makeRotateArguments, makeDuplicateArguments
26.614 +
26.615 + /** Can an adapter simply drop arguments to convert the target to newType? */
26.616 + public static boolean canDropArguments(MethodType newType, MethodType targetType,
26.617 + int dropArgPos, int dropArgCount) {
26.618 + if (dropArgCount == 0)
26.619 + return canRetypeOnly(newType, targetType);
26.620 + if (!convOpSupported(OP_DROP_ARGS)) return false;
26.621 + if (diffReturnTypes(newType, targetType, false) != 0)
26.622 + return false;
26.623 + int nptypes = newType.parameterCount();
26.624 + // parameter types must be the same up to the drop point
26.625 + if (dropArgPos != 0 && diffParamTypes(newType, 0, targetType, 0, dropArgPos, false) != 0)
26.626 + return false;
26.627 + int afterPos = dropArgPos + dropArgCount;
26.628 + int afterCount = nptypes - afterPos;
26.629 + if (dropArgPos < 0 || dropArgPos >= nptypes ||
26.630 + dropArgCount < 1 || afterPos > nptypes ||
26.631 + targetType.parameterCount() != nptypes - dropArgCount)
26.632 + return false;
26.633 + // parameter types after the drop point must also be the same
26.634 + if (afterCount != 0 && diffParamTypes(newType, afterPos, targetType, dropArgPos, afterCount, false) != 0)
26.635 + return false;
26.636 + return true;
26.637 + }
26.638 +
26.639 + /** Factory method: Drop selected arguments.
26.640 + * Allow unchecked retyping of remaining arguments, pairwise.
26.641 + * Return null if this is not possible.
26.642 + */
26.643 + public static MethodHandle makeDropArguments(Access token,
26.644 + MethodType newType, MethodHandle target,
26.645 + int dropArgPos, int dropArgCount) {
26.646 + Access.check(token);
26.647 + if (dropArgCount == 0)
26.648 + return makeRetypeOnly(IMPL_TOKEN, newType, target);
26.649 + MethodType mt = target.type();
26.650 + int argCount = mt.parameterCount();
26.651 + if (!canDropArguments(newType, mt, dropArgPos, dropArgCount))
26.652 + return null;
26.653 + int dropSlotCount, dropSlotPos;
26.654 + if (dropArgCount >= argCount) {
26.655 + assert(dropArgPos == argCount-1);
26.656 + dropSlotPos = 0;
26.657 + dropSlotCount = mt.parameterSlotCount();
26.658 + } else {
26.659 + // arglist: [0: keep... | dpos: drop... | dpos+dcount: keep... ]
26.660 + int lastDroppedArg = dropArgPos + dropArgCount - 1;
26.661 + int lastKeptArg = dropArgPos - 1; // might be -1, which is OK
26.662 + dropSlotPos = mt.parameterSlotDepth(1+lastDroppedArg);
26.663 + int lastKeptSlot = mt.parameterSlotDepth(1+lastKeptArg);
26.664 + dropSlotCount = lastKeptSlot - dropSlotPos;
26.665 + assert(dropSlotCount >= dropArgCount);
26.666 + }
26.667 + long conv = makeConv(OP_DROP_ARGS, dropArgPos, +dropSlotCount);
26.668 + return new AdapterMethodHandle(target, newType, dropSlotCount, conv);
26.669 + }
26.670 +
26.671 + /** Can an adapter spread an argument to convert the target to newType? */
26.672 + public static boolean canSpreadArguments(MethodType newType, MethodType targetType,
26.673 + Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
26.674 + if (!convOpSupported(OP_SPREAD_ARGS)) return false;
26.675 + if (diffReturnTypes(newType, targetType, false) != 0)
26.676 + return false;
26.677 + int nptypes = newType.parameterCount();
26.678 + // parameter types must be the same up to the spread point
26.679 + if (spreadArgPos != 0 && diffParamTypes(newType, 0, targetType, 0, spreadArgPos, false) != 0)
26.680 + return false;
26.681 + int afterPos = spreadArgPos + spreadArgCount;
26.682 + int afterCount = nptypes - afterPos;
26.683 + if (spreadArgPos < 0 || spreadArgPos >= nptypes ||
26.684 + spreadArgCount < 0 ||
26.685 + targetType.parameterCount() != nptypes - 1 + spreadArgCount)
26.686 + return false;
26.687 + // parameter types after the spread point must also be the same
26.688 + if (afterCount != 0 && diffParamTypes(newType, spreadArgPos+1, targetType, afterPos, afterCount, false) != 0)
26.689 + return false;
26.690 + // match the array element type to the spread arg types
26.691 + Class<?> rawSpreadArgType = newType.parameterType(spreadArgPos);
26.692 + if (rawSpreadArgType != spreadArgType && !canCheckCast(rawSpreadArgType, spreadArgType))
26.693 + return false;
26.694 + for (int i = 0; i < spreadArgCount; i++) {
26.695 + Class<?> src = VerifyType.spreadArgElementType(spreadArgType, i);
26.696 + Class<?> dst = targetType.parameterType(spreadArgPos + i);
26.697 + if (src == null || !VerifyType.isNullConversion(src, dst))
26.698 + return false;
26.699 + }
26.700 + return true;
26.701 + }
26.702 +
26.703 + /** Factory method: Spread selected argument. */
26.704 + public static MethodHandle makeSpreadArguments(Access token,
26.705 + MethodType newType, MethodHandle target,
26.706 + Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
26.707 + Access.check(token);
26.708 + MethodType mt = target.type();
26.709 + int argCount = mt.parameterCount();
26.710 + if (!canSpreadArguments(newType, mt, spreadArgType, spreadArgPos, spreadArgCount))
26.711 + return null;
26.712 + int spreadSlotCount, spreadSlotPos;
26.713 + if (spreadArgCount >= argCount) {
26.714 + assert(spreadArgPos == argCount-1);
26.715 + spreadSlotPos = 0;
26.716 + spreadSlotCount = mt.parameterSlotCount();
26.717 + } else {
26.718 + // arglist: [0: keep... | dpos: spread... | dpos+dcount: keep... ]
26.719 + int lastSpreadArg = spreadArgPos + spreadArgCount - 1;
26.720 + int lastKeptArg = spreadArgPos - 1; // might be -1, which is OK
26.721 + spreadSlotPos = mt.parameterSlotDepth(1+lastSpreadArg);
26.722 + int lastKeptSlot = mt.parameterSlotDepth(1+lastKeptArg);
26.723 + spreadSlotCount = lastKeptSlot - spreadSlotPos;
26.724 + assert(spreadSlotCount >= spreadArgCount);
26.725 + }
26.726 + long conv = makeConv(OP_SPREAD_ARGS, spreadArgPos, spreadSlotCount);
26.727 + return new AdapterMethodHandle(target, newType, conv, spreadArgType);
26.728 + }
26.729 +
26.730 + // TO DO: makeCollectArguments, makeFlyby, makeRicochet
26.731 +}
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
27.2 +++ b/src/share/classes/sun/dyn/BoundMethodHandle.java Tue May 05 23:12:47 2009 -0700
27.3 @@ -0,0 +1,180 @@
27.4 +/*
27.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
27.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
27.7 + *
27.8 + * This code is free software; you can redistribute it and/or modify it
27.9 + * under the terms of the GNU General Public License version 2 only, as
27.10 + * published by the Free Software Foundation. Sun designates this
27.11 + * particular file as subject to the "Classpath" exception as provided
27.12 + * by Sun in the LICENSE file that accompanied this code.
27.13 + *
27.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
27.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
27.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27.17 + * version 2 for more details (a copy is included in the LICENSE file that
27.18 + * accompanied this code).
27.19 + *
27.20 + * You should have received a copy of the GNU General Public License version
27.21 + * 2 along with this work; if not, write to the Free Software Foundation,
27.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27.23 + *
27.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
27.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
27.26 + * have any questions.
27.27 + */
27.28 +
27.29 +package sun.dyn;
27.30 +
27.31 +import sun.dyn.util.VerifyType;
27.32 +import sun.dyn.util.Wrapper;
27.33 +import java.dyn.*;
27.34 +
27.35 +/**
27.36 + * The flavor of method handle which emulates an invoke instruction
27.37 + * on a predetermined argument. The JVM dispatches to the correct method
27.38 + * when the handle is created, not when it is invoked.
27.39 + * @author jrose
27.40 + */
27.41 +public class BoundMethodHandle extends MethodHandle {
27.42 + //MethodHandle vmtarget; // next BMH or final DMH or methodOop
27.43 + private final Object argument; // argument to insert
27.44 + private final int vmargslot; // position at which it is inserted
27.45 +
27.46 + // Constructors in this class *must* be package scoped or private.
27.47 +
27.48 + /** Bind a direct MH to its receiver (or first ref. argument).
27.49 + * The JVM will pre-dispatch the MH if it is not already static.
27.50 + */
27.51 + BoundMethodHandle(DirectMethodHandle mh, Object argument) {
27.52 + super(Access.TOKEN, mh.type().dropParameterType(0));
27.53 + // check the type now, once for all:
27.54 + this.argument = checkReferenceArgument(argument, mh, 0);
27.55 + this.vmargslot = this.type().parameterSlotCount();
27.56 + if (MethodHandleNatives.JVM_SUPPORT) {
27.57 + this.vmtarget = null; // maybe updated by JVM
27.58 + MethodHandleNatives.init(this, mh, 0);
27.59 + } else {
27.60 + this.vmtarget = mh;
27.61 + }
27.62 + }
27.63 +
27.64 + private static final int REF_ARG = 0, PRIM_ARG = 1, SELF_ARG = 2;
27.65 +
27.66 + /** Insert an argument into an arbitrary method handle.
27.67 + * If argnum is zero, inserts the first argument, etc.
27.68 + * The argument type must be a reference.
27.69 + */
27.70 + BoundMethodHandle(MethodHandle mh, Object argument, int argnum) {
27.71 + this(mh, argument, argnum, mh.type().parameterType(argnum).isPrimitive() ? PRIM_ARG : REF_ARG);
27.72 + }
27.73 +
27.74 + /** Insert an argument into an arbitrary method handle.
27.75 + * If argnum is zero, inserts the first argument, etc.
27.76 + */
27.77 + BoundMethodHandle(MethodHandle mh, Object argument, int argnum, int whichArg) {
27.78 + super(Access.TOKEN, mh.type().dropParameterType(argnum));
27.79 + if (whichArg == PRIM_ARG)
27.80 + this.argument = bindPrimitiveArgument(argument, mh, argnum);
27.81 + else {
27.82 + if (whichArg == SELF_ARG) argument = this;
27.83 + this.argument = checkReferenceArgument(argument, mh, argnum);
27.84 + }
27.85 + this.vmargslot = this.type().parameterSlotDepth(argnum);
27.86 + if (MethodHandleNatives.JVM_SUPPORT) {
27.87 + this.vmtarget = null; // maybe updated by JVM
27.88 + MethodHandleNatives.init(this, mh, argnum);
27.89 + } else {
27.90 + this.vmtarget = mh;
27.91 + }
27.92 + }
27.93 +
27.94 + /** For the AdapterMethodHandle subclass.
27.95 + */
27.96 + BoundMethodHandle(MethodType type, Object argument, int vmargslot) {
27.97 + super(Access.TOKEN, type);
27.98 + this.argument = argument;
27.99 + this.vmargslot = vmargslot;
27.100 + assert(this.getClass() == AdapterMethodHandle.class);
27.101 + }
27.102 +
27.103 + /** Initialize the current object as a method handle, binding it
27.104 + * as the {@code argnum}th argument of the method handle {@code entryPoint}.
27.105 + * The invocation type of the resulting method handle will be the
27.106 + * same as {@code entryPoint}, except that the {@code argnum}th argument
27.107 + * type will be dropped.
27.108 + */
27.109 + public BoundMethodHandle(MethodHandle entryPoint, int argnum) {
27.110 + this(entryPoint, null, argnum, SELF_ARG);
27.111 +
27.112 + // Note: If the conversion fails, perhaps because of a bad entryPoint,
27.113 + // the MethodHandle.type field will not be filled in, and therefore
27.114 + // no MH.invoke call will ever succeed. The caller may retain a pointer
27.115 + // to the broken method handle, but no harm can be done with it.
27.116 + }
27.117 +
27.118 + /** Initialize the current object as a method handle, binding it
27.119 + * as the first argument of the method handle {@code entryPoint}.
27.120 + * The invocation type of the resulting method handle will be the
27.121 + * same as {@code entryPoint}, except that the first argument
27.122 + * type will be dropped.
27.123 + */
27.124 + public BoundMethodHandle(MethodHandle entryPoint) {
27.125 + this(entryPoint, null, 0, SELF_ARG);
27.126 + }
27.127 +
27.128 + /** Make sure the given {@code argument} can be used as {@code argnum}-th
27.129 + * parameter of the given method handle {@code mh}, which must be a reference.
27.130 + * <p>
27.131 + * If this fails, throw a suitable {@code WrongMethodTypeException},
27.132 + * which will prevent the creation of an illegally typed bound
27.133 + * method handle.
27.134 + */
27.135 + final static Object checkReferenceArgument(Object argument, MethodHandle mh, int argnum) {
27.136 + Class<?> ptype = mh.type().parameterType(argnum);
27.137 + if (ptype.isPrimitive()) {
27.138 + // fail
27.139 + } else if (argument == null) {
27.140 + return null;
27.141 + } else if (VerifyType.isNullReferenceConversion(argument.getClass(), ptype)) {
27.142 + return argument;
27.143 + }
27.144 + throw badBoundArgumentException(argument, mh, argnum);
27.145 + }
27.146 +
27.147 + /** Make sure the given {@code argument} can be used as {@code argnum}-th
27.148 + * parameter of the given method handle {@code mh}, which must be a primitive.
27.149 + * <p>
27.150 + * If this fails, throw a suitable {@code WrongMethodTypeException},
27.151 + * which will prevent the creation of an illegally typed bound
27.152 + * method handle.
27.153 + */
27.154 + final static Object bindPrimitiveArgument(Object argument, MethodHandle mh, int argnum) {
27.155 + Class<?> ptype = mh.type().parameterType(argnum);
27.156 + Wrapper wrap = Wrapper.forPrimitiveType(ptype);
27.157 + Object zero = wrap.zero();
27.158 + if (zero == null) {
27.159 + // fail
27.160 + } else if (argument == null) {
27.161 + if (ptype != int.class && wrap.isSubwordOrInt())
27.162 + return Integer.valueOf(0);
27.163 + else
27.164 + return zero;
27.165 + } else if (VerifyType.isNullReferenceConversion(argument.getClass(), zero.getClass())) {
27.166 + if (ptype != int.class && wrap.isSubwordOrInt())
27.167 + return Wrapper.INT.wrap(argument);
27.168 + else
27.169 + return argument;
27.170 + }
27.171 + throw badBoundArgumentException(argument, mh, argnum);
27.172 + }
27.173 +
27.174 + final static RuntimeException badBoundArgumentException(Object argument, MethodHandle mh, int argnum) {
27.175 + String atype = (argument == null) ? "null" : argument.getClass().toString();
27.176 + return new WrongMethodTypeException("cannot bind "+atype+" argument to parameter #"+argnum+" of "+mh.type());
27.177 + }
27.178 +
27.179 + @Override
27.180 + public String toString() {
27.181 + return "Bound[" + super.toString() + "]";
27.182 + }
27.183 +}
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
28.2 +++ b/src/share/classes/sun/dyn/CallSiteImpl.java Tue May 05 23:12:47 2009 -0700
28.3 @@ -0,0 +1,70 @@
28.4 +/*
28.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
28.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
28.7 + *
28.8 + * This code is free software; you can redistribute it and/or modify it
28.9 + * under the terms of the GNU General Public License version 2 only, as
28.10 + * published by the Free Software Foundation. Sun designates this
28.11 + * particular file as subject to the "Classpath" exception as provided
28.12 + * by Sun in the LICENSE file that accompanied this code.
28.13 + *
28.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
28.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
28.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
28.17 + * version 2 for more details (a copy is included in the LICENSE file that
28.18 + * accompanied this code).
28.19 + *
28.20 + * You should have received a copy of the GNU General Public License version
28.21 + * 2 along with this work; if not, write to the Free Software Foundation,
28.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
28.23 + *
28.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
28.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
28.26 + * have any questions.
28.27 + */
28.28 +
28.29 +package sun.dyn;
28.30 +
28.31 +import java.dyn.*;
28.32 +
28.33 +/**
28.34 + * The CallSite privately created by the JVM at every invokedynamic instruction.
28.35 + * @author jrose
28.36 + */
28.37 +class CallSiteImpl extends CallSite {
28.38 + // Fields used only by the JVM. Do not use or change.
28.39 + private Object vmmethod;
28.40 +
28.41 + // Values supplied by the JVM:
28.42 + int callerMID, callerBCI;
28.43 +
28.44 + private CallSiteImpl(Class<?> caller, String name, MethodType type) {
28.45 + super(caller, name, type);
28.46 + }
28.47 +
28.48 + @Override
28.49 + public void setTarget(MethodHandle mh) {
28.50 + checkTarget(mh);
28.51 + if (MethodHandleNatives.JVM_SUPPORT)
28.52 + MethodHandleNatives.linkCallSite(this, (MethodHandle) mh);
28.53 + else
28.54 + super.setTarget(mh);
28.55 + }
28.56 +
28.57 + private static final MethodHandle PRIVATE_INITIALIZE_CALL_SITE =
28.58 + MethodHandleImpl.IMPL_LOOKUP.findStatic(CallSite.class, "privateInitializeCallSite",
28.59 + MethodType.make(void.class, CallSite.class, int.class, int.class));
28.60 +
28.61 + // this is the up-call from the JVM:
28.62 + static CallSite makeSite(Class<?> caller, String name, MethodType type,
28.63 + int callerMID, int callerBCI) {
28.64 + MethodHandle bsm = Linkage.getBootstrapMethod(caller);
28.65 + if (bsm == null)
28.66 + throw new InvokeDynamicBootstrapError("class has no bootstrap method: "+caller);
28.67 + CallSite site = bsm.<CallSite>invoke(caller, name, type);
28.68 + if (site == null)
28.69 + throw new InvokeDynamicBootstrapError("class bootstrap method failed to create a call site: "+caller);
28.70 + PRIVATE_INITIALIZE_CALL_SITE.<void>invoke(site, callerMID, callerBCI);
28.71 + return site;
28.72 + }
28.73 +}
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
29.2 +++ b/src/share/classes/sun/dyn/DirectMethodHandle.java Tue May 05 23:12:47 2009 -0700
29.3 @@ -0,0 +1,56 @@
29.4 +/*
29.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
29.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
29.7 + *
29.8 + * This code is free software; you can redistribute it and/or modify it
29.9 + * under the terms of the GNU General Public License version 2 only, as
29.10 + * published by the Free Software Foundation. Sun designates this
29.11 + * particular file as subject to the "Classpath" exception as provided
29.12 + * by Sun in the LICENSE file that accompanied this code.
29.13 + *
29.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
29.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
29.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
29.17 + * version 2 for more details (a copy is included in the LICENSE file that
29.18 + * accompanied this code).
29.19 + *
29.20 + * You should have received a copy of the GNU General Public License version
29.21 + * 2 along with this work; if not, write to the Free Software Foundation,
29.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
29.23 + *
29.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
29.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
29.26 + * have any questions.
29.27 + */
29.28 +
29.29 +package sun.dyn;
29.30 +
29.31 +import java.dyn.*;
29.32 +import static sun.dyn.MethodHandleNatives.Constants.*;
29.33 +
29.34 +/**
29.35 + * The flavor of method handle which emulates invokespecial or invokestatic.
29.36 + * @author jrose
29.37 + */
29.38 +class DirectMethodHandle extends MethodHandle {
29.39 + //inherited oop vmtarget; // methodOop or virtual class/interface oop
29.40 + private final int vmindex; // method index within class or interface
29.41 + { vmindex = VM_INDEX_UNINITIALIZED; } // JVM may change this
29.42 +
29.43 + // Constructors in this class *must* be package scoped or private.
29.44 + DirectMethodHandle(MethodType mtype, MemberName m, boolean doDispatch, Class<?> lookupClass) {
29.45 + super(Access.TOKEN, mtype);
29.46 +
29.47 + assert(m.isMethod() || !doDispatch && m.isConstructor());
29.48 + if (!m.isResolved())
29.49 + throw new InternalError();
29.50 +
29.51 + // Null check and replace privilege token (as passed to JVM) with null.
29.52 + if (lookupClass.equals(Access.class)) lookupClass = null;
29.53 + MethodHandleNatives.init(this, (Object) m, doDispatch, lookupClass);
29.54 + }
29.55 +
29.56 + boolean isValid() {
29.57 + return (vmindex != VM_INDEX_UNINITIALIZED);
29.58 + }
29.59 +}
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
30.2 +++ b/src/share/classes/sun/dyn/FilterGeneric.java Tue May 05 23:12:47 2009 -0700
30.3 @@ -0,0 +1,338 @@
30.4 +/*
30.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
30.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
30.7 + *
30.8 + * This code is free software; you can redistribute it and/or modify it
30.9 + * under the terms of the GNU General Public License version 2 only, as
30.10 + * published by the Free Software Foundation. Sun designates this
30.11 + * particular file as subject to the "Classpath" exception as provided
30.12 + * by Sun in the LICENSE file that accompanied this code.
30.13 + *
30.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
30.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
30.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
30.17 + * version 2 for more details (a copy is included in the LICENSE file that
30.18 + * accompanied this code).
30.19 + *
30.20 + * You should have received a copy of the GNU General Public License version
30.21 + * 2 along with this work; if not, write to the Free Software Foundation,
30.22 + * Inc., 51 Franklin Sf, tifth Floor, Boston, MA 02110-1301 USA.
30.23 + *
30.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
30.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
30.26 + * have any questions.
30.27 + */
30.28 +
30.29 +package sun.dyn;
30.30 +
30.31 +import java.dyn.JavaMethodHandle;
30.32 +import java.dyn.MethodHandle;
30.33 +import java.dyn.MethodType;
30.34 +import java.dyn.NoAccessException;
30.35 +import java.lang.reflect.Constructor;
30.36 +import java.lang.reflect.InvocationTargetException;
30.37 +
30.38 +/**
30.39 + * "Flyby adapters" which apply arbitrary conversions to arguments
30.40 + * on the way to a ultimate target.
30.41 + * For simplicity, these are all generically typed.
30.42 + * @author jrose
30.43 + */
30.44 +class FilterGeneric {
30.45 + // type for the outgoing call (will be generic)
30.46 + private final MethodType targetType;
30.47 + // position of (first) argument to participate in filtering
30.48 + private final short argumentPosition;
30.49 + // number of arguments to participate in filtering
30.50 + private final short argumentCount;
30.51 + // how the result interacts with the filtered arguments: Prepend, Append, Replace, Discard
30.52 + private final char replaceMode;
30.53 + // prototype adapter (clone and customize for each new target & conversion!)
30.54 + private final Adapter adapter;
30.55 + // entry point for adapter (Adapter mh, a...) => ...
30.56 + private final MethodHandle entryPoint;
30.57 + // more of them (loosely cached)
30.58 + private FilterGeneric variations;
30.59 +
30.60 + /** Compute and cache information common to all unboxing adapters
30.61 + * that can call out to targets of the erasure-family of the given erased type.
30.62 + */
30.63 + // TO DO: Make this private.
30.64 + FilterGeneric(MethodType targetType, short argumentPosition, short argumentCount, char replaceMode) {
30.65 + if (argumentCount == 0) {
30.66 + if (replaceMode == 'P' || replaceMode == 'A') replaceMode = 'R';
30.67 + if (replaceMode == 'I') argumentPosition = 0;
30.68 + }
30.69 + this.targetType = targetType;
30.70 + this.argumentPosition = argumentPosition;
30.71 + this.argumentCount = argumentCount;
30.72 + this.replaceMode = replaceMode;
30.73 + validate(targetType, argumentPosition, argumentCount, replaceMode);
30.74 + Adapter ad = findAdapter(targetType, argumentPosition, argumentCount, replaceMode, filterType());
30.75 + if (ad == null)
30.76 + ad = buildAdapterFromBytecodes(targetType, argumentPosition, argumentCount, replaceMode, filterType());
30.77 + this.adapter = ad;
30.78 + this.entryPoint = ad.prototypeEntryPoint();
30.79 + }
30.80 +
30.81 + Adapter makeInstance(MethodHandle filter, MethodHandle target) {
30.82 + return adapter.makeInstance(entryPoint, filter, target);
30.83 + }
30.84 +
30.85 + /** Build an adapter of the given generic type, which invokes typedTarget
30.86 + * on the incoming arguments, after unboxing as necessary.
30.87 + * The return value is boxed if necessary.
30.88 + * @param genericType the required type of the result
30.89 + * @param typedTarget the target
30.90 + * @return an adapter method handle
30.91 + */
30.92 + public static MethodHandle make(MethodHandle target, int pos, MethodHandle filter) {
30.93 + return FilterGeneric.of(target.type(), (short)pos, (short)1, 'R').makeInstance(filter, target);
30.94 + }
30.95 +
30.96 + /** Return the adapter information for this type's erasure. */
30.97 + static FilterGeneric of(MethodType type, short ap, short ac, char mode) {
30.98 + if (type.generic() != type)
30.99 + throw new IllegalArgumentException("must be generic: "+type);
30.100 + validate(type, ap, ac, mode);
30.101 + MethodTypeImpl form = MethodTypeImpl.of(type);
30.102 + FilterGeneric filterGen = form.filterGeneric;
30.103 + if (filterGen == null)
30.104 + form.filterGeneric = filterGen = new FilterGeneric(type, (short)0, (short)1, 'R');
30.105 + return find(filterGen, ap, ac, mode);
30.106 + }
30.107 +
30.108 + static FilterGeneric find(FilterGeneric gen, short ap, short ac, char mode) {
30.109 + for (;;) {
30.110 + if (gen.argumentPosition == ap &&
30.111 + gen.argumentCount == ac &&
30.112 + gen.replaceMode == mode) {
30.113 + return gen;
30.114 + }
30.115 + FilterGeneric gen2 = gen.variations;
30.116 + if (gen2 == null) break;
30.117 + gen = gen2;
30.118 + }
30.119 + FilterGeneric gen2 = new FilterGeneric(gen.targetType, ap, ac, mode);
30.120 + gen.variations = gen2; // OK if this smashes another cached chain
30.121 + return gen2;
30.122 + }
30.123 +
30.124 + private static void validate(MethodType type, short ap, short ac, char mode) {
30.125 + int endpos = ap + ac;
30.126 + switch (mode) {
30.127 + case 'P': case 'A': case 'R': case 'D':
30.128 + if (ap >= 0 && ac >= 0 &&
30.129 + endpos >= 0 && endpos <= type.parameterCount())
30.130 + return;
30.131 + default:
30.132 + throw new InternalError("configuration "+patternName(ap, ac, mode));
30.133 + }
30.134 + }
30.135 +
30.136 + public String toString() {
30.137 + return "FilterGeneric/"+patternName()+targetType;
30.138 + }
30.139 +
30.140 + String patternName() {
30.141 + return patternName(argumentPosition, argumentCount, replaceMode);
30.142 + }
30.143 +
30.144 + static String patternName(short ap, short ac, char mode) {
30.145 + return ""+mode+ap+(ac>1?"_"+ac:"");
30.146 + }
30.147 +
30.148 + Class<?> filterType() {
30.149 + return Object.class; // result of filter operation; an uninteresting type
30.150 + }
30.151 +
30.152 + static MethodType targetType(MethodType entryType, short ap, short ac, char mode,
30.153 + Class<?> arg) {
30.154 + MethodType type = entryType;
30.155 + int pos = ap;
30.156 + switch (mode) {
30.157 + case 'A':
30.158 + pos += ac;
30.159 + case 'P':
30.160 + type = type.insertParameterType(pos, arg);
30.161 + break;
30.162 + case 'I':
30.163 + for (int i = 1; i < ac; i++)
30.164 + type = type.dropParameterType(pos);
30.165 + assert(type.parameterType(pos) == arg);
30.166 + break;
30.167 + case 'D':
30.168 + break;
30.169 + }
30.170 + return type;
30.171 + }
30.172 +
30.173 + static MethodType entryType(MethodType targetType, short ap, short ac, char mode,
30.174 + Class<?> arg) {
30.175 + MethodType type = targetType;
30.176 + int pos = ap;
30.177 + switch (mode) {
30.178 + case 'A':
30.179 + pos += ac;
30.180 + case 'P':
30.181 + type = type.dropParameterType(pos);
30.182 + break;
30.183 + case 'I':
30.184 + for (int i = 1; i < ac; i++)
30.185 + type = type.insertParameterType(pos, arg);
30.186 + assert(type.parameterType(pos) == arg);
30.187 + break;
30.188 + case 'D':
30.189 + break;
30.190 + }
30.191 + return type;
30.192 + }
30.193 +
30.194 + /* Create an adapter that handles spreading calls for the given type. */
30.195 + static Adapter findAdapter(MethodType targetType, short ap, short ac, char mode, Class<?> arg) {
30.196 + MethodType entryType = entryType(targetType, ap, ac, mode, arg);
30.197 + int argc = targetType.parameterCount();
30.198 + String pname = patternName(ap, ac, mode);
30.199 + String cname0 = "F"+argc;
30.200 + String cname1 = "F"+argc+mode;
30.201 + String cname2 = "F"+argc+pname;
30.202 + String[] cnames = { cname0, cname1, cname1+"X", cname2 };
30.203 + String iname = "invoke_"+pname;
30.204 + // e.g., F5R; invoke_R3
30.205 + for (String cname : cnames) {
30.206 + Class<? extends Adapter> acls = Adapter.findSubClass(cname);
30.207 + if (acls == null) continue;
30.208 + // see if it has the required invoke method
30.209 + MethodHandle entryPoint = null;
30.210 + try {
30.211 + entryPoint = MethodHandleImpl.IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls);
30.212 + } catch (NoAccessException ex) {
30.213 + }
30.214 + if (entryPoint == null) continue;
30.215 + Constructor<? extends Adapter> ctor = null;
30.216 + try {
30.217 + ctor = acls.getDeclaredConstructor(MethodHandle.class);
30.218 + } catch (NoSuchMethodException ex) {
30.219 + } catch (SecurityException ex) {
30.220 + }
30.221 + if (ctor == null) continue;
30.222 + try {
30.223 + // Produce an instance configured as a prototype.
30.224 + return ctor.newInstance(entryPoint);
30.225 + } catch (IllegalArgumentException ex) {
30.226 + } catch (InvocationTargetException ex) {
30.227 + } catch (InstantiationException ex) {
30.228 + } catch (IllegalAccessException ex) {
30.229 + }
30.230 + }
30.231 + return null;
30.232 + }
30.233 +
30.234 + static Adapter buildAdapterFromBytecodes(MethodType targetType, short ap, short ac, char mode, Class<?> arg) {
30.235 + throw new UnsupportedOperationException("NYI");
30.236 + }
30.237 +
30.238 + /**
30.239 + * This adapter takes some untyped arguments, and returns an untyped result.
30.240 + * Internally, it applies the invoker to the target, which causes the
30.241 + * objects to be unboxed; the result is a raw type in L/I/J/F/D.
30.242 + * This result is passed to convert, which is responsible for
30.243 + * converting the raw result into a boxed object.
30.244 + * The invoker is kept separate from the target because it can be
30.245 + * generated once per type erasure family, and reused across adapters.
30.246 + */
30.247 + static abstract class Adapter extends JavaMethodHandle {
30.248 + protected final MethodHandle filter;
30.249 + protected final MethodHandle target;
30.250 +
30.251 + protected boolean isPrototype() { return target == null; }
30.252 + protected Adapter(MethodHandle entryPoint) {
30.253 + this(entryPoint, entryPoint, null);
30.254 + assert(isPrototype());
30.255 + }
30.256 + protected MethodHandle prototypeEntryPoint() {
30.257 + if (!isPrototype()) throw new InternalError();
30.258 + return filter;
30.259 + }
30.260 +
30.261 + protected Adapter(MethodHandle entryPoint,
30.262 + MethodHandle filter, MethodHandle target) {
30.263 + super(entryPoint);
30.264 + this.filter = filter;
30.265 + this.target = target;
30.266 + }
30.267 +
30.268 + /** Make a copy of self, with new fields. */
30.269 + protected abstract Adapter makeInstance(MethodHandle entryPoint,
30.270 + MethodHandle filter, MethodHandle target);
30.271 + // { return new ThisType(entryPoint, filter, target); }
30.272 +
30.273 + static private final String CLASS_PREFIX; // "sun.dyn.FilterGeneric$"
30.274 + static {
30.275 + String aname = Adapter.class.getName();
30.276 + String sname = Adapter.class.getSimpleName();
30.277 + if (!aname.endsWith(sname)) throw new InternalError();
30.278 + CLASS_PREFIX = aname.substring(0, aname.length() - sname.length());
30.279 + }
30.280 + /** Find a sibing class of Adapter. */
30.281 + static Class<? extends Adapter> findSubClass(String name) {
30.282 + String cname = Adapter.CLASS_PREFIX + name;
30.283 + try {
30.284 + return Class.forName(cname).asSubclass(Adapter.class);
30.285 + } catch (ClassNotFoundException ex) {
30.286 + return null;
30.287 + } catch (ClassCastException ex) {
30.288 + return null;
30.289 + }
30.290 + }
30.291 + }
30.292 +
30.293 + //* generated classes follow this pattern:
30.294 + static class F1RX extends Adapter {
30.295 + protected F1RX(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
30.296 + protected F1RX(MethodHandle e, MethodHandle f, MethodHandle t)
30.297 + { super(e, f, t); }
30.298 + protected F1RX makeInstance(MethodHandle e, MethodHandle f, MethodHandle t)
30.299 + { return new F1RX(e, f, t); }
30.300 + protected Object filter(Object a0) { return filter.<Object>invoke(a0); }
30.301 + protected Object target(Object a0) { return target.<Object>invoke(a0); }
30.302 + protected Object invoke_R0(Object a0) { return target(filter(a0)); }
30.303 + }
30.304 + static class F2RX extends Adapter {
30.305 + protected F2RX(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
30.306 + protected F2RX(MethodHandle e, MethodHandle f, MethodHandle t)
30.307 + { super(e, f, t); }
30.308 + protected F2RX makeInstance(MethodHandle e, MethodHandle f, MethodHandle t)
30.309 + { return new F2RX(e, f, t); }
30.310 + protected Object filter(Object a0) { return filter.<Object>invoke(a0); }
30.311 + protected Object target(Object a0, Object a1) { return target.<Object>invoke(a0, a1); }
30.312 + protected Object invoke_R0(Object a0, Object a1) { return target(filter(a0), a1); }
30.313 + protected Object invoke_R1(Object a0, Object a1) { return target(a0, filter(a1)); }
30.314 + }
30.315 + static class F3RX extends Adapter {
30.316 + protected F3RX(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
30.317 + protected F3RX(MethodHandle e, MethodHandle f, MethodHandle t)
30.318 + { super(e, f, t); }
30.319 + protected F3RX makeInstance(MethodHandle e, MethodHandle f, MethodHandle t)
30.320 + { return new F3RX(e, f, t); }
30.321 + protected Object filter(Object a0) { return filter.<Object>invoke(a0); }
30.322 + protected Object target(Object a0, Object a1, Object a2) { return target.<Object>invoke(a0, a1, a2); }
30.323 + protected Object invoke_R0(Object a0, Object a1, Object a2) { return target(filter(a0), a1, a2); }
30.324 + protected Object invoke_R1(Object a0, Object a1, Object a2) { return target(a0, filter(a1), a2); }
30.325 + protected Object invoke_R2(Object a0, Object a1, Object a2) { return target(a0, a1, filter(a2)); }
30.326 + }
30.327 + static class F4RX extends Adapter {
30.328 + protected F4RX(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
30.329 + protected F4RX(MethodHandle e, MethodHandle f, MethodHandle t)
30.330 + { super(e, f, t); }
30.331 + protected F4RX makeInstance(MethodHandle e, MethodHandle f, MethodHandle t)
30.332 + { return new F4RX(e, f, t); }
30.333 + protected Object filter(Object a0) { return filter.<Object>invoke(a0); }
30.334 + protected Object target(Object a0, Object a1, Object a2, Object a3) { return target.<Object>invoke(a0, a1, a2, a3); }
30.335 + protected Object invoke_R0(Object a0, Object a1, Object a2, Object a3) { return target(filter(a0), a1, a2, a3); }
30.336 + protected Object invoke_R1(Object a0, Object a1, Object a2, Object a3) { return target(a0, filter(a1), a2, a3); }
30.337 + protected Object invoke_R2(Object a0, Object a1, Object a2, Object a3) { return target(a0, a1, filter(a2), a3); }
30.338 + protected Object invoke_R3(Object a0, Object a1, Object a2, Object a3) { return target(a0, a1, a2, filter(a3)); }
30.339 + }
30.340 + // */
30.341 +}
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
31.2 +++ b/src/share/classes/sun/dyn/FilterOneArgument.java Tue May 05 23:12:47 2009 -0700
31.3 @@ -0,0 +1,73 @@
31.4 +/*
31.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
31.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
31.7 + *
31.8 + * This code is free software; you can redistribute it and/or modify it
31.9 + * under the terms of the GNU General Public License version 2 only, as
31.10 + * published by the Free Software Foundation. Sun designates this
31.11 + * particular file as subject to the "Classpath" exception as provided
31.12 + * by Sun in the LICENSE file that accompanied this code.
31.13 + *
31.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
31.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
31.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
31.17 + * version 2 for more details (a copy is included in the LICENSE file that
31.18 + * accompanied this code).
31.19 + *
31.20 + * You should have received a copy of the GNU General Public License version
31.21 + * 2 along with this work; if not, write to the Free Software Foundation,
31.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
31.23 + *
31.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
31.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
31.26 + * have any questions.
31.27 + */
31.28 +
31.29 +package sun.dyn;
31.30 +
31.31 +import java.dyn.JavaMethodHandle;
31.32 +import java.dyn.MethodHandle;
31.33 +import java.dyn.MethodHandles;
31.34 +import java.dyn.MethodType;
31.35 +
31.36 +/**
31.37 + * Unary function composition, useful for many small plumbing jobs.
31.38 + * The invoke method takes a single reference argument, and returns a reference
31.39 + * Internally, it first calls the {@code filter} method on the argument,
31.40 + * Making up the difference between the raw method type and the
31.41 + * final method type is the responsibility of a JVM-level adapter.
31.42 + * @author jrose
31.43 + */
31.44 +public class FilterOneArgument extends JavaMethodHandle {
31.45 + protected final MethodHandle filter; // Object -> Object
31.46 + protected final MethodHandle target; // Object -> Object
31.47 +
31.48 + protected Object entryPoint(Object argument) {
31.49 + Object filteredArgument = filter.<Object>invoke(argument);
31.50 + return target.<Object>invoke(filteredArgument);
31.51 + }
31.52 +
31.53 + private static final MethodHandle entryPoint =
31.54 + MethodHandleImpl.IMPL_LOOKUP.findVirtual(FilterOneArgument.class, "entryPoint", MethodType.makeGeneric(1));
31.55 +
31.56 + protected FilterOneArgument(MethodHandle filter, MethodHandle target) {
31.57 + super(entryPoint);
31.58 + this.filter = filter;
31.59 + this.target = target;
31.60 + }
31.61 +
31.62 + public static MethodHandle make(MethodHandle filter, MethodHandle target) {
31.63 + if (filter == null) return target;
31.64 + if (target == null) return filter;
31.65 + return new FilterOneArgument(filter, target);
31.66 + }
31.67 +
31.68 + public String toString() {
31.69 + return filter + "|>" + target;
31.70 + }
31.71 +
31.72 +// MethodHandle make(MethodHandle filter1, MethodHandle filter2, MethodHandle target) {
31.73 +// MethodHandle filter = make(filter1, filter2);
31.74 +// return make(filter, target);
31.75 +// }
31.76 +}
32.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
32.2 +++ b/src/share/classes/sun/dyn/FromGeneric.java Tue May 05 23:12:47 2009 -0700
32.3 @@ -0,0 +1,627 @@
32.4 +/*
32.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
32.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
32.7 + *
32.8 + * This code is free software; you can redistribute it and/or modify it
32.9 + * under the terms of the GNU General Public License version 2 only, as
32.10 + * published by the Free Software Foundation. Sun designates this
32.11 + * particular file as subject to the "Classpath" exception as provided
32.12 + * by Sun in the LICENSE file that accompanied this code.
32.13 + *
32.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
32.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
32.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
32.17 + * version 2 for more details (a copy is included in the LICENSE file that
32.18 + * accompanied this code).
32.19 + *
32.20 + * You should have received a copy of the GNU General Public License version
32.21 + * 2 along with this work; if not, write to the Free Software Foundation,
32.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
32.23 + *
32.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
32.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
32.26 + * have any questions.
32.27 + */
32.28 +
32.29 +package sun.dyn;
32.30 +
32.31 +import java.dyn.JavaMethodHandle;
32.32 +import java.dyn.MethodHandle;
32.33 +import java.dyn.MethodHandles;
32.34 +import java.dyn.MethodType;
32.35 +import java.dyn.NoAccessException;
32.36 +import java.lang.reflect.Constructor;
32.37 +import java.lang.reflect.InvocationTargetException;
32.38 +import sun.dyn.util.ValueConversions;
32.39 +import sun.dyn.util.Wrapper;
32.40 +
32.41 +/**
32.42 + * Adapters which mediate between incoming calls which are not generic
32.43 + * and outgoing calls which are. Any call can be represented generically
32.44 + * boxing up its arguments, and (on return) unboxing the return value.
32.45 + * <p>
32.46 + * A call is "generic" (in MethodHandle terms) if its MethodType features
32.47 + * only Object arguments. A non-generic call therefore features
32.48 + * primitives and/or reference types other than Object.
32.49 + * An adapter has types for its incoming and outgoing calls.
32.50 + * The incoming call type is simply determined by the adapter's type
32.51 + * (the MethodType it presents to callers). The outgoing call type
32.52 + * is determined by the adapter's target (a MethodHandle that the adapter
32.53 + * either binds internally or else takes as a leading argument).
32.54 + * (To stretch the term, adapter-like method handles may have multiple
32.55 + * targets or be polymorphic across multiple call types.)
32.56 + * <p>
32.57 + * This adapter can sometimes be more directly implemented
32.58 + * by the JVM's built-in OP_SPREAD_ARGS adapter.
32.59 + * @author jrose
32.60 + */
32.61 +class FromGeneric {
32.62 + // type for the outgoing call (may have primitives, etc.)
32.63 + private final MethodType targetType;
32.64 + // type of the outgoing call internal to the adapter
32.65 + private final MethodType internalType;
32.66 + // prototype adapter (clone and customize for each new target!)
32.67 + private final Adapter adapter;
32.68 + // entry point for adapter (Adapter mh, a...) => ...
32.69 + private final MethodHandle entryPoint;
32.70 + // unboxing invoker of type (MH, Object**N) => raw return value
32.71 + // it makes up the difference of internalType => targetType
32.72 + private final MethodHandle unboxingInvoker;
32.73 + // conversion which boxes a the target's raw return value
32.74 + private final MethodHandle returnConversion;
32.75 +
32.76 + /** Compute and cache information common to all unboxing adapters
32.77 + * that can call out to targets of the erasure-family of the given erased type.
32.78 + */
32.79 + private FromGeneric(MethodType targetType) {
32.80 + this.targetType = targetType;
32.81 + MethodType internalType0;
32.82 + // the target invoker will generally need casts on reference arguments
32.83 + Adapter ad = findAdapter(internalType0 = targetType.erase());
32.84 + if (ad != null) {
32.85 + // Immediate hit to exactly the adapter we want,
32.86 + // with no monkeying around with primitive types.
32.87 + this.internalType = internalType0;
32.88 + this.adapter = ad;
32.89 + this.entryPoint = ad.prototypeEntryPoint();
32.90 + this.returnConversion = computeReturnConversion(targetType, internalType0);
32.91 + this.unboxingInvoker = computeUnboxingInvoker(targetType, internalType0);
32.92 + return;
32.93 + }
32.94 +
32.95 + // outgoing primitive arguments will be wrapped; unwrap them
32.96 + MethodType primsAsObj = MethodTypeImpl.of(targetType).primArgsAsBoxes();
32.97 + MethodType objArgsRawRet = MethodTypeImpl.of(primsAsObj).primsAsInts();
32.98 + if (objArgsRawRet != targetType)
32.99 + ad = findAdapter(internalType0 = objArgsRawRet);
32.100 + if (ad == null) {
32.101 + ad = buildAdapterFromBytecodes(internalType0 = targetType);
32.102 + }
32.103 + this.internalType = internalType0;
32.104 + this.adapter = ad;
32.105 + MethodType tepType = targetType.insertParameterType(0, adapter.getClass());
32.106 + this.entryPoint = ad.prototypeEntryPoint();
32.107 + this.returnConversion = computeReturnConversion(targetType, internalType0);
32.108 + this.unboxingInvoker = computeUnboxingInvoker(targetType, internalType0);
32.109 + }
32.110 +
32.111 + /**
32.112 + * The typed target will be called according to targetType.
32.113 + * The adapter code will in fact see the raw result from internalType,
32.114 + * and must box it into an object. Produce a converter for this.
32.115 + */
32.116 + private static MethodHandle computeReturnConversion(
32.117 + MethodType targetType, MethodType internalType) {
32.118 + Class<?> tret = targetType.returnType();
32.119 + Class<?> iret = internalType.returnType();
32.120 + Wrapper wrap = Wrapper.forBasicType(tret);
32.121 + if (!iret.isPrimitive()) {
32.122 + assert(iret == Object.class);
32.123 + return ValueConversions.identity();
32.124 + } else if (wrap.primitiveType() == iret) {
32.125 + return ValueConversions.box(wrap, false);
32.126 + } else {
32.127 + assert(tret == double.class ? iret == long.class : iret == int.class);
32.128 + return ValueConversions.boxRaw(wrap, false);
32.129 + }
32.130 + }
32.131 +
32.132 + /**
32.133 + * The typed target will need an exact invocation point; provide it here.
32.134 + * The adapter will possibly need to make a slightly different call,
32.135 + * so adapt the invoker. This way, the logic for making up the
32.136 + * difference between what the adapter can call and what the target
32.137 + * needs can be cached once per type.
32.138 + */
32.139 + private static MethodHandle computeUnboxingInvoker(
32.140 + MethodType targetType, MethodType internalType) {
32.141 + // All the adapters we have here have reference-untyped internal calls.
32.142 + assert(internalType == internalType.erase());
32.143 + MethodHandle invoker = MethodHandles.exactInvoker(targetType);
32.144 + // cast all narrow reference types, unbox all primitive arguments:
32.145 + MethodType fixArgsType = internalType.changeReturnType(targetType.returnType());
32.146 + MethodHandle fixArgs = AdapterMethodHandle.convertArguments(Access.TOKEN,
32.147 + invoker, Invokers.invokerType(fixArgsType),
32.148 + invoker.type(), null);
32.149 + if (fixArgs == null)
32.150 + throw new InternalError("bad fixArgs");
32.151 + // reinterpret the calling sequence as raw:
32.152 + MethodHandle retyper = AdapterMethodHandle.makeRawRetypeOnly(Access.TOKEN,
32.153 + Invokers.invokerType(internalType), fixArgs);
32.154 + if (retyper == null)
32.155 + throw new InternalError("bad retyper");
32.156 + return retyper;
32.157 + }
32.158 +
32.159 + Adapter makeInstance(MethodHandle typedTarget) {
32.160 + MethodType type = typedTarget.type();
32.161 + if (type == targetType) {
32.162 + return adapter.makeInstance(entryPoint, unboxingInvoker, returnConversion, typedTarget);
32.163 + }
32.164 + // my erased-type is not exactly the same as the desired type
32.165 + assert(type.erase() == targetType); // else we are busted
32.166 + MethodHandle invoker = computeUnboxingInvoker(type, internalType);
32.167 + return adapter.makeInstance(entryPoint, invoker, returnConversion, typedTarget);
32.168 + }
32.169 +
32.170 + /** Build an adapter of the given generic type, which invokes typedTarget
32.171 + * on the incoming arguments, after unboxing as necessary.
32.172 + * The return value is boxed if necessary.
32.173 + * @param genericType the required type of the result
32.174 + * @param typedTarget the target
32.175 + * @return an adapter method handle
32.176 + */
32.177 + public static MethodHandle make(MethodHandle typedTarget) {
32.178 + MethodType type = typedTarget.type();
32.179 + if (type == type.generic()) return typedTarget;
32.180 + return FromGeneric.of(type).makeInstance(typedTarget);
32.181 + }
32.182 +
32.183 + /** Return the adapter information for this type's erasure. */
32.184 + static FromGeneric of(MethodType type) {
32.185 + MethodTypeImpl form = MethodTypeImpl.of(type);
32.186 + FromGeneric fromGen = form.fromGeneric;
32.187 + if (fromGen == null)
32.188 + form.fromGeneric = fromGen = new FromGeneric(form.erasedType());
32.189 + return fromGen;
32.190 + }
32.191 +
32.192 + public String toString() {
32.193 + return "FromGeneric"+targetType;
32.194 + }
32.195 +
32.196 + /* Create an adapter that handles spreading calls for the given type. */
32.197 + static Adapter findAdapter(MethodType internalType) {
32.198 + MethodType entryType = internalType.generic();
32.199 + MethodTypeImpl form = MethodTypeImpl.of(internalType);
32.200 + Class<?> rtype = internalType.returnType();
32.201 + int argc = form.parameterCount();
32.202 + int lac = form.longPrimitiveParameterCount();
32.203 + int iac = form.primitiveParameterCount() - lac;
32.204 + String intsAndLongs = (iac > 0 ? "I"+iac : "")+(lac > 0 ? "J"+lac : "");
32.205 + String rawReturn = String.valueOf(Wrapper.forPrimitiveType(rtype).basicTypeChar());
32.206 + String cname0 = rawReturn + argc;
32.207 + String cname1 = "A" + argc;
32.208 + String[] cnames = { cname0+intsAndLongs, cname0, cname1+intsAndLongs, cname1 };
32.209 + String iname = "invoke_"+cname0+intsAndLongs;
32.210 + // e.g., D5I2, D5, L5I2, L5; invoke_D5
32.211 + for (String cname : cnames) {
32.212 + Class<? extends Adapter> acls = Adapter.findSubClass(cname);
32.213 + if (acls == null) continue;
32.214 + // see if it has the required invoke method
32.215 + MethodHandle entryPoint = null;
32.216 + try {
32.217 + entryPoint = MethodHandleImpl.IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls);
32.218 + } catch (NoAccessException ex) {
32.219 + }
32.220 + if (entryPoint == null) continue;
32.221 + Constructor<? extends Adapter> ctor = null;
32.222 + try {
32.223 + ctor = acls.getDeclaredConstructor(MethodHandle.class);
32.224 + } catch (NoSuchMethodException ex) {
32.225 + } catch (SecurityException ex) {
32.226 + }
32.227 + if (ctor == null) continue;
32.228 + try {
32.229 + // Produce an instance configured as a prototype.
32.230 + return ctor.newInstance(entryPoint);
32.231 + } catch (IllegalArgumentException ex) {
32.232 + } catch (InvocationTargetException ex) {
32.233 + } catch (InstantiationException ex) {
32.234 + } catch (IllegalAccessException ex) {
32.235 + }
32.236 + }
32.237 + return null;
32.238 + }
32.239 +
32.240 + static Adapter buildAdapterFromBytecodes(MethodType internalType) {
32.241 + throw new UnsupportedOperationException("NYI");
32.242 + }
32.243 +
32.244 + /**
32.245 + * This adapter takes some untyped arguments, and returns an untyped result.
32.246 + * Internally, it applies the invoker to the target, which causes the
32.247 + * objects to be unboxed; the result is a raw type in L/I/J/F/D.
32.248 + * This result is passed to convert, which is responsible for
32.249 + * converting the raw result into a boxed object.
32.250 + * The invoker is kept separate from the target because it can be
32.251 + * generated once per type erasure family, and reused across adapters.
32.252 + */
32.253 + static abstract class Adapter extends JavaMethodHandle {
32.254 + /*
32.255 + * class X<<R,int N>> extends Adapter {
32.256 + * (MH, Object**N)=>raw(R) invoker;
32.257 + * (any**N)=>R target;
32.258 + * raw(R)=>Object convert;
32.259 + * Object invoke(Object**N a) = convert(invoker(target, a...))
32.260 + * }
32.261 + */
32.262 + protected final MethodHandle invoker; // (MH, Object**N) => raw(R)
32.263 + protected final MethodHandle convert; // raw(R) => Object
32.264 + protected final MethodHandle target; // (any**N) => R
32.265 +
32.266 + protected boolean isPrototype() { return target == null; }
32.267 + protected Adapter(MethodHandle entryPoint) {
32.268 + this(entryPoint, null, entryPoint, null);
32.269 + assert(isPrototype());
32.270 + }
32.271 + protected MethodHandle prototypeEntryPoint() {
32.272 + if (!isPrototype()) throw new InternalError();
32.273 + return convert;
32.274 + }
32.275 +
32.276 + protected Adapter(MethodHandle entryPoint,
32.277 + MethodHandle invoker, MethodHandle convert, MethodHandle target) {
32.278 + super(entryPoint);
32.279 + this.invoker = invoker;
32.280 + this.convert = convert;
32.281 + this.target = target;
32.282 + }
32.283 +
32.284 + /** Make a copy of self, with new fields. */
32.285 + protected abstract Adapter makeInstance(MethodHandle entryPoint,
32.286 + MethodHandle invoker, MethodHandle convert, MethodHandle target);
32.287 + // { return new ThisType(entryPoint, convert, target); }
32.288 +
32.289 + /// Conversions on the value returned from the target.
32.290 + protected Object convert_L(Object result) { return convert.<Object>invoke(result); }
32.291 + protected Object convert_I(int result) { return convert.<Object>invoke(result); }
32.292 + protected Object convert_J(long result) { return convert.<Object>invoke(result); }
32.293 + protected Object convert_F(float result) { return convert.<Object>invoke(result); }
32.294 + protected Object convert_D(double result) { return convert.<Object>invoke(result); }
32.295 +
32.296 + static private final String CLASS_PREFIX; // "sun.dyn.FromGeneric$"
32.297 + static {
32.298 + String aname = Adapter.class.getName();
32.299 + String sname = Adapter.class.getSimpleName();
32.300 + if (!aname.endsWith(sname)) throw new InternalError();
32.301 + CLASS_PREFIX = aname.substring(0, aname.length() - sname.length());
32.302 + }
32.303 + /** Find a sibing class of Adapter. */
32.304 + static Class<? extends Adapter> findSubClass(String name) {
32.305 + String cname = Adapter.CLASS_PREFIX + name;
32.306 + try {
32.307 + return Class.forName(cname).asSubclass(Adapter.class);
32.308 + } catch (ClassNotFoundException ex) {
32.309 + return null;
32.310 + } catch (ClassCastException ex) {
32.311 + return null;
32.312 + }
32.313 + }
32.314 + }
32.315 +
32.316 + /* generated classes follow this pattern:
32.317 + static class xA2 extends Adapter {
32.318 + protected xA2(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
32.319 + protected xA2(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.320 + { super(e, i, c, t); }
32.321 + protected xA2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.322 + { return new xA2(e, i, c, t); }
32.323 + protected Object invoke_L2(Object a0, Object a1) { return convert_L(invoker.<Object>invoke(target, a0, a1)); }
32.324 + protected Object invoke_I2(Object a0, Object a1) { return convert_I(invoker.<int >invoke(target, a0, a1)); }
32.325 + protected Object invoke_J2(Object a0, Object a1) { return convert_J(invoker.<long >invoke(target, a0, a1)); }
32.326 + protected Object invoke_F2(Object a0, Object a1) { return convert_F(invoker.<float >invoke(target, a0, a1)); }
32.327 + protected Object invoke_D2(Object a0, Object a1) { return convert_D(invoker.<double>invoke(target, a0, a1)); }
32.328 + }
32.329 + // */
32.330 +
32.331 +/*
32.332 +: SHELL; n=FromGeneric; cp -p $n.java $n.java-; sed < $n.java- > $n.java+ -e '/{{*{{/,/}}*}}/w /tmp/genclasses.java' -e '/}}*}}/q'; (cd /tmp; javac -d . genclasses.java; java -cp . genclasses) >> $n.java+; echo '}' >> $n.java+; mv $n.java+ $n.java; mv $n.java- $n.java~
32.333 +//{{{
32.334 +import java.util.*;
32.335 +class genclasses {
32.336 + static String[] TYPES = { "Object", "int ", "long ", "float ", "double" };
32.337 + static String[] TCHARS = { "L", "I", "J", "F", "D", "A" };
32.338 + static String[][] TEMPLATES = { {
32.339 + "@for@ arity=0..10 rcat<=4 nrefs<=99 nints=0 nlongs=0",
32.340 + " //@each-cat@",
32.341 + " static class @cat@ extends Adapter {",
32.342 + " protected @cat@(MethodHandle entryPoint) { super(entryPoint); } // to build prototype",
32.343 + " protected @cat@(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)",
32.344 + " { super(e, i, c, t); }",
32.345 + " protected @cat@ makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)",
32.346 + " { return new @cat@(e, i, c, t); }",
32.347 + " //@each-R@",
32.348 + " protected Object invoke_@catN@(@Tvav@) { return convert_@Rc@(invoker.<@R@>invoke(target@av@)); }",
32.349 + " //@end-R@",
32.350 + " }",
32.351 + } };
32.352 + static final String NEWLINE_INDENT = "\n ";
32.353 + enum VAR {
32.354 + cat, catN, R, Rc, av, Tvav, Ovav;
32.355 + public final String pattern = "@"+toString().replace('_','.')+"@";
32.356 + public String binding;
32.357 + static void makeBindings(boolean topLevel, int rcat, int nrefs, int nints, int nlongs) {
32.358 + int nargs = nrefs + nints + nlongs;
32.359 + if (topLevel)
32.360 + VAR.cat.binding = catstr(ALL_RETURN_TYPES ? TYPES.length : rcat, nrefs, nints, nlongs);
32.361 + VAR.catN.binding = catstr(rcat, nrefs, nints, nlongs);
32.362 + VAR.R.binding = TYPES[rcat];
32.363 + VAR.Rc.binding = TCHARS[rcat];
32.364 + String[] Tv = new String[nargs];
32.365 + String[] av = new String[nargs];
32.366 + String[] Tvav = new String[nargs];
32.367 + String[] Ovav = new String[nargs];
32.368 + for (int i = 0; i < nargs; i++) {
32.369 + int tcat = (i < nrefs) ? 0 : (i < nrefs + nints) ? 1 : 2;
32.370 + Tv[i] = TYPES[tcat];
32.371 + av[i] = arg(i);
32.372 + Tvav[i] = param(Tv[i], av[i]);
32.373 + Ovav[i] = param("Object", av[i]);
32.374 + }
32.375 + VAR.av.binding = comma(", ", av);
32.376 + VAR.Tvav.binding = comma(Tvav);
32.377 + VAR.Ovav.binding = comma(Ovav);
32.378 + }
32.379 + static String arg(int i) { return "a"+i; }
32.380 + static String param(String t, String a) { return t+" "+a; }
32.381 + static String comma(String[] v) { return comma("", v); }
32.382 + static String comma(String sep, String[] v) {
32.383 + if (v.length == 0) return "";
32.384 + String res = sep+v[0];
32.385 + for (int i = 1; i < v.length; i++) res += ", "+v[i];
32.386 + return res;
32.387 + }
32.388 + static String transform(String string) {
32.389 + for (VAR var : values())
32.390 + string = string.replaceAll(var.pattern, var.binding);
32.391 + return string;
32.392 + }
32.393 + }
32.394 + static String[] stringsIn(String[] strings, int beg, int end) {
32.395 + return Arrays.copyOfRange(strings, beg, Math.min(end, strings.length));
32.396 + }
32.397 + static String[] stringsBefore(String[] strings, int pos) {
32.398 + return stringsIn(strings, 0, pos);
32.399 + }
32.400 + static String[] stringsAfter(String[] strings, int pos) {
32.401 + return stringsIn(strings, pos, strings.length);
32.402 + }
32.403 + static int indexAfter(String[] strings, int pos, String tag) {
32.404 + return Math.min(indexBefore(strings, pos, tag) + 1, strings.length);
32.405 + }
32.406 + static int indexBefore(String[] strings, int pos, String tag) {
32.407 + for (int i = pos, end = strings.length; ; i++) {
32.408 + if (i == end || strings[i].endsWith(tag)) return i;
32.409 + }
32.410 + }
32.411 + static int MIN_ARITY, MAX_ARITY, MAX_RCAT, MAX_REFS, MAX_INTS, MAX_LONGS;
32.412 + static boolean ALL_ARG_TYPES, ALL_RETURN_TYPES;
32.413 + static HashSet<String> done = new HashSet<String>();
32.414 + public static void main(String... av) {
32.415 + for (String[] template : TEMPLATES) {
32.416 + int forLinesLimit = indexBefore(template, 0, "@each-cat@");
32.417 + String[] forLines = stringsBefore(template, forLinesLimit);
32.418 + template = stringsAfter(template, forLinesLimit);
32.419 + for (String forLine : forLines)
32.420 + expandTemplate(forLine, template);
32.421 + }
32.422 + }
32.423 + static void expandTemplate(String forLine, String[] template) {
32.424 + String[] params = forLine.split("[^0-9]+");
32.425 + if (params[0].length() == 0) params = stringsAfter(params, 1);
32.426 + System.out.println("//params="+Arrays.asList(params));
32.427 + int pcur = 0;
32.428 + MIN_ARITY = Integer.valueOf(params[pcur++]);
32.429 + MAX_ARITY = Integer.valueOf(params[pcur++]);
32.430 + MAX_RCAT = Integer.valueOf(params[pcur++]);
32.431 + MAX_REFS = Integer.valueOf(params[pcur++]);
32.432 + MAX_INTS = Integer.valueOf(params[pcur++]);
32.433 + MAX_LONGS = Integer.valueOf(params[pcur++]);
32.434 + if (pcur != params.length) throw new RuntimeException("bad extra param: "+forLine);
32.435 + if (MAX_RCAT >= TYPES.length) MAX_RCAT = TYPES.length - 1;
32.436 + ALL_ARG_TYPES = (indexBefore(template, 0, "@each-Tv@") < template.length);
32.437 + ALL_RETURN_TYPES = (indexBefore(template, 0, "@each-R@") < template.length);
32.438 + for (int nargs = MIN_ARITY; nargs <= MAX_ARITY; nargs++) {
32.439 + for (int rcat = 0; rcat <= MAX_RCAT; rcat++) {
32.440 + expandTemplate(template, true, rcat, nargs, 0, 0);
32.441 + if (ALL_ARG_TYPES) break;
32.442 + expandTemplateForPrims(template, true, rcat, nargs, 1, 1);
32.443 + if (ALL_RETURN_TYPES) break;
32.444 + }
32.445 + }
32.446 + }
32.447 + static String catstr(int rcat, int nrefs, int nints, int nlongs) {
32.448 + int nargs = nrefs + nints + nlongs;
32.449 + String cat = TCHARS[rcat] + nargs;
32.450 + if (!ALL_ARG_TYPES) cat += (nints==0?"":"I"+nints)+(nlongs==0?"":"J"+nlongs);
32.451 + return cat;
32.452 + }
32.453 + static void expandTemplateForPrims(String[] template, boolean topLevel, int rcat, int nargs, int minints, int minlongs) {
32.454 + for (int isLong = 0; isLong <= 1; isLong++) {
32.455 + for (int nprims = 1; nprims <= nargs; nprims++) {
32.456 + int nrefs = nargs - nprims;
32.457 + int nints = ((1-isLong) * nprims);
32.458 + int nlongs = (isLong * nprims);
32.459 + expandTemplate(template, topLevel, rcat, nrefs, nints, nlongs);
32.460 + }
32.461 + }
32.462 + }
32.463 + static void expandTemplate(String[] template, boolean topLevel,
32.464 + int rcat, int nrefs, int nints, int nlongs) {
32.465 + int nargs = nrefs + nints + nlongs;
32.466 + if (nrefs > MAX_REFS || nints > MAX_INTS || nlongs > MAX_LONGS) return;
32.467 + VAR.makeBindings(topLevel, rcat, nrefs, nints, nlongs);
32.468 + if (topLevel && !done.add(VAR.cat.binding)) {
32.469 + System.out.println(" //repeat "+VAR.cat.binding);
32.470 + return;
32.471 + }
32.472 + for (int i = 0; i < template.length; i++) {
32.473 + String line = template[i];
32.474 + if (line.endsWith("@each-cat@")) {
32.475 + // ignore
32.476 + } else if (line.endsWith("@each-R@")) {
32.477 + int blockEnd = indexAfter(template, i, "@end-R@");
32.478 + String[] block = stringsIn(template, i+1, blockEnd-1);
32.479 + for (int rcat1 = rcat; rcat1 <= MAX_RCAT; rcat1++)
32.480 + expandTemplate(block, false, rcat1, nrefs, nints, nlongs);
32.481 + VAR.makeBindings(topLevel, rcat, nrefs, nints, nlongs);
32.482 + i = blockEnd-1; continue;
32.483 + } else if (line.endsWith("@each-Tv@")) {
32.484 + int blockEnd = indexAfter(template, i, "@end-Tv@");
32.485 + String[] block = stringsIn(template, i+1, blockEnd-1);
32.486 + expandTemplate(block, false, rcat, nrefs, nints, nlongs);
32.487 + expandTemplateForPrims(block, false, rcat, nargs, nints+1, nlongs+1);
32.488 + VAR.makeBindings(topLevel, rcat, nrefs, nints, nlongs);
32.489 + i = blockEnd-1; continue;
32.490 + } else {
32.491 + System.out.println(VAR.transform(line));
32.492 + }
32.493 + }
32.494 + }
32.495 +}
32.496 +//}}} */
32.497 +//params=[0, 10, 4, 99, 0, 0]
32.498 + static class A0 extends Adapter {
32.499 + protected A0(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
32.500 + protected A0(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.501 + { super(e, i, c, t); }
32.502 + protected A0 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.503 + { return new A0(e, i, c, t); }
32.504 + protected Object invoke_L0() { return convert_L(invoker.<Object>invoke(target)); }
32.505 + protected Object invoke_I0() { return convert_I(invoker.<int >invoke(target)); }
32.506 + protected Object invoke_J0() { return convert_J(invoker.<long >invoke(target)); }
32.507 + protected Object invoke_F0() { return convert_F(invoker.<float >invoke(target)); }
32.508 + protected Object invoke_D0() { return convert_D(invoker.<double>invoke(target)); }
32.509 + }
32.510 + static class A1 extends Adapter {
32.511 + protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
32.512 + protected A1(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.513 + { super(e, i, c, t); }
32.514 + protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.515 + { return new A1(e, i, c, t); }
32.516 + protected Object invoke_L1(Object a0) { return convert_L(invoker.<Object>invoke(target, a0)); }
32.517 + protected Object invoke_I1(Object a0) { return convert_I(invoker.<int >invoke(target, a0)); }
32.518 + protected Object invoke_J1(Object a0) { return convert_J(invoker.<long >invoke(target, a0)); }
32.519 + protected Object invoke_F1(Object a0) { return convert_F(invoker.<float >invoke(target, a0)); }
32.520 + protected Object invoke_D1(Object a0) { return convert_D(invoker.<double>invoke(target, a0)); }
32.521 + }
32.522 + static class A2 extends Adapter {
32.523 + protected A2(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
32.524 + protected A2(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.525 + { super(e, i, c, t); }
32.526 + protected A2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.527 + { return new A2(e, i, c, t); }
32.528 + protected Object invoke_L2(Object a0, Object a1) { return convert_L(invoker.<Object>invoke(target, a0, a1)); }
32.529 + protected Object invoke_I2(Object a0, Object a1) { return convert_I(invoker.<int >invoke(target, a0, a1)); }
32.530 + protected Object invoke_J2(Object a0, Object a1) { return convert_J(invoker.<long >invoke(target, a0, a1)); }
32.531 + protected Object invoke_F2(Object a0, Object a1) { return convert_F(invoker.<float >invoke(target, a0, a1)); }
32.532 + protected Object invoke_D2(Object a0, Object a1) { return convert_D(invoker.<double>invoke(target, a0, a1)); }
32.533 + }
32.534 + static class A3 extends Adapter {
32.535 + protected A3(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
32.536 + protected A3(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.537 + { super(e, i, c, t); }
32.538 + protected A3 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.539 + { return new A3(e, i, c, t); }
32.540 + protected Object invoke_L3(Object a0, Object a1, Object a2) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2)); }
32.541 + protected Object invoke_I3(Object a0, Object a1, Object a2) { return convert_I(invoker.<int >invoke(target, a0, a1, a2)); }
32.542 + protected Object invoke_J3(Object a0, Object a1, Object a2) { return convert_J(invoker.<long >invoke(target, a0, a1, a2)); }
32.543 + protected Object invoke_F3(Object a0, Object a1, Object a2) { return convert_F(invoker.<float >invoke(target, a0, a1, a2)); }
32.544 + protected Object invoke_D3(Object a0, Object a1, Object a2) { return convert_D(invoker.<double>invoke(target, a0, a1, a2)); }
32.545 + }
32.546 + static class A4 extends Adapter {
32.547 + protected A4(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
32.548 + protected A4(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.549 + { super(e, i, c, t); }
32.550 + protected A4 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.551 + { return new A4(e, i, c, t); }
32.552 + protected Object invoke_L4(Object a0, Object a1, Object a2, Object a3) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3)); }
32.553 + protected Object invoke_I4(Object a0, Object a1, Object a2, Object a3) { return convert_I(invoker.<int >invoke(target, a0, a1, a2, a3)); }
32.554 + protected Object invoke_J4(Object a0, Object a1, Object a2, Object a3) { return convert_J(invoker.<long >invoke(target, a0, a1, a2, a3)); }
32.555 + protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3) { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3)); }
32.556 + protected Object invoke_D4(Object a0, Object a1, Object a2, Object a3) { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3)); }
32.557 + }
32.558 + static class A5 extends Adapter {
32.559 + protected A5(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
32.560 + protected A5(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.561 + { super(e, i, c, t); }
32.562 + protected A5 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.563 + { return new A5(e, i, c, t); }
32.564 + protected Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4)); }
32.565 + protected Object invoke_I5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_I(invoker.<int >invoke(target, a0, a1, a2, a3, a4)); }
32.566 + protected Object invoke_J5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_J(invoker.<long >invoke(target, a0, a1, a2, a3, a4)); }
32.567 + protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4)); }
32.568 + protected Object invoke_D5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4)); }
32.569 + }
32.570 + static class A6 extends Adapter {
32.571 + protected A6(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
32.572 + protected A6(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.573 + { super(e, i, c, t); }
32.574 + protected A6 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.575 + { return new A6(e, i, c, t); }
32.576 + protected Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5)); }
32.577 + protected Object invoke_I6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_I(invoker.<int >invoke(target, a0, a1, a2, a3, a4, a5)); }
32.578 + protected Object invoke_J6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_J(invoker.<long >invoke(target, a0, a1, a2, a3, a4, a5)); }
32.579 + protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4, a5)); }
32.580 + protected Object invoke_D6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4, a5)); }
32.581 + }
32.582 + static class A7 extends Adapter {
32.583 + protected A7(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
32.584 + protected A7(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.585 + { super(e, i, c, t); }
32.586 + protected A7 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.587 + { return new A7(e, i, c, t); }
32.588 + protected Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6)); }
32.589 + protected Object invoke_I7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_I(invoker.<int >invoke(target, a0, a1, a2, a3, a4, a5, a6)); }
32.590 + protected Object invoke_J7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_J(invoker.<long >invoke(target, a0, a1, a2, a3, a4, a5, a6)); }
32.591 + protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4, a5, a6)); }
32.592 + protected Object invoke_D7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4, a5, a6)); }
32.593 + }
32.594 + static class A8 extends Adapter {
32.595 + protected A8(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
32.596 + protected A8(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.597 + { super(e, i, c, t); }
32.598 + protected A8 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.599 + { return new A8(e, i, c, t); }
32.600 + protected Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
32.601 + protected Object invoke_I8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_I(invoker.<int >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
32.602 + protected Object invoke_J8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_J(invoker.<long >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
32.603 + protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
32.604 + protected Object invoke_D8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
32.605 + }
32.606 + static class A9 extends Adapter {
32.607 + protected A9(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
32.608 + protected A9(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.609 + { super(e, i, c, t); }
32.610 + protected A9 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.611 + { return new A9(e, i, c, t); }
32.612 + protected Object invoke_L9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
32.613 + protected Object invoke_I9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_I(invoker.<int >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
32.614 + protected Object invoke_J9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_J(invoker.<long >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
32.615 + protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
32.616 + protected Object invoke_D9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
32.617 + }
32.618 + static class A10 extends Adapter {
32.619 + protected A10(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
32.620 + protected A10(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.621 + { super(e, i, c, t); }
32.622 + protected A10 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
32.623 + { return new A10(e, i, c, t); }
32.624 + protected Object invoke_L10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
32.625 + protected Object invoke_I10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_I(invoker.<int >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
32.626 + protected Object invoke_J10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_J(invoker.<long >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
32.627 + protected Object invoke_F10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
32.628 + protected Object invoke_D10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
32.629 + }
32.630 +}
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
33.2 +++ b/src/share/classes/sun/dyn/Invokers.java Tue May 05 23:12:47 2009 -0700
33.3 @@ -0,0 +1,86 @@
33.4 +/*
33.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
33.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33.7 + *
33.8 + * This code is free software; you can redistribute it and/or modify it
33.9 + * under the terms of the GNU General Public License version 2 only, as
33.10 + * published by the Free Software Foundation. Sun designates this
33.11 + * particular file as subject to the "Classpath" exception as provided
33.12 + * by Sun in the LICENSE file that accompanied this code.
33.13 + *
33.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
33.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
33.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
33.17 + * version 2 for more details (a copy is included in the LICENSE file that
33.18 + * accompanied this code).
33.19 + *
33.20 + * You should have received a copy of the GNU General Public License version
33.21 + * 2 along with this work; if not, write to the Free Software Foundation,
33.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
33.23 + *
33.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
33.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
33.26 + * have any questions.
33.27 + */
33.28 +
33.29 +package sun.dyn;
33.30 +
33.31 +import java.dyn.MethodHandle;
33.32 +import java.dyn.MethodHandles;
33.33 +import java.dyn.MethodType;
33.34 +
33.35 +
33.36 +/**
33.37 + * Construction and caching of often-used invokers.
33.38 + * @author jrose
33.39 + */
33.40 +public class Invokers {
33.41 + // exact type (sans leading taget MH) for the outgoing call
33.42 + private final MethodType targetType;
33.43 +
33.44 + // exact invoker for the outgoing call
33.45 + private /*lazy*/ MethodHandle exactInvoker;
33.46 +
33.47 + // generic (untyped) invoker for the outgoing call
33.48 + private /*lazy*/ MethodHandle genericInvoker;
33.49 +
33.50 + /** Compute and cache information common to all collecting adapters
33.51 + * that implement members of the erasure-family of the given erased type.
33.52 + */
33.53 + public Invokers(Access token, MethodType targetType) {
33.54 + Access.check(token);
33.55 + this.targetType = targetType;
33.56 + }
33.57 +
33.58 + public static MethodType invokerType(MethodType targetType) {
33.59 + return targetType.insertParameterType(0, MethodHandle.class);
33.60 + }
33.61 +
33.62 + public MethodHandle exactInvoker() {
33.63 + MethodHandle invoker = exactInvoker;
33.64 + if (invoker != null) return invoker;
33.65 + invoker = MethodHandleImpl.IMPL_LOOKUP.findVirtual(MethodHandle.class, "invoke", targetType);
33.66 + if (invoker == null) throw new InternalError("JVM cannot find invoker for "+targetType);
33.67 + assert(invokerType(targetType) == invoker.type());
33.68 + exactInvoker = invoker;
33.69 + return invoker;
33.70 + }
33.71 +
33.72 + public MethodHandle genericInvoker() {
33.73 + MethodHandle invoker1 = exactInvoker();
33.74 + MethodHandle invoker = genericInvoker;
33.75 + if (invoker != null) return invoker;
33.76 + MethodType genericType = targetType.generic();
33.77 + invoker = MethodHandles.convertArguments(invoker1, invokerType(genericType));
33.78 + genericInvoker = invoker;
33.79 + return invoker;
33.80 + }
33.81 +
33.82 + public MethodHandle varargsInvoker() {
33.83 + throw new UnsupportedOperationException("NYI");
33.84 + }
33.85 +
33.86 + public String toString() {
33.87 + return "Invokers"+targetType;
33.88 + }
33.89 +}
34.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
34.2 +++ b/src/share/classes/sun/dyn/MemberName.java Tue May 05 23:12:47 2009 -0700
34.3 @@ -0,0 +1,552 @@
34.4 +/*
34.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
34.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
34.7 + *
34.8 + * This code is free software; you can redistribute it and/or modify it
34.9 + * under the terms of the GNU General Public License version 2 only, as
34.10 + * published by the Free Software Foundation. Sun designates this
34.11 + * particular file as subject to the "Classpath" exception as provided
34.12 + * by Sun in the LICENSE file that accompanied this code.
34.13 + *
34.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
34.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
34.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
34.17 + * version 2 for more details (a copy is included in the LICENSE file that
34.18 + * accompanied this code).
34.19 + *
34.20 + * You should have received a copy of the GNU General Public License version
34.21 + * 2 along with this work; if not, write to the Free Software Foundation,
34.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
34.23 + *
34.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
34.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
34.26 + * have any questions.
34.27 + */
34.28 +
34.29 +package sun.dyn;
34.30 +
34.31 +import sun.dyn.util.BytecodeSignature;
34.32 +import java.dyn.*;
34.33 +import java.lang.reflect.Constructor;
34.34 +import java.lang.reflect.Field;
34.35 +import java.lang.reflect.Method;
34.36 +import java.lang.reflect.Member;
34.37 +import java.lang.reflect.Modifier;
34.38 +import java.util.ArrayList;
34.39 +import java.util.Collections;
34.40 +import java.util.Iterator;
34.41 +import java.util.List;
34.42 +import static sun.dyn.MethodHandleNatives.Constants.*;
34.43 +
34.44 +/**
34.45 + * Compact information which fully characterizes a method or field reference.
34.46 + * When resolved, it includes a direct pointer to JVM metadata.
34.47 + * This representation is stateless and only decriptive.
34.48 + * It provides no private information and no capability to use the member.
34.49 + * <p>
34.50 + * By contrast, a java.lang.reflect.Method contains fuller information
34.51 + * about the internals of a method (except its bytecodes) and also
34.52 + * allows invocation. A MemberName is much lighter than a reflect.Method,
34.53 + * since it contains about 7 fields to Method's 16 (plus its sub-arrays),
34.54 + * and those seven fields omit much of the information in Method.
34.55 + * @author jrose
34.56 + */
34.57 +public final class MemberName implements Member, Cloneable {
34.58 + private Class<?> clazz; // class in which the method is defined
34.59 + private String name; // may be null if not yet materialized
34.60 + private Object type; // may be null if not yet materialized
34.61 + private int flags; // modifier bits; see reflect.Modifier
34.62 +
34.63 + private Object vmtarget; // VM-specific target value
34.64 + private int vmindex; // method index within class or interface
34.65 +
34.66 + { vmindex = VM_INDEX_UNINITIALIZED; }
34.67 +
34.68 + public Class<?> getDeclaringClass() {
34.69 + if (clazz == null && isResolved()) {
34.70 + expandFromVM();
34.71 + }
34.72 + return clazz;
34.73 + }
34.74 +
34.75 + public ClassLoader getClassLoader() {
34.76 + return clazz.getClassLoader();
34.77 + }
34.78 +
34.79 + public String getName() {
34.80 + if (name == null) {
34.81 + expandFromVM();
34.82 + if (name == null) return null;
34.83 + }
34.84 + return name;
34.85 + }
34.86 +
34.87 + public MethodType getMethodType() {
34.88 + if (type == null) {
34.89 + expandFromVM();
34.90 + if (type == null) return null;
34.91 + }
34.92 + if (!isInvocable())
34.93 + throw newIllegalArgumentException("not invocable, no method type");
34.94 + if (type instanceof MethodType) {
34.95 + return (MethodType) type;
34.96 + }
34.97 + if (type instanceof String) {
34.98 + String sig = (String) type;
34.99 + MethodType res = MethodType.fromBytecodeString(sig, getClassLoader());
34.100 + this.type = res;
34.101 + return res;
34.102 + }
34.103 + if (type instanceof Object[]) {
34.104 + Object[] typeInfo = (Object[]) type;
34.105 + Class<?>[] ptypes = (Class<?>[]) typeInfo[1];
34.106 + Class<?> rtype = (Class<?>) typeInfo[0];
34.107 + MethodType res = MethodType.make(rtype, ptypes);
34.108 + this.type = res;
34.109 + return res;
34.110 + }
34.111 + throw new InternalError("bad method type "+type);
34.112 + }
34.113 +
34.114 + public MethodType getInvocationType() {
34.115 + MethodType itype = getMethodType();
34.116 + if (!isStatic())
34.117 + itype = itype.insertParameterType(0, clazz);
34.118 + return itype;
34.119 + }
34.120 +
34.121 + public Class<?>[] getParameterTypes() {
34.122 + return getMethodType().parameterArray();
34.123 + }
34.124 +
34.125 + public Class<?> getReturnType() {
34.126 + return getMethodType().returnType();
34.127 + }
34.128 +
34.129 + public Class<?> getFieldType() {
34.130 + if (type == null) {
34.131 + expandFromVM();
34.132 + if (type == null) return null;
34.133 + }
34.134 + if (isInvocable())
34.135 + throw newIllegalArgumentException("not a field or nested class, no simple type");
34.136 + if (type instanceof Class<?>) {
34.137 + return (Class<?>) type;
34.138 + }
34.139 + if (type instanceof String) {
34.140 + String sig = (String) type;
34.141 + MethodType mtype = MethodType.fromBytecodeString("()"+sig, getClassLoader());
34.142 + Class<?> res = mtype.returnType();
34.143 + this.type = res;
34.144 + return res;
34.145 + }
34.146 + throw new InternalError("bad field type "+type);
34.147 + }
34.148 +
34.149 + public Object getType() {
34.150 + return (isInvocable() ? getMethodType() : getFieldType());
34.151 + }
34.152 +
34.153 + public String getSignature() {
34.154 + if (type == null) {
34.155 + expandFromVM();
34.156 + if (type == null) return null;
34.157 + }
34.158 + if (type instanceof String)
34.159 + return (String) type;
34.160 + if (isInvocable())
34.161 + return BytecodeSignature.unparse(getMethodType());
34.162 + else
34.163 + return BytecodeSignature.unparse(getFieldType());
34.164 + }
34.165 +
34.166 + public int getModifiers() {
34.167 + return (flags & RECOGNIZED_MODIFIERS);
34.168 + }
34.169 +
34.170 + private void setFlags(int flags) {
34.171 + this.flags = flags;
34.172 + assert(testAnyFlags(ALL_KINDS));
34.173 + }
34.174 +
34.175 + private boolean testFlags(int mask, int value) {
34.176 + return (flags & mask) == value;
34.177 + }
34.178 + private boolean testAllFlags(int mask) {
34.179 + return testFlags(mask, mask);
34.180 + }
34.181 + private boolean testAnyFlags(int mask) {
34.182 + return !testFlags(mask, 0);
34.183 + }
34.184 +
34.185 + public boolean isStatic() {
34.186 + return Modifier.isStatic(flags);
34.187 + }
34.188 + public boolean isPublic() {
34.189 + return Modifier.isPublic(flags);
34.190 + }
34.191 + public boolean isPrivate() {
34.192 + return Modifier.isPrivate(flags);
34.193 + }
34.194 + public boolean isProtected() {
34.195 + return Modifier.isProtected(flags);
34.196 + }
34.197 + public boolean isFinal() {
34.198 + return Modifier.isFinal(flags);
34.199 + }
34.200 + public boolean isAbstract() {
34.201 + return Modifier.isAbstract(flags);
34.202 + }
34.203 + // let the rest (native, volatile, transient, etc.) be tested via Modifier.isFoo
34.204 +
34.205 + // unofficial modifier flags, used by HotSpot:
34.206 + static final int BRIDGE = 0x00000040;
34.207 + static final int VARARGS = 0x00000080;
34.208 + static final int SYNTHETIC = 0x00001000;
34.209 + static final int ANNOTATION= 0x00002000;
34.210 + static final int ENUM = 0x00004000;
34.211 + public boolean isBridge() {
34.212 + return testAllFlags(IS_METHOD | BRIDGE);
34.213 + }
34.214 + public boolean isVarargs() {
34.215 + return testAllFlags(VARARGS) && isInvocable();
34.216 + }
34.217 + public boolean isSynthetic() {
34.218 + return testAllFlags(SYNTHETIC);
34.219 + }
34.220 +
34.221 + static final String CONSTRUCTOR_NAME = "<init>"; // the ever-popular
34.222 +
34.223 + // modifiers exported by the JVM:
34.224 + static final int RECOGNIZED_MODIFIERS = 0xFFFF;
34.225 +
34.226 + // private flags, not part of RECOGNIZED_MODIFIERS:
34.227 + static final int
34.228 + IS_METHOD = MN_IS_METHOD, // method (not constructor)
34.229 + IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor
34.230 + IS_FIELD = MN_IS_FIELD, // field
34.231 + IS_TYPE = MN_IS_TYPE; // nested type
34.232 + static final int // for MethodHandleNatives.getMembers
34.233 + SEARCH_SUPERCLASSES = MN_SEARCH_SUPERCLASSES,
34.234 + SEARCH_INTERFACES = MN_SEARCH_INTERFACES;
34.235 +
34.236 + static final int ALL_ACCESS = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED;
34.237 + static final int ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE;
34.238 + static final int IS_INVOCABLE = IS_METHOD | IS_CONSTRUCTOR;
34.239 + static final int IS_FIELD_OR_METHOD = IS_METHOD | IS_FIELD;
34.240 + static final int SEARCH_ALL_SUPERS = SEARCH_SUPERCLASSES | SEARCH_INTERFACES;
34.241 +
34.242 + public boolean isInvocable() {
34.243 + return testAnyFlags(IS_INVOCABLE);
34.244 + }
34.245 + public boolean isFieldOrMethod() {
34.246 + return testAnyFlags(IS_FIELD_OR_METHOD);
34.247 + }
34.248 + public boolean isMethod() {
34.249 + return testAllFlags(IS_METHOD);
34.250 + }
34.251 + public boolean isConstructor() {
34.252 + return testAllFlags(IS_CONSTRUCTOR);
34.253 + }
34.254 + public boolean isField() {
34.255 + return testAllFlags(IS_FIELD);
34.256 + }
34.257 + public boolean isType() {
34.258 + return testAllFlags(IS_TYPE);
34.259 + }
34.260 + public boolean isPackage() {
34.261 + return !testAnyFlags(ALL_ACCESS);
34.262 + }
34.263 +
34.264 + /** Initialize a query. It is not resolved. */
34.265 + private void init(Class<?> defClass, String name, Object type, int flags) {
34.266 + // defining class is allowed to be null (for a naked name/type pair)
34.267 + name.toString(); // null check
34.268 + type.equals(type); // null check
34.269 + // fill in fields:
34.270 + this.clazz = defClass;
34.271 + this.name = name;
34.272 + this.type = type;
34.273 + setFlags(flags);
34.274 + assert(!isResolved());
34.275 + }
34.276 +
34.277 + private void expandFromVM() {
34.278 + if (!isResolved()) return;
34.279 + if (type instanceof Object[])
34.280 + type = null; // don't saddle JVM w/ typeInfo
34.281 + MethodHandleNatives.expand(this);
34.282 + }
34.283 +
34.284 + // Capturing information from the Core Reflection API:
34.285 + private static int flagsMods(int flags, int mods) {
34.286 + assert((flags & RECOGNIZED_MODIFIERS) == 0);
34.287 + assert((mods & ~RECOGNIZED_MODIFIERS) == 0);
34.288 + return flags | mods;
34.289 + }
34.290 + public MemberName(Method m) {
34.291 + Object[] typeInfo = { m.getReturnType(), m.getParameterTypes() };
34.292 + init(m.getDeclaringClass(), m.getName(), typeInfo, flagsMods(IS_METHOD, m.getModifiers()));
34.293 + // fill in vmtarget, vmindex while we have m in hand:
34.294 + MethodHandleNatives.init(this, m);
34.295 + assert(isResolved());
34.296 + }
34.297 + public MemberName(Constructor ctor) {
34.298 + Object[] typeInfo = { void.class, ctor.getParameterTypes() };
34.299 + init(ctor.getDeclaringClass(), CONSTRUCTOR_NAME, typeInfo, flagsMods(IS_CONSTRUCTOR, ctor.getModifiers()));
34.300 + // fill in vmtarget, vmindex while we have ctor in hand:
34.301 + MethodHandleNatives.init(this, ctor);
34.302 + assert(isResolved());
34.303 + }
34.304 + public MemberName(Field fld) {
34.305 + init(fld.getDeclaringClass(), fld.getName(), fld.getType(), flagsMods(IS_FIELD, fld.getModifiers()));
34.306 + // fill in vmtarget, vmindex while we have fld in hand:
34.307 + MethodHandleNatives.init(this, fld);
34.308 + assert(isResolved());
34.309 + }
34.310 + public MemberName(Class<?> type) {
34.311 + init(type.getDeclaringClass(), type.getSimpleName(), type, flagsMods(IS_TYPE, type.getModifiers()));
34.312 + vmindex = 0; // isResolved
34.313 + assert(isResolved());
34.314 + }
34.315 +
34.316 + // bare-bones constructor; the JVM will fill it in
34.317 + MemberName() { }
34.318 +
34.319 + // locally useful cloner
34.320 + @Override protected MemberName clone() {
34.321 + try {
34.322 + return (MemberName) super.clone();
34.323 + } catch (CloneNotSupportedException ex) {
34.324 + throw new InternalError();
34.325 + }
34.326 + }
34.327 +
34.328 + // %%% define equals/hashcode?
34.329 +
34.330 + // Construction from symbolic parts, for queries:
34.331 + public MemberName(Class<?> defClass, String name, Class<?> type, int modifiers) {
34.332 + init(defClass, name, type, IS_FIELD | (modifiers & RECOGNIZED_MODIFIERS));
34.333 + }
34.334 + public MemberName(Class<?> defClass, String name, Class<?> type) {
34.335 + this(defClass, name, type, 0);
34.336 + }
34.337 + public MemberName(Class<?> defClass, String name, MethodType type, int modifiers) {
34.338 + int flagBit = (name.equals(CONSTRUCTOR_NAME) ? IS_CONSTRUCTOR : IS_METHOD);
34.339 + init(defClass, name, type, flagBit | (modifiers & RECOGNIZED_MODIFIERS));
34.340 + }
34.341 + public MemberName(Class<?> defClass, String name, MethodType type) {
34.342 + this(defClass, name, type, 0);
34.343 + }
34.344 +
34.345 + boolean isResolved() {
34.346 + return (vmindex != VM_INDEX_UNINITIALIZED);
34.347 + }
34.348 +
34.349 + public boolean hasReceiverTypeDispatch() {
34.350 + return (isMethod() && getVMIndex(Access.TOKEN) >= 0);
34.351 + }
34.352 +
34.353 + @Override
34.354 + public String toString() {
34.355 + if (isType())
34.356 + return type.toString(); // class java.lang.String
34.357 + // else it is a field, method, or constructor
34.358 + StringBuilder buf = new StringBuilder();
34.359 + if (getDeclaringClass() != null) {
34.360 + buf.append(getName(clazz));
34.361 + buf.append('.');
34.362 + }
34.363 + buf.append(getName());
34.364 + if (!isInvocable()) buf.append('/');
34.365 + buf.append(getName(getType()));
34.366 + /*
34.367 + buf.append('/');
34.368 + // key: Public, private, pRotected, sTatic, Final, sYnchronized,
34.369 + // transient/Varargs, native, (interface), abstract, sTrict, sYnthetic,
34.370 + // (annotation), Enum, (unused)
34.371 + final String FIELD_MOD_CHARS = "PprTF?vt????Y?E?";
34.372 + final String METHOD_MOD_CHARS = "PprTFybVn?atY???";
34.373 + String modChars = (isInvocable() ? METHOD_MOD_CHARS : FIELD_MOD_CHARS);
34.374 + for (int i = 0; i < modChars.length(); i++) {
34.375 + if ((flags & (1 << i)) != 0) {
34.376 + char mc = modChars.charAt(i);
34.377 + if (mc != '.')
34.378 + buf.append(mc);
34.379 + }
34.380 + }
34.381 + */
34.382 + return buf.toString();
34.383 + }
34.384 + private static String getName(Object obj) {
34.385 + if (obj instanceof Class<?>)
34.386 + return ((Class<?>)obj).getName();
34.387 + return obj.toString();
34.388 + }
34.389 +
34.390 + // Queries to the JVM:
34.391 + public int getVMIndex(Access token) {
34.392 + Access.check(token);
34.393 + if (!isResolved())
34.394 + throw newIllegalStateException("not resolved");
34.395 + return vmindex;
34.396 + }
34.397 +// public Object getVMTarget(Access token) {
34.398 +// Access.check(token);
34.399 +// if (!isResolved())
34.400 +// throw newIllegalStateException("not resolved");
34.401 +// return vmtarget;
34.402 +// }
34.403 + private RuntimeException newIllegalStateException(String message) {
34.404 + return new IllegalStateException(message+": "+this);
34.405 + }
34.406 +
34.407 + // handy shared exception makers (they simplify the common case code)
34.408 + public static RuntimeException newIllegalArgumentException(String message) {
34.409 + return new IllegalArgumentException(message);
34.410 + }
34.411 + public static NoAccessException newNoAccessException(MemberName name, Class<?> lookupClass) {
34.412 + return newNoAccessException("cannot access", name, lookupClass);
34.413 + }
34.414 + public static NoAccessException newNoAccessException(String message,
34.415 + MemberName name, Class<?> lookupClass) {
34.416 + message += ": " + name;
34.417 + if (lookupClass != null) message += ", from " + lookupClass.getName();
34.418 + return new NoAccessException(message);
34.419 + }
34.420 +
34.421 + /** Actually making a query requires an access check. */
34.422 + public static Factory getFactory(Access token) {
34.423 + Access.check(token);
34.424 + return Factory.INSTANCE;
34.425 + }
34.426 + public static Factory getFactory() {
34.427 + return getFactory(Access.getToken());
34.428 + }
34.429 + public static class Factory {
34.430 + private Factory() { } // singleton pattern
34.431 + static Factory INSTANCE = new Factory();
34.432 +
34.433 + private static int ALLOWED_FLAGS = SEARCH_ALL_SUPERS | ALL_KINDS;
34.434 +
34.435 + /// Queries
34.436 + List<MemberName> getMembers(Class<?> defc,
34.437 + String matchName, Object matchType,
34.438 + int matchFlags, Class<?> lookupClass) {
34.439 + matchFlags &= ALLOWED_FLAGS;
34.440 + String matchSig = null;
34.441 + if (matchType != null) {
34.442 + matchSig = BytecodeSignature.unparse(matchType);
34.443 + if (matchSig.startsWith("("))
34.444 + matchFlags &= ~(ALL_KINDS & ~IS_INVOCABLE);
34.445 + else
34.446 + matchFlags &= ~(ALL_KINDS & ~IS_FIELD);
34.447 + }
34.448 + final int BUF_MAX = 0x2000;
34.449 + int len1 = matchName == null ? 10 : matchType == null ? 4 : 1;
34.450 + MemberName[] buf = newMemberBuffer(len1);
34.451 + int totalCount = 0;
34.452 + ArrayList<MemberName[]> bufs = null;
34.453 + for (;;) {
34.454 + int bufCount = MethodHandleNatives.getMembers(defc,
34.455 + matchName, matchSig, matchFlags,
34.456 + MethodHandleNatives.asNativeCaller(lookupClass),
34.457 + totalCount, buf);
34.458 + if (bufCount <= buf.length) {
34.459 + if (bufCount >= 0)
34.460 + totalCount += bufCount;
34.461 + break;
34.462 + }
34.463 + // JVM returned tp us with an intentional overflow!
34.464 + totalCount += buf.length;
34.465 + int excess = bufCount - buf.length;
34.466 + if (bufs == null) bufs = new ArrayList<MemberName[]>(1);
34.467 + bufs.add(buf);
34.468 + int len2 = buf.length;
34.469 + len2 = Math.max(len2, excess);
34.470 + len2 = Math.max(len2, totalCount / 4);
34.471 + buf = newMemberBuffer(Math.min(BUF_MAX, len2));
34.472 + }
34.473 + ArrayList<MemberName> result = new ArrayList<MemberName>(totalCount);
34.474 + if (bufs != null) {
34.475 + for (MemberName[] buf0 : bufs) {
34.476 + Collections.addAll(result, buf0);
34.477 + }
34.478 + }
34.479 + Collections.addAll(result, buf);
34.480 + // Signature matching is not the same as type matching, since
34.481 + // one signature might correspond to several types.
34.482 + // So if matchType is a Class or MethodType, refilter the results.
34.483 + if (matchType != null && matchType != matchSig) {
34.484 + for (Iterator<MemberName> it = result.iterator(); it.hasNext();) {
34.485 + MemberName m = it.next();
34.486 + if (!matchType.equals(m.getType()))
34.487 + it.remove();
34.488 + }
34.489 + }
34.490 + return result;
34.491 + }
34.492 + boolean resolveInPlace(MemberName m, boolean searchSupers, Class<?> lookupClass) {
34.493 + Class<?> caller = MethodHandleNatives.asNativeCaller(lookupClass);
34.494 + MethodHandleNatives.resolve(m, caller);
34.495 + if (m.isResolved()) return true;
34.496 + int matchFlags = m.flags | (searchSupers ? SEARCH_ALL_SUPERS : 0);
34.497 + String matchSig = m.getSignature();
34.498 + MemberName[] buf = { m };
34.499 + int n = MethodHandleNatives.getMembers(m.getDeclaringClass(),
34.500 + m.getName(), matchSig, matchFlags, caller, 0, buf);
34.501 + if (n != 1) return false;
34.502 + return m.isResolved();
34.503 + }
34.504 + public MemberName resolveOrNull(MemberName m, boolean searchSupers, Class<?> lookupClass) {
34.505 + MemberName result = m.clone();
34.506 + if (resolveInPlace(result, searchSupers, lookupClass))
34.507 + return result;
34.508 + return null;
34.509 + }
34.510 + public MemberName resolveOrFail(MemberName m, boolean searchSupers, Class<?> lookupClass) {
34.511 + MemberName result = resolveOrNull(m, searchSupers, lookupClass);
34.512 + if (result != null)
34.513 + return result;
34.514 + throw newNoAccessException(m, lookupClass);
34.515 + }
34.516 + public List<MemberName> getMethods(Class<?> defc, boolean searchSupers,
34.517 + Class<?> lookupClass) {
34.518 + return getMethods(defc, searchSupers, null, null, lookupClass);
34.519 + }
34.520 + public List<MemberName> getMethods(Class<?> defc, boolean searchSupers,
34.521 + String name, MethodType type, Class<?> lookupClass) {
34.522 + int matchFlags = IS_METHOD | (searchSupers ? SEARCH_ALL_SUPERS : 0);
34.523 + return getMembers(defc, name, type, matchFlags, lookupClass);
34.524 + }
34.525 + public List<MemberName> getConstructors(Class<?> defc, Class<?> lookupClass) {
34.526 + return getMembers(defc, null, null, IS_CONSTRUCTOR, lookupClass);
34.527 + }
34.528 + public List<MemberName> getFields(Class<?> defc, boolean searchSupers,
34.529 + Class<?> lookupClass) {
34.530 + return getFields(defc, searchSupers, null, null, lookupClass);
34.531 + }
34.532 + public List<MemberName> getFields(Class<?> defc, boolean searchSupers,
34.533 + String name, Class<?> type, Class<?> lookupClass) {
34.534 + int matchFlags = IS_FIELD | (searchSupers ? SEARCH_ALL_SUPERS : 0);
34.535 + return getMembers(defc, name, type, matchFlags, lookupClass);
34.536 + }
34.537 + public List<MemberName> getNestedTypes(Class<?> defc, boolean searchSupers,
34.538 + Class<?> lookupClass) {
34.539 + int matchFlags = IS_TYPE | (searchSupers ? SEARCH_ALL_SUPERS : 0);
34.540 + return getMembers(defc, null, null, matchFlags, lookupClass);
34.541 + }
34.542 + private static MemberName[] newMemberBuffer(int length) {
34.543 + MemberName[] buf = new MemberName[length];
34.544 + // fill the buffer with dummy structs for the JVM to fill in
34.545 + for (int i = 0; i < length; i++)
34.546 + buf[i] = new MemberName();
34.547 + return buf;
34.548 + }
34.549 + }
34.550 +
34.551 +// static {
34.552 +// System.out.println("Hello world! My methods are:");
34.553 +// System.out.println(Factory.INSTANCE.getMethods(MemberName.class, true, null));
34.554 +// }
34.555 +}
35.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
35.2 +++ b/src/share/classes/sun/dyn/MethodHandleImpl.java Tue May 05 23:12:47 2009 -0700
35.3 @@ -0,0 +1,355 @@
35.4 +/*
35.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
35.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
35.7 + *
35.8 + * This code is free software; you can redistribute it and/or modify it
35.9 + * under the terms of the GNU General Public License version 2 only, as
35.10 + * published by the Free Software Foundation. Sun designates this
35.11 + * particular file as subject to the "Classpath" exception as provided
35.12 + * by Sun in the LICENSE file that accompanied this code.
35.13 + *
35.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
35.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
35.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
35.17 + * version 2 for more details (a copy is included in the LICENSE file that
35.18 + * accompanied this code).
35.19 + *
35.20 + * You should have received a copy of the GNU General Public License version
35.21 + * 2 along with this work; if not, write to the Free Software Foundation,
35.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
35.23 + *
35.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
35.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
35.26 + * have any questions.
35.27 + */
35.28 +
35.29 +package sun.dyn;
35.30 +
35.31 +import java.dyn.MethodHandle;
35.32 +import java.dyn.MethodHandles;
35.33 +import java.dyn.MethodHandles.Lookup;
35.34 +import java.dyn.MethodType;
35.35 +import sun.dyn.util.VerifyType;
35.36 +import java.dyn.NoAccessException;
35.37 +import static sun.dyn.MemberName.newIllegalArgumentException;
35.38 +import static sun.dyn.MemberName.newNoAccessException;
35.39 +
35.40 +/**
35.41 + * Base class for method handles, containing JVM-specific fields and logic.
35.42 + * TO DO: It should not be a base class.
35.43 + * @author jrose
35.44 + */
35.45 +public abstract class MethodHandleImpl {
35.46 +
35.47 + // Fields which really belong in MethodHandle:
35.48 + private byte vmentry; // adapter stub or method entry point
35.49 + //private int vmslots; // optionally, hoist type.form.vmslots
35.50 + protected Object vmtarget; // VM-specific, class-specific target value
35.51 + //MethodType type; // defined in MethodHandle
35.52 +
35.53 + // TO DO: vmtarget should be invisible to Java, since the JVM puts internal
35.54 + // managed pointers into it. Making it visible exposes it to debuggers,
35.55 + // which can cause errors when they treat the pointer as an Object.
35.56 +
35.57 + // These two dummy fields are present to force 'I' and 'J' signatures
35.58 + // into this class's constant pool, so they can be transferred
35.59 + // to vmentry when this class is loaded.
35.60 + static final int INT_FIELD = 0;
35.61 + static final long LONG_FIELD = 0;
35.62 +
35.63 + // type is defined in java.dyn.MethodHandle, which is platform-independent
35.64 +
35.65 + // vmentry (a void* field) is used *only* by by the JVM.
35.66 + // The JVM adjusts its type to int or long depending on system wordsize.
35.67 + // Since it is statically typed as neither int nor long, it is impossible
35.68 + // to use this field from Java bytecode. (Please don't try to, either.)
35.69 +
35.70 + // The vmentry is an assembly-language stub which is jumped to
35.71 + // immediately after the method type is verified.
35.72 + // For a direct MH, this stub loads the vmtarget's entry point
35.73 + // and jumps to it.
35.74 +
35.75 + /**
35.76 + * VM-based method handles must have a security token.
35.77 + * This security token can only be obtained by trusted code.
35.78 + * Do not create method handles directly; use factory methods.
35.79 + */
35.80 + public MethodHandleImpl(Access token) {
35.81 + Access.check(token);
35.82 + }
35.83 +
35.84 + /** Initialize the method type form to participate in JVM calls.
35.85 + * This is done once for each erased type.
35.86 + */
35.87 + public static void init(Access token, MethodType self) {
35.88 + Access.check(token);
35.89 + if (MethodHandleNatives.JVM_SUPPORT)
35.90 + MethodHandleNatives.init(self);
35.91 + }
35.92 +
35.93 + /// Factory methods to create method handles:
35.94 +
35.95 + private static final MemberName.Factory LOOKUP = MemberName.Factory.INSTANCE;
35.96 +
35.97 + static private Lookup IMPL_LOOKUP_INIT;
35.98 +
35.99 + public static void initLookup(Access token, Lookup lookup) {
35.100 + Access.check(token);
35.101 + if (IMPL_LOOKUP_INIT != null || lookup.lookupClass() != Access.class)
35.102 + throw new InternalError();
35.103 + IMPL_LOOKUP_INIT = lookup;
35.104 + }
35.105 +
35.106 + public static Lookup getLookup(Access token) {
35.107 + Access.check(token);
35.108 + return IMPL_LOOKUP;
35.109 + }
35.110 +
35.111 + static {
35.112 + // Force initialization:
35.113 + Lookup.PUBLIC_LOOKUP.lookupClass();
35.114 + if (IMPL_LOOKUP_INIT == null)
35.115 + throw new InternalError();
35.116 + }
35.117 +
35.118 + public static void initStatics() {
35.119 + // Trigger preceding sequence.
35.120 + }
35.121 +
35.122 + /** Shared secret with MethodHandles.Lookup, a copy of Lookup.IMPL_LOOKUP. */
35.123 + static final Lookup IMPL_LOOKUP = IMPL_LOOKUP_INIT;
35.124 +
35.125 +
35.126 + /** Look up a given method.
35.127 + * Callable only from java.dyn and related packages.
35.128 + * <p>
35.129 + * The resulting method handle type will be of the given type,
35.130 + * with a receiver type {@code rcvc} prepended if the member is not static.
35.131 + * <p>
35.132 + * Access checks are made as of the given lookup class.
35.133 + * In particular, if the method is protected and {@code defc} is in a
35.134 + * different package from the lookup class, then {@code rcvc} must be
35.135 + * the lookup class or a subclass.
35.136 + * @param token Proof that the lookup class has access to this package.
35.137 + * @param member Resolved method or constructor to call.
35.138 + * @param name Name of the desired method.
35.139 + * @param rcvc Receiver type of desired non-static method (else null)
35.140 + * @param doDispatch whether the method handle will test the receiver type
35.141 + * @param lookupClass access-check relative to this class
35.142 + * @return a direct handle to the matching method
35.143 + * @throws NoAccessException if the given method cannot be accessed by the lookup class
35.144 + */
35.145 + public static
35.146 + MethodHandle findMethod(Access token, MemberName method,
35.147 + boolean doDispatch, Class<?> lookupClass) {
35.148 + Access.check(token); // only trusted calls
35.149 + MethodType mtype = method.getMethodType();
35.150 + if (method.isStatic()) {
35.151 + doDispatch = false;
35.152 + } else {
35.153 + // adjust the advertised receiver type to be exactly the one requested
35.154 + // (in the case of invokespecial, this will be the calling class)
35.155 + mtype = mtype.insertParameterType(0, method.getDeclaringClass());
35.156 + if (method.isConstructor())
35.157 + doDispatch = true;
35.158 + }
35.159 + DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, lookupClass);
35.160 + if (!mh.isValid())
35.161 + throw newNoAccessException(method, lookupClass);
35.162 + return mh;
35.163 + }
35.164 +
35.165 + public static
35.166 + MethodHandle accessField(Access token,
35.167 + MemberName member, boolean isSetter,
35.168 + Class<?> lookupClass) {
35.169 + Access.check(token);
35.170 + // FIXME: Use sun.misc.Unsafe to dig up the dirt on the field.
35.171 + throw new UnsupportedOperationException("Not yet implemented");
35.172 + }
35.173 +
35.174 + public static
35.175 + MethodHandle accessArrayElement(Access token,
35.176 + Class<?> arrayClass, boolean isSetter) {
35.177 + Access.check(token);
35.178 + if (!arrayClass.isArray())
35.179 + throw newIllegalArgumentException("not an array: "+arrayClass);
35.180 + // FIXME: Use sun.misc.Unsafe to dig up the dirt on the array.
35.181 + throw new UnsupportedOperationException("Not yet implemented");
35.182 + }
35.183 +
35.184 + /** Bind a predetermined first argument to the given direct method handle.
35.185 + * Callable only from MethodHandles.
35.186 + * @param token Proof that the caller has access to this package.
35.187 + * @param target Any direct method handle.
35.188 + * @param receiver Receiver (or first static method argument) to pre-bind.
35.189 + * @return a BoundMethodHandle for the given DirectMethodHandle, or null if it does not exist
35.190 + */
35.191 + public static
35.192 + MethodHandle bindReceiver(Access token,
35.193 + MethodHandle target, Object receiver) {
35.194 + Access.check(token);
35.195 + if (target instanceof DirectMethodHandle)
35.196 + return new BoundMethodHandle((DirectMethodHandle)target, receiver, 0);
35.197 + return null; // let caller try something else
35.198 + }
35.199 +
35.200 + /** Bind a predetermined argument to the given arbitrary method handle.
35.201 + * Callable only from MethodHandles.
35.202 + * @param token Proof that the caller has access to this package.
35.203 + * @param target Any method handle.
35.204 + * @param receiver Argument (which can be a boxed primitive) to pre-bind.
35.205 + * @return a suitable BoundMethodHandle
35.206 + */
35.207 + public static
35.208 + MethodHandle bindArgument(Access token,
35.209 + MethodHandle target, int argnum, Object receiver) {
35.210 + Access.check(token);
35.211 + throw new UnsupportedOperationException("NYI");
35.212 + }
35.213 +
35.214 + public static MethodHandle convertArguments(Access token,
35.215 + MethodHandle target,
35.216 + MethodType newType,
35.217 + MethodType oldType,
35.218 + int[] permutationOrNull) {
35.219 + Access.check(token);
35.220 + MethodHandle res = AdapterMethodHandle.makePairwiseConvert(token, newType, target);
35.221 + if (res != null)
35.222 + return res;
35.223 + int argc = oldType.parameterCount();
35.224 + // The JVM can't do it directly, so fill in the gap with a Java adapter.
35.225 + // TO DO: figure out what to put here from case-by-case experience
35.226 + // Use a heavier method: Convert all the arguments to Object,
35.227 + // then back to the desired types. We might have to use Java-based
35.228 + // method handles to do this.
35.229 + MethodType objType = MethodType.makeGeneric(argc);
35.230 + MethodHandle objTarget = AdapterMethodHandle.makePairwiseConvert(token, objType, target);
35.231 + if (objTarget == null)
35.232 + objTarget = FromGeneric.make(target);
35.233 + res = AdapterMethodHandle.makePairwiseConvert(token, newType, objTarget);
35.234 + if (res != null)
35.235 + return res;
35.236 + return ToGeneric.make(newType, objTarget);
35.237 + }
35.238 +
35.239 + public static MethodHandle spreadArguments(Access token,
35.240 + MethodHandle target,
35.241 + MethodType newType,
35.242 + int spreadArg) {
35.243 + Access.check(token);
35.244 + // TO DO: maybe allow the restarg to be Object and implicitly cast to Object[]
35.245 + MethodType oldType = target.type();
35.246 + // spread the last argument of newType to oldType
35.247 + int spreadCount = oldType.parameterCount() - spreadArg;
35.248 + Class<Object[]> spreadArgType = Object[].class;
35.249 + MethodHandle res = AdapterMethodHandle.makeSpreadArguments(token, newType, target, spreadArgType, spreadArg, spreadCount);
35.250 + if (res != null)
35.251 + return res;
35.252 + // try an intermediate adapter
35.253 + Class<?> spreadType = null;
35.254 + if (spreadArg < 0 || spreadArg >= newType.parameterCount()
35.255 + || !VerifyType.isSpreadArgType(spreadType = newType.parameterType(spreadArg)))
35.256 + throw newIllegalArgumentException("no restarg in "+newType);
35.257 + Class<?>[] ptypes = oldType.parameterArray();
35.258 + for (int i = 0; i < spreadCount; i++)
35.259 + ptypes[spreadArg + i] = VerifyType.spreadArgElementType(spreadType, i);
35.260 + MethodType midType = MethodType.make(newType.returnType(), ptypes);
35.261 + // after spreading, some arguments may need further conversion
35.262 + target = convertArguments(token, target, midType, oldType, null);
35.263 + if (target == null)
35.264 + throw new UnsupportedOperationException("NYI: convert "+midType+" =calls=> "+oldType);
35.265 + res = AdapterMethodHandle.makeSpreadArguments(token, newType, target, spreadArgType, spreadArg, spreadCount);
35.266 + return res;
35.267 + }
35.268 +
35.269 + public static MethodHandle collectArguments(Access token,
35.270 + MethodHandle target,
35.271 + MethodType newType,
35.272 + int collectArg) {
35.273 + if (collectArg > 0)
35.274 + throw new UnsupportedOperationException("NYI");
35.275 + throw new UnsupportedOperationException("NYI");
35.276 + }
35.277 + public static
35.278 + MethodHandle dropArguments(Access token, MethodHandle target,
35.279 + MethodType newType, int argnum) {
35.280 + Access.check(token);
35.281 + throw new UnsupportedOperationException("NYI");
35.282 + }
35.283 +
35.284 + public static
35.285 + MethodHandle makeGuardWithTest(Access token,
35.286 + final MethodHandle test,
35.287 + final MethodHandle target,
35.288 + final MethodHandle fallback) {
35.289 + Access.check(token);
35.290 + // %%% This is just a sketch. It needs to be de-boxed.
35.291 + // Adjust the handles to accept varargs lists.
35.292 + MethodType type = target.type();
35.293 + Class<?> rtype = type.returnType();
35.294 + if (type.parameterCount() != 1 || type.parameterType(0).isPrimitive()) {
35.295 + MethodType vatestType = MethodType.make(boolean.class, Object[].class);
35.296 + MethodType vatargetType = MethodType.make(rtype, Object[].class);
35.297 + MethodHandle vaguard = makeGuardWithTest(token,
35.298 + MethodHandles.spreadArguments(test, vatestType),
35.299 + MethodHandles.spreadArguments(target, vatargetType),
35.300 + MethodHandles.spreadArguments(fallback, vatargetType));
35.301 + return MethodHandles.collectArguments(vaguard, type);
35.302 + }
35.303 + if (rtype.isPrimitive()) {
35.304 + MethodType boxtype = type.changeReturnType(Object.class);
35.305 + MethodHandle boxguard = makeGuardWithTest(token,
35.306 + test,
35.307 + MethodHandles.convertArguments(target, boxtype),
35.308 + MethodHandles.convertArguments(fallback, boxtype));
35.309 + return MethodHandles.convertArguments(boxguard, type);
35.310 + }
35.311 + // Got here? Reduced calling sequence to Object(Object).
35.312 + class Guarder {
35.313 + Object invoke(Object x) {
35.314 + // If javac supports MethodHandle.invoke directly:
35.315 + //z = vatest.invoke<boolean>(arguments);
35.316 + // If javac does not support direct MH.invoke calls:
35.317 + boolean z = (Boolean) MethodHandles.invoke_1(test, x);
35.318 + MethodHandle mh = (z ? target : fallback);
35.319 + return MethodHandles.invoke_1(mh, x);
35.320 + }
35.321 + MethodHandle handle() {
35.322 + MethodType invokeType = MethodType.makeGeneric(0, true);
35.323 + MethodHandle vh = IMPL_LOOKUP.bind(this, "invoke", invokeType);
35.324 + return MethodHandles.collectArguments(vh, target.type());
35.325 + }
35.326 + }
35.327 + return new Guarder().handle();
35.328 + }
35.329 +
35.330 + public static
35.331 + MethodHandle combineArguments(Access token, MethodHandle target, MethodHandle checker, int pos) {
35.332 + Access.check(token);
35.333 + throw new UnsupportedOperationException("Not yet implemented");
35.334 + }
35.335 +
35.336 + protected static String basicToString(MethodHandle target) {
35.337 + MemberName name = null;
35.338 + if (target != null)
35.339 + name = MethodHandleNatives.getMethodName(target);
35.340 + if (name == null)
35.341 + return "<unknown>";
35.342 + return name.getName();
35.343 + }
35.344 +
35.345 + protected static String addTypeString(MethodHandle target, String name) {
35.346 + if (target == null) return name;
35.347 + return name+target.type();
35.348 + }
35.349 + static RuntimeException newIllegalArgumentException(String string) {
35.350 + return new IllegalArgumentException(string);
35.351 + }
35.352 +
35.353 + @Override
35.354 + public String toString() {
35.355 + MethodHandle self = (MethodHandle) this;
35.356 + return addTypeString(self, basicToString(self));
35.357 + }
35.358 +}
36.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
36.2 +++ b/src/share/classes/sun/dyn/MethodHandleNatives.java Tue May 05 23:12:47 2009 -0700
36.3 @@ -0,0 +1,271 @@
36.4 +/*
36.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
36.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
36.7 + *
36.8 + * This code is free software; you can redistribute it and/or modify it
36.9 + * under the terms of the GNU General Public License version 2 only, as
36.10 + * published by the Free Software Foundation. Sun designates this
36.11 + * particular file as subject to the "Classpath" exception as provided
36.12 + * by Sun in the LICENSE file that accompanied this code.
36.13 + *
36.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
36.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
36.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
36.17 + * version 2 for more details (a copy is included in the LICENSE file that
36.18 + * accompanied this code).
36.19 + *
36.20 + * You should have received a copy of the GNU General Public License version
36.21 + * 2 along with this work; if not, write to the Free Software Foundation,
36.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
36.23 + *
36.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
36.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
36.26 + * have any questions.
36.27 + */
36.28 +
36.29 +package sun.dyn;
36.30 +
36.31 +import java.dyn.MethodHandle;
36.32 +import java.dyn.MethodType;
36.33 +import java.lang.reflect.AccessibleObject;
36.34 +import java.lang.reflect.Field;
36.35 +import static sun.dyn.MethodHandleNatives.Constants.*;
36.36 +
36.37 +/**
36.38 + * The JVM interface for the method handles package is all here.
36.39 + * @author jrose
36.40 + */
36.41 +class MethodHandleNatives {
36.42 +
36.43 + private MethodHandleNatives() { } // static only
36.44 +
36.45 + /// MethodName support
36.46 +
36.47 + static native void init(MemberName self, Object ref);
36.48 + static native void expand(MemberName self);
36.49 + static native void resolve(MemberName self, Class<?> caller);
36.50 + static native int getMembers(Class<?> defc, String matchName, String matchSig,
36.51 + int matchFlags, Class<?> caller, int skip, MemberName[] results);
36.52 +
36.53 + static Class<?> asNativeCaller(Class<?> lookupClass) {
36.54 + if (lookupClass == null) // means "public only, non-privileged"
36.55 + return sun.dyn.empty.Empty.class;
36.56 + if (lookupClass == Access.class) // means "internal, privileged"
36.57 + return null; // to the JVM, null means completely privileged
36.58 + return lookupClass;
36.59 + }
36.60 +
36.61 + /// MethodHandle support
36.62 +
36.63 + /** Initialize the method handle to adapt the call. */
36.64 + static native void init(AdapterMethodHandle self, MethodHandle target, int argnum);
36.65 + /** Initialize the method handle to call the correct method, directly. */
36.66 + static native void init(BoundMethodHandle self, Object target, int argnum);
36.67 + /** Initialize the method handle to call as if by an invoke* instruction. */
36.68 + static native void init(DirectMethodHandle self, Object ref, boolean doDispatch, Class<?> caller);
36.69 +
36.70 + /** Initialize a method type, once per form. */
36.71 + static native void init(MethodType self);
36.72 +
36.73 + /** Tell the JVM that we need to change the target of an invokedynamic. */
36.74 + static native void linkCallSite(CallSiteImpl site, MethodHandle target);
36.75 +
36.76 + /** Fetch the vmtarget field.
36.77 + * It will be sanitized as necessary to avoid exposing non-Java references.
36.78 + * This routine is for debugging and reflection.
36.79 + */
36.80 + static native Object getTarget(MethodHandle self, int format);
36.81 +
36.82 + /** Fetch the name of the handled method, if available.
36.83 + * This routine is for debugging and reflection.
36.84 + */
36.85 + static MemberName getMethodName(MethodHandle self) {
36.86 + if (!JVM_SUPPORT) return null;
36.87 + return (MemberName) getTarget(self, ETF_METHOD_NAME);
36.88 + }
36.89 +
36.90 + /** Fetch the reflective version of the handled method, if available.
36.91 + */
36.92 + static AccessibleObject getTargetMethod(MethodHandle self) {
36.93 + if (!JVM_SUPPORT) return null;
36.94 + return (AccessibleObject) getTarget(self, ETF_REFLECT_METHOD);
36.95 + }
36.96 +
36.97 + /** Fetch the target of this method handle.
36.98 + * If it directly targets a method, return a tuple of method info.
36.99 + * The info is of the form new Object[]{defclass, name, sig, refclass}.
36.100 + * If it is chained to another method handle, return that handle.
36.101 + */
36.102 + static Object getTargetInfo(MethodHandle self) {
36.103 + if (!JVM_SUPPORT) return null;
36.104 + return getTarget(self, ETF_HANDLE_OR_METHOD_NAME);
36.105 + }
36.106 +
36.107 + static Object[] makeTarget(Class<?> defc, String name, String sig, int mods, Class<?> refc) {
36.108 + return new Object[] { defc, name, sig, mods, refc };
36.109 + }
36.110 +
36.111 + /** Fetch MH-related JVM parameter.
36.112 + * which=0 retrieves MethodHandlePushLimit
36.113 + * which=1 retrieves stack slot push size (in address units)
36.114 + */
36.115 + static native int getConstant(int which);
36.116 +
36.117 + /** True iff this HotSpot JVM has built-in support for method handles.
36.118 + * If false, some test cases might run, but functionality will be missing.
36.119 + */
36.120 + public static final boolean JVM_SUPPORT;
36.121 +
36.122 + /** Java copy of MethodHandlePushLimit in range 2..255. */
36.123 + static final int JVM_PUSH_LIMIT;
36.124 + /** JVM stack motion (in words) after one slot is pushed, usually -1.
36.125 + */
36.126 + static final int JVM_STACK_MOVE_UNIT;
36.127 +
36.128 + private static native void registerNatives();
36.129 + static {
36.130 + boolean JVM_SUPPORT_;
36.131 + int JVM_PUSH_LIMIT_;
36.132 + int JVM_STACK_MOVE_UNIT_;
36.133 + try {
36.134 + registerNatives();
36.135 + JVM_SUPPORT_ = true;
36.136 + JVM_PUSH_LIMIT_ = getConstant(Constants.GC_JVM_PUSH_LIMIT);
36.137 + JVM_STACK_MOVE_UNIT_ = getConstant(Constants.GC_JVM_STACK_MOVE_LIMIT);
36.138 + //sun.reflect.Reflection.registerMethodsToFilter(MethodHandleImpl.class, "init");
36.139 + } catch (UnsatisfiedLinkError ee) {
36.140 + // ignore; if we use init() methods later we'll see linkage errors
36.141 + JVM_SUPPORT_ = false;
36.142 + JVM_PUSH_LIMIT_ = 3; // arbitrary
36.143 + JVM_STACK_MOVE_UNIT_ = -1; // arbitrary
36.144 + //System.out.println("Warning: Running with JVM_SUPPORT=false");
36.145 + //System.out.println(ee);
36.146 + JVM_SUPPORT = JVM_SUPPORT_;
36.147 + JVM_PUSH_LIMIT = JVM_PUSH_LIMIT_;
36.148 + JVM_STACK_MOVE_UNIT = JVM_STACK_MOVE_UNIT_;
36.149 + throw ee; // just die; hopeless to try to run with an older JVM
36.150 + }
36.151 + JVM_SUPPORT = JVM_SUPPORT_;
36.152 + JVM_PUSH_LIMIT = JVM_PUSH_LIMIT_;
36.153 + JVM_STACK_MOVE_UNIT = JVM_STACK_MOVE_UNIT_;
36.154 + }
36.155 +
36.156 + // All compile-time constants go here.
36.157 + // There is an opportunity to check them against the JVM's idea of them.
36.158 + static class Constants {
36.159 + Constants() { } // static only
36.160 + // MethodHandleImpl
36.161 + static final int // for getConstant
36.162 + GC_JVM_PUSH_LIMIT = 0,
36.163 + GC_JVM_STACK_MOVE_LIMIT = 1;
36.164 + static final int
36.165 + ETF_HANDLE_OR_METHOD_NAME = 0, // all available data (immediate MH or method)
36.166 + ETF_DIRECT_HANDLE = 1, // ultimate method handle (will be a DMH, may be self)
36.167 + ETF_METHOD_NAME = 2, // ultimate method as MemberName
36.168 + ETF_REFLECT_METHOD = 3; // ultimate method as java.lang.reflect object (sans refClass)
36.169 +
36.170 + // MemberName
36.171 + // The JVM uses values of -2 and above for vtable indexes.
36.172 + // Field values are simple positive offsets.
36.173 + // Ref: src/share/vm/oops/methodOop.hpp
36.174 + // This value is negative enough to avoid such numbers,
36.175 + // but not too negative.
36.176 + static final int
36.177 + MN_IS_METHOD = 0x00010000, // method (not constructor)
36.178 + MN_IS_CONSTRUCTOR = 0x00020000, // constructor
36.179 + MN_IS_FIELD = 0x00040000, // field
36.180 + MN_IS_TYPE = 0x00080000, // nested type
36.181 + MN_SEARCH_SUPERCLASSES = 0x00100000, // for MHN.getMembers
36.182 + MN_SEARCH_INTERFACES = 0x00200000, // for MHN.getMembers
36.183 + VM_INDEX_UNINITIALIZED = -99;
36.184 +
36.185 + // AdapterMethodHandle
36.186 + /** Conversions recognized by the JVM.
36.187 + * They must align with the constants in sun.dyn_AdapterMethodHandle,
36.188 + * in the JVM file hotspot/src/share/vm/classfile/javaClasses.hpp.
36.189 + */
36.190 + static final int
36.191 + OP_RETYPE_ONLY = 0x0, // no argument changes; straight retype
36.192 + OP_CHECK_CAST = 0x1, // ref-to-ref conversion; requires a Class argument
36.193 + OP_PRIM_TO_PRIM = 0x2, // converts from one primitive to another
36.194 + OP_REF_TO_PRIM = 0x3, // unboxes a wrapper to produce a primitive
36.195 + OP_PRIM_TO_REF = 0x4, // boxes a primitive into a wrapper (NYI)
36.196 + OP_SWAP_ARGS = 0x5, // swap arguments (vminfo is 2nd arg)
36.197 + OP_ROT_ARGS = 0x6, // rotate arguments (vminfo is displaced arg)
36.198 + OP_DUP_ARGS = 0x7, // duplicates one or more arguments (at TOS)
36.199 + OP_DROP_ARGS = 0x8, // remove one or more argument slots
36.200 + OP_COLLECT_ARGS = 0x9, // combine one or more arguments into a varargs (NYI)
36.201 + OP_SPREAD_ARGS = 0xA, // expand in place a varargs array (of known size)
36.202 + OP_FLYBY = 0xB, // operate first on reified argument list (NYI)
36.203 + OP_RICOCHET = 0xC, // run an adapter chain on the return value (NYI)
36.204 + CONV_OP_LIMIT = 0xD; // limit of CONV_OP enumeration
36.205 + /** Shift and mask values for decoding the AMH.conversion field.
36.206 + * These numbers are shared with the JVM for creating AMHs.
36.207 + */
36.208 + static final int
36.209 + CONV_OP_MASK = 0xF00, // this nybble contains the conversion op field
36.210 + CONV_VMINFO_MASK = 0x0FF, // LSB is reserved for JVM use
36.211 + CONV_VMINFO_SHIFT = 0, // position of bits in CONV_VMINFO_MASK
36.212 + CONV_OP_SHIFT = 8, // position of bits in CONV_OP_MASK
36.213 + CONV_DEST_TYPE_SHIFT = 12, // byte 2 has the adapter BasicType (if needed)
36.214 + CONV_SRC_TYPE_SHIFT = 16, // byte 2 has the source BasicType (if needed)
36.215 + CONV_STACK_MOVE_SHIFT = 20, // high 12 bits give signed SP change
36.216 + CONV_STACK_MOVE_MASK = (1 << (32 - CONV_STACK_MOVE_SHIFT)) - 1;
36.217 +
36.218 + /** Which conv-ops are implemented by the JVM? */
36.219 + static final int CONV_OP_IMPLEMENTED_MASK =
36.220 + // TODO: The following expression should be replaced by
36.221 + // a JVM query.
36.222 + ((1<<OP_RETYPE_ONLY)
36.223 + |(1<<OP_CHECK_CAST)
36.224 + |(1<<OP_PRIM_TO_PRIM)
36.225 + |(1<<OP_REF_TO_PRIM)
36.226 + |(1<<OP_SWAP_ARGS)
36.227 + |(1<<OP_ROT_ARGS)
36.228 + |(1<<OP_DUP_ARGS)
36.229 + |(1<<OP_DROP_ARGS)
36.230 + );
36.231 +
36.232 + /**
36.233 + * Basic types as encoded in the JVM. These code values are not
36.234 + * intended for use outside this class. They are used as part of
36.235 + * a private interface between the JVM and this class.
36.236 + */
36.237 + static final int
36.238 + T_BOOLEAN = 4,
36.239 + T_CHAR = 5,
36.240 + T_FLOAT = 6,
36.241 + T_DOUBLE = 7,
36.242 + T_BYTE = 8,
36.243 + T_SHORT = 9,
36.244 + T_INT = 10,
36.245 + T_LONG = 11,
36.246 + T_OBJECT = 12,
36.247 + //T_ARRAY = 13
36.248 + T_VOID = 14;
36.249 + //T_ADDRESS = 15
36.250 + }
36.251 +
36.252 + private static native int getNamedCon(int which, Object[] name);
36.253 + static boolean verifyConstants() {
36.254 + Object[] box = { null };
36.255 + for (int i = 0; ; i++) {
36.256 + box[0] = null;
36.257 + int vmval = getNamedCon(i, box);
36.258 + if (box[0] == null) break;
36.259 + String name = (String) box[0];
36.260 + try {
36.261 + Field con = Constants.class.getDeclaredField(name);
36.262 + int jval = con.getInt(null);
36.263 + if (jval != vmval)
36.264 + throw new InternalError(name+": JVM has "+vmval+" while Java has "+jval);
36.265 + } catch (Exception ex) {
36.266 + throw new InternalError(name+": access failed, got "+ex);
36.267 + }
36.268 + }
36.269 + return true;
36.270 + }
36.271 + static {
36.272 + if (JVM_SUPPORT) verifyConstants();
36.273 + }
36.274 +}
37.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
37.2 +++ b/src/share/classes/sun/dyn/MethodTypeImpl.java Tue May 05 23:12:47 2009 -0700
37.3 @@ -0,0 +1,502 @@
37.4 +/*
37.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
37.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
37.7 + *
37.8 + * This code is free software; you can redistribute it and/or modify it
37.9 + * under the terms of the GNU General Public License version 2 only, as
37.10 + * published by the Free Software Foundation. Sun designates this
37.11 + * particular file as subject to the "Classpath" exception as provided
37.12 + * by Sun in the LICENSE file that accompanied this code.
37.13 + *
37.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
37.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
37.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
37.17 + * version 2 for more details (a copy is included in the LICENSE file that
37.18 + * accompanied this code).
37.19 + *
37.20 + * You should have received a copy of the GNU General Public License version
37.21 + * 2 along with this work; if not, write to the Free Software Foundation,
37.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
37.23 + *
37.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
37.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
37.26 + * have any questions.
37.27 + */
37.28 +
37.29 +package sun.dyn;
37.30 +
37.31 +import java.dyn.*;
37.32 +import sun.dyn.util.Wrapper;
37.33 +
37.34 +/**
37.35 + * Shared information for a group of method types, which differ
37.36 + * only by reference types, and therefore share a common erasure
37.37 + * and wrapping.
37.38 + * <p>
37.39 + * For an empirical discussion of the structure of method types,
37.40 + * see <a href="http://groups.google.com/group/jvm-languages/browse_thread/thread/ac9308ae74da9b7e/">
37.41 + * the thread "Avoiding Boxing" on jvm-languages</a>.
37.42 + * There are approximately 2000 distinct erased method types in the JDK.
37.43 + * There are a little over 10 times that number of unerased types.
37.44 + * No more than half of these are likely to be loaded at once.
37.45 + * @author John Rose
37.46 + */
37.47 +public class MethodTypeImpl {
37.48 + final int[] argToSlotTable, slotToArgTable;
37.49 + final long argCounts; // packed slot & value counts
37.50 + final long primCounts; // packed prim & double counts
37.51 + final int vmslots; // total number of parameter slots
37.52 + final MethodType erasedType; // the canonical erasure
37.53 + /*lazy*/ MethodType primsAsBoxes; // replace prims by wrappers
37.54 + /*lazy*/ MethodType primArgsAsBoxes; // wrap args only; make raw return
37.55 + /*lazy*/ MethodType primsAsInts; // replace prims by int/long
37.56 + /*lazy*/ MethodType primsAsLongs; // replace prims by long
37.57 + /*lazy*/ MethodType primsAtEnd; // reorder primitives to the end
37.58 +
37.59 + // Cached adapter information:
37.60 + /*lazy*/ ToGeneric toGeneric; // convert cs. with prims to w/o
37.61 + /*lazy*/ FromGeneric fromGeneric; // convert cs. w/o prims to with
37.62 + /*lazy*/ FilterGeneric filterGeneric; // convert argument(s) on the fly
37.63 + ///*lazy*/ Invokers invokers; // cache of handy higher-order adapters
37.64 +
37.65 + public MethodType erasedType() {
37.66 + return erasedType;
37.67 + }
37.68 +
37.69 + public static MethodTypeImpl of(MethodType type) {
37.70 + return METHOD_TYPE_FRIEND.form(type);
37.71 + }
37.72 +
37.73 + /** Access methods for the internals of MethodType, supplied to
37.74 + * MethodTypeForm as a trusted agent.
37.75 + */
37.76 + static public interface MethodTypeFriend {
37.77 + Class<?>[] ptypes(MethodType mt);
37.78 + MethodTypeImpl form(MethodType mt);
37.79 + void setForm(MethodType mt, MethodTypeImpl form);
37.80 + MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted);
37.81 + MethodTypeImpl newMethodTypeForm(MethodType mt);
37.82 + Invokers getInvokers(MethodType mt);
37.83 + void setInvokers(MethodType mt, Invokers inv);
37.84 + }
37.85 + public static void setMethodTypeFriend(Access token, MethodTypeFriend am) {
37.86 + Access.check(token);
37.87 + if (METHOD_TYPE_FRIEND != null)
37.88 + throw new InternalError(); // just once
37.89 + METHOD_TYPE_FRIEND = am;
37.90 + }
37.91 + static private MethodTypeFriend METHOD_TYPE_FRIEND;
37.92 +
37.93 + protected MethodTypeImpl(MethodType erasedType) {
37.94 + this.erasedType = erasedType;
37.95 +
37.96 + Class<?>[] ptypes = METHOD_TYPE_FRIEND.ptypes(erasedType);
37.97 + int ptypeCount = ptypes.length;
37.98 + int pslotCount = ptypeCount; // temp. estimate
37.99 + int rtypeCount = 1; // temp. estimate
37.100 + int rslotCount = 1; // temp. estimate
37.101 +
37.102 + int[] argToSlotTab = null, slotToArgTab = null;
37.103 +
37.104 + // Walk the argument types, looking for primitives.
37.105 + int pac = 0, lac = 0, prc = 0, lrc = 0;
37.106 + Class<?> epts[] = ptypes;
37.107 + for (int i = 0; i < epts.length; i++) {
37.108 + Class<?> pt = epts[i];
37.109 + if (pt != Object.class) {
37.110 + assert(pt.isPrimitive());
37.111 + ++pac;
37.112 + if (hasTwoArgSlots(pt)) ++lac;
37.113 + }
37.114 + }
37.115 + pslotCount += lac; // #slots = #args + #longs
37.116 + Class<?> rt = erasedType.returnType();
37.117 + if (rt != Object.class) {
37.118 + ++prc; // even void.class counts as a prim here
37.119 + if (hasTwoArgSlots(rt)) ++lrc;
37.120 + // adjust #slots, #args
37.121 + if (rt == void.class)
37.122 + rtypeCount = rslotCount = 0;
37.123 + else
37.124 + rslotCount += lrc;
37.125 + }
37.126 + if (lac != 0) {
37.127 + int slot = ptypeCount + lac;
37.128 + slotToArgTab = new int[slot+1];
37.129 + argToSlotTab = new int[1+ptypeCount];
37.130 + argToSlotTab[0] = slot; // argument "-1" is past end of slots
37.131 + for (int i = 0; i < epts.length; i++) {
37.132 + Class<?> pt = epts[i];
37.133 + if (hasTwoArgSlots(pt)) --slot;
37.134 + --slot;
37.135 + slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
37.136 + argToSlotTab[1+i] = slot;
37.137 + }
37.138 + assert(slot == 0); // filled the table
37.139 + }
37.140 + this.primCounts = pack(lrc, prc, lac, pac);
37.141 + this.argCounts = pack(rslotCount, rtypeCount, pslotCount, ptypeCount);
37.142 + if (slotToArgTab == null) {
37.143 + int slot = ptypeCount; // first arg is deepest in stack
37.144 + slotToArgTab = new int[slot+1];
37.145 + argToSlotTab = new int[1+ptypeCount];
37.146 + argToSlotTab[0] = slot; // argument "-1" is past end of slots
37.147 + for (int i = 0; i < ptypeCount; i++) {
37.148 + --slot;
37.149 + slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
37.150 + argToSlotTab[1+i] = slot;
37.151 + }
37.152 + }
37.153 + this.argToSlotTable = argToSlotTab;
37.154 + this.slotToArgTable = slotToArgTab;
37.155 +
37.156 + if (pslotCount >= 256) throw new IllegalArgumentException("too many arguments");
37.157 +
37.158 + // send a few bits down to the JVM:
37.159 + this.vmslots = parameterSlotCount();
37.160 +
37.161 + // short circuit some no-op canonicalizations:
37.162 + if (!hasPrimitives()) {
37.163 + primsAsBoxes = erasedType;
37.164 + primArgsAsBoxes = erasedType;
37.165 + primsAsInts = erasedType;
37.166 + primsAsLongs = erasedType;
37.167 + primsAtEnd = erasedType;
37.168 + }
37.169 + }
37.170 +
37.171 + /** Turn all primitive types to corresponding wrapper types.
37.172 + */
37.173 + public MethodType primsAsBoxes() {
37.174 + MethodType ct = primsAsBoxes;
37.175 + if (ct != null) return ct;
37.176 + MethodType t = erasedType;
37.177 + ct = canonicalize(erasedType, WRAP, WRAP);
37.178 + if (ct == null) ct = t; // no prims to box
37.179 + return primsAsBoxes = ct;
37.180 + }
37.181 +
37.182 + /** Turn all primitive argument types to corresponding wrapper types.
37.183 + * Subword and void return types are promoted to int.
37.184 + */
37.185 + public MethodType primArgsAsBoxes() {
37.186 + MethodType ct = primArgsAsBoxes;
37.187 + if (ct != null) return ct;
37.188 + MethodType t = erasedType;
37.189 + ct = canonicalize(erasedType, RAW_RETURN, WRAP);
37.190 + if (ct == null) ct = t; // no prims to box
37.191 + return primArgsAsBoxes = ct;
37.192 + }
37.193 +
37.194 + /** Turn all primitive types to either int or long.
37.195 + * Floating point return types are not changed, because
37.196 + * they may require special calling sequences.
37.197 + * A void return value is turned to int.
37.198 + */
37.199 + public MethodType primsAsInts() {
37.200 + MethodType ct = primsAsInts;
37.201 + if (ct != null) return ct;
37.202 + MethodType t = erasedType;
37.203 + ct = canonicalize(t, RAW_RETURN, INTS);
37.204 + if (ct == null) ct = t; // no prims to int-ify
37.205 + return primsAsInts = ct;
37.206 + }
37.207 +
37.208 + /** Turn all primitive types to either int or long.
37.209 + * Floating point return types are not changed, because
37.210 + * they may require special calling sequences.
37.211 + * A void return value is turned to int.
37.212 + */
37.213 + public MethodType primsAsLongs() {
37.214 + MethodType ct = primsAsLongs;
37.215 + if (ct != null) return ct;
37.216 + MethodType t = erasedType;
37.217 + ct = canonicalize(t, RAW_RETURN, LONGS);
37.218 + if (ct == null) ct = t; // no prims to int-ify
37.219 + return primsAsLongs = ct;
37.220 + }
37.221 +
37.222 + /** Stably sort parameters into 3 buckets: ref, int, long. */
37.223 + public MethodType primsAtEnd() {
37.224 + MethodType ct = primsAtEnd;
37.225 + if (ct != null) return ct;
37.226 + MethodType t = erasedType;
37.227 +
37.228 + int pac = primitiveParameterCount();
37.229 + if (pac == 0)
37.230 + return primsAtEnd = t;
37.231 +
37.232 + int argc = parameterCount();
37.233 + int lac = longPrimitiveParameterCount();
37.234 + if (pac == argc && (lac == 0 || lac == argc))
37.235 + return primsAtEnd = t;
37.236 +
37.237 + // known to have a mix of 2 or 3 of ref, int, long
37.238 + return primsAtEnd = reorderParameters(t, primsAtEndOrder(t), null);
37.239 +
37.240 + }
37.241 +
37.242 + /** Compute a new ordering of parameters so that all references
37.243 + * are before all ints or longs, and all ints are before all longs.
37.244 + * For this ordering, doubles count as longs, and all other primitive
37.245 + * values count as ints.
37.246 + * As a special case, if the parameters are already in the specified
37.247 + * order, this method returns a null reference, rather than an array
37.248 + * specifying a null permutation.
37.249 + * <p>
37.250 + * For example, the type {@code (int,boolean,int,Object,String)void}
37.251 + * produces the order {@code {3,4,0,1,2}}, the type
37.252 + * {@code (long,int,String)void} produces {@code {2,1,2}}, and
37.253 + * the type {@code (Object,int)Object} produces {@code null}.
37.254 + */
37.255 + public static int[] primsAtEndOrder(MethodType mt) {
37.256 + MethodTypeImpl form = METHOD_TYPE_FRIEND.form(mt);
37.257 + if (form.primsAtEnd == form.erasedType)
37.258 + // quick check shows no reordering is necessary
37.259 + return null;
37.260 +
37.261 + int argc = form.parameterCount();
37.262 + int[] paramOrder = new int[argc];
37.263 +
37.264 + // 3-way bucket sort:
37.265 + int pac = form.primitiveParameterCount();
37.266 + int lac = form.longPrimitiveParameterCount();
37.267 + int rfill = 0, ifill = argc - pac, lfill = argc - lac;
37.268 +
37.269 + Class<?>[] ptypes = METHOD_TYPE_FRIEND.ptypes(mt);
37.270 + boolean changed = false;
37.271 + for (int i = 0; i < ptypes.length; i++) {
37.272 + Class<?> pt = ptypes[i];
37.273 + int ord;
37.274 + if (!pt.isPrimitive()) ord = rfill++;
37.275 + else if (!hasTwoArgSlots(pt)) ord = ifill++;
37.276 + else ord = lfill++;
37.277 + if (ord != i) changed = true;
37.278 + paramOrder[i] = ord;
37.279 + }
37.280 + assert(rfill == argc - pac && ifill == argc - lac && lfill == argc);
37.281 + if (!changed) {
37.282 + form.primsAtEnd = form.erasedType;
37.283 + return null;
37.284 + }
37.285 + return paramOrder;
37.286 + }
37.287 +
37.288 + /** Put the existing parameters of mt into a new order, given by newParamOrder.
37.289 + * The third argument is logically appended to mt.parameterArray,
37.290 + * so that elements of newParamOrder can index either pre-existing or
37.291 + * new parameter types.
37.292 + */
37.293 + public static MethodType reorderParameters(MethodType mt, int[] newParamOrder, Class<?>[] moreParams) {
37.294 + if (newParamOrder == null) return mt; // no-op reordering
37.295 + Class<?>[] ptypes = METHOD_TYPE_FRIEND.ptypes(mt);
37.296 + Class<?>[] ntypes = new Class<?>[newParamOrder.length];
37.297 + int ordMax = ptypes.length + (moreParams == null ? 0 : moreParams.length);
37.298 + boolean changed = (ntypes.length != ptypes.length);
37.299 + for (int i = 0; i < newParamOrder.length; i++) {
37.300 + int ord = newParamOrder[i];
37.301 + if (ord != i) changed = true;
37.302 + Class<?> nt;
37.303 + if (ord < ptypes.length) nt = ptypes[ord];
37.304 + else if (ord == ordMax) nt = mt.returnType();
37.305 + else nt = moreParams[ord - ptypes.length];
37.306 + ntypes[i] = nt;
37.307 + }
37.308 + if (!changed) return mt;
37.309 + return METHOD_TYPE_FRIEND.makeImpl(mt.returnType(), ntypes, true);
37.310 + }
37.311 +
37.312 + private static boolean hasTwoArgSlots(Class<?> type) {
37.313 + return type == long.class || type == double.class;
37.314 + }
37.315 +
37.316 + private static long pack(int a, int b, int c, int d) {
37.317 + assert(((a|b|c|d) & ~0xFFFF) == 0);
37.318 + long hw = ((a << 16) | b), lw = ((c << 16) | d);
37.319 + return (hw << 32) | lw;
37.320 + }
37.321 + private static char unpack(long packed, int word) { // word==0 => return a, ==3 => return d
37.322 + assert(word <= 3);
37.323 + return (char)(packed >> ((3-word) * 16));
37.324 + }
37.325 +
37.326 + public int parameterCount() { // # outgoing values
37.327 + return unpack(argCounts, 3);
37.328 + }
37.329 + public int parameterSlotCount() { // # outgoing interpreter slots
37.330 + return unpack(argCounts, 2);
37.331 + }
37.332 + public int returnCount() { // = 0 (V), or 1
37.333 + return unpack(argCounts, 1);
37.334 + }
37.335 + public int returnSlotCount() { // = 0 (V), 2 (J/D), or 1
37.336 + return unpack(argCounts, 0);
37.337 + }
37.338 + public int primitiveParameterCount() {
37.339 + return unpack(primCounts, 3);
37.340 + }
37.341 + public int longPrimitiveParameterCount() {
37.342 + return unpack(primCounts, 2);
37.343 + }
37.344 + public int primitiveReturnCount() { // = 0 (obj), or 1
37.345 + return unpack(primCounts, 1);
37.346 + }
37.347 + public int longPrimitiveReturnCount() { // = 1 (J/D), or 0
37.348 + return unpack(primCounts, 0);
37.349 + }
37.350 + public boolean hasPrimitives() {
37.351 + return primCounts != 0;
37.352 + }
37.353 +// public boolean hasNonVoidPrimitives() {
37.354 +// if (primCounts == 0) return false;
37.355 +// if (primitiveParameterCount() != 0) return true;
37.356 +// return (primitiveReturnCount() != 0 && returnCount() != 0);
37.357 +// }
37.358 + public boolean hasLongPrimitives() {
37.359 + return (longPrimitiveParameterCount() | longPrimitiveReturnCount()) != 0;
37.360 + }
37.361 + public int parameterToArgSlot(int i) {
37.362 + return argToSlotTable[1+i];
37.363 + }
37.364 + public int argSlotToParameter(int argSlot) {
37.365 + // Note: Empty slots are represented by zero in this table.
37.366 + // Valid arguments slots contain incremented entries, so as to be non-zero.
37.367 + // We return -1 the caller to mean an empty slot.
37.368 + return slotToArgTable[argSlot] - 1;
37.369 + }
37.370 +
37.371 + public static void initForm(Access token, MethodType mt) {
37.372 + Access.check(token);
37.373 + MethodTypeImpl form = findForm(mt);
37.374 + METHOD_TYPE_FRIEND.setForm(mt, form);
37.375 + if (form.erasedType == mt) {
37.376 + // This is a principal (erased) type; show it to the JVM.
37.377 + MethodHandleImpl.init(token, mt);
37.378 + }
37.379 + }
37.380 +
37.381 + static MethodTypeImpl findForm(MethodType mt) {
37.382 + MethodType erased = canonicalize(mt, ERASE, ERASE);
37.383 + if (erased == null) {
37.384 + // It is already erased. Make a new MethodTypeForm.
37.385 + return METHOD_TYPE_FRIEND.newMethodTypeForm(mt);
37.386 + } else {
37.387 + // Share the MethodTypeForm with the erased version.
37.388 + return METHOD_TYPE_FRIEND.form(erased);
37.389 + }
37.390 + }
37.391 +
37.392 + /** Codes for {@link #canonicalize(java.lang.Class, int).
37.393 + * ERASE means change every reference to {@code Object}.
37.394 + * WRAP means convert primitives (including {@code void} to their
37.395 + * corresponding wrapper types. UNWRAP means the reverse of WRAP.
37.396 + * INTS means convert all non-void primitive types to int or long,
37.397 + * according to size. LONGS means convert all non-void primitives
37.398 + * to long, regardless of size. RAW_RETURN means convert a type
37.399 + * (assumed to be a return type) to int if it is smaller than an int,
37.400 + * or if it is void.
37.401 + */
37.402 + public static final int NO_CHANGE = 0, ERASE = 1, WRAP = 2, UNWRAP = 3, INTS = 4, LONGS = 5, RAW_RETURN = 6;
37.403 +
37.404 + /** Canonicalize the types in the given method type.
37.405 + * If any types change, intern the new type, and return it.
37.406 + * Otherwise return null.
37.407 + */
37.408 + public static MethodType canonicalize(MethodType mt, int howRet, int howArgs) {
37.409 + Class<?>[] ptypes = METHOD_TYPE_FRIEND.ptypes(mt);
37.410 + Class<?>[] ptc = MethodTypeImpl.canonicalizes(ptypes, howArgs);
37.411 + Class<?> rtype = mt.returnType();
37.412 + Class<?> rtc = MethodTypeImpl.canonicalize(rtype, howRet);
37.413 + if (ptc == null && rtc == null) {
37.414 + // It is already canonical.
37.415 + return null;
37.416 + }
37.417 + // Find the erased version of the method type:
37.418 + if (rtc == null) rtc = rtype;
37.419 + if (ptc == null) ptc = ptypes;
37.420 + return METHOD_TYPE_FRIEND.makeImpl(rtc, ptc, true);
37.421 + }
37.422 +
37.423 + /** Canonicalize the given return or param type.
37.424 + * Return null if the type is already canonicalized.
37.425 + */
37.426 + static Class<?> canonicalize(Class<?> t, int how) {
37.427 + Class<?> ct;
37.428 + if (t == Object.class) {
37.429 + // no change, ever
37.430 + } else if (!t.isPrimitive()) {
37.431 + switch (how) {
37.432 + case UNWRAP:
37.433 + ct = Wrapper.asPrimitiveType(t);
37.434 + if (ct != t) return ct;
37.435 + break;
37.436 + case RAW_RETURN:
37.437 + case ERASE:
37.438 + return Object.class;
37.439 + }
37.440 + } else if (t == void.class) {
37.441 + // no change, usually
37.442 + switch (how) {
37.443 + case RAW_RETURN:
37.444 + return int.class;
37.445 + case WRAP:
37.446 + return Void.class;
37.447 + }
37.448 + } else {
37.449 + // non-void primitive
37.450 + switch (how) {
37.451 + case WRAP:
37.452 + return Wrapper.asWrapperType(t);
37.453 + case INTS:
37.454 + if (t == int.class || t == long.class)
37.455 + return null; // no change
37.456 + if (t == double.class)
37.457 + return long.class;
37.458 + return int.class;
37.459 + case LONGS:
37.460 + if (t == long.class)
37.461 + return null; // no change
37.462 + return long.class;
37.463 + case RAW_RETURN:
37.464 + if (t == int.class || t == long.class ||
37.465 + t == float.class || t == double.class)
37.466 + return null; // no change
37.467 + // everything else returns as an int
37.468 + return int.class;
37.469 + }
37.470 + }
37.471 + // no change; return null to signify
37.472 + return null;
37.473 + }
37.474 +
37.475 + /** Canonicalize each param type in the given array.
37.476 + * Return null if all types are already canonicalized.
37.477 + */
37.478 + static Class<?>[] canonicalizes(Class<?>[] ts, int how) {
37.479 + Class<?>[] cs = null;
37.480 + for (int imax = ts.length, i = 0; i < imax; i++) {
37.481 + Class<?> c = canonicalize(ts[i], how);
37.482 + if (c != null) {
37.483 + if (cs == null)
37.484 + cs = ts.clone();
37.485 + cs[i] = c;
37.486 + }
37.487 + }
37.488 + return cs;
37.489 + }
37.490 +
37.491 + public static Invokers invokers(Access token, MethodType type) {
37.492 + Access.check(token);
37.493 + Invokers inv = METHOD_TYPE_FRIEND.getInvokers(type);
37.494 + if (inv != null) return inv;
37.495 + inv = new Invokers(token, type);
37.496 + METHOD_TYPE_FRIEND.setInvokers(type, inv);
37.497 + return inv;
37.498 + }
37.499 +
37.500 + @Override
37.501 + public String toString() {
37.502 + return "Form"+erasedType;
37.503 + }
37.504 +
37.505 +}
38.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
38.2 +++ b/src/share/classes/sun/dyn/ToGeneric.java Tue May 05 23:12:47 2009 -0700
38.3 @@ -0,0 +1,1018 @@
38.4 +/*
38.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
38.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
38.7 + *
38.8 + * This code is free software; you can redistribute it and/or modify it
38.9 + * under the terms of the GNU General Public License version 2 only, as
38.10 + * published by the Free Software Foundation. Sun designates this
38.11 + * particular file as subject to the "Classpath" exception as provided
38.12 + * by Sun in the LICENSE file that accompanied this code.
38.13 + *
38.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
38.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
38.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
38.17 + * version 2 for more details (a copy is included in the LICENSE file that
38.18 + * accompanied this code).
38.19 + *
38.20 + * You should have received a copy of the GNU General Public License version
38.21 + * 2 along with this work; if not, write to the Free Software Foundation,
38.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
38.23 + *
38.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
38.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
38.26 + * have any questions.
38.27 + */
38.28 +
38.29 +package sun.dyn;
38.30 +
38.31 +import java.dyn.JavaMethodHandle;
38.32 +import java.dyn.MethodHandle;
38.33 +import java.dyn.MethodHandles;
38.34 +import java.dyn.MethodType;
38.35 +import java.dyn.NoAccessException;
38.36 +import java.lang.reflect.Constructor;
38.37 +import java.lang.reflect.InvocationTargetException;
38.38 +import sun.dyn.util.ValueConversions;
38.39 +import sun.dyn.util.Wrapper;
38.40 +
38.41 +/**
38.42 + * Adapters which mediate between incoming calls which are not generic
38.43 + * and outgoing calls which are. Any call can be represented generically
38.44 + * boxing up its arguments, and (on return) unboxing the return value.
38.45 + * <p>
38.46 + * A call is "generic" (in MethodHandle terms) if its MethodType features
38.47 + * only Object arguments. A non-generic call therefore features
38.48 + * primitives and/or reference types other than Object.
38.49 + * An adapter has types for its incoming and outgoing calls.
38.50 + * The incoming call type is simply determined by the adapter's type
38.51 + * (the MethodType it presents to callers). The outgoing call type
38.52 + * is determined by the adapter's target (a MethodHandle that the adapter
38.53 + * either binds internally or else takes as a leading argument).
38.54 + * (To stretch the term, adapter-like method handles may have multiple
38.55 + * targets or be polymorphic across multiple call types.)
38.56 + * @author jrose
38.57 + */
38.58 +class ToGeneric {
38.59 + // type for the incoming call (may be erased)
38.60 + private final MethodType entryType;
38.61 + // incoming type with primitives moved to the end and turned to int/long
38.62 + private final MethodType rawEntryType;
38.63 + // adapter for the erased type
38.64 + private final Adapter adapter;
38.65 + // entry point for adapter (Adapter mh, a...) => ...
38.66 + private final MethodHandle entryPoint;
38.67 + // permutation of arguments for primsAtEndType
38.68 + private final int[] primsAtEndOrder;
38.69 + // optional final argument list conversions (at least, invokes the target)
38.70 + private final MethodHandle invoker;
38.71 + // conversion which unboxes a primitive return value
38.72 + private final MethodHandle returnConversion;
38.73 +
38.74 + /** Compute and cache information common to all collecting adapters
38.75 + * that implement members of the erasure-family of the given erased type.
38.76 + */
38.77 + private ToGeneric(MethodType entryType) {
38.78 + assert(entryType.erase() == entryType); // for now
38.79 + // incoming call will first "forget" all reference types except Object
38.80 + this.entryType = entryType;
38.81 + MethodHandle invoker0 = MethodHandles.exactInvoker(entryType.generic());
38.82 + MethodType rawEntryTypeInit;
38.83 + Adapter ad = findAdapter(rawEntryTypeInit = entryType);
38.84 + if (ad != null) {
38.85 + // Immediate hit to exactly the adapter we want,
38.86 + // with no monkeying around with primitive types.
38.87 + this.returnConversion = computeReturnConversion(entryType, rawEntryTypeInit, false);
38.88 + this.rawEntryType = rawEntryTypeInit;
38.89 + this.adapter = ad;
38.90 + this.entryPoint = ad.prototypeEntryPoint();
38.91 + this.primsAtEndOrder = null;
38.92 + this.invoker = invoker0;
38.93 + return;
38.94 + }
38.95 +
38.96 + // next, it will reorder primitives after references
38.97 + MethodType primsAtEnd = MethodTypeImpl.of(entryType).primsAtEnd();
38.98 + // at the same time, it will "forget" all primitive types except int/long
38.99 + this.primsAtEndOrder = MethodTypeImpl.primsAtEndOrder(entryType);
38.100 + if (primsAtEndOrder != null) {
38.101 + // reordering is required; build on top of a simpler ToGeneric
38.102 + ToGeneric va2 = ToGeneric.of(primsAtEnd);
38.103 + this.adapter = va2.adapter;
38.104 + this.entryPoint = MethodHandleImpl.convertArguments(Access.TOKEN,
38.105 + va2.entryPoint, primsAtEnd, entryType, primsAtEndOrder);
38.106 + // example: for entryType of (int,Object,Object), the reordered
38.107 + // type is (Object,Object,int) and the order is {1,2,0},
38.108 + // and putPAE is (mh,int0,obj1,obj2) => mh.invoke(obj1,obj2,int0)
38.109 + if (true) throw new UnsupportedOperationException("NYI");
38.110 + return;
38.111 + }
38.112 +
38.113 + // after any needed argument reordering, it will reinterpret
38.114 + // primitive arguments according to their "raw" types int/long
38.115 + MethodType intsAtEnd = MethodTypeImpl.of(primsAtEnd).primsAsInts();
38.116 + ad = findAdapter(rawEntryTypeInit = intsAtEnd);
38.117 + if (ad == null) {
38.118 + // Perhaps the adapter is available only for longs.
38.119 + // If so, we can use it, but there will have to be a little
38.120 + // more stack motion on each call.
38.121 + MethodType longsAtEnd = MethodTypeImpl.of(primsAtEnd).primsAsLongs();
38.122 + ad = findAdapter(rawEntryTypeInit = longsAtEnd);
38.123 + if (ad == null) {
38.124 + // If there is no statically compiled adapter,
38.125 + // build one by means of dynamic bytecode generation.
38.126 + ad = buildAdapterFromBytecodes(rawEntryTypeInit = intsAtEnd);
38.127 + }
38.128 + }
38.129 + MethodHandle rawEntryPoint = ad.prototypeEntryPoint();
38.130 + MethodType tepType = entryType.insertParameterType(0, ad.getClass());
38.131 + this.entryPoint =
38.132 + AdapterMethodHandle.makeRawRetypeOnly(Access.TOKEN, tepType, rawEntryPoint);
38.133 + if (this.entryPoint == null)
38.134 + throw new UnsupportedOperationException("cannot retype to "+entryType
38.135 + +" from "+rawEntryPoint.type().dropParameterType(0));
38.136 + this.returnConversion = computeReturnConversion(entryType, rawEntryTypeInit, false);
38.137 + this.rawEntryType = rawEntryTypeInit;
38.138 + this.adapter = ad;
38.139 + this.invoker = makeRawArgumentFilter(invoker0,
38.140 + rawEntryPoint.type().dropParameterType(0), entryType);
38.141 + }
38.142 +
38.143 + /** A generic argument list will be created by a call of type 'raw'.
38.144 + * The values need to be reboxed for to match 'cooked'.
38.145 + * Do this on the fly.
38.146 + */
38.147 + // TO DO: Use a generic argument converter in a different file
38.148 + static MethodHandle makeRawArgumentFilter(MethodHandle invoker,
38.149 + MethodType raw, MethodType cooked) {
38.150 + MethodHandle filteredInvoker = null;
38.151 + for (int i = 0, nargs = raw.parameterCount(); i < nargs; i++) {
38.152 + Class<?> src = raw.parameterType(i);
38.153 + Class<?> dst = cooked.parameterType(i);
38.154 + if (src == dst) continue;
38.155 + assert(src.isPrimitive() && dst.isPrimitive());
38.156 + if (filteredInvoker == null) {
38.157 + filteredInvoker =
38.158 + AdapterMethodHandle.makeCheckCast(Access.TOKEN,
38.159 + invoker.type().generic(), invoker, 0, MethodHandle.class);
38.160 + if (filteredInvoker == null) throw new UnsupportedOperationException("NYI");
38.161 + }
38.162 + MethodHandle reboxer = ValueConversions.rebox(dst, false);
38.163 + FilterGeneric gen = new FilterGeneric(filteredInvoker.type(), (short)(1+i), (short)1, 'R');
38.164 + filteredInvoker = gen.makeInstance(reboxer, filteredInvoker);
38.165 + }
38.166 + if (filteredInvoker == null) return invoker;
38.167 + return AdapterMethodHandle.makeRetypeOnly(Access.TOKEN, invoker.type(), filteredInvoker);
38.168 + }
38.169 +
38.170 + /**
38.171 + * Caller will be expecting a result from a call to {@code type},
38.172 + * while the internal adapter entry point is rawEntryType.
38.173 + * Also, the internal target method will be returning a boxed value,
38.174 + * as an untyped object.
38.175 + * <p>
38.176 + * Produce a value converter which will be typed to convert from
38.177 + * {@code Object} to the return value of {@code rawEntryType}, and will
38.178 + * in fact ensure that the value is compatible with the return type of
38.179 + * {@code type}.
38.180 + */
38.181 + private static MethodHandle computeReturnConversion(
38.182 + MethodType type, MethodType rawEntryType, boolean mustCast) {
38.183 + Class<?> tret = type.returnType();
38.184 + Class<?> rret = rawEntryType.returnType();
38.185 + if (mustCast || !tret.isPrimitive()) {
38.186 + assert(!tret.isPrimitive());
38.187 + assert(!rret.isPrimitive());
38.188 + if (rret == Object.class && !mustCast)
38.189 + return null;
38.190 + return ValueConversions.cast(tret, false);
38.191 + } else if (tret == rret) {
38.192 + return ValueConversions.unbox(tret, false);
38.193 + } else {
38.194 + assert(rret.isPrimitive());
38.195 + assert(tret == double.class ? rret == long.class : rret == int.class);
38.196 + return ValueConversions.unboxRaw(tret, false);
38.197 + }
38.198 + }
38.199 +
38.200 + Adapter makeInstance(MethodType type, MethodHandle genericTarget) {
38.201 + genericTarget.getClass(); // check for NPE
38.202 + MethodHandle convert = returnConversion;
38.203 + if (primsAtEndOrder != null)
38.204 + // reorder arguments passed to genericTarget, if primsAtEndOrder
38.205 + throw new UnsupportedOperationException("NYI");
38.206 + if (type == entryType) {
38.207 + if (convert == null) convert = ValueConversions.identity();
38.208 + return adapter.makeInstance(entryPoint, invoker, convert, genericTarget);
38.209 + }
38.210 + // my erased-type is not exactly the same as the desired type
38.211 + assert(type.erase() == entryType); // else we are busted
38.212 + if (convert == null)
38.213 + convert = computeReturnConversion(type, rawEntryType, true);
38.214 + // retype erased reference arguments (the cast makes it safe to do this)
38.215 + MethodType tepType = type.insertParameterType(0, adapter.getClass());
38.216 + MethodHandle typedEntryPoint =
38.217 + AdapterMethodHandle.makeRawRetypeOnly(Access.TOKEN, tepType, entryPoint);
38.218 + return adapter.makeInstance(typedEntryPoint, invoker, convert, genericTarget);
38.219 + }
38.220 +
38.221 + /** Build an adapter of the given type, which invokes genericTarget
38.222 + * on the incoming arguments, after boxing as necessary.
38.223 + * The return value is unboxed if necessary.
38.224 + * @param type the required type of the
38.225 + * @param genericTarget the target, which must accept and return only Object values
38.226 + * @return an adapter method handle
38.227 + */
38.228 + public static MethodHandle make(MethodType type, MethodHandle genericTarget) {
38.229 + MethodType gtype = genericTarget.type();
38.230 + if (type.generic() != gtype)
38.231 + throw new IllegalArgumentException();
38.232 + if (type == gtype) return genericTarget;
38.233 + return ToGeneric.of(type).makeInstance(type, genericTarget);
38.234 + }
38.235 +
38.236 + /** Return the adapter information for this type's erasure. */
38.237 + static ToGeneric of(MethodType type) {
38.238 + MethodTypeImpl form = MethodTypeImpl.of(type);
38.239 + ToGeneric toGen = form.toGeneric;
38.240 + if (toGen == null)
38.241 + form.toGeneric = toGen = new ToGeneric(form.erasedType());
38.242 + return toGen;
38.243 + }
38.244 +
38.245 + public String toString() {
38.246 + return "ToGeneric"+entryType
38.247 + +(primsAtEndOrder!=null?"[reorder]":"");
38.248 + }
38.249 +
38.250 + /* Create an adapter for the given incoming call type. */
38.251 + static Adapter findAdapter(MethodType entryPointType) {
38.252 + MethodTypeImpl form = MethodTypeImpl.of(entryPointType);
38.253 + Class<?> rtype = entryPointType.returnType();
38.254 + int argc = form.parameterCount();
38.255 + int lac = form.longPrimitiveParameterCount();
38.256 + int iac = form.primitiveParameterCount() - lac;
38.257 + String intsAndLongs = (iac > 0 ? "I"+iac : "")+(lac > 0 ? "J"+lac : "");
38.258 + String rawReturn = String.valueOf(Wrapper.forPrimitiveType(rtype).basicTypeChar());
38.259 + String iname0 = "invoke_"+rawReturn;
38.260 + String iname1 = "invoke";
38.261 + String[] inames = { iname0, iname1 };
38.262 + String cname0 = rawReturn + argc;
38.263 + String cname1 = "A" + argc;
38.264 + String[] cnames = { cname1, cname1+intsAndLongs, cname0, cname0+intsAndLongs };
38.265 + // e.g., D5I2, D5, L5I2, L5
38.266 + for (String cname : cnames) {
38.267 + Class<? extends Adapter> acls = Adapter.findSubClass(cname);
38.268 + if (acls == null) continue;
38.269 + // see if it has the required invoke method
38.270 + for (String iname : inames) {
38.271 + MethodHandle entryPoint = null;
38.272 + try {
38.273 + entryPoint = MethodHandleImpl.IMPL_LOOKUP.
38.274 + findSpecial(acls, iname, entryPointType, acls);
38.275 + } catch (NoAccessException ex) {
38.276 + }
38.277 + if (entryPoint == null) continue;
38.278 + Constructor<? extends Adapter> ctor = null;
38.279 + try {
38.280 + // Prototype builder:
38.281 + ctor = acls.getDeclaredConstructor(MethodHandle.class);
38.282 + } catch (NoSuchMethodException ex) {
38.283 + } catch (SecurityException ex) {
38.284 + }
38.285 + if (ctor == null) continue;
38.286 + try {
38.287 + return ctor.newInstance(entryPoint);
38.288 + } catch (IllegalArgumentException ex) {
38.289 + } catch (InvocationTargetException ex) {
38.290 + } catch (InstantiationException ex) {
38.291 + } catch (IllegalAccessException ex) {
38.292 + }
38.293 + }
38.294 + }
38.295 + return null;
38.296 + }
38.297 +
38.298 + static Adapter buildAdapterFromBytecodes(MethodType entryPointType) {
38.299 + throw new UnsupportedOperationException("NYI");
38.300 + }
38.301 +
38.302 + /**
38.303 + * The invoke method takes some particular but unconstrained spread
38.304 + * of raw argument types, and returns a raw return type (in L/I/J/F/D).
38.305 + * Internally, it converts the incoming arguments uniformly into objects.
38.306 + * This series of objects is then passed to the {@code target} method,
38.307 + * which returns a result object. This result is finally converted,
38.308 + * via another method handle {@code convert}, which is responsible for
38.309 + * converting the object result into the raw return value.
38.310 + */
38.311 + static abstract class Adapter extends JavaMethodHandle {
38.312 + /*
38.313 + * class X<<R,A...>> extends Adapter {
38.314 + * Object...=>Object target;
38.315 + * Object=>R convert;
38.316 + * R invoke(A... a...) = convert(invoker(target, a...)))
38.317 + * }
38.318 + */
38.319 + protected final MethodHandle invoker; // (MH, Object...) -> Object
38.320 + protected final MethodHandle target; // Object... -> Object
38.321 + protected final MethodHandle convert; // Object -> R
38.322 +
38.323 + protected boolean isPrototype() { return target == null; }
38.324 + /* Prototype constructor. */
38.325 + protected Adapter(MethodHandle entryPoint) {
38.326 + super(entryPoint);
38.327 + this.invoker = null;
38.328 + this.convert = entryPoint;
38.329 + this.target = null;
38.330 + assert(isPrototype());
38.331 + }
38.332 + protected MethodHandle prototypeEntryPoint() {
38.333 + if (!isPrototype()) throw new InternalError();
38.334 + return convert;
38.335 + }
38.336 +
38.337 + protected Adapter(MethodHandle entryPoint, MethodHandle invoker, MethodHandle convert, MethodHandle target) {
38.338 + super(entryPoint);
38.339 + this.invoker = invoker;
38.340 + this.convert = convert;
38.341 + this.target = target;
38.342 + }
38.343 +
38.344 + /** Make a copy of self, with new fields. */
38.345 + protected abstract Adapter makeInstance(MethodHandle entryPoint,
38.346 + MethodHandle invoker, MethodHandle convert, MethodHandle target);
38.347 + // { return new ThisType(entryPoint, convert, target); }
38.348 +
38.349 + // Code to run when the arguments (<= 4) have all been boxed.
38.350 + protected Object target() { return invoker.<Object>invoke(target); }
38.351 + protected Object target(Object a0) { return invoker.<Object>invoke(target, a0); }
38.352 + protected Object target(Object a0, Object a1)
38.353 + { return invoker.<Object>invoke(target, a0, a1); }
38.354 + protected Object target(Object a0, Object a1, Object a2)
38.355 + { return invoker.<Object>invoke(target, a0, a1, a2); }
38.356 + protected Object target(Object a0, Object a1, Object a2, Object a3)
38.357 + { return invoker.<Object>invoke(target, a0, a1, a2, a3); }
38.358 + /*
38.359 + protected Object target_0(Object... av) { return invoker.<Object>invoke(target, av); }
38.360 + protected Object target_1(Object a0, Object... av)
38.361 + { return invoker.<Object>invoke(target, a0, (Object)av); }
38.362 + protected Object target_2(Object a0, Object a1, Object... av)
38.363 + { return invoker.<Object>invoke(target, a0, a1, (Object)av); }
38.364 + protected Object target_3(Object a0, Object a1, Object a2, Object... av)
38.365 + { return invoker.<Object>invoke(target, a0, a1, a2, (Object)av); }
38.366 + protected Object target_4(Object a0, Object a1, Object a2, Object a3, Object... av)
38.367 + { return invoker.<Object>invoke(target, a0, a1, a2, a3, (Object)av); }
38.368 + // */
38.369 + // (For more than 4 arguments, generate the code in the adapter itself.)
38.370 +
38.371 + // Code to run when the generic target has finished and produced a value.
38.372 + protected Object return_L(Object res) { return convert.<Object>invoke(res); }
38.373 + protected int return_I(Object res) { return convert.<int >invoke(res); }
38.374 + protected long return_J(Object res) { return convert.<long >invoke(res); }
38.375 + protected float return_F(Object res) { return convert.<float >invoke(res); }
38.376 + protected double return_D(Object res) { return convert.<double>invoke(res); }
38.377 +
38.378 + static private final String CLASS_PREFIX; // "sun.dyn.ToGeneric$"
38.379 + static {
38.380 + String aname = Adapter.class.getName();
38.381 + String sname = Adapter.class.getSimpleName();
38.382 + if (!aname.endsWith(sname)) throw new InternalError();
38.383 + CLASS_PREFIX = aname.substring(0, aname.length() - sname.length());
38.384 + }
38.385 + /** Find a sibing class of Adapter. */
38.386 + static Class<? extends Adapter> findSubClass(String name) {
38.387 + String cname = Adapter.CLASS_PREFIX + name;
38.388 + try {
38.389 + return Class.forName(cname).asSubclass(Adapter.class);
38.390 + } catch (ClassNotFoundException ex) {
38.391 + return null;
38.392 + } catch (ClassCastException ex) {
38.393 + return null;
38.394 + }
38.395 + }
38.396 + }
38.397 +
38.398 + /* generated classes follow this pattern:
38.399 + static class A1 extends Adapter {
38.400 + protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
38.401 + protected A1(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
38.402 + protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A1(e, i, c, t); }
38.403 + protected Object target(Object a0) { return invoker.<Object>invoke(target, a0); }
38.404 + protected Object targetA1(Object a0) { return target(a0); }
38.405 + protected Object targetA1(int a0) { return target(a0); }
38.406 + protected Object targetA1(long a0) { return target(a0); }
38.407 + protected Object invoke_L(Object a0) { return return_L(targetA1(a0)); }
38.408 + protected int invoke_I(Object a0) { return return_I(targetA1(a0)); }
38.409 + protected long invoke_J(Object a0) { return return_J(targetA1(a0)); }
38.410 + protected float invoke_F(Object a0) { return return_F(targetA1(a0)); }
38.411 + protected double invoke_D(Object a0) { return return_D(targetA1(a0)); }
38.412 + protected Object invoke_L(int a0) { return return_L(targetA1(a0)); }
38.413 + protected int invoke_I(int a0) { return return_I(targetA1(a0)); }
38.414 + protected long invoke_J(int a0) { return return_J(targetA1(a0)); }
38.415 + protected float invoke_F(int a0) { return return_F(targetA1(a0)); }
38.416 + protected double invoke_D(int a0) { return return_D(targetA1(a0)); }
38.417 + protected Object invoke_L(long a0) { return return_L(targetA1(a0)); }
38.418 + protected int invoke_I(long a0) { return return_I(targetA1(a0)); }
38.419 + protected long invoke_J(long a0) { return return_J(targetA1(a0)); }
38.420 + protected float invoke_F(long a0) { return return_F(targetA1(a0)); }
38.421 + protected double invoke_D(long a0) { return return_D(targetA1(a0)); }
38.422 + }
38.423 + // */
38.424 +
38.425 +/*
38.426 +: SHELL; n=ToGeneric; cp -p $n.java $n.java-; sed < $n.java- > $n.java+ -e '/{{*{{/,/}}*}}/w /tmp/genclasses.java' -e '/}}*}}/q'; (cd /tmp; javac -d . genclasses.java; java -cp . genclasses) >> $n.java+; echo '}' >> $n.java+; mv $n.java+ $n.java; mv $n.java- $n.java~
38.427 +//{{{
38.428 +import java.util.*;
38.429 +class genclasses {
38.430 + static String[] TYPES = { "Object", "int ", "long ", "float ", "double" };
38.431 + static String[] TCHARS = { "L", "I", "J", "F", "D", "A" };
38.432 + static String[][] TEMPLATES = { {
38.433 + "@for@ arity=0..3 rcat<=4 nrefs<=99 nints<=99 nlongs<=99",
38.434 + "@for@ arity=4..5 rcat<=2 nrefs<=99 nints<=99 nlongs<=99",
38.435 + "@for@ arity=6..10 rcat<=2 nrefs<=99 nints=0 nlongs<=99",
38.436 + " //@each-cat@",
38.437 + " static class @cat@ extends Adapter {",
38.438 + " protected @cat@(MethodHandle entryPoint) { super(entryPoint); } // to build prototype",
38.439 + " protected @cat@(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }",
38.440 + " protected @cat@ makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new @cat@(e, i, c, t); }",
38.441 + " protected Object target(@Ovav@) { return invoker.<Object>invoke(target, @av@); }",
38.442 + " //@each-Tv@",
38.443 + " protected Object target@cat@(@Tvav@) { return target(@av@); }",
38.444 + " //@end-Tv@",
38.445 + " //@each-Tv@",
38.446 + " //@each-R@",
38.447 + " protected @R@ invoke_@Rc@(@Tvav@) { return return_@Rc@(target@cat@(@av@)); }",
38.448 + " //@end-R@",
38.449 + " //@end-Tv@",
38.450 + " }",
38.451 + } };
38.452 + enum VAR {
38.453 + cat, R, Rc, Tv, av, Tvav, Ovav;
38.454 + public final String pattern = "@"+toString().replace('_','.')+"@";
38.455 + public String binding;
38.456 + static void makeBindings(boolean topLevel, int rcat, int nrefs, int nints, int nlongs) {
38.457 + int nargs = nrefs + nints + nlongs;
38.458 + if (topLevel)
38.459 + VAR.cat.binding = catstr(ALL_RETURN_TYPES ? TYPES.length : rcat, nrefs, nints, nlongs);
38.460 + VAR.R.binding = TYPES[rcat];
38.461 + VAR.Rc.binding = TCHARS[rcat];
38.462 + String[] Tv = new String[nargs];
38.463 + String[] av = new String[nargs];
38.464 + String[] Tvav = new String[nargs];
38.465 + String[] Ovav = new String[nargs];
38.466 + for (int i = 0; i < nargs; i++) {
38.467 + int tcat = (i < nrefs) ? 0 : (i < nrefs + nints) ? 1 : 2;
38.468 + Tv[i] = TYPES[tcat];
38.469 + av[i] = arg(i);
38.470 + Tvav[i] = param(Tv[i], av[i]);
38.471 + Ovav[i] = param("Object", av[i]);
38.472 + }
38.473 + VAR.Tv.binding = comma(Tv);
38.474 + VAR.av.binding = comma(av);
38.475 + VAR.Tvav.binding = comma(Tvav);
38.476 + VAR.Ovav.binding = comma(Ovav);
38.477 + }
38.478 + static String arg(int i) { return "a"+i; }
38.479 + static String param(String t, String a) { return t+" "+a; }
38.480 + static String comma(String[] v) { return comma(v, ""); }
38.481 + static String comma(String sep, String[] v) {
38.482 + if (v.length == 0) return "";
38.483 + String res = sep+v[0];
38.484 + for (int i = 1; i < v.length; i++) res += ", "+v[i];
38.485 + return res;
38.486 + }
38.487 + static String transform(String string) {
38.488 + for (VAR var : values())
38.489 + string = string.replaceAll(var.pattern, var.binding);
38.490 + return string;
38.491 + }
38.492 + }
38.493 + static String[] stringsIn(String[] strings, int beg, int end) {
38.494 + return Arrays.copyOfRange(strings, beg, Math.min(end, strings.length));
38.495 + }
38.496 + static String[] stringsBefore(String[] strings, int pos) {
38.497 + return stringsIn(strings, 0, pos);
38.498 + }
38.499 + static String[] stringsAfter(String[] strings, int pos) {
38.500 + return stringsIn(strings, pos, strings.length);
38.501 + }
38.502 + static int indexAfter(String[] strings, int pos, String tag) {
38.503 + return Math.min(indexBefore(strings, pos, tag) + 1, strings.length);
38.504 + }
38.505 + static int indexBefore(String[] strings, int pos, String tag) {
38.506 + for (int i = pos, end = strings.length; ; i++) {
38.507 + if (i == end || strings[i].endsWith(tag)) return i;
38.508 + }
38.509 + }
38.510 + static int MIN_ARITY, MAX_ARITY, MAX_RCAT, MAX_REFS, MAX_INTS, MAX_LONGS;
38.511 + static boolean ALL_ARG_TYPES, ALL_RETURN_TYPES;
38.512 + static HashSet<String> done = new HashSet<String>();
38.513 + public static void main(String... av) {
38.514 + for (String[] template : TEMPLATES) {
38.515 + int forLinesLimit = indexBefore(template, 0, "@each-cat@");
38.516 + String[] forLines = stringsBefore(template, forLinesLimit);
38.517 + template = stringsAfter(template, forLinesLimit);
38.518 + for (String forLine : forLines)
38.519 + expandTemplate(forLine, template);
38.520 + }
38.521 + }
38.522 + static void expandTemplate(String forLine, String[] template) {
38.523 + String[] params = forLine.split("[^0-9]+");
38.524 + if (params[0].length() == 0) params = stringsAfter(params, 1);
38.525 + System.out.println("//params="+Arrays.asList(params));
38.526 + int pcur = 0;
38.527 + MIN_ARITY = Integer.valueOf(params[pcur++]);
38.528 + MAX_ARITY = Integer.valueOf(params[pcur++]);
38.529 + MAX_RCAT = Integer.valueOf(params[pcur++]);
38.530 + MAX_REFS = Integer.valueOf(params[pcur++]);
38.531 + MAX_INTS = Integer.valueOf(params[pcur++]);
38.532 + MAX_LONGS = Integer.valueOf(params[pcur++]);
38.533 + if (pcur != params.length) throw new RuntimeException("bad extra param: "+forLine);
38.534 + if (MAX_RCAT >= TYPES.length) MAX_RCAT = TYPES.length - 1;
38.535 + ALL_ARG_TYPES = (indexBefore(template, 0, "@each-Tv@") < template.length);
38.536 + ALL_RETURN_TYPES = (indexBefore(template, 0, "@each-R@") < template.length);
38.537 + for (int nargs = MIN_ARITY; nargs <= MAX_ARITY; nargs++) {
38.538 + for (int rcat = 0; rcat <= MAX_RCAT; rcat++) {
38.539 + expandTemplate(template, true, rcat, nargs, 0, 0);
38.540 + if (ALL_ARG_TYPES) break;
38.541 + expandTemplateForPrims(template, true, rcat, nargs, 1, 1);
38.542 + if (ALL_RETURN_TYPES) break;
38.543 + }
38.544 + }
38.545 + }
38.546 + static String catstr(int rcat, int nrefs, int nints, int nlongs) {
38.547 + int nargs = nrefs + nints + nlongs;
38.548 + String cat = TCHARS[rcat] + nargs;
38.549 + if (!ALL_ARG_TYPES) cat += (nints==0?"":"I"+nints)+(nlongs==0?"":"J"+nlongs);
38.550 + return cat;
38.551 + }
38.552 + static void expandTemplateForPrims(String[] template, boolean topLevel, int rcat, int nargs, int minints, int minlongs) {
38.553 + for (int isLong = 0; isLong <= 1; isLong++) {
38.554 + for (int nprims = 1; nprims <= nargs; nprims++) {
38.555 + int nrefs = nargs - nprims;
38.556 + int nints = ((1-isLong) * nprims);
38.557 + int nlongs = (isLong * nprims);
38.558 + expandTemplate(template, topLevel, rcat, nrefs, nints, nlongs);
38.559 + }
38.560 + }
38.561 + }
38.562 + static void expandTemplate(String[] template, boolean topLevel,
38.563 + int rcat, int nrefs, int nints, int nlongs) {
38.564 + int nargs = nrefs + nints + nlongs;
38.565 + if (nrefs > MAX_REFS || nints > MAX_INTS || nlongs > MAX_LONGS) return;
38.566 + VAR.makeBindings(topLevel, rcat, nrefs, nints, nlongs);
38.567 + if (topLevel && !done.add(VAR.cat.binding)) {
38.568 + System.out.println(" //repeat "+VAR.cat.binding);
38.569 + return;
38.570 + }
38.571 + for (int i = 0; i < template.length; i++) {
38.572 + String line = template[i];
38.573 + if (line.endsWith("@each-cat@")) {
38.574 + // ignore
38.575 + } else if (line.endsWith("@each-R@")) {
38.576 + int blockEnd = indexAfter(template, i, "@end-R@");
38.577 + String[] block = stringsIn(template, i+1, blockEnd-1);
38.578 + for (int rcat1 = rcat; rcat1 <= MAX_RCAT; rcat1++)
38.579 + expandTemplate(block, false, rcat1, nrefs, nints, nlongs);
38.580 + VAR.makeBindings(topLevel, rcat, nrefs, nints, nlongs);
38.581 + i = blockEnd-1; continue;
38.582 + } else if (line.endsWith("@each-Tv@")) {
38.583 + int blockEnd = indexAfter(template, i, "@end-Tv@");
38.584 + String[] block = stringsIn(template, i+1, blockEnd-1);
38.585 + expandTemplate(block, false, rcat, nrefs, nints, nlongs);
38.586 + expandTemplateForPrims(block, false, rcat, nargs, nints+1, nlongs+1);
38.587 + VAR.makeBindings(topLevel, rcat, nrefs, nints, nlongs);
38.588 + i = blockEnd-1; continue;
38.589 + } else {
38.590 + System.out.println(VAR.transform(line));
38.591 + }
38.592 + }
38.593 + }
38.594 +}
38.595 +//}}} */
38.596 +//params=[0, 3, 4, 99, 99, 99]
38.597 + static class A0 extends Adapter {
38.598 + protected A0(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
38.599 + protected A0(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
38.600 + protected A0 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A0(e, i, c, t); }
38.601 + protected Object target() { return invoker.<Object>invoke(target); }
38.602 + protected Object targetA0() { return target(); }
38.603 + protected Object invoke_L() { return return_L(targetA0()); }
38.604 + protected int invoke_I() { return return_I(targetA0()); }
38.605 + protected long invoke_J() { return return_J(targetA0()); }
38.606 + protected float invoke_F() { return return_F(targetA0()); }
38.607 + protected double invoke_D() { return return_D(targetA0()); }
38.608 + }
38.609 + static class A1 extends Adapter {
38.610 + protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
38.611 + protected A1(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
38.612 + protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A1(e, i, c, t); }
38.613 + protected Object target(Object a0) { return invoker.<Object>invoke(target, a0); }
38.614 + protected Object targetA1(Object a0) { return target(a0); }
38.615 + protected Object targetA1(int a0) { return target(a0); }
38.616 + protected Object targetA1(long a0) { return target(a0); }
38.617 + protected Object invoke_L(Object a0) { return return_L(targetA1(a0)); }
38.618 + protected int invoke_I(Object a0) { return return_I(targetA1(a0)); }
38.619 + protected long invoke_J(Object a0) { return return_J(targetA1(a0)); }
38.620 + protected float invoke_F(Object a0) { return return_F(targetA1(a0)); }
38.621 + protected double invoke_D(Object a0) { return return_D(targetA1(a0)); }
38.622 + protected Object invoke_L(int a0) { return return_L(targetA1(a0)); }
38.623 + protected int invoke_I(int a0) { return return_I(targetA1(a0)); }
38.624 + protected long invoke_J(int a0) { return return_J(targetA1(a0)); }
38.625 + protected float invoke_F(int a0) { return return_F(targetA1(a0)); }
38.626 + protected double invoke_D(int a0) { return return_D(targetA1(a0)); }
38.627 + protected Object invoke_L(long a0) { return return_L(targetA1(a0)); }
38.628 + protected int invoke_I(long a0) { return return_I(targetA1(a0)); }
38.629 + protected long invoke_J(long a0) { return return_J(targetA1(a0)); }
38.630 + protected float invoke_F(long a0) { return return_F(targetA1(a0)); }
38.631 + protected double invoke_D(long a0) { return return_D(targetA1(a0)); }
38.632 + }
38.633 + static class A2 extends Adapter {
38.634 + protected A2(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
38.635 + protected A2(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
38.636 + protected A2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A2(e, i, c, t); }
38.637 + protected Object target(Object a0, Object a1) { return invoker.<Object>invoke(target, a0, a1); }
38.638 + protected Object targetA2(Object a0, Object a1) { return target(a0, a1); }
38.639 + protected Object targetA2(Object a0, int a1) { return target(a0, a1); }
38.640 + protected Object targetA2(int a0, int a1) { return target(a0, a1); }
38.641 + protected Object targetA2(Object a0, long a1) { return target(a0, a1); }
38.642 + protected Object targetA2(long a0, long a1) { return target(a0, a1); }
38.643 + protected Object invoke_L(Object a0, Object a1) { return return_L(targetA2(a0, a1)); }
38.644 + protected int invoke_I(Object a0, Object a1) { return return_I(targetA2(a0, a1)); }
38.645 + protected long invoke_J(Object a0, Object a1) { return return_J(targetA2(a0, a1)); }
38.646 + protected float invoke_F(Object a0, Object a1) { return return_F(targetA2(a0, a1)); }
38.647 + protected double invoke_D(Object a0, Object a1) { return return_D(targetA2(a0, a1)); }
38.648 + protected Object invoke_L(Object a0, int a1) { return return_L(targetA2(a0, a1)); }
38.649 + protected int invoke_I(Object a0, int a1) { return return_I(targetA2(a0, a1)); }
38.650 + protected long invoke_J(Object a0, int a1) { return return_J(targetA2(a0, a1)); }
38.651 + protected float invoke_F(Object a0, int a1) { return return_F(targetA2(a0, a1)); }
38.652 + protected double invoke_D(Object a0, int a1) { return return_D(targetA2(a0, a1)); }
38.653 + protected Object invoke_L(int a0, int a1) { return return_L(targetA2(a0, a1)); }
38.654 + protected int invoke_I(int a0, int a1) { return return_I(targetA2(a0, a1)); }
38.655 + protected long invoke_J(int a0, int a1) { return return_J(targetA2(a0, a1)); }
38.656 + protected float invoke_F(int a0, int a1) { return return_F(targetA2(a0, a1)); }
38.657 + protected double invoke_D(int a0, int a1) { return return_D(targetA2(a0, a1)); }
38.658 + protected Object invoke_L(Object a0, long a1) { return return_L(targetA2(a0, a1)); }
38.659 + protected int invoke_I(Object a0, long a1) { return return_I(targetA2(a0, a1)); }
38.660 + protected long invoke_J(Object a0, long a1) { return return_J(targetA2(a0, a1)); }
38.661 + protected float invoke_F(Object a0, long a1) { return return_F(targetA2(a0, a1)); }
38.662 + protected double invoke_D(Object a0, long a1) { return return_D(targetA2(a0, a1)); }
38.663 + protected Object invoke_L(long a0, long a1) { return return_L(targetA2(a0, a1)); }
38.664 + protected int invoke_I(long a0, long a1) { return return_I(targetA2(a0, a1)); }
38.665 + protected long invoke_J(long a0, long a1) { return return_J(targetA2(a0, a1)); }
38.666 + protected float invoke_F(long a0, long a1) { return return_F(targetA2(a0, a1)); }
38.667 + protected double invoke_D(long a0, long a1) { return return_D(targetA2(a0, a1)); }
38.668 + }
38.669 + static class A3 extends Adapter {
38.670 + protected A3(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
38.671 + protected A3(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
38.672 + protected A3 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A3(e, i, c, t); }
38.673 + protected Object target(Object a0, Object a1, Object a2) { return invoker.<Object>invoke(target, a0, a1, a2); }
38.674 + protected Object targetA3(Object a0, Object a1, Object a2) { return target(a0, a1, a2); }
38.675 + protected Object targetA3(Object a0, Object a1, int a2) { return target(a0, a1, a2); }
38.676 + protected Object targetA3(Object a0, int a1, int a2) { return target(a0, a1, a2); }
38.677 + protected Object targetA3(int a0, int a1, int a2) { return target(a0, a1, a2); }
38.678 + protected Object targetA3(Object a0, Object a1, long a2) { return target(a0, a1, a2); }
38.679 + protected Object targetA3(Object a0, long a1, long a2) { return target(a0, a1, a2); }
38.680 + protected Object targetA3(long a0, long a1, long a2) { return target(a0, a1, a2); }
38.681 + protected Object invoke_L(Object a0, Object a1, Object a2) { return return_L(targetA3(a0, a1, a2)); }
38.682 + protected int invoke_I(Object a0, Object a1, Object a2) { return return_I(targetA3(a0, a1, a2)); }
38.683 + protected long invoke_J(Object a0, Object a1, Object a2) { return return_J(targetA3(a0, a1, a2)); }
38.684 + protected float invoke_F(Object a0, Object a1, Object a2) { return return_F(targetA3(a0, a1, a2)); }
38.685 + protected double invoke_D(Object a0, Object a1, Object a2) { return return_D(targetA3(a0, a1, a2)); }
38.686 + protected Object invoke_L(Object a0, Object a1, int a2) { return return_L(targetA3(a0, a1, a2)); }
38.687 + protected int invoke_I(Object a0, Object a1, int a2) { return return_I(targetA3(a0, a1, a2)); }
38.688 + protected long invoke_J(Object a0, Object a1, int a2) { return return_J(targetA3(a0, a1, a2)); }
38.689 + protected float invoke_F(Object a0, Object a1, int a2) { return return_F(targetA3(a0, a1, a2)); }
38.690 + protected double invoke_D(Object a0, Object a1, int a2) { return return_D(targetA3(a0, a1, a2)); }
38.691 + protected Object invoke_L(Object a0, int a1, int a2) { return return_L(targetA3(a0, a1, a2)); }
38.692 + protected int invoke_I(Object a0, int a1, int a2) { return return_I(targetA3(a0, a1, a2)); }
38.693 + protected long invoke_J(Object a0, int a1, int a2) { return return_J(targetA3(a0, a1, a2)); }
38.694 + protected float invoke_F(Object a0, int a1, int a2) { return return_F(targetA3(a0, a1, a2)); }
38.695 + protected double invoke_D(Object a0, int a1, int a2) { return return_D(targetA3(a0, a1, a2)); }
38.696 + protected Object invoke_L(int a0, int a1, int a2) { return return_L(targetA3(a0, a1, a2)); }
38.697 + protected int invoke_I(int a0, int a1, int a2) { return return_I(targetA3(a0, a1, a2)); }
38.698 + protected long invoke_J(int a0, int a1, int a2) { return return_J(targetA3(a0, a1, a2)); }
38.699 + protected float invoke_F(int a0, int a1, int a2) { return return_F(targetA3(a0, a1, a2)); }
38.700 + protected double invoke_D(int a0, int a1, int a2) { return return_D(targetA3(a0, a1, a2)); }
38.701 + protected Object invoke_L(Object a0, Object a1, long a2) { return return_L(targetA3(a0, a1, a2)); }
38.702 + protected int invoke_I(Object a0, Object a1, long a2) { return return_I(targetA3(a0, a1, a2)); }
38.703 + protected long invoke_J(Object a0, Object a1, long a2) { return return_J(targetA3(a0, a1, a2)); }
38.704 + protected float invoke_F(Object a0, Object a1, long a2) { return return_F(targetA3(a0, a1, a2)); }
38.705 + protected double invoke_D(Object a0, Object a1, long a2) { return return_D(targetA3(a0, a1, a2)); }
38.706 + protected Object invoke_L(Object a0, long a1, long a2) { return return_L(targetA3(a0, a1, a2)); }
38.707 + protected int invoke_I(Object a0, long a1, long a2) { return return_I(targetA3(a0, a1, a2)); }
38.708 + protected long invoke_J(Object a0, long a1, long a2) { return return_J(targetA3(a0, a1, a2)); }
38.709 + protected float invoke_F(Object a0, long a1, long a2) { return return_F(targetA3(a0, a1, a2)); }
38.710 + protected double invoke_D(Object a0, long a1, long a2) { return return_D(targetA3(a0, a1, a2)); }
38.711 + protected Object invoke_L(long a0, long a1, long a2) { return return_L(targetA3(a0, a1, a2)); }
38.712 + protected int invoke_I(long a0, long a1, long a2) { return return_I(targetA3(a0, a1, a2)); }
38.713 + protected long invoke_J(long a0, long a1, long a2) { return return_J(targetA3(a0, a1, a2)); }
38.714 + protected float invoke_F(long a0, long a1, long a2) { return return_F(targetA3(a0, a1, a2)); }
38.715 + protected double invoke_D(long a0, long a1, long a2) { return return_D(targetA3(a0, a1, a2)); }
38.716 + }
38.717 +//params=[4, 5, 2, 99, 99, 99]
38.718 + static class A4 extends Adapter {
38.719 + protected A4(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
38.720 + protected A4(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
38.721 + protected A4 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A4(e, i, c, t); }
38.722 + protected Object target(Object a0, Object a1, Object a2, Object a3) { return invoker.<Object>invoke(target, a0, a1, a2, a3); }
38.723 + protected Object targetA4(Object a0, Object a1, Object a2, Object a3) { return target(a0, a1, a2, a3); }
38.724 + protected Object targetA4(Object a0, Object a1, Object a2, int a3) { return target(a0, a1, a2, a3); }
38.725 + protected Object targetA4(Object a0, Object a1, int a2, int a3) { return target(a0, a1, a2, a3); }
38.726 + protected Object targetA4(Object a0, int a1, int a2, int a3) { return target(a0, a1, a2, a3); }
38.727 + protected Object targetA4(int a0, int a1, int a2, int a3) { return target(a0, a1, a2, a3); }
38.728 + protected Object targetA4(Object a0, Object a1, Object a2, long a3) { return target(a0, a1, a2, a3); }
38.729 + protected Object targetA4(Object a0, Object a1, long a2, long a3) { return target(a0, a1, a2, a3); }
38.730 + protected Object targetA4(Object a0, long a1, long a2, long a3) { return target(a0, a1, a2, a3); }
38.731 + protected Object targetA4(long a0, long a1, long a2, long a3) { return target(a0, a1, a2, a3); }
38.732 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3) { return return_L(targetA4(a0, a1, a2, a3)); }
38.733 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3) { return return_I(targetA4(a0, a1, a2, a3)); }
38.734 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3) { return return_J(targetA4(a0, a1, a2, a3)); }
38.735 + protected Object invoke_L(Object a0, Object a1, Object a2, int a3) { return return_L(targetA4(a0, a1, a2, a3)); }
38.736 + protected int invoke_I(Object a0, Object a1, Object a2, int a3) { return return_I(targetA4(a0, a1, a2, a3)); }
38.737 + protected long invoke_J(Object a0, Object a1, Object a2, int a3) { return return_J(targetA4(a0, a1, a2, a3)); }
38.738 + protected Object invoke_L(Object a0, Object a1, int a2, int a3) { return return_L(targetA4(a0, a1, a2, a3)); }
38.739 + protected int invoke_I(Object a0, Object a1, int a2, int a3) { return return_I(targetA4(a0, a1, a2, a3)); }
38.740 + protected long invoke_J(Object a0, Object a1, int a2, int a3) { return return_J(targetA4(a0, a1, a2, a3)); }
38.741 + protected Object invoke_L(Object a0, int a1, int a2, int a3) { return return_L(targetA4(a0, a1, a2, a3)); }
38.742 + protected int invoke_I(Object a0, int a1, int a2, int a3) { return return_I(targetA4(a0, a1, a2, a3)); }
38.743 + protected long invoke_J(Object a0, int a1, int a2, int a3) { return return_J(targetA4(a0, a1, a2, a3)); }
38.744 + protected Object invoke_L(int a0, int a1, int a2, int a3) { return return_L(targetA4(a0, a1, a2, a3)); }
38.745 + protected int invoke_I(int a0, int a1, int a2, int a3) { return return_I(targetA4(a0, a1, a2, a3)); }
38.746 + protected long invoke_J(int a0, int a1, int a2, int a3) { return return_J(targetA4(a0, a1, a2, a3)); }
38.747 + protected Object invoke_L(Object a0, Object a1, Object a2, long a3) { return return_L(targetA4(a0, a1, a2, a3)); }
38.748 + protected int invoke_I(Object a0, Object a1, Object a2, long a3) { return return_I(targetA4(a0, a1, a2, a3)); }
38.749 + protected long invoke_J(Object a0, Object a1, Object a2, long a3) { return return_J(targetA4(a0, a1, a2, a3)); }
38.750 + protected Object invoke_L(Object a0, Object a1, long a2, long a3) { return return_L(targetA4(a0, a1, a2, a3)); }
38.751 + protected int invoke_I(Object a0, Object a1, long a2, long a3) { return return_I(targetA4(a0, a1, a2, a3)); }
38.752 + protected long invoke_J(Object a0, Object a1, long a2, long a3) { return return_J(targetA4(a0, a1, a2, a3)); }
38.753 + protected Object invoke_L(Object a0, long a1, long a2, long a3) { return return_L(targetA4(a0, a1, a2, a3)); }
38.754 + protected int invoke_I(Object a0, long a1, long a2, long a3) { return return_I(targetA4(a0, a1, a2, a3)); }
38.755 + protected long invoke_J(Object a0, long a1, long a2, long a3) { return return_J(targetA4(a0, a1, a2, a3)); }
38.756 + protected Object invoke_L(long a0, long a1, long a2, long a3) { return return_L(targetA4(a0, a1, a2, a3)); }
38.757 + protected int invoke_I(long a0, long a1, long a2, long a3) { return return_I(targetA4(a0, a1, a2, a3)); }
38.758 + protected long invoke_J(long a0, long a1, long a2, long a3) { return return_J(targetA4(a0, a1, a2, a3)); }
38.759 + }
38.760 + static class A5 extends Adapter {
38.761 + protected A5(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
38.762 + protected A5(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
38.763 + protected A5 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A5(e, i, c, t); }
38.764 + protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4) { return invoker.<Object>invoke(target, a0, a1, a2, a3, a4); }
38.765 + protected Object targetA5(Object a0, Object a1, Object a2, Object a3, Object a4) { return target(a0, a1, a2, a3, a4); }
38.766 + protected Object targetA5(Object a0, Object a1, Object a2, Object a3, int a4) { return target(a0, a1, a2, a3, a4); }
38.767 + protected Object targetA5(Object a0, Object a1, Object a2, int a3, int a4) { return target(a0, a1, a2, a3, a4); }
38.768 + protected Object targetA5(Object a0, Object a1, int a2, int a3, int a4) { return target(a0, a1, a2, a3, a4); }
38.769 + protected Object targetA5(Object a0, int a1, int a2, int a3, int a4) { return target(a0, a1, a2, a3, a4); }
38.770 + protected Object targetA5(int a0, int a1, int a2, int a3, int a4) { return target(a0, a1, a2, a3, a4); }
38.771 + protected Object targetA5(Object a0, Object a1, Object a2, Object a3, long a4) { return target(a0, a1, a2, a3, a4); }
38.772 + protected Object targetA5(Object a0, Object a1, Object a2, long a3, long a4) { return target(a0, a1, a2, a3, a4); }
38.773 + protected Object targetA5(Object a0, Object a1, long a2, long a3, long a4) { return target(a0, a1, a2, a3, a4); }
38.774 + protected Object targetA5(Object a0, long a1, long a2, long a3, long a4) { return target(a0, a1, a2, a3, a4); }
38.775 + protected Object targetA5(long a0, long a1, long a2, long a3, long a4) { return target(a0, a1, a2, a3, a4); }
38.776 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); }
38.777 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); }
38.778 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); }
38.779 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, int a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); }
38.780 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, int a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); }
38.781 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, int a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); }
38.782 + protected Object invoke_L(Object a0, Object a1, Object a2, int a3, int a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); }
38.783 + protected int invoke_I(Object a0, Object a1, Object a2, int a3, int a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); }
38.784 + protected long invoke_J(Object a0, Object a1, Object a2, int a3, int a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); }
38.785 + protected Object invoke_L(Object a0, Object a1, int a2, int a3, int a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); }
38.786 + protected int invoke_I(Object a0, Object a1, int a2, int a3, int a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); }
38.787 + protected long invoke_J(Object a0, Object a1, int a2, int a3, int a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); }
38.788 + protected Object invoke_L(Object a0, int a1, int a2, int a3, int a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); }
38.789 + protected int invoke_I(Object a0, int a1, int a2, int a3, int a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); }
38.790 + protected long invoke_J(Object a0, int a1, int a2, int a3, int a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); }
38.791 + protected Object invoke_L(int a0, int a1, int a2, int a3, int a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); }
38.792 + protected int invoke_I(int a0, int a1, int a2, int a3, int a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); }
38.793 + protected long invoke_J(int a0, int a1, int a2, int a3, int a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); }
38.794 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); }
38.795 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); }
38.796 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); }
38.797 + protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); }
38.798 + protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); }
38.799 + protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); }
38.800 + protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); }
38.801 + protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); }
38.802 + protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); }
38.803 + protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); }
38.804 + protected int invoke_I(Object a0, long a1, long a2, long a3, long a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); }
38.805 + protected long invoke_J(Object a0, long a1, long a2, long a3, long a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); }
38.806 + protected Object invoke_L(long a0, long a1, long a2, long a3, long a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); }
38.807 + protected int invoke_I(long a0, long a1, long a2, long a3, long a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); }
38.808 + protected long invoke_J(long a0, long a1, long a2, long a3, long a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); }
38.809 + }
38.810 +//params=[6, 10, 2, 99, 0, 99]
38.811 + static class A6 extends Adapter {
38.812 + protected A6(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
38.813 + protected A6(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
38.814 + protected A6 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A6(e, i, c, t); }
38.815 + protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5); }
38.816 + protected Object targetA6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return target(a0, a1, a2, a3, a4, a5); }
38.817 + protected Object targetA6(Object a0, Object a1, Object a2, Object a3, Object a4, long a5) { return target(a0, a1, a2, a3, a4, a5); }
38.818 + protected Object targetA6(Object a0, Object a1, Object a2, Object a3, long a4, long a5) { return target(a0, a1, a2, a3, a4, a5); }
38.819 + protected Object targetA6(Object a0, Object a1, Object a2, long a3, long a4, long a5) { return target(a0, a1, a2, a3, a4, a5); }
38.820 + protected Object targetA6(Object a0, Object a1, long a2, long a3, long a4, long a5) { return target(a0, a1, a2, a3, a4, a5); }
38.821 + protected Object targetA6(Object a0, long a1, long a2, long a3, long a4, long a5) { return target(a0, a1, a2, a3, a4, a5); }
38.822 + protected Object targetA6(long a0, long a1, long a2, long a3, long a4, long a5) { return target(a0, a1, a2, a3, a4, a5); }
38.823 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); }
38.824 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); }
38.825 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); }
38.826 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); }
38.827 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); }
38.828 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); }
38.829 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4, long a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); }
38.830 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4, long a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); }
38.831 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4, long a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); }
38.832 + protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4, long a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); }
38.833 + protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4, long a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); }
38.834 + protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4, long a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); }
38.835 + protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4, long a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); }
38.836 + protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4, long a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); }
38.837 + protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4, long a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); }
38.838 + protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4, long a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); }
38.839 + protected int invoke_I(Object a0, long a1, long a2, long a3, long a4, long a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); }
38.840 + protected long invoke_J(Object a0, long a1, long a2, long a3, long a4, long a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); }
38.841 + protected Object invoke_L(long a0, long a1, long a2, long a3, long a4, long a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); }
38.842 + protected int invoke_I(long a0, long a1, long a2, long a3, long a4, long a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); }
38.843 + protected long invoke_J(long a0, long a1, long a2, long a3, long a4, long a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); }
38.844 + }
38.845 + static class A7 extends Adapter {
38.846 + protected A7(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
38.847 + protected A7(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
38.848 + protected A7 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A7(e, i, c, t); }
38.849 + protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6); }
38.850 + protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return target(a0, a1, a2, a3, a4, a5, a6); }
38.851 + protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6) { return target(a0, a1, a2, a3, a4, a5, a6); }
38.852 + protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6) { return target(a0, a1, a2, a3, a4, a5, a6); }
38.853 + protected Object targetA7(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6) { return target(a0, a1, a2, a3, a4, a5, a6); }
38.854 + protected Object targetA7(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6) { return target(a0, a1, a2, a3, a4, a5, a6); }
38.855 + protected Object targetA7(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6) { return target(a0, a1, a2, a3, a4, a5, a6); }
38.856 + protected Object targetA7(Object a0, long a1, long a2, long a3, long a4, long a5, long a6) { return target(a0, a1, a2, a3, a4, a5, a6); }
38.857 + protected Object targetA7(long a0, long a1, long a2, long a3, long a4, long a5, long a6) { return target(a0, a1, a2, a3, a4, a5, a6); }
38.858 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.859 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.860 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.861 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.862 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.863 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.864 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.865 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.866 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.867 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.868 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.869 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.870 + protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.871 + protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.872 + protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.873 + protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.874 + protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.875 + protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.876 + protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4, long a5, long a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.877 + protected int invoke_I(Object a0, long a1, long a2, long a3, long a4, long a5, long a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.878 + protected long invoke_J(Object a0, long a1, long a2, long a3, long a4, long a5, long a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.879 + protected Object invoke_L(long a0, long a1, long a2, long a3, long a4, long a5, long a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.880 + protected int invoke_I(long a0, long a1, long a2, long a3, long a4, long a5, long a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.881 + protected long invoke_J(long a0, long a1, long a2, long a3, long a4, long a5, long a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); }
38.882 + }
38.883 + static class A8 extends Adapter {
38.884 + protected A8(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
38.885 + protected A8(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
38.886 + protected A8 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A8(e, i, c, t); }
38.887 + protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7); }
38.888 + protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
38.889 + protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
38.890 + protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
38.891 + protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
38.892 + protected Object targetA8(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
38.893 + protected Object targetA8(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
38.894 + protected Object targetA8(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
38.895 + protected Object targetA8(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
38.896 + protected Object targetA8(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
38.897 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.898 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.899 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.900 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.901 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.902 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.903 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.904 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.905 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.906 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.907 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.908 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.909 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.910 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.911 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.912 + protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.913 + protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.914 + protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.915 + protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.916 + protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.917 + protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.918 + protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.919 + protected int invoke_I(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.920 + protected long invoke_J(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.921 + protected Object invoke_L(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.922 + protected int invoke_I(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.923 + protected long invoke_J(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); }
38.924 + }
38.925 + static class A9 extends Adapter {
38.926 + protected A9(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
38.927 + protected A9(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
38.928 + protected A9 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A9(e, i, c, t); }
38.929 + protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8); }
38.930 + protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
38.931 + protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
38.932 + protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
38.933 + protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
38.934 + protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
38.935 + protected Object targetA9(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
38.936 + protected Object targetA9(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
38.937 + protected Object targetA9(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
38.938 + protected Object targetA9(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
38.939 + protected Object targetA9(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
38.940 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.941 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.942 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.943 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.944 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.945 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.946 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.947 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.948 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.949 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.950 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.951 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.952 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.953 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.954 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.955 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.956 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.957 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.958 + protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.959 + protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.960 + protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.961 + protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.962 + protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.963 + protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.964 + protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.965 + protected int invoke_I(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.966 + protected long invoke_J(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.967 + protected Object invoke_L(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.968 + protected int invoke_I(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.969 + protected long invoke_J(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
38.970 + }
38.971 + static class A10 extends Adapter {
38.972 + protected A10(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
38.973 + protected A10(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
38.974 + protected A10 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A10(e, i, c, t); }
38.975 + protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
38.976 + protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
38.977 + protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
38.978 + protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
38.979 + protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
38.980 + protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
38.981 + protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
38.982 + protected Object targetA10(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
38.983 + protected Object targetA10(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
38.984 + protected Object targetA10(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
38.985 + protected Object targetA10(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
38.986 + protected Object targetA10(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
38.987 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.988 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.989 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.990 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.991 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.992 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.993 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.994 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.995 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.996 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.997 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.998 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.999 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.1000 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.1001 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.1002 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.1003 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.1004 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.1005 + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.1006 + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.1007 + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.1008 + protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.1009 + protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.1010 + protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.1011 + protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.1012 + protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.1013 + protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.1014 + protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.1015 + protected int invoke_I(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.1016 + protected long invoke_J(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.1017 + protected Object invoke_L(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.1018 + protected int invoke_I(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.1019 + protected long invoke_J(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
38.1020 + }
38.1021 +}
39.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
39.2 +++ b/src/share/classes/sun/dyn/anon/AnonymousClassLoader.java Tue May 05 23:12:47 2009 -0700
39.3 @@ -0,0 +1,297 @@
39.4 +/*
39.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
39.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
39.7 + *
39.8 + * This code is free software; you can redistribute it and/or modify it
39.9 + * under the terms of the GNU General Public License version 2 only, as
39.10 + * published by the Free Software Foundation. Sun designates this
39.11 + * particular file as subject to the "Classpath" exception as provided
39.12 + * by Sun in the LICENSE file that accompanied this code.
39.13 + *
39.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
39.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
39.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
39.17 + * version 2 for more details (a copy is included in the LICENSE file that
39.18 + * accompanied this code).
39.19 + *
39.20 + * You should have received a copy of the GNU General Public License version
39.21 + * 2 along with this work; if not, write to the Free Software Foundation,
39.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
39.23 + *
39.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
39.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
39.26 + * have any questions.
39.27 + */
39.28 +
39.29 +package sun.dyn.anon;
39.30 +
39.31 +import java.io.IOException;
39.32 +import java.io.InputStream;
39.33 +import java.lang.reflect.InvocationTargetException;
39.34 +import java.lang.reflect.Method;
39.35 +
39.36 +/**
39.37 + * Anonymous class loader. Will load any valid classfile, producing
39.38 + * a {@link Class} metaobject, without installing that class in the
39.39 + * system dictionary. Therefore, {@link Class#forName(String)} will never
39.40 + * produce a reference to an anonymous class.
39.41 + * <p>
39.42 + * The access permissions of the anonymous class are borrowed from
39.43 + * a <em>host class</em>. The new class behaves as if it were an
39.44 + * inner class of the host class. It can access the host's private
39.45 + * members, if the creator of the class loader has permission to
39.46 + * do so (or to create accessible reflective objects).
39.47 + * <p>
39.48 + * When the anonymous class is loaded, elements of its constant pool
39.49 + * can be patched to new values. This provides a hook to pre-resolve
39.50 + * named classes in the constant pool to other classes, including
39.51 + * anonymous ones. Also, string constants can be pre-resolved to
39.52 + * any reference. (The verifier treats non-string, non-class reference
39.53 + * constants as plain objects.)
39.54 + * <p>
39.55 + * Why include the patching function? It makes some use cases much easier.
39.56 + * Second, the constant pool needed some internal patching anyway,
39.57 + * to anonymize the loaded class itself. Finally, if you are going
39.58 + * to use this seriously, you'll want to build anonymous classes
39.59 + * on top of pre-existing anonymous classes, and that requires patching.
39.60 + *
39.61 + * <p>%%% TO-DO:
39.62 + * <ul>
39.63 + * <li>needs better documentation</li>
39.64 + * <li>needs more security work (for safe delegation)</li>
39.65 + * <li>needs a clearer story about error processing</li>
39.66 + * <li>patch member references also (use ';' as delimiter char)</li>
39.67 + * <li>patch method references to (conforming) method handles</li>
39.68 + * </ul>
39.69 + *
39.70 + * @author jrose
39.71 + * @author Remi Forax
39.72 + * @see <a href="http://blogs.sun.com/jrose/entry/anonymous_classes_in_the_vm">
39.73 + * http://blogs.sun.com/jrose/entry/anonymous_classes_in_the_vm</a>
39.74 + */
39.75 +
39.76 +public class AnonymousClassLoader {
39.77 + final Class<?> hostClass;
39.78 +
39.79 + // Note: Do not refactor the calls to checkHostClass unless you
39.80 + // also adjust this constant:
39.81 + private static int CHC_CALLERS = 3;
39.82 +
39.83 + public AnonymousClassLoader() {
39.84 + this.hostClass = checkHostClass(null);
39.85 + }
39.86 + public AnonymousClassLoader(Class<?> hostClass) {
39.87 + this.hostClass = checkHostClass(hostClass);
39.88 + }
39.89 +
39.90 + private static Class<?> getTopLevelClass(Class<?> clazz) {
39.91 + for(Class<?> outer = clazz.getDeclaringClass(); outer != null;
39.92 + outer = outer.getDeclaringClass()) {
39.93 + clazz = outer;
39.94 + }
39.95 + return clazz;
39.96 + }
39.97 +
39.98 + private static Class<?> checkHostClass(Class<?> hostClass) {
39.99 + // called only from the constructor
39.100 + // does a context-sensitive check on caller class
39.101 + // CC[0..3] = {Reflection, this.checkHostClass, this.<init>, caller}
39.102 + Class<?> caller = sun.reflect.Reflection.getCallerClass(CHC_CALLERS);
39.103 +
39.104 + if (caller == null) {
39.105 + // called from the JVM directly
39.106 + if (hostClass == null)
39.107 + return AnonymousClassLoader.class; // anything central will do
39.108 + return hostClass;
39.109 + }
39.110 +
39.111 + if (hostClass == null)
39.112 + hostClass = caller; // default value is caller itself
39.113 +
39.114 + // anonymous class will access hostClass on behalf of caller
39.115 + Class<?> callee = hostClass;
39.116 +
39.117 + if (caller == callee)
39.118 + // caller can always nominate itself to grant caller's own access rights
39.119 + return hostClass;
39.120 +
39.121 + // normalize caller and callee to their top-level classes:
39.122 + caller = getTopLevelClass(caller);
39.123 + callee = getTopLevelClass(callee);
39.124 + if (caller == callee)
39.125 + return caller;
39.126 +
39.127 + ClassLoader callerCL = caller.getClassLoader();
39.128 + if (callerCL == null) {
39.129 + // caller is trusted code, so accept the proposed hostClass
39.130 + return hostClass;
39.131 + }
39.132 +
39.133 + // %%% should do something with doPrivileged, because trusted
39.134 + // code should have a way to execute on behalf of
39.135 + // partially-trusted clients
39.136 +
39.137 + // Does the caller have the right to access the private
39.138 + // members of the callee? If not, raise an error.
39.139 + final int ACC_PRIVATE = 2;
39.140 + try {
39.141 + sun.reflect.Reflection.ensureMemberAccess(caller, callee, null, ACC_PRIVATE);
39.142 + } catch (IllegalAccessException ee) {
39.143 + throw new IllegalArgumentException(ee);
39.144 + }
39.145 +
39.146 + return hostClass;
39.147 + }
39.148 +
39.149 + public Class<?> loadClass(byte[] classFile) {
39.150 + if (defineAnonymousClass == null) {
39.151 + // no JVM support; try to fake an approximation
39.152 + try {
39.153 + return fakeLoadClass(new ConstantPoolParser(classFile).createPatch());
39.154 + } catch (InvalidConstantPoolFormatException ee) {
39.155 + throw new IllegalArgumentException(ee);
39.156 + }
39.157 + }
39.158 + return loadClass(classFile, null);
39.159 + }
39.160 +
39.161 + public Class<?> loadClass(ConstantPoolPatch classPatch) {
39.162 + if (defineAnonymousClass == null) {
39.163 + // no JVM support; try to fake an approximation
39.164 + return fakeLoadClass(classPatch);
39.165 + }
39.166 + Object[] patches = classPatch.patchArray;
39.167 + // Convert class names (this late in the game)
39.168 + // to use slash '/' instead of dot '.'.
39.169 + // Java likes dots, but the JVM likes slashes.
39.170 + for (int i = 0; i < patches.length; i++) {
39.171 + Object value = patches[i];
39.172 + if (value != null) {
39.173 + byte tag = classPatch.getTag(i);
39.174 + switch (tag) {
39.175 + case ConstantPoolVisitor.CONSTANT_Class:
39.176 + if (value instanceof String) {
39.177 + if (patches == classPatch.patchArray)
39.178 + patches = patches.clone();
39.179 + patches[i] = ((String)value).replace('.', '/');
39.180 + }
39.181 + break;
39.182 + case ConstantPoolVisitor.CONSTANT_Fieldref:
39.183 + case ConstantPoolVisitor.CONSTANT_Methodref:
39.184 + case ConstantPoolVisitor.CONSTANT_InterfaceMethodref:
39.185 + case ConstantPoolVisitor.CONSTANT_NameAndType:
39.186 + // When/if the JVM supports these patches,
39.187 + // we'll probably need to reformat them also.
39.188 + // Meanwhile, let the class loader create the error.
39.189 + break;
39.190 + }
39.191 + }
39.192 + }
39.193 + return loadClass(classPatch.outer.classFile, classPatch.patchArray);
39.194 + }
39.195 +
39.196 + private Class<?> loadClass(byte[] classFile, Object[] patchArray) {
39.197 + try {
39.198 + return (Class<?>)
39.199 + defineAnonymousClass.invoke(unsafe,
39.200 + hostClass, classFile, patchArray);
39.201 + } catch (Exception ex) {
39.202 + throwReflectedException(ex);
39.203 + throw new RuntimeException("error loading into "+hostClass, ex);
39.204 + }
39.205 + }
39.206 +
39.207 + private static void throwReflectedException(Exception ex) {
39.208 + if (ex instanceof InvocationTargetException) {
39.209 + Throwable tex = ((InvocationTargetException)ex).getTargetException();
39.210 + if (tex instanceof Error)
39.211 + throw (Error) tex;
39.212 + ex = (Exception) tex;
39.213 + }
39.214 + if (ex instanceof RuntimeException) {
39.215 + throw (RuntimeException) ex;
39.216 + }
39.217 + }
39.218 +
39.219 + private Class<?> fakeLoadClass(ConstantPoolPatch classPatch) {
39.220 + // Implementation:
39.221 + // 1. Make up a new name nobody has used yet.
39.222 + // 2. Inspect the tail-header of the class to find the this_class index.
39.223 + // 3. Patch the CONSTANT_Class for this_class to the new name.
39.224 + // 4. Add other CP entries required by (e.g.) string patches.
39.225 + // 5. Flatten Class constants down to their names, making sure that
39.226 + // the host class loader can pick them up again accurately.
39.227 + // 6. Generate the edited class file bytes.
39.228 + //
39.229 + // Potential limitations:
39.230 + // * The class won't be truly anonymous, and may interfere with others.
39.231 + // * Flattened class constants might not work, because of loader issues.
39.232 + // * Pseudo-string constants will not flatten down to real strings.
39.233 + // * Method handles will (of course) fail to flatten to linkage strings.
39.234 + if (true) throw new UnsupportedOperationException("NYI");
39.235 + Object[] cpArray;
39.236 + try {
39.237 + cpArray = classPatch.getOriginalCP();
39.238 + } catch (InvalidConstantPoolFormatException ex) {
39.239 + throw new RuntimeException(ex);
39.240 + }
39.241 + int thisClassIndex = classPatch.getParser().getThisClassIndex();
39.242 + String thisClassName = (String) cpArray[thisClassIndex];
39.243 + synchronized (AnonymousClassLoader.class) {
39.244 + thisClassName = thisClassName+"\\|"+(++fakeNameCounter);
39.245 + }
39.246 + classPatch.putUTF8(thisClassIndex, thisClassName);
39.247 + byte[] classFile = null;
39.248 + return unsafe.defineClass(null, classFile, 0, classFile.length,
39.249 + hostClass.getClassLoader(),
39.250 + hostClass.getProtectionDomain());
39.251 + }
39.252 + private static int fakeNameCounter = 99999;
39.253 +
39.254 + // ignore two warnings on this line:
39.255 + static sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
39.256 + // preceding line requires that this class be on the boot class path
39.257 +
39.258 + static private final Method defineAnonymousClass;
39.259 + static {
39.260 + Method dac = null;
39.261 + Class<? extends sun.misc.Unsafe> unsafeClass = unsafe.getClass();
39.262 + try {
39.263 + dac = unsafeClass.getMethod("defineAnonymousClass",
39.264 + Class.class,
39.265 + byte[].class,
39.266 + Object[].class);
39.267 + } catch (Exception ee) {
39.268 + dac = null;
39.269 + }
39.270 + defineAnonymousClass = dac;
39.271 + }
39.272 +
39.273 + private static void noJVMSupport() {
39.274 + throw new UnsupportedOperationException("no JVM support for anonymous classes");
39.275 + }
39.276 +
39.277 +
39.278 + private static native Class<?> loadClassInternal(Class<?> hostClass,
39.279 + byte[] classFile,
39.280 + Object[] patchArray);
39.281 +
39.282 + public static byte[] readClassFile(Class<?> templateClass) throws IOException {
39.283 + String templateName = templateClass.getName();
39.284 + int lastDot = templateName.lastIndexOf('.');
39.285 + java.net.URL url = templateClass.getResource(templateName.substring(lastDot+1)+".class");
39.286 + java.net.URLConnection connection = url.openConnection();
39.287 + int contentLength = connection.getContentLength();
39.288 + if (contentLength < 0)
39.289 + throw new IOException("invalid content length "+contentLength);
39.290 +
39.291 + byte[] classFile = new byte[contentLength];
39.292 + InputStream tcs = connection.getInputStream();
39.293 + for (int fill = 0, nr; fill < classFile.length; fill += nr) {
39.294 + nr = tcs.read(classFile, fill, classFile.length - fill);
39.295 + if (nr < 0)
39.296 + throw new IOException("premature end of file");
39.297 + }
39.298 + return classFile;
39.299 + }
39.300 +}
40.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
40.2 +++ b/src/share/classes/sun/dyn/anon/ConstantPoolParser.java Tue May 05 23:12:47 2009 -0700
40.3 @@ -0,0 +1,368 @@
40.4 +/*
40.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
40.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
40.7 + *
40.8 + * This code is free software; you can redistribute it and/or modify it
40.9 + * under the terms of the GNU General Public License version 2 only, as
40.10 + * published by the Free Software Foundation. Sun designates this
40.11 + * particular file as subject to the "Classpath" exception as provided
40.12 + * by Sun in the LICENSE file that accompanied this code.
40.13 + *
40.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
40.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
40.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
40.17 + * version 2 for more details (a copy is included in the LICENSE file that
40.18 + * accompanied this code).
40.19 + *
40.20 + * You should have received a copy of the GNU General Public License version
40.21 + * 2 along with this work; if not, write to the Free Software Foundation,
40.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
40.23 + *
40.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
40.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
40.26 + * have any questions.
40.27 + */
40.28 +
40.29 +package sun.dyn.anon;
40.30 +
40.31 +import java.io.IOException;
40.32 +import java.io.OutputStream;
40.33 +import java.nio.BufferUnderflowException;
40.34 +import java.nio.ByteBuffer;
40.35 +
40.36 +import static sun.dyn.anon.ConstantPoolVisitor.*;
40.37 +
40.38 +/** A constant pool parser.
40.39 + */
40.40 +public class ConstantPoolParser {
40.41 + final byte[] classFile;
40.42 + final byte[] tags;
40.43 + final char[] firstHeader; // maghi, maglo, minor, major, cplen
40.44 +
40.45 + // these are filled in on first parse:
40.46 + int endOffset;
40.47 + char[] secondHeader; // flags, this_class, super_class, intlen
40.48 +
40.49 + // used to decode UTF8 array
40.50 + private char[] charArray = new char[80];
40.51 +
40.52 + /** Creates a constant pool parser.
40.53 + * @param classFile an array of bytes containing a class.
40.54 + * @throws InvalidConstantPoolFormatException if the header of the class has errors.
40.55 + */
40.56 + public ConstantPoolParser(byte[] classFile) throws InvalidConstantPoolFormatException {
40.57 + this.classFile = classFile;
40.58 + this.firstHeader = parseHeader(classFile);
40.59 + this.tags = new byte[firstHeader[4]];
40.60 + }
40.61 +
40.62 + /** Create a constant pool parser by loading the bytecodes of the
40.63 + * class taken as argument.
40.64 + *
40.65 + * @param templateClass the class to parse.
40.66 + *
40.67 + * @throws IOException raised if an I/O occurs when loading
40.68 + * the bytecode of the template class.
40.69 + * @throws InvalidConstantPoolFormatException if the header of the class has errors.
40.70 + *
40.71 + * @see #ConstantPoolParser(byte[])
40.72 + * @see AnonymousClassLoader#readClassFile(Class)
40.73 + */
40.74 + public ConstantPoolParser(Class<?> templateClass) throws IOException, InvalidConstantPoolFormatException {
40.75 + this(AnonymousClassLoader.readClassFile(templateClass));
40.76 + }
40.77 +
40.78 + /** Creates an empty patch to patch the class file
40.79 + * used by the current parser.
40.80 + * @return a new class patch.
40.81 + */
40.82 + public ConstantPoolPatch createPatch() {
40.83 + return new ConstantPoolPatch(this);
40.84 + }
40.85 +
40.86 + /** Report the tag of the indicated CP entry.
40.87 + * @param index
40.88 + * @return one of {@link ConstantPoolVisitor#CONSTANT_Utf8}, etc.
40.89 + */
40.90 + public byte getTag(int index) {
40.91 + getEndOffset(); // trigger an exception if we haven't parsed yet
40.92 + return tags[index];
40.93 + }
40.94 +
40.95 + /** Report the length of the constant pool. */
40.96 + public int getLength() {
40.97 + return firstHeader[4];
40.98 + }
40.99 +
40.100 + /** Report the offset, within the class file, of the start of the constant pool. */
40.101 + public int getStartOffset() {
40.102 + return firstHeader.length * 2;
40.103 + }
40.104 +
40.105 + /** Report the offset, within the class file, of the end of the constant pool. */
40.106 + public int getEndOffset() {
40.107 + if (endOffset == 0)
40.108 + throw new IllegalStateException("class file has not yet been parsed");
40.109 + return endOffset;
40.110 + }
40.111 +
40.112 + /** Report the CP index of this class's own name. */
40.113 + public int getThisClassIndex() {
40.114 + getEndOffset(); // provoke exception if not yet parsed
40.115 + return secondHeader[1];
40.116 + }
40.117 +
40.118 + /** Report the total size of the class file. */
40.119 + public int getTailLength() {
40.120 + return classFile.length - getEndOffset();
40.121 + }
40.122 +
40.123 + /** Write the head (header plus constant pool)
40.124 + * of the class file to the indicated stream.
40.125 + */
40.126 + public void writeHead(OutputStream out) throws IOException {
40.127 + out.write(classFile, 0, getEndOffset());
40.128 + }
40.129 +
40.130 + /** Write the head (header plus constant pool)
40.131 + * of the class file to the indicated stream,
40.132 + * incorporating the non-null entries of the given array
40.133 + * as patches.
40.134 + */
40.135 + void writePatchedHead(OutputStream out, Object[] patchArray) {
40.136 + // this will be useful to partially emulate the class loader on old JVMs
40.137 + throw new UnsupportedOperationException("Not yet implemented");
40.138 + }
40.139 +
40.140 + /** Write the tail (everything after the constant pool)
40.141 + * of the class file to the indicated stream.
40.142 + */
40.143 + public void writeTail(OutputStream out) throws IOException {
40.144 + out.write(classFile, getEndOffset(), getTailLength());
40.145 + }
40.146 +
40.147 + private static char[] parseHeader(byte[] classFile) throws InvalidConstantPoolFormatException {
40.148 + char[] result = new char[5];
40.149 + ByteBuffer buffer = ByteBuffer.wrap(classFile);
40.150 + for (int i = 0; i < result.length; i++)
40.151 + result[i] = (char) getUnsignedShort(buffer);
40.152 + int magic = result[0] << 16 | result[1] << 0;
40.153 + if (magic != 0xCAFEBABE)
40.154 + throw new InvalidConstantPoolFormatException("invalid magic number "+magic);
40.155 + // skip major, minor version
40.156 + int len = result[4];
40.157 + if (len < 1)
40.158 + throw new InvalidConstantPoolFormatException("constant pool length < 1");
40.159 + return result;
40.160 + }
40.161 +
40.162 + /** Parse the constant pool of the class
40.163 + * calling a method visit* each time a constant pool entry is parsed.
40.164 + *
40.165 + * The order of the calls to visit* is not guaranteed to be the same
40.166 + * than the order of the constant pool entry in the bytecode array.
40.167 + *
40.168 + * @param visitor
40.169 + * @throws InvalidConstantPoolFormatException
40.170 + */
40.171 + public void parse(ConstantPoolVisitor visitor) throws InvalidConstantPoolFormatException {
40.172 + ByteBuffer buffer = ByteBuffer.wrap(classFile);
40.173 + buffer.position(getStartOffset()); //skip header
40.174 +
40.175 + Object[] values = new Object[getLength()];
40.176 + try {
40.177 + parseConstantPool(buffer, values, visitor);
40.178 + } catch(BufferUnderflowException e) {
40.179 + throw new InvalidConstantPoolFormatException(e);
40.180 + }
40.181 + if (endOffset == 0) {
40.182 + endOffset = buffer.position();
40.183 + secondHeader = new char[4];
40.184 + for (int i = 0; i < secondHeader.length; i++) {
40.185 + secondHeader[i] = (char) getUnsignedShort(buffer);
40.186 + }
40.187 + }
40.188 + resolveConstantPool(values, visitor);
40.189 + }
40.190 +
40.191 + private char[] getCharArray(int utfLength) {
40.192 + if (utfLength <= charArray.length)
40.193 + return charArray;
40.194 + return charArray = new char[utfLength];
40.195 + }
40.196 +
40.197 + private void parseConstantPool(ByteBuffer buffer, Object[] values, ConstantPoolVisitor visitor) throws InvalidConstantPoolFormatException {
40.198 + for (int i = 1; i < tags.length; ) {
40.199 + byte tag = (byte) getUnsignedByte(buffer);
40.200 + assert(tags[i] == 0 || tags[i] == tag);
40.201 + tags[i] = tag;
40.202 + switch (tag) {
40.203 + case CONSTANT_Utf8:
40.204 + int utfLen = getUnsignedShort(buffer);
40.205 + String value = getUTF8(buffer, utfLen, getCharArray(utfLen));
40.206 + visitor.visitUTF8(i, CONSTANT_Utf8, value);
40.207 + tags[i] = tag;
40.208 + values[i++] = value;
40.209 + break;
40.210 + case CONSTANT_Integer:
40.211 + visitor.visitConstantValue(i, tag, buffer.getInt());
40.212 + i++;
40.213 + break;
40.214 + case CONSTANT_Float:
40.215 + visitor.visitConstantValue(i, tag, buffer.getFloat());
40.216 + i++;
40.217 + break;
40.218 + case CONSTANT_Long:
40.219 + visitor.visitConstantValue(i, tag, buffer.getLong());
40.220 + i+=2;
40.221 + break;
40.222 + case CONSTANT_Double:
40.223 + visitor.visitConstantValue(i, tag, buffer.getDouble());
40.224 + i+=2;
40.225 + break;
40.226 +
40.227 + case CONSTANT_Class: // fall through:
40.228 + case CONSTANT_String:
40.229 + tags[i] = tag;
40.230 + values[i++] = new int[] { getUnsignedShort(buffer) };
40.231 + break;
40.232 +
40.233 + case CONSTANT_Fieldref: // fall through:
40.234 + case CONSTANT_Methodref: // fall through:
40.235 + case CONSTANT_InterfaceMethodref: // fall through:
40.236 + case CONSTANT_NameAndType:
40.237 + tags[i] = tag;
40.238 + values[i++] = new int[] { getUnsignedShort(buffer), getUnsignedShort(buffer) };
40.239 + break;
40.240 + default:
40.241 + throw new AssertionError("invalid constant "+tag);
40.242 + }
40.243 + }
40.244 + }
40.245 +
40.246 + private void resolveConstantPool(Object[] values, ConstantPoolVisitor visitor) {
40.247 + // clean out the int[] values, which are temporary
40.248 + for (int beg = 1, end = values.length-1, beg2, end2;
40.249 + beg <= end;
40.250 + beg = beg2, end = end2) {
40.251 + beg2 = end; end2 = beg-1;
40.252 + //System.out.println("CP resolve pass: "+beg+".."+end);
40.253 + for (int i = beg; i <= end; i++) {
40.254 + Object value = values[i];
40.255 + if (!(value instanceof int[]))
40.256 + continue;
40.257 + int[] array = (int[]) value;
40.258 + byte tag = tags[i];
40.259 + switch (tag) {
40.260 + case CONSTANT_String:
40.261 + String stringBody = (String) values[array[0]];
40.262 + visitor.visitConstantString(i, tag, stringBody, array[0]);
40.263 + values[i] = null;
40.264 + break;
40.265 + case CONSTANT_Class: {
40.266 + String className = (String) values[array[0]];
40.267 + // use the external form favored by Class.forName:
40.268 + className = className.replace('/', '.');
40.269 + visitor.visitConstantString(i, tag, className, array[0]);
40.270 + values[i] = className;
40.271 + break;
40.272 + }
40.273 + case CONSTANT_NameAndType: {
40.274 + String memberName = (String) values[array[0]];
40.275 + String signature = (String) values[array[1]];
40.276 + visitor.visitDescriptor(i, tag, memberName, signature,
40.277 + array[0], array[1]);
40.278 + values[i] = new String[] {memberName, signature};
40.279 + break;
40.280 + }
40.281 + case CONSTANT_Fieldref: // fall through:
40.282 + case CONSTANT_Methodref: // fall through:
40.283 + case CONSTANT_InterfaceMethodref: {
40.284 + Object className = values[array[0]];
40.285 + Object nameAndType = values[array[1]];
40.286 + if (!(className instanceof String) ||
40.287 + !(nameAndType instanceof String[])) {
40.288 + // one more pass is needed
40.289 + if (beg2 > i) beg2 = i;
40.290 + if (end2 < i) end2 = i;
40.291 + continue;
40.292 + }
40.293 + String[] nameAndTypeArray = (String[]) nameAndType;
40.294 + visitor.visitMemberRef(i, tag,
40.295 + (String)className,
40.296 + nameAndTypeArray[0],
40.297 + nameAndTypeArray[1],
40.298 + array[0], array[1]);
40.299 + values[i] = null;
40.300 + }
40.301 + break;
40.302 + default:
40.303 + continue;
40.304 + }
40.305 + }
40.306 + }
40.307 + }
40.308 +
40.309 + private static int getUnsignedByte(ByteBuffer buffer) {
40.310 + return buffer.get() & 0xFF;
40.311 + }
40.312 +
40.313 + private static int getUnsignedShort(ByteBuffer buffer) {
40.314 + int b1 = getUnsignedByte(buffer);
40.315 + int b2 = getUnsignedByte(buffer);
40.316 + return (b1 << 8) + (b2 << 0);
40.317 + }
40.318 +
40.319 + private static String getUTF8(ByteBuffer buffer, int utfLen, char[] charArray) throws InvalidConstantPoolFormatException {
40.320 + int utfLimit = buffer.position() + utfLen;
40.321 + int index = 0;
40.322 + while (buffer.position() < utfLimit) {
40.323 + int c = buffer.get() & 0xff;
40.324 + if (c > 127) {
40.325 + buffer.position(buffer.position() - 1);
40.326 + return getUTF8Extended(buffer, utfLimit, charArray, index);
40.327 + }
40.328 + charArray[index++] = (char)c;
40.329 + }
40.330 + return new String(charArray, 0, index);
40.331 + }
40.332 +
40.333 + private static String getUTF8Extended(ByteBuffer buffer, int utfLimit, char[] charArray, int index) throws InvalidConstantPoolFormatException {
40.334 + int c, c2, c3;
40.335 + while (buffer.position() < utfLimit) {
40.336 + c = buffer.get() & 0xff;
40.337 + switch (c >> 4) {
40.338 + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
40.339 + /* 0xxxxxxx*/
40.340 + charArray[index++] = (char)c;
40.341 + break;
40.342 + case 12: case 13:
40.343 + /* 110x xxxx 10xx xxxx*/
40.344 + c2 = buffer.get();
40.345 + if ((c2 & 0xC0) != 0x80)
40.346 + throw new InvalidConstantPoolFormatException(
40.347 + "malformed input around byte " + buffer.position());
40.348 + charArray[index++] = (char)(((c & 0x1F) << 6) |
40.349 + (c2 & 0x3F));
40.350 + break;
40.351 + case 14:
40.352 + /* 1110 xxxx 10xx xxxx 10xx xxxx */
40.353 + c2 = buffer.get();
40.354 + c3 = buffer.get();
40.355 + if (((c2 & 0xC0) != 0x80) || ((c3 & 0xC0) != 0x80))
40.356 + throw new InvalidConstantPoolFormatException(
40.357 + "malformed input around byte " + (buffer.position()));
40.358 + charArray[index++] = (char)(((c & 0x0F) << 12) |
40.359 + ((c2 & 0x3F) << 6) |
40.360 + ((c3 & 0x3F) << 0));
40.361 + break;
40.362 + default:
40.363 + /* 10xx xxxx, 1111 xxxx */
40.364 + throw new InvalidConstantPoolFormatException(
40.365 + "malformed input around byte " + buffer.position());
40.366 + }
40.367 + }
40.368 + // The number of chars produced may be less than utflen
40.369 + return new String(charArray, 0, index);
40.370 + }
40.371 +}
41.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
41.2 +++ b/src/share/classes/sun/dyn/anon/ConstantPoolPatch.java Tue May 05 23:12:47 2009 -0700
41.3 @@ -0,0 +1,503 @@
41.4 +/*
41.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
41.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
41.7 + *
41.8 + * This code is free software; you can redistribute it and/or modify it
41.9 + * under the terms of the GNU General Public License version 2 only, as
41.10 + * published by the Free Software Foundation. Sun designates this
41.11 + * particular file as subject to the "Classpath" exception as provided
41.12 + * by Sun in the LICENSE file that accompanied this code.
41.13 + *
41.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
41.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
41.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
41.17 + * version 2 for more details (a copy is included in the LICENSE file that
41.18 + * accompanied this code).
41.19 + *
41.20 + * You should have received a copy of the GNU General Public License version
41.21 + * 2 along with this work; if not, write to the Free Software Foundation,
41.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
41.23 + *
41.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
41.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
41.26 + * have any questions.
41.27 + */
41.28 +
41.29 +package sun.dyn.anon;
41.30 +
41.31 +import java.io.IOException;
41.32 +import java.io.OutputStream;
41.33 +import java.util.Arrays;
41.34 +import java.util.HashSet;
41.35 +import java.util.IdentityHashMap;
41.36 +import java.util.Map;
41.37 +
41.38 +import static sun.dyn.anon.ConstantPoolVisitor.*;
41.39 +
41.40 +/** A class and its patched constant pool.
41.41 + *
41.42 + * This class allow to modify (patch) a constant pool
41.43 + * by changing the value of its entry.
41.44 + * Entry are referenced using index that can be get
41.45 + * by parsing the constant pool using
41.46 + * {@link ConstantPoolParser#parse(ConstantPoolVisitor)}.
41.47 + *
41.48 + * @see ConstantPoolVisitor
41.49 + * @see ConstantPoolParser#createPatch()
41.50 + */
41.51 +public class ConstantPoolPatch {
41.52 + final ConstantPoolParser outer;
41.53 + final Object[] patchArray;
41.54 +
41.55 + ConstantPoolPatch(ConstantPoolParser outer) {
41.56 + this.outer = outer;
41.57 + this.patchArray = new Object[outer.getLength()];
41.58 + }
41.59 +
41.60 + /** Create a {@link ConstantPoolParser} and
41.61 + * a {@link ConstantPoolPatch} in one step.
41.62 + * Equivalent to {@code new ConstantPoolParser(classFile).createPatch()}.
41.63 + *
41.64 + * @param classFile an array of bytes containing a class.
41.65 + * @see #ConstantPoolParser(Class)
41.66 + */
41.67 + public ConstantPoolPatch(byte[] classFile) throws InvalidConstantPoolFormatException {
41.68 + this(new ConstantPoolParser(classFile));
41.69 + }
41.70 +
41.71 + /** Create a {@link ConstantPoolParser} and
41.72 + * a {@link ConstantPoolPatch} in one step.
41.73 + * Equivalent to {@code new ConstantPoolParser(templateClass).createPatch()}.
41.74 + *
41.75 + * @param templateClass the class to parse.
41.76 + * @see #ConstantPoolParser(Class)
41.77 + */
41.78 + public ConstantPoolPatch(Class<?> templateClass) throws IOException, InvalidConstantPoolFormatException {
41.79 + this(new ConstantPoolParser(templateClass));
41.80 + }
41.81 +
41.82 +
41.83 + /** Creates a patch from an existing patch.
41.84 + * All changes are copied from that patch.
41.85 + * @param patch a patch
41.86 + *
41.87 + * @see ConstantPoolParser#createPatch()
41.88 + */
41.89 + public ConstantPoolPatch(ConstantPoolPatch patch) {
41.90 + outer = patch.outer;
41.91 + patchArray = patch.patchArray.clone();
41.92 + }
41.93 +
41.94 + /** Which parser built this patch? */
41.95 + public ConstantPoolParser getParser() {
41.96 + return outer;
41.97 + }
41.98 +
41.99 + /** Report the tag at the given index in the constant pool. */
41.100 + public byte getTag(int index) {
41.101 + return outer.getTag(index);
41.102 + }
41.103 +
41.104 + /** Report the current patch at the given index of the constant pool.
41.105 + * Null means no patch will be made.
41.106 + * To observe the unpatched entry at the given index, use
41.107 + * {@link #getParser()}{@code .}@link ConstantPoolParser#parse(ConstantPoolVisitor)}
41.108 + */
41.109 + public Object getPatch(int index) {
41.110 + Object value = patchArray[index];
41.111 + if (value == null) return null;
41.112 + switch (getTag(index)) {
41.113 + case CONSTANT_Fieldref:
41.114 + case CONSTANT_Methodref:
41.115 + case CONSTANT_InterfaceMethodref:
41.116 + if (value instanceof String)
41.117 + value = stripSemis(2, (String) value);
41.118 + break;
41.119 + case CONSTANT_NameAndType:
41.120 + if (value instanceof String)
41.121 + value = stripSemis(1, (String) value);
41.122 + break;
41.123 + }
41.124 + return value;
41.125 + }
41.126 +
41.127 + /** Clear all patches. */
41.128 + public void clear() {
41.129 + Arrays.fill(patchArray, null);
41.130 + }
41.131 +
41.132 + /** Clear one patch. */
41.133 + public void clear(int index) {
41.134 + patchArray[index] = null;
41.135 + }
41.136 +
41.137 + /** Produce the patches as an array. */
41.138 + public Object[] getPatches() {
41.139 + return patchArray.clone();
41.140 + }
41.141 +
41.142 + /** Produce the original constant pool as an array. */
41.143 + public Object[] getOriginalCP() throws InvalidConstantPoolFormatException {
41.144 + return getOriginalCP(0, patchArray.length, -1);
41.145 + }
41.146 +
41.147 + /** Walk the constant pool, applying patches using the given map.
41.148 + *
41.149 + * @param utf8Map Utf8 strings to modify, if encountered
41.150 + * @param classMap Classes (or their names) to modify, if encountered
41.151 + * @param valueMap Constant values to modify, if encountered
41.152 + * @param deleteUsedEntries if true, delete map entries that are used
41.153 + */
41.154 + public void putPatches(final Map<String,String> utf8Map,
41.155 + final Map<String,Object> classMap,
41.156 + final Map<Object,Object> valueMap,
41.157 + boolean deleteUsedEntries) throws InvalidConstantPoolFormatException {
41.158 + final HashSet<String> usedUtf8Keys;
41.159 + final HashSet<String> usedClassKeys;
41.160 + final HashSet<Object> usedValueKeys;
41.161 + if (deleteUsedEntries) {
41.162 + usedUtf8Keys = (utf8Map == null) ? null : new HashSet<String>();
41.163 + usedClassKeys = (classMap == null) ? null : new HashSet<String>();
41.164 + usedValueKeys = (valueMap == null) ? null : new HashSet<Object>();
41.165 + } else {
41.166 + usedUtf8Keys = null;
41.167 + usedClassKeys = null;
41.168 + usedValueKeys = null;
41.169 + }
41.170 +
41.171 + outer.parse(new ConstantPoolVisitor() {
41.172 +
41.173 + @Override
41.174 + public void visitUTF8(int index, byte tag, String utf8) {
41.175 + putUTF8(index, utf8Map.get(utf8));
41.176 + if (usedUtf8Keys != null) usedUtf8Keys.add(utf8);
41.177 + }
41.178 +
41.179 + @Override
41.180 + public void visitConstantValue(int index, byte tag, Object value) {
41.181 + putConstantValue(index, tag, valueMap.get(value));
41.182 + if (usedValueKeys != null) usedValueKeys.add(value);
41.183 + }
41.184 +
41.185 + @Override
41.186 + public void visitConstantString(int index, byte tag, String name, int nameIndex) {
41.187 + if (tag == CONSTANT_Class) {
41.188 + putConstantValue(index, tag, classMap.get(name));
41.189 + if (usedClassKeys != null) usedClassKeys.add(name);
41.190 + } else {
41.191 + assert(tag == CONSTANT_String);
41.192 + visitConstantValue(index, tag, name);
41.193 + }
41.194 + }
41.195 + });
41.196 + if (usedUtf8Keys != null) utf8Map.keySet().removeAll(usedUtf8Keys);
41.197 + if (usedClassKeys != null) classMap.keySet().removeAll(usedClassKeys);
41.198 + if (usedValueKeys != null) valueMap.keySet().removeAll(usedValueKeys);
41.199 + }
41.200 +
41.201 + Object[] getOriginalCP(final int startIndex,
41.202 + final int endIndex,
41.203 + final int tagMask) throws InvalidConstantPoolFormatException {
41.204 + final Object[] cpArray = new Object[endIndex - startIndex];
41.205 + outer.parse(new ConstantPoolVisitor() {
41.206 +
41.207 + void show(int index, byte tag, Object value) {
41.208 + if (index < startIndex || index >= endIndex) return;
41.209 + if (((1 << tag) & tagMask) == 0) return;
41.210 + cpArray[index - startIndex] = value;
41.211 + }
41.212 +
41.213 + @Override
41.214 + public void visitUTF8(int index, byte tag, String utf8) {
41.215 + show(index, tag, utf8);
41.216 + }
41.217 +
41.218 + @Override
41.219 + public void visitConstantValue(int index, byte tag, Object value) {
41.220 + assert(tag != CONSTANT_String);
41.221 + show(index, tag, value);
41.222 + }
41.223 +
41.224 + @Override
41.225 + public void visitConstantString(int index, byte tag,
41.226 + String value, int j) {
41.227 + show(index, tag, value);
41.228 + }
41.229 +
41.230 + @Override
41.231 + public void visitMemberRef(int index, byte tag,
41.232 + String className, String memberName,
41.233 + String signature,
41.234 + int j, int k) {
41.235 + show(index, tag, new String[]{ className, memberName, signature });
41.236 + }
41.237 +
41.238 + @Override
41.239 + public void visitDescriptor(int index, byte tag,
41.240 + String memberName, String signature,
41.241 + int j, int k) {
41.242 + show(index, tag, new String[]{ memberName, signature });
41.243 + }
41.244 + });
41.245 + return cpArray;
41.246 + }
41.247 +
41.248 + /** Write the head (header plus constant pool)
41.249 + * of the patched class file to the indicated stream.
41.250 + */
41.251 + void writeHead(OutputStream out) throws IOException {
41.252 + outer.writePatchedHead(out, patchArray);
41.253 + }
41.254 +
41.255 + /** Write the tail (everything after the constant pool)
41.256 + * of the patched class file to the indicated stream.
41.257 + */
41.258 + void writeTail(OutputStream out) throws IOException {
41.259 + outer.writeTail(out);
41.260 + }
41.261 +
41.262 + private void checkConstantTag(byte tag, Object value) {
41.263 + if (value == null)
41.264 + throw new IllegalArgumentException(
41.265 + "invalid null constant value");
41.266 + if (classForTag(tag) != value.getClass())
41.267 + throw new IllegalArgumentException(
41.268 + "invalid constant value"
41.269 + + (tag == CONSTANT_None ? ""
41.270 + : " for tag "+tagName(tag))
41.271 + + " of class "+value.getClass());
41.272 + }
41.273 +
41.274 + private void checkTag(int index, byte putTag) {
41.275 + byte tag = outer.tags[index];
41.276 + if (tag != putTag)
41.277 + throw new IllegalArgumentException(
41.278 + "invalid put operation"
41.279 + + " for " + tagName(putTag)
41.280 + + " at index " + index + " found " + tagName(tag));
41.281 + }
41.282 +
41.283 + private void checkTagMask(int index, int tagBitMask) {
41.284 + byte tag = outer.tags[index];
41.285 + int tagBit = ((tag & 0x1F) == tag) ? (1 << tag) : 0;
41.286 + if ((tagBit & tagBitMask) == 0)
41.287 + throw new IllegalArgumentException(
41.288 + "invalid put operation"
41.289 + + " at index " + index + " found " + tagName(tag));
41.290 + }
41.291 +
41.292 + private static void checkMemberName(String memberName) {
41.293 + if (memberName.indexOf(';') >= 0)
41.294 + throw new IllegalArgumentException("memberName " + memberName + " contains a ';'");
41.295 + }
41.296 +
41.297 + /** Set the entry of the constant pool indexed by index to
41.298 + * a new string.
41.299 + *
41.300 + * @param index an index to a constant pool entry containing a
41.301 + * {@link ConstantPoolVisitor#CONSTANT_Utf8} value.
41.302 + * @param utf8 a string
41.303 + *
41.304 + * @see ConstantPoolVisitor#visitUTF8(int, byte, String)
41.305 + */
41.306 + public void putUTF8(int index, String utf8) {
41.307 + if (utf8 == null) { clear(index); return; }
41.308 + checkTag(index, CONSTANT_Utf8);
41.309 + patchArray[index] = utf8;
41.310 + }
41.311 +
41.312 + /** Set the entry of the constant pool indexed by index to
41.313 + * a new value, depending on its dynamic type.
41.314 + *
41.315 + * @param index an index to a constant pool entry containing a
41.316 + * one of the following structures:
41.317 + * {@link ConstantPoolVisitor#CONSTANT_Integer},
41.318 + * {@link ConstantPoolVisitor#CONSTANT_Float},
41.319 + * {@link ConstantPoolVisitor#CONSTANT_Long},
41.320 + * {@link ConstantPoolVisitor#CONSTANT_Double},
41.321 + * {@link ConstantPoolVisitor#CONSTANT_String}, or
41.322 + * {@link ConstantPoolVisitor#CONSTANT_Class}
41.323 + * @param value a boxed int, float, long or double; or a string or class object
41.324 + * @throws IllegalArgumentException if the type of the constant does not
41.325 + * match the constant pool entry type,
41.326 + * as reported by {@link #getTag(int)}
41.327 + *
41.328 + * @see #putConstantValue(int, byte, Object)
41.329 + * @see ConstantPoolVisitor#visitConstantValue(int, byte, Object)
41.330 + * @see ConstantPoolVisitor#visitConstantString(int, byte, String, int)
41.331 + */
41.332 + public void putConstantValue(int index, Object value) {
41.333 + if (value == null) { clear(index); return; }
41.334 + byte tag = tagForConstant(value.getClass());
41.335 + checkConstantTag(tag, value);
41.336 + checkTag(index, tag);
41.337 + patchArray[index] = value;
41.338 + }
41.339 +
41.340 + /** Set the entry of the constant pool indexed by index to
41.341 + * a new value.
41.342 + *
41.343 + * @param index an index to a constant pool entry matching the given tag
41.344 + * @param tag one of the following values:
41.345 + * {@link ConstantPoolVisitor#CONSTANT_Integer},
41.346 + * {@link ConstantPoolVisitor#CONSTANT_Float},
41.347 + * {@link ConstantPoolVisitor#CONSTANT_Long},
41.348 + * {@link ConstantPoolVisitor#CONSTANT_Double},
41.349 + * {@link ConstantPoolVisitor#CONSTANT_String}, or
41.350 + * {@link ConstantPoolVisitor#CONSTANT_Class}
41.351 + * @param value a boxed number, string, or class object
41.352 + * @throws IllegalArgumentException if the type of the constant does not
41.353 + * match the constant pool entry type, or if a class name contains
41.354 + * '/' or ';'
41.355 + *
41.356 + * @see #putConstantValue(int, Object)
41.357 + * @see ConstantPoolVisitor#visitConstantValue(int, byte, Object)
41.358 + * @see ConstantPoolVisitor#visitConstantString(int, byte, String, int)
41.359 + */
41.360 + public void putConstantValue(int index, byte tag, Object value) {
41.361 + if (value == null) { clear(index); return; }
41.362 + checkTag(index, tag);
41.363 + if (tag == CONSTANT_Class && value instanceof String) {
41.364 + checkClassName((String) value);
41.365 + } else if (tag == CONSTANT_String) {
41.366 + // the JVM accepts any object as a patch for a string
41.367 + } else {
41.368 + // make sure the incoming value is the right type
41.369 + checkConstantTag(tag, value);
41.370 + }
41.371 + checkTag(index, tag);
41.372 + patchArray[index] = value;
41.373 + }
41.374 +
41.375 + /** Set the entry of the constant pool indexed by index to
41.376 + * a new {@link ConstantPoolVisitor#CONSTANT_NameAndType} value.
41.377 + *
41.378 + * @param index an index to a constant pool entry containing a
41.379 + * {@link ConstantPoolVisitor#CONSTANT_NameAndType} value.
41.380 + * @param memberName a memberName
41.381 + * @param signature a signature
41.382 + * @throws IllegalArgumentException if memberName contains the character ';'
41.383 + *
41.384 + * @see ConstantPoolVisitor#visitDescriptor(int, byte, String, String, int, int)
41.385 + */
41.386 + public void putDescriptor(int index, String memberName, String signature) {
41.387 + checkTag(index, CONSTANT_NameAndType);
41.388 + checkMemberName(memberName);
41.389 + patchArray[index] = addSemis(memberName, signature);
41.390 + }
41.391 +
41.392 + /** Set the entry of the constant pool indexed by index to
41.393 + * a new {@link ConstantPoolVisitor#CONSTANT_Fieldref},
41.394 + * {@link ConstantPoolVisitor#CONSTANT_Methodref}, or
41.395 + * {@link ConstantPoolVisitor#CONSTANT_InterfaceMethodref} value.
41.396 + *
41.397 + * @param index an index to a constant pool entry containing a member reference
41.398 + * @param className a class name
41.399 + * @param memberName a field or method name
41.400 + * @param signature a field or method signature
41.401 + * @throws IllegalArgumentException if memberName contains the character ';'
41.402 + * or signature is not a correct signature
41.403 + *
41.404 + * @see ConstantPoolVisitor#visitMemberRef(int, byte, String, String, String, int, int)
41.405 + */
41.406 + public void putMemberRef(int index, byte tag,
41.407 + String className, String memberName, String signature) {
41.408 + checkTagMask(tag, CONSTANT_MemberRef_MASK);
41.409 + checkTag(index, tag);
41.410 + checkClassName(className);
41.411 + checkMemberName(memberName);
41.412 + if (signature.startsWith("(") == (tag == CONSTANT_Fieldref))
41.413 + throw new IllegalArgumentException("bad signature: "+signature);
41.414 + patchArray[index] = addSemis(className, memberName, signature);
41.415 + }
41.416 +
41.417 + static private final int CONSTANT_MemberRef_MASK =
41.418 + CONSTANT_Fieldref
41.419 + | CONSTANT_Methodref
41.420 + | CONSTANT_InterfaceMethodref;
41.421 +
41.422 + private static final Map<Class<?>, Byte> CONSTANT_VALUE_CLASS_TAG
41.423 + = new IdentityHashMap<Class<?>, Byte>();
41.424 + private static final Class[] CONSTANT_VALUE_CLASS = new Class[16];
41.425 + static {
41.426 + Object[][] values = {
41.427 + {Integer.class, CONSTANT_Integer},
41.428 + {Long.class, CONSTANT_Long},
41.429 + {Float.class, CONSTANT_Float},
41.430 + {Double.class, CONSTANT_Double},
41.431 + {String.class, CONSTANT_String},
41.432 + {Class.class, CONSTANT_Class}
41.433 + };
41.434 + for (Object[] value : values) {
41.435 + Class<?> cls = (Class<?>)value[0];
41.436 + Byte tag = (Byte) value[1];
41.437 + CONSTANT_VALUE_CLASS_TAG.put(cls, tag);
41.438 + CONSTANT_VALUE_CLASS[(byte)tag] = cls;
41.439 + }
41.440 + }
41.441 +
41.442 + static Class<?> classForTag(byte tag) {
41.443 + if ((tag & 0xFF) >= CONSTANT_VALUE_CLASS.length)
41.444 + return null;
41.445 + return CONSTANT_VALUE_CLASS[tag];
41.446 + }
41.447 +
41.448 + static byte tagForConstant(Class<?> cls) {
41.449 + Byte tag = CONSTANT_VALUE_CLASS_TAG.get(cls);
41.450 + return (tag == null) ? CONSTANT_None : (byte)tag;
41.451 + }
41.452 +
41.453 + private static void checkClassName(String className) {
41.454 + if (className.indexOf('/') >= 0 || className.indexOf(';') >= 0)
41.455 + throw new IllegalArgumentException("invalid class name " + className);
41.456 + }
41.457 +
41.458 + static String addSemis(String name, String... names) {
41.459 + StringBuilder buf = new StringBuilder(name.length() * 5);
41.460 + buf.append(name);
41.461 + for (String name2 : names) {
41.462 + buf.append(';').append(name2);
41.463 + }
41.464 + String res = buf.toString();
41.465 + assert(stripSemis(names.length, res)[0].equals(name));
41.466 + assert(stripSemis(names.length, res)[1].equals(names[0]));
41.467 + assert(names.length == 1 ||
41.468 + stripSemis(names.length, res)[2].equals(names[1]));
41.469 + return res;
41.470 + }
41.471 +
41.472 + static String[] stripSemis(int count, String string) {
41.473 + String[] res = new String[count+1];
41.474 + int pos = 0;
41.475 + for (int i = 0; i < count; i++) {
41.476 + int pos2 = string.indexOf(';', pos);
41.477 + if (pos2 < 0) pos2 = string.length(); // yuck
41.478 + res[i] = string.substring(pos, pos2);
41.479 + pos = pos2;
41.480 + }
41.481 + res[count] = string.substring(pos);
41.482 + return res;
41.483 + }
41.484 +
41.485 + public String toString() {
41.486 + StringBuilder buf = new StringBuilder(this.getClass().getName());
41.487 + buf.append("{");
41.488 + Object[] origCP = null;
41.489 + for (int i = 0; i < patchArray.length; i++) {
41.490 + if (patchArray[i] == null) continue;
41.491 + if (origCP != null) {
41.492 + buf.append(", ");
41.493 + } else {
41.494 + try {
41.495 + origCP = getOriginalCP();
41.496 + } catch (InvalidConstantPoolFormatException ee) {
41.497 + origCP = new Object[0];
41.498 + }
41.499 + }
41.500 + Object orig = (i < origCP.length) ? origCP[i] : "?";
41.501 + buf.append(orig).append("=").append(patchArray[i]);
41.502 + }
41.503 + buf.append("}");
41.504 + return buf.toString();
41.505 + }
41.506 +}
42.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
42.2 +++ b/src/share/classes/sun/dyn/anon/ConstantPoolVisitor.java Tue May 05 23:12:47 2009 -0700
42.3 @@ -0,0 +1,192 @@
42.4 +/*
42.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
42.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
42.7 + *
42.8 + * This code is free software; you can redistribute it and/or modify it
42.9 + * under the terms of the GNU General Public License version 2 only, as
42.10 + * published by the Free Software Foundation. Sun designates this
42.11 + * particular file as subject to the "Classpath" exception as provided
42.12 + * by Sun in the LICENSE file that accompanied this code.
42.13 + *
42.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
42.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
42.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
42.17 + * version 2 for more details (a copy is included in the LICENSE file that
42.18 + * accompanied this code).
42.19 + *
42.20 + * You should have received a copy of the GNU General Public License version
42.21 + * 2 along with this work; if not, write to the Free Software Foundation,
42.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
42.23 + *
42.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
42.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
42.26 + * have any questions.
42.27 + */
42.28 +
42.29 +package sun.dyn.anon;
42.30 +
42.31 +/**
42.32 + * A visitor called by {@link ConstantPoolParser#parse(ConstantPoolVisitor)}
42.33 + * when a constant pool entry is parsed.
42.34 + * <p>
42.35 + * A visit* method is called when a constant pool entry is parsed.
42.36 + * The first argument is always the constant pool index.
42.37 + * The second argument is always the constant pool tag,
42.38 + * even for methods like {@link #visitUTF8(int, byte, String)} which only apply to one tag.
42.39 + * String arguments refer to Utf8 or NameAndType entries declared elsewhere,
42.40 + * and are always accompanied by the indexes of those entries.
42.41 + * <p>
42.42 + * The order of the calls to the visit* methods is not necessarily related
42.43 + * to the order of the entries in the constant pool.
42.44 + * If one entry has a reference to another entry, the latter (lower-level)
42.45 + * entry will be visited first.
42.46 + * <p>
42.47 + * The following table shows the relation between constant pool entry
42.48 + * types and the corresponding visit* methods:
42.49 + *
42.50 + * <table border=1 cellpadding=5 summary="constant pool visitor methods">
42.51 + * <tr><th>Tag(s)</th><th>Method</th></tr>
42.52 + * <tr>
42.53 + * <td>{@link #CONSTANT_Utf8}</td>
42.54 + * <td>{@link #visitUTF8(int, byte, String)}</td>
42.55 + * </tr><tr>
42.56 + * <td>{@link #CONSTANT_Integer}, {@link #CONSTANT_Float},
42.57 + * {@link #CONSTANT_Long}, {@link #CONSTANT_Double}</td>
42.58 + * <td>{@link #visitConstantValue(int, byte, Object)}</td>
42.59 + * </tr><tr>
42.60 + * <td>{@link #CONSTANT_String}, {@link #CONSTANT_Class}</td>
42.61 + * <td>{@link #visitConstantString(int, byte, String, int)}</td>
42.62 + * </tr><tr>
42.63 + * <td>{@link #CONSTANT_NameAndType}</td>
42.64 + * <td>{@link #visitDescriptor(int, byte, String, String, int, int)}</td>
42.65 + * </tr><tr>
42.66 + * <td>{@link #CONSTANT_Fieldref},
42.67 + * {@link #CONSTANT_Methodref},
42.68 + * {@link #CONSTANT_InterfaceMethodref}</td>
42.69 + * <td>{@link #visitMemberRef(int, byte, String, String, String, int, int)}</td>
42.70 + * </tr>
42.71 + * </table>
42.72 + *
42.73 + * @see ConstantPoolPatch
42.74 + * @author Remi Forax
42.75 + * @author jrose
42.76 + */
42.77 +public class ConstantPoolVisitor {
42.78 + /** Called each time an UTF8 constant pool entry is found.
42.79 + * @param index the constant pool index
42.80 + * @param tag always {@link #CONSTANT_Utf8}
42.81 + * @param utf8 string encoded in modified UTF-8 format passed as a {@code String}
42.82 + *
42.83 + * @see ConstantPoolPatch#putUTF8(int, String)
42.84 + */
42.85 + public void visitUTF8(int index, byte tag, String utf8) {
42.86 + // do nothing
42.87 + }
42.88 +
42.89 + /** Called for each constant pool entry that encodes an integer,
42.90 + * a float, a long, or a double.
42.91 + * Constant strings and classes are not managed by this method but
42.92 + * by {@link #visitConstantString(int, byte, String, int)}.
42.93 + *
42.94 + * @param index the constant pool index
42.95 + * @param tag one of {@link #CONSTANT_Integer},
42.96 + * {@link #CONSTANT_Float},
42.97 + * {@link #CONSTANT_Long},
42.98 + * or {@link #CONSTANT_Double}
42.99 + * @param value encoded value
42.100 + *
42.101 + * @see ConstantPoolPatch#putConstantValue(int, Object)
42.102 + */
42.103 + public void visitConstantValue(int index, byte tag, Object value) {
42.104 + // do nothing
42.105 + }
42.106 +
42.107 + /** Called for each constant pool entry that encodes a string or a class.
42.108 + * @param index the constant pool index
42.109 + * @param tag one of {@link #CONSTANT_String},
42.110 + * {@link #CONSTANT_Class},
42.111 + * @param name string body or class name (using dot separator)
42.112 + * @param nameIndex the index of the Utf8 string for the name
42.113 + *
42.114 + * @see ConstantPoolPatch#putConstantValue(int, byte, Object)
42.115 + */
42.116 + public void visitConstantString(int index, byte tag,
42.117 + String name, int nameIndex) {
42.118 + // do nothing
42.119 + }
42.120 +
42.121 + /** Called for each constant pool entry that encodes a name and type.
42.122 + * @param index the constant pool index
42.123 + * @param tag always {@link #CONSTANT_NameAndType}
42.124 + * @param memberName a field or method name
42.125 + * @param signature the member signature
42.126 + * @param memberNameIndex index of the Utf8 string for the member name
42.127 + * @param signatureIndex index of the Utf8 string for the signature
42.128 + *
42.129 + * @see ConstantPoolPatch#putDescriptor(int, String, String)
42.130 + */
42.131 + public void visitDescriptor(int index, byte tag,
42.132 + String memberName, String signature,
42.133 + int memberNameIndex, int signatureIndex) {
42.134 + // do nothing
42.135 + }
42.136 +
42.137 + /** Called for each constant pool entry that encodes a field or method.
42.138 + * @param index the constant pool index
42.139 + * @param tag one of {@link #CONSTANT_Fieldref},
42.140 + * or {@link #CONSTANT_Methodref},
42.141 + * or {@link #CONSTANT_InterfaceMethodref}
42.142 + * @param className the class name (using dot separator)
42.143 + * @param memberName name of the field or method
42.144 + * @param signature the field or method signature
42.145 + * @param classNameIndex index of the Utf8 string for the class name
42.146 + * @param descriptorIndex index of the NameAndType descriptor constant
42.147 + *
42.148 + * @see ConstantPoolPatch#putMemberRef(int, byte, String, String, String)
42.149 + */
42.150 + public void visitMemberRef(int index, byte tag,
42.151 + String className, String memberName, String signature,
42.152 + int classNameIndex, int descriptorIndex) {
42.153 + // do nothing
42.154 + }
42.155 +
42.156 + public static final byte
42.157 + CONSTANT_None = 0,
42.158 + CONSTANT_Utf8 = 1,
42.159 + //CONSTANT_Unicode = 2, /* unused */
42.160 + CONSTANT_Integer = 3,
42.161 + CONSTANT_Float = 4,
42.162 + CONSTANT_Long = 5,
42.163 + CONSTANT_Double = 6,
42.164 + CONSTANT_Class = 7,
42.165 + CONSTANT_String = 8,
42.166 + CONSTANT_Fieldref = 9,
42.167 + CONSTANT_Methodref = 10,
42.168 + CONSTANT_InterfaceMethodref = 11,
42.169 + CONSTANT_NameAndType = 12;
42.170 +
42.171 + private static String[] TAG_NAMES = {
42.172 + "Empty",
42.173 + "Utf8",
42.174 + null, //"Unicode",
42.175 + "Integer",
42.176 + "Float",
42.177 + "Long",
42.178 + "Double",
42.179 + "Class",
42.180 + "String",
42.181 + "Fieldref",
42.182 + "Methodref",
42.183 + "InterfaceMethodref",
42.184 + "NameAndType"
42.185 + };
42.186 +
42.187 + public static String tagName(byte tag) {
42.188 + String name = null;
42.189 + if ((tag & 0xFF) < TAG_NAMES.length)
42.190 + name = TAG_NAMES[tag];
42.191 + if (name == null)
42.192 + name = "Unknown#"+(tag&0xFF);
42.193 + return name;
42.194 + }
42.195 +}
43.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
43.2 +++ b/src/share/classes/sun/dyn/anon/InvalidConstantPoolFormatException.java Tue May 05 23:12:47 2009 -0700
43.3 @@ -0,0 +1,45 @@
43.4 +/*
43.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
43.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
43.7 + *
43.8 + * This code is free software; you can redistribute it and/or modify it
43.9 + * under the terms of the GNU General Public License version 2 only, as
43.10 + * published by the Free Software Foundation. Sun designates this
43.11 + * particular file as subject to the "Classpath" exception as provided
43.12 + * by Sun in the LICENSE file that accompanied this code.
43.13 + *
43.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
43.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
43.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
43.17 + * version 2 for more details (a copy is included in the LICENSE file that
43.18 + * accompanied this code).
43.19 + *
43.20 + * You should have received a copy of the GNU General Public License version
43.21 + * 2 along with this work; if not, write to the Free Software Foundation,
43.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
43.23 + *
43.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
43.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
43.26 + * have any questions.
43.27 + */
43.28 +
43.29 +package sun.dyn.anon;
43.30 +
43.31 +/** Exception used when there is an error in the constant pool
43.32 + * format.
43.33 + */
43.34 +public class InvalidConstantPoolFormatException extends Exception {
43.35 + private static final long serialVersionUID=-6103888330523770949L;
43.36 +
43.37 + public InvalidConstantPoolFormatException(String message,Throwable cause) {
43.38 + super(message,cause);
43.39 + }
43.40 +
43.41 + public InvalidConstantPoolFormatException(String message) {
43.42 + super(message);
43.43 + }
43.44 +
43.45 + public InvalidConstantPoolFormatException(Throwable cause) {
43.46 + super(cause);
43.47 + }
43.48 +}
44.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
44.2 +++ b/src/share/classes/sun/dyn/empty/Empty.java Tue May 05 23:12:47 2009 -0700
44.3 @@ -0,0 +1,36 @@
44.4 +/*
44.5 + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
44.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44.7 + *
44.8 + * This code is free software; you can redistribute it and/or modify it
44.9 + * under the terms of the GNU General Public License version 2 only, as
44.10 + * published by the Free Software Foundation. Sun designates this
44.11 + * particular file as subject to the "Classpath" exception as provided
44.12 + * by Sun in the LICENSE file that accompanied this code.
44.13 + *
44.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
44.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
44.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
44.17 + * version 2 for more details (a copy is included in the LICENSE file that
44.18 + * accompanied this code).
44.19 + *
44.20 + * You should have received a copy of the GNU General Public License version
44.21 + * 2 along with this work; if not, write to the Free Software Foundation,
44.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
44.23 + *
44.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
44.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
44.26 + * have any questions.
44.27 + */
44.28 +
44.29 +package sun.dyn.empty;
44.30 +
44.31 +/**
44.32 + * An empty class in an empty package.
44.33 + * Used as a proxy for unprivileged code, since making access checks
44.34 + * against it will only succeed against public methods in public types.
44.35 + * @author jrose
44.36 + */
44.37 +public class Empty {
44.38 + private Empty() { throw new InternalError(); }
44.39 +}
45.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
45.2 +++ b/src/share/classes/sun/dyn/package-info.java Tue May 05 23:12:47 2009 -0700
45.3 @@ -0,0 +1,35 @@
45.4 +/*
45.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
45.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
45.7 + *
45.8 + * This code is free software; you can redistribute it and/or modify it
45.9 + * under the terms of the GNU General Public License version 2 only, as
45.10 + * published by the Free Software Foundation. Sun designates this
45.11 + * particular file as subject to the "Classpath" exception as provided
45.12 + * by Sun in the LICENSE file that accompanied this code.
45.13 + *
45.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
45.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
45.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
45.17 + * version 2 for more details (a copy is included in the LICENSE file that
45.18 + * accompanied this code).
45.19 + *
45.20 + * You should have received a copy of the GNU General Public License version
45.21 + * 2 along with this work; if not, write to the Free Software Foundation,
45.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
45.23 + *
45.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
45.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
45.26 + * have any questions.
45.27 + */
45.28 +
45.29 +/**
45.30 + * Implementation details for JSR 292 RI, package java.dyn.
45.31 + * This particular version is specific to Hotspot.
45.32 + * There is also a backport version of this sub-package which uses reflection,
45.33 + * and can therefore run (slowly) on older versions of Java.
45.34 + * Other JVM vendors may create their own versions of this sub-package.
45.35 + * @author jrose
45.36 + */
45.37 +
45.38 +package sun.dyn;
46.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
46.2 +++ b/src/share/classes/sun/dyn/util/BytecodeName.java Tue May 05 23:12:47 2009 -0700
46.3 @@ -0,0 +1,711 @@
46.4 +/*
46.5 + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved.
46.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
46.7 + *
46.8 + * This code is free software; you can redistribute it and/or modify it
46.9 + * under the terms of the GNU General Public License version 2 only, as
46.10 + * published by the Free Software Foundation. Sun designates this
46.11 + * particular file as subject to the "Classpath" exception as provided
46.12 + * by Sun in the LICENSE file that accompanied this code.
46.13 + *
46.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
46.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
46.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
46.17 + * version 2 for more details (a copy is included in the LICENSE file that
46.18 + * accompanied this code).
46.19 + *
46.20 + * You should have received a copy of the GNU General Public License version
46.21 + * 2 along with this work; if not, write to the Free Software Foundation,
46.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
46.23 + *
46.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
46.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
46.26 + * have any questions.
46.27 + */
46.28 +
46.29 +package sun.dyn.util;
46.30 +
46.31 +/**
46.32 + * Utility routines for dealing with bytecode-level names.
46.33 + * Includes universal mangling rules for the JVM.
46.34 + *
46.35 + * <h3>Avoiding Dangerous Characters </h3>
46.36 + *
46.37 + * <p>
46.38 + * The JVM defines a very small set of characters which are illegal
46.39 + * in name spellings. We will slightly extend and regularize this set
46.40 + * into a group of <cite>dangerous characters</cite>.
46.41 + * These characters will then be replaced, in mangled names, by escape sequences.
46.42 + * In addition, accidental escape sequences must be further escaped.
46.43 + * Finally, a special prefix will be applied if and only if
46.44 + * the mangling would otherwise fail to begin with the escape character.
46.45 + * This happens to cover the corner case of the null string,
46.46 + * and also clearly marks symbols which need demangling.
46.47 + * </p>
46.48 + * <p>
46.49 + * Dangerous characters are the union of all characters forbidden
46.50 + * or otherwise restricted by the JVM specification,
46.51 + * plus their mates, if they are brackets
46.52 + * (<code><big><b>[</b></big></code> and <code><big><b>]</b></big></code>,
46.53 + * <code><big><b><</b></big></code> and <code><big><b>></b></big></code>),
46.54 + * plus, arbitrarily, the colon character <code><big><b>:</b></big></code>.
46.55 + * There is no distinction between type, method, and field names.
46.56 + * This makes it easier to convert between mangled names of different
46.57 + * types, since they do not need to be decoded (demangled).
46.58 + * </p>
46.59 + * <p>
46.60 + * The escape character is backslash <code><big><b>\</b></big></code>
46.61 + * (also known as reverse solidus).
46.62 + * This character is, until now, unheard of in bytecode names,
46.63 + * but traditional in the proposed role.
46.64 + *
46.65 + * </p>
46.66 + * <h3> Replacement Characters </h3>
46.67 + *
46.68 + *
46.69 + * <p>
46.70 + * Every escape sequence is two characters
46.71 + * (in fact, two UTF8 bytes) beginning with
46.72 + * the escape character and followed by a
46.73 + * <cite>replacement character</cite>.
46.74 + * (Since the replacement character is never a backslash,
46.75 + * iterated manglings do not double in size.)
46.76 + * </p>
46.77 + * <p>
46.78 + * Each dangerous character has some rough visual similarity
46.79 + * to its corresponding replacement character.
46.80 + * This makes mangled symbols easier to recognize by sight.
46.81 + * </p>
46.82 + * <p>
46.83 + * The dangerous characters are
46.84 + * <code><big><b>/</b></big></code> (forward slash, used to delimit package components),
46.85 + * <code><big><b>.</b></big></code> (dot, also a package delimiter),
46.86 + * <code><big><b>;</b></big></code> (semicolon, used in signatures),
46.87 + * <code><big><b>$</b></big></code> (dollar, used in inner classes and synthetic members),
46.88 + * <code><big><b><</b></big></code> (left angle),
46.89 + * <code><big><b>></b></big></code> (right angle),
46.90 + * <code><big><b>[</b></big></code> (left square bracket, used in array types),
46.91 + * <code><big><b>]</b></big></code> (right square bracket, reserved in this scheme for language use),
46.92 + * and <code><big><b>:</b></big></code> (colon, reserved in this scheme for language use).
46.93 + * Their replacements are, respectively,
46.94 + * <code><big><b>|</b></big></code> (vertical bar),
46.95 + * <code><big><b>,</b></big></code> (comma),
46.96 + * <code><big><b>?</b></big></code> (question mark),
46.97 + * <code><big><b>%</b></big></code> (percent),
46.98 + * <code><big><b>^</b></big></code> (caret),
46.99 + * <code><big><b>_</b></big></code> (underscore), and
46.100 + * <code><big><b>{</b></big></code> (left curly bracket),
46.101 + * <code><big><b>}</b></big></code> (right curly bracket),
46.102 + * <code><big><b>!</b></big></code> (exclamation mark).
46.103 + * In addition, the replacement character for the escape character itself is
46.104 + * <code><big><b>-</b></big></code> (hyphen),
46.105 + * and the replacement character for the null prefix is
46.106 + * <code><big><b>=</b></big></code> (equal sign).
46.107 + * </p>
46.108 + * <p>
46.109 + * An escape character <code><big><b>\</b></big></code>
46.110 + * followed by any of these replacement characters
46.111 + * is an escape sequence, and there are no other escape sequences.
46.112 + * An equal sign is only part of an escape sequence
46.113 + * if it is the second character in the whole string, following a backslash.
46.114 + * Two consecutive backslashes do <em>not</em> form an escape sequence.
46.115 + * </p>
46.116 + * <p>
46.117 + * Each escape sequence replaces a so-called <cite>original character</cite>
46.118 + * which is either one of the dangerous characters or the escape character.
46.119 + * A null prefix replaces an initial null string, not a character.
46.120 + * </p>
46.121 + * <p>
46.122 + * All this implies that escape sequences cannot overlap and may be
46.123 + * determined all at once for a whole string. Note that a spelling
46.124 + * string can contain <cite>accidental escapes</cite>, apparent escape
46.125 + * sequences which must not be interpreted as manglings.
46.126 + * These are disabled by replacing their leading backslash with an
46.127 + * escape sequence (<code><big><b>\-</b></big></code>). To mangle a string, three logical steps
46.128 + * are required, though they may be carried out in one pass:
46.129 + * </p>
46.130 + * <ol>
46.131 + * <li>In each accidental escape, replace the backslash with an escape sequence
46.132 + * (<code><big><b>\-</b></big></code>).</li>
46.133 + * <li>Replace each dangerous character with an escape sequence
46.134 + * (<code><big><b>\|</b></big></code> for <code><big><b>/</b></big></code>, etc.).</li>
46.135 + * <li>If the first two steps introduced any change, <em>and</em>
46.136 + * if the string does not already begin with a backslash, prepend a null prefix (<code><big><b>\=</b></big></code>).</li>
46.137 + * </ol>
46.138 + *
46.139 + * To demangle a mangled string that begins with an escape,
46.140 + * remove any null prefix, and then replace (in parallel)
46.141 + * each escape sequence by its original character.
46.142 + * <p>Spelling strings which contain accidental
46.143 + * escapes <em>must</em> have them replaced, even if those
46.144 + * strings do not contain dangerous characters.
46.145 + * This restriction means that mangling a string always
46.146 + * requires a scan of the string for escapes.
46.147 + * But then, a scan would be required anyway,
46.148 + * to check for dangerous characters.
46.149 + *
46.150 + * </p>
46.151 + * <h3> Nice Properties </h3>
46.152 + *
46.153 + * <p>
46.154 + * If a bytecode name does not contain any escape sequence,
46.155 + * demangling is a no-op: The string demangles to itself.
46.156 + * Such a string is called <cite>self-mangling</cite>.
46.157 + * Almost all strings are self-mangling.
46.158 + * In practice, to demangle almost any name “found in nature”,
46.159 + * simply verify that it does not begin with a backslash.
46.160 + * </p>
46.161 + * <p>
46.162 + * Mangling is a one-to-one function, while demangling
46.163 + * is a many-to-one function.
46.164 + * A mangled string is defined as <cite>validly mangled</cite> if
46.165 + * it is in fact the unique mangling of its spelling string.
46.166 + * Three examples of invalidly mangled strings are <code><big><b>\=foo</b></big></code>,
46.167 + * <code><big><b>\-bar</b></big></code>, and <code><big><b>baz\!</b></big></code>, which demangle to <code><big><b>foo</b></big></code>, <code><big><b>\bar</b></big></code>, and
46.168 + * <code><big><b>baz\!</b></big></code>, but then remangle to <code><big><b>foo</b></big></code>, <code><big><b>\bar</b></big></code>, and <code><big><b>\=baz\-!</b></big></code>.
46.169 + * If a language back-end or runtime is using mangled names,
46.170 + * it should never present an invalidly mangled bytecode
46.171 + * name to the JVM. If the runtime encounters one,
46.172 + * it should also report an error, since such an occurrence
46.173 + * probably indicates a bug in name encoding which
46.174 + * will lead to errors in linkage.
46.175 + * However, this note does not propose that the JVM verifier
46.176 + * detect invalidly mangled names.
46.177 + * </p>
46.178 + * <p>
46.179 + * As a result of these rules, it is a simple matter to
46.180 + * compute validly mangled substrings and concatenations
46.181 + * of validly mangled strings, and (with a little care)
46.182 + * these correspond to corresponding operations on their
46.183 + * spelling strings.
46.184 + * </p>
46.185 + * <ul>
46.186 + * <li>Any prefix of a validly mangled string is also validly mangled,
46.187 + * although a null prefix may need to be removed.</li>
46.188 + * <li>Any suffix of a validly mangled string is also validly mangled,
46.189 + * although a null prefix may need to be added.</li>
46.190 + * <li>Two validly mangled strings, when concatenated,
46.191 + * are also validly mangled, although any null prefix
46.192 + * must be removed from the second string,
46.193 + * and a trailing backslash on the first string may need escaping,
46.194 + * if it would participate in an accidental escape when followed
46.195 + * by the first character of the second string.</li>
46.196 + * </ul>
46.197 + * <p>If languages that include non-Java symbol spellings use this
46.198 + * mangling convention, they will enjoy the following advantages:
46.199 + * </p>
46.200 + * <ul>
46.201 + * <li>They can interoperate via symbols they share in common.</li>
46.202 + * <li>Low-level tools, such as backtrace printers, will have readable displays.</li>
46.203 + * <li>Future JVM and language extensions can safely use the dangerous characters
46.204 + * for structuring symbols, but will never interfere with valid spellings.</li>
46.205 + * <li>Runtimes and compilers can use standard libraries for mangling and demangling.</li>
46.206 + * <li>Occasional transliterations and name composition will be simple and regular,
46.207 + * for classes, methods, and fields.</li>
46.208 + * <li>Bytecode names will continue to be compact.
46.209 + * When mangled, spellings will at most double in length, either in
46.210 + * UTF8 or UTF16 format, and most will not change at all.</li>
46.211 + * </ul>
46.212 + *
46.213 + *
46.214 + * <h3> Suggestions for Human Readable Presentations </h3>
46.215 + *
46.216 + *
46.217 + * <p>
46.218 + * For human readable displays of symbols,
46.219 + * it will be better to present a string-like quoted
46.220 + * representation of the spelling, because JVM users
46.221 + * are generally familiar with such tokens.
46.222 + * We suggest using single or double quotes before and after
46.223 + * mangled symbols which are not valid Java identifiers,
46.224 + * with quotes, backslashes, and non-printing characters
46.225 + * escaped as if for literals in the Java language.
46.226 + * </p>
46.227 + * <p>
46.228 + * For example, an HTML-like spelling
46.229 + * <code><big><b><pre></b></big></code> mangles to
46.230 + * <code><big><b>\^pre\_</b></big></code> and could
46.231 + * display more cleanly as
46.232 + * <code><big><b>'<pre>'</b></big></code>,
46.233 + * with the quotes included.
46.234 + * Such string-like conventions are <em>not</em> suitable
46.235 + * for mangled bytecode names, in part because
46.236 + * dangerous characters must be eliminated, rather
46.237 + * than just quoted. Otherwise internally structured
46.238 + * strings like package prefixes and method signatures
46.239 + * could not be reliably parsed.
46.240 + * </p>
46.241 + * <p>
46.242 + * In such human-readable displays, invalidly mangled
46.243 + * names should <em>not</em> be demangled and quoted,
46.244 + * for this would be misleading. Likewise, JVM symbols
46.245 + * which contain dangerous characters (like dots in field
46.246 + * names or brackets in method names) should not be
46.247 + * simply quoted. The bytecode names
46.248 + * <code><big><b>\=phase\,1</b></big></code> and
46.249 + * <code><big><b>phase.1</b></big></code> are distinct,
46.250 + * and in demangled displays they should be presented as
46.251 + * <code><big><b>'phase.1'</b></big></code> and something like
46.252 + * <code><big><b>'phase'.1</b></big></code>, respectively.
46.253 + * </p>
46.254 + *
46.255 + * @author John Rose
46.256 + * @version 1.2, 02/06/2008
46.257 + * @see http://blogs.sun.com/jrose/entry/symbolic_freedom_in_the_vm
46.258 + */
46.259 +public class BytecodeName {
46.260 + private BytecodeName() { } // static only class
46.261 +
46.262 + /** Given a source name, produce the corresponding bytecode name.
46.263 + * The source name should not be qualified, because any syntactic
46.264 + * markers (dots, slashes, dollar signs, colons, etc.) will be mangled.
46.265 + * @param s the source name
46.266 + * @return a valid bytecode name which represents the source name
46.267 + */
46.268 + public static String toBytecodeName(String s) {
46.269 + String bn = mangle(s);
46.270 + assert((Object)bn == s || looksMangled(bn)) : bn;
46.271 + assert(s.equals(toSourceName(bn))) : s;
46.272 + return bn;
46.273 + }
46.274 +
46.275 + /** Given an unqualified bytecode name, produce the corresponding source name.
46.276 + * The bytecode name must not contain dangerous characters.
46.277 + * In particular, it must not be qualified or segmented by colon {@code ':'}.
46.278 + * @param s the bytecode name
46.279 + * @return the source name, which may possibly have unsafe characters
46.280 + * @throws IllegalArgumentException if the bytecode name is not {@link #isSafeBytecodeName safe}
46.281 + * @see #isSafeBytecodeName(java.lang.String)
46.282 + */
46.283 + public static String toSourceName(String s) {
46.284 + checkSafeBytecodeName(s);
46.285 + String sn = s;
46.286 + if (looksMangled(s)) {
46.287 + sn = demangle(s);
46.288 + assert(s.equals(mangle(sn))) : s+" => "+sn+" => "+mangle(sn);
46.289 + }
46.290 + return sn;
46.291 + }
46.292 +
46.293 + /**
46.294 + * Given a bytecode name from a classfile, separate it into
46.295 + * components delimited by dangerous characters.
46.296 + * Each resulting array element will be either a dangerous character,
46.297 + * or else a safe bytecode name.
46.298 + * (The safe name might possibly be mangled to hide further dangerous characters.)
46.299 + * For example, the qualified class name {@code java/lang/String}
46.300 + * will be parsed into the array {@code {"java", '/', "lang", '/', "String"}}.
46.301 + * The name {@code <init>} will be parsed into { '<', "init", '>'}}
46.302 + * The name {@code foo/bar$:baz} will be parsed into
46.303 + * {@code {"foo", '/', "bar", '$', ':', "baz"}}.
46.304 + */
46.305 + public static Object[] parseBytecodeName(String s) {
46.306 + int slen = s.length();
46.307 + Object[] res = null;
46.308 + for (int pass = 0; pass <= 1; pass++) {
46.309 + int fillp = 0;
46.310 + int lasti = 0;
46.311 + for (int i = 0; i <= slen; i++) {
46.312 + int whichDC = -1;
46.313 + if (i < slen) {
46.314 + whichDC = DANGEROUS_CHARS.indexOf(s.charAt(i));
46.315 + if (whichDC < DANGEROUS_CHAR_FIRST_INDEX) continue;
46.316 + }
46.317 + // got to end of string or next dangerous char
46.318 + if (lasti < i) {
46.319 + // normal component
46.320 + if (pass != 0)
46.321 + res[fillp] = s.substring(lasti, i);
46.322 + fillp++;
46.323 + lasti = i+1;
46.324 + }
46.325 + if (whichDC >= DANGEROUS_CHAR_FIRST_INDEX) {
46.326 + if (pass != 0)
46.327 + res[fillp] = DANGEROUS_CHARS_CA[whichDC];
46.328 + fillp++;
46.329 + }
46.330 + }
46.331 + if (pass != 0) break;
46.332 + // between passes, build the result array
46.333 + res = new String[fillp];
46.334 + if (fillp <= 1) {
46.335 + if (fillp != 0) res[0] = s;
46.336 + break;
46.337 + }
46.338 + }
46.339 + return res;
46.340 + }
46.341 +
46.342 + /**
46.343 + * Given a series of components, create a bytecode name for a classfile.
46.344 + * This is the inverse of {@link #parseBytecodeName(java.lang.String)}.
46.345 + * Each component must either be an interned one-character string of
46.346 + * a dangerous character, or else a safe bytecode name.
46.347 + * @param components a series of name components
46.348 + * @return the concatenation of all components
46.349 + * @throws IllegalArgumentException if any component contains an unsafe
46.350 + * character, and is not an interned one-character string
46.351 + * @throws NullPointerException if any component is null
46.352 + */
46.353 + public static String unparseBytecodeName(Object[] components) {
46.354 + for (Object c : components) {
46.355 + if (c instanceof String)
46.356 + checkSafeBytecodeName((String) c); // may fail
46.357 + }
46.358 + return appendAll(components);
46.359 + }
46.360 + private static String appendAll(Object[] components) {
46.361 + if (components.length <= 1) {
46.362 + if (components.length == 1) {
46.363 + return String.valueOf(components[0]);
46.364 + }
46.365 + return "";
46.366 + }
46.367 + int slen = 0;
46.368 + for (Object c : components) {
46.369 + if (c instanceof String)
46.370 + slen += String.valueOf(c).length();
46.371 + else
46.372 + slen += 1;
46.373 + }
46.374 + StringBuilder sb = new StringBuilder(slen);
46.375 + for (Object c : components) {
46.376 + sb.append(c);
46.377 + }
46.378 + return sb.toString();
46.379 + }
46.380 +
46.381 + /**
46.382 + * Given a bytecode name, produce the corresponding display name.
46.383 + * This is the source name, plus quotes if needed.
46.384 + * If the bytecode name contains dangerous characters,
46.385 + * assume that they are being used as punctuation,
46.386 + * and pass them through unchanged.
46.387 + * @param s the original bytecode name (which may be qualified)
46.388 + * @return a human-readable presentation
46.389 + */
46.390 + public static String toDisplayName(String s) {
46.391 + Object[] components = parseBytecodeName(s);
46.392 + for (int i = 0; i < components.length; i++) {
46.393 + if (!(components[i] instanceof String))
46.394 + continue;
46.395 + String c = (String) components[i];
46.396 + // pretty up the name by demangling it
46.397 + String sn = toSourceName(c);
46.398 + if ((Object)sn != c || !isJavaIdent(sn)) {
46.399 + components[i] = quoteDisplay(sn);
46.400 + }
46.401 + }
46.402 + return appendAll(components);
46.403 + }
46.404 + private static boolean isJavaIdent(String s) {
46.405 + int slen = s.length();
46.406 + if (slen == 0) return false;
46.407 + if (!Character.isUnicodeIdentifierStart(s.charAt(0)))
46.408 + return false;
46.409 + for (int i = 1; i < slen; i++) {
46.410 + if (!Character.isUnicodeIdentifierPart(s.charAt(0)))
46.411 + return false;
46.412 + }
46.413 + return true;
46.414 + }
46.415 + private static String quoteDisplay(String s) {
46.416 + // TO DO: Replace wierd characters in s by C-style escapes.
46.417 + return "'"+s.replaceAll("['\\\\]", "\\\\$0")+"'";
46.418 + }
46.419 +
46.420 + private static void checkSafeBytecodeName(String s)
46.421 + throws IllegalArgumentException {
46.422 + if (!isSafeBytecodeName(s)) {
46.423 + throw new IllegalArgumentException(s);
46.424 + }
46.425 + }
46.426 +
46.427 + /**
46.428 + * Report whether a simple name is safe as a bytecode name.
46.429 + * Such names are acceptable in class files as class, method, and field names.
46.430 + * Additionally, they are free of "dangerous" characters, even if those
46.431 + * characters are legal in some (or all) names in class files.
46.432 + * @param s the proposed bytecode name
46.433 + * @return true if the name is non-empty and all of its characters are safe
46.434 + */
46.435 + public static boolean isSafeBytecodeName(String s) {
46.436 + if (s.length() == 0) return false;
46.437 + // check occurrences of each DANGEROUS char
46.438 + for (char xc : DANGEROUS_CHARS_A) {
46.439 + if (xc == ESCAPE_C) continue; // not really that dangerous
46.440 + if (s.indexOf(xc) >= 0) return false;
46.441 + }
46.442 + return true;
46.443 + }
46.444 +
46.445 + /**
46.446 + * Report whether a character is safe in a bytecode name.
46.447 + * This is true of any unicode character except the following
46.448 + * <em>dangerous characters</em>: {@code ".;:$[]<>/"}.
46.449 + * @param s the proposed character
46.450 + * @return true if the character is safe to use in classfiles
46.451 + */
46.452 + public static boolean isSafeBytecodeChar(char c) {
46.453 + return DANGEROUS_CHARS.indexOf(c) < DANGEROUS_CHAR_FIRST_INDEX;
46.454 + }
46.455 +
46.456 + private static boolean looksMangled(String s) {
46.457 + return s.charAt(0) == ESCAPE_C;
46.458 + }
46.459 +
46.460 + private static String mangle(String s) {
46.461 + if (s.length() == 0)
46.462 + return NULL_ESCAPE;
46.463 +
46.464 + // build this lazily, when we first need an escape:
46.465 + StringBuilder sb = null;
46.466 +
46.467 + for (int i = 0, slen = s.length(); i < slen; i++) {
46.468 + char c = s.charAt(i);
46.469 +
46.470 + boolean needEscape = false;
46.471 + if (c == ESCAPE_C) {
46.472 + if (i+1 < slen) {
46.473 + char c1 = s.charAt(i+1);
46.474 + if ((i == 0 && c1 == NULL_ESCAPE_C)
46.475 + || c1 != originalOfReplacement(c1)) {
46.476 + // an accidental escape
46.477 + needEscape = true;
46.478 + }
46.479 + }
46.480 + } else {
46.481 + needEscape = isDangerous(c);
46.482 + }
46.483 +
46.484 + if (!needEscape) {
46.485 + if (sb != null) sb.append(c);
46.486 + continue;
46.487 + }
46.488 +
46.489 + // build sb if this is the first escape
46.490 + if (sb == null) {
46.491 + sb = new StringBuilder(s.length()+10);
46.492 + // mangled names must begin with a backslash:
46.493 + if (s.charAt(0) != ESCAPE_C && i > 0)
46.494 + sb.append(NULL_ESCAPE);
46.495 + // append the string so far, which is unremarkable:
46.496 + sb.append(s.substring(0, i));
46.497 + }
46.498 +
46.499 + // rewrite \ to \-, / to \|, etc.
46.500 + sb.append(ESCAPE_C);
46.501 + sb.append(replacementOf(c));
46.502 + }
46.503 +
46.504 + if (sb != null) return sb.toString();
46.505 +
46.506 + return s;
46.507 + }
46.508 +
46.509 + private static String demangle(String s) {
46.510 + // build this lazily, when we first meet an escape:
46.511 + StringBuilder sb = null;
46.512 +
46.513 + int stringStart = 0;
46.514 + if (s.startsWith(NULL_ESCAPE))
46.515 + stringStart = 2;
46.516 +
46.517 + for (int i = stringStart, slen = s.length(); i < slen; i++) {
46.518 + char c = s.charAt(i);
46.519 +
46.520 + if (c == ESCAPE_C && i+1 < slen) {
46.521 + // might be an escape sequence
46.522 + char rc = s.charAt(i+1);
46.523 + char oc = originalOfReplacement(rc);
46.524 + if (oc != rc) {
46.525 + // build sb if this is the first escape
46.526 + if (sb == null) {
46.527 + sb = new StringBuilder(s.length());
46.528 + // append the string so far, which is unremarkable:
46.529 + sb.append(s.substring(stringStart, i));
46.530 + }
46.531 + ++i; // skip both characters
46.532 + c = oc;
46.533 + }
46.534 + }
46.535 +
46.536 + if (sb != null)
46.537 + sb.append(c);
46.538 + }
46.539 +
46.540 + if (sb != null) return sb.toString();
46.541 +
46.542 + return s.substring(stringStart);
46.543 + }
46.544 +
46.545 + static char ESCAPE_C = '\\';
46.546 + // empty escape sequence to avoid a null name or illegal prefix
46.547 + static char NULL_ESCAPE_C = '=';
46.548 + static String NULL_ESCAPE = ESCAPE_C+""+NULL_ESCAPE_C;
46.549 +
46.550 + static final String DANGEROUS_CHARS = "\\/.;:$[]<>"; // \\ must be first
46.551 + static final String REPLACEMENT_CHARS = "-|,?!%{}^_";
46.552 + static final int DANGEROUS_CHAR_FIRST_INDEX = 1; // index after \\
46.553 + static char[] DANGEROUS_CHARS_A = DANGEROUS_CHARS.toCharArray();
46.554 + static char[] REPLACEMENT_CHARS_A = REPLACEMENT_CHARS.toCharArray();
46.555 + static final Character[] DANGEROUS_CHARS_CA;
46.556 + static {
46.557 + Character[] dcca = new Character[DANGEROUS_CHARS.length()];
46.558 + for (int i = 0; i < dcca.length; i++)
46.559 + dcca[i] = Character.valueOf(DANGEROUS_CHARS.charAt(i));
46.560 + DANGEROUS_CHARS_CA = dcca;
46.561 + }
46.562 +
46.563 + static final long[] SPECIAL_BITMAP = new long[2]; // 128 bits
46.564 + static {
46.565 + String SPECIAL = DANGEROUS_CHARS + REPLACEMENT_CHARS;
46.566 + //System.out.println("SPECIAL = "+SPECIAL);
46.567 + for (char c : SPECIAL.toCharArray()) {
46.568 + SPECIAL_BITMAP[c >>> 6] |= 1L << c;
46.569 + }
46.570 + }
46.571 + static boolean isSpecial(char c) {
46.572 + if ((c >>> 6) < SPECIAL_BITMAP.length)
46.573 + return ((SPECIAL_BITMAP[c >>> 6] >> c) & 1) != 0;
46.574 + else
46.575 + return false;
46.576 + }
46.577 + static char replacementOf(char c) {
46.578 + if (!isSpecial(c)) return c;
46.579 + int i = DANGEROUS_CHARS.indexOf(c);
46.580 + if (i < 0) return c;
46.581 + return REPLACEMENT_CHARS.charAt(i);
46.582 + }
46.583 + static char originalOfReplacement(char c) {
46.584 + if (!isSpecial(c)) return c;
46.585 + int i = REPLACEMENT_CHARS.indexOf(c);
46.586 + if (i < 0) return c;
46.587 + return DANGEROUS_CHARS.charAt(i);
46.588 + }
46.589 + static boolean isDangerous(char c) {
46.590 + if (!isSpecial(c)) return false;
46.591 + return (DANGEROUS_CHARS.indexOf(c) >= DANGEROUS_CHAR_FIRST_INDEX);
46.592 + }
46.593 + static int indexOfDangerousChar(String s, int from) {
46.594 + for (int i = from, slen = s.length(); i < slen; i++) {
46.595 + if (isDangerous(s.charAt(i)))
46.596 + return i;
46.597 + }
46.598 + return -1;
46.599 + }
46.600 + static int lastIndexOfDangerousChar(String s, int from) {
46.601 + for (int i = Math.min(from, s.length()-1); i >= 0; i--) {
46.602 + if (isDangerous(s.charAt(i)))
46.603 + return i;
46.604 + }
46.605 + return -1;
46.606 + }
46.607 +
46.608 + // test driver
46.609 + static void main(String[] av) {
46.610 + // If verbose is enabled, quietly check everything.
46.611 + // Otherwise, print the output for the user to check.
46.612 + boolean verbose = false;
46.613 +
46.614 + int maxlen = 0;
46.615 +
46.616 + while (av.length > 0 && av[0].startsWith("-")) {
46.617 + String flag = av[0].intern();
46.618 + av = java.util.Arrays.copyOfRange(av, 1, av.length); // Java 1.6 or later
46.619 + if (flag == "-" || flag == "--") break;
46.620 + else if (flag == "-q")
46.621 + verbose = false;
46.622 + else if (flag == "-v")
46.623 + verbose = true;
46.624 + else if (flag.startsWith("-l"))
46.625 + maxlen = Integer.valueOf(flag.substring(2));
46.626 + else
46.627 + throw new Error("Illegal flag argument: "+flag);
46.628 + }
46.629 +
46.630 + if (maxlen == 0)
46.631 + maxlen = (verbose ? 2 : 4);
46.632 + if (verbose) System.out.println("Note: maxlen = "+maxlen);
46.633 +
46.634 + switch (av.length) {
46.635 + case 0: av = new String[] {
46.636 + DANGEROUS_CHARS.substring(0) +
46.637 + REPLACEMENT_CHARS.substring(0, 1) +
46.638 + NULL_ESCAPE + "x"
46.639 + }; // and fall through:
46.640 + case 1:
46.641 + char[] cv = av[0].toCharArray();
46.642 + av = new String[cv.length];
46.643 + int avp = 0;
46.644 + for (char c : cv) {
46.645 + String s = String.valueOf(c);
46.646 + if (c == 'x') s = "foo"; // tradition...
46.647 + av[avp++] = s;
46.648 + }
46.649 + }
46.650 + if (verbose)
46.651 + System.out.println("Note: Verbose output mode enabled. Use '-q' to suppress.");
46.652 + Tester t = new Tester();
46.653 + t.maxlen = maxlen;
46.654 + t.verbose = verbose;
46.655 + t.tokens = av;
46.656 + t.test("", 0);
46.657 + }
46.658 +
46.659 + static class Tester {
46.660 + boolean verbose;
46.661 + int maxlen;
46.662 + java.util.Map<String,String> map = new java.util.HashMap<String,String>();
46.663 + String[] tokens;
46.664 +
46.665 + void test(String stringSoFar, int tokensSoFar) {
46.666 + test(stringSoFar);
46.667 + if (tokensSoFar <= maxlen) {
46.668 + for (String token : tokens) {
46.669 + if (token.length() == 0) continue; // skip empty tokens
46.670 + if (stringSoFar.indexOf(token) != stringSoFar.lastIndexOf(token))
46.671 + continue; // there are already two occs. of this token
46.672 + if (token.charAt(0) == ESCAPE_C && token.length() == 1 && maxlen < 4)
46.673 + test(stringSoFar+token, tokensSoFar); // want lots of \'s
46.674 + else if (tokensSoFar < maxlen)
46.675 + test(stringSoFar+token, tokensSoFar+1);
46.676 + }
46.677 + }
46.678 + }
46.679 +
46.680 + void test(String s) {
46.681 + // for small batches, do not test the null string
46.682 + if (s.length() == 0 && maxlen >=1 && maxlen <= 2) return;
46.683 + String bn = testSourceName(s);
46.684 + if (bn == null) return;
46.685 + if (bn == s) {
46.686 + //if (verbose) System.out.println(s+" == id");
46.687 + } else {
46.688 + if (verbose) System.out.println(s+" => "+bn+" "+toDisplayName(bn));
46.689 + String bnbn = testSourceName(bn);
46.690 + if (bnbn == null) return;
46.691 + if (verbose) System.out.println(bn+" => "+bnbn+" "+toDisplayName(bnbn));
46.692 + /*
46.693 + String bn3 = testSourceName(bnbn);
46.694 + if (bn3 == null) return;
46.695 + if (verbose) System.out.println(bnbn+" => "+bn3);
46.696 + */
46.697 + }
46.698 + }
46.699 +
46.700 + String testSourceName(String s) {
46.701 + if (map.containsKey(s)) return null;
46.702 + String bn = toBytecodeName(s);
46.703 + map.put(s, bn);
46.704 + String sn = toSourceName(bn);
46.705 + if (!sn.equals(s)) {
46.706 + String bad = (s+" => "+bn+" != "+sn);
46.707 + if (!verbose) throw new Error("Bad mangling: "+bad);
46.708 + System.out.println("*** "+bad);
46.709 + return null;
46.710 + }
46.711 + return bn;
46.712 + }
46.713 + }
46.714 +}
47.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
47.2 +++ b/src/share/classes/sun/dyn/util/BytecodeSignature.java Tue May 05 23:12:47 2009 -0700
47.3 @@ -0,0 +1,137 @@
47.4 +/*
47.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
47.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
47.7 + *
47.8 + * This code is free software; you can redistribute it and/or modify it
47.9 + * under the terms of the GNU General Public License version 2 only, as
47.10 + * published by the Free Software Foundation. Sun designates this
47.11 + * particular file as subject to the "Classpath" exception as provided
47.12 + * by Sun in the LICENSE file that accompanied this code.
47.13 + *
47.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
47.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
47.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
47.17 + * version 2 for more details (a copy is included in the LICENSE file that
47.18 + * accompanied this code).
47.19 + *
47.20 + * You should have received a copy of the GNU General Public License version
47.21 + * 2 along with this work; if not, write to the Free Software Foundation,
47.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
47.23 + *
47.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
47.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
47.26 + * have any questions.
47.27 + */
47.28 +
47.29 +package sun.dyn.util;
47.30 +
47.31 +import java.dyn.MethodType;
47.32 +import java.util.ArrayList;
47.33 +import java.util.List;
47.34 +
47.35 +/**
47.36 + * Utility routines for dealing with bytecode-level signatures.
47.37 + * @author jrose
47.38 + */
47.39 +public class BytecodeSignature {
47.40 +
47.41 + private BytecodeSignature() { } // cannot instantiate
47.42 +
47.43 + public static List<Class<?>> parseMethod(String bytecodeSignature, ClassLoader loader) {
47.44 + return parseMethod(bytecodeSignature, 0, bytecodeSignature.length(), loader);
47.45 + }
47.46 +
47.47 + static List<Class<?>> parseMethod(String bytecodeSignature,
47.48 + int start, int end, ClassLoader loader) {
47.49 + if (loader == null)
47.50 + loader = ClassLoader.getSystemClassLoader();
47.51 + String str = bytecodeSignature;
47.52 + int[] i = {start};
47.53 + ArrayList<Class<?>> ptypes = new ArrayList<Class<?>>();
47.54 + if (i[0] < end && str.charAt(i[0]) == '(') {
47.55 + ++i[0]; // skip '('
47.56 + while (i[0] < end && str.charAt(i[0]) != ')') {
47.57 + Class<?> pt = parseSig(str, i, end, loader);
47.58 + if (pt == null || pt == void.class)
47.59 + parseError(str, "bad argument type");
47.60 + ptypes.add(pt);
47.61 + }
47.62 + ++i[0]; // skip ')'
47.63 + } else {
47.64 + parseError(str, "not a method type");
47.65 + }
47.66 + Class<?> rtype = parseSig(str, i, end, loader);
47.67 + if (rtype == null || i[0] != end)
47.68 + parseError(str, "bad return type");
47.69 + ptypes.add(rtype);
47.70 + return ptypes;
47.71 + }
47.72 +
47.73 + static private void parseError(String str, String msg) {
47.74 + throw new IllegalArgumentException("bad signature: "+str+": "+msg);
47.75 + }
47.76 +
47.77 + static private Class<?> parseSig(String str, int[] i, int end, ClassLoader loader) {
47.78 + if (i[0] == end) return null;
47.79 + char c = str.charAt(i[0]++);
47.80 + if (c == 'L') {
47.81 + int begc = i[0], endc = str.indexOf(';', begc);
47.82 + if (endc < 0) return null;
47.83 + i[0] = endc+1;
47.84 + String name = str.substring(begc, endc).replace('/', '.');
47.85 + try {
47.86 + return loader.loadClass(name);
47.87 + } catch (ClassNotFoundException ex) {
47.88 + throw new TypeNotPresentException(name, ex);
47.89 + }
47.90 + } else if (c == '[') {
47.91 + Class<?> t = parseSig(str, i, end, loader);
47.92 + if (t != null)
47.93 + t = java.lang.reflect.Array.newInstance(t, 0).getClass();
47.94 + return t;
47.95 + } else {
47.96 + return Wrapper.forBasicType(c).primitiveType();
47.97 + }
47.98 + }
47.99 +
47.100 + public static String unparse(Class<?> type) {
47.101 + StringBuilder sb = new StringBuilder();
47.102 + unparseSig(type, sb);
47.103 + return sb.toString();
47.104 + }
47.105 +
47.106 + public static String unparse(MethodType type) {
47.107 + return unparseMethod(type.returnType(), type.parameterList());
47.108 + }
47.109 +
47.110 + public static String unparse(Object type) {
47.111 + if (type instanceof Class<?>)
47.112 + return unparse((Class<?>) type);
47.113 + if (type instanceof MethodType)
47.114 + return unparse((MethodType) type);
47.115 + return (String) type;
47.116 + }
47.117 +
47.118 + public static String unparseMethod(Class<?> rtype, List<Class<?>> ptypes) {
47.119 + StringBuilder sb = new StringBuilder();
47.120 + sb.append('(');
47.121 + for (Class<?> pt : ptypes)
47.122 + unparseSig(pt, sb);
47.123 + sb.append(')');
47.124 + unparseSig(rtype, sb);
47.125 + return sb.toString();
47.126 + }
47.127 +
47.128 + static private void unparseSig(Class<?> t, StringBuilder sb) {
47.129 + char c = Wrapper.forBasicType(t).basicTypeChar();
47.130 + if (c != 'L') {
47.131 + sb.append(c);
47.132 + } else {
47.133 + boolean lsemi = (!t.isArray());
47.134 + if (lsemi) sb.append('L');
47.135 + sb.append(t.getName().replace('.', '/'));
47.136 + if (lsemi) sb.append(';');
47.137 + }
47.138 + }
47.139 +
47.140 +}
48.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
48.2 +++ b/src/share/classes/sun/dyn/util/ValueConversions.java Tue May 05 23:12:47 2009 -0700
48.3 @@ -0,0 +1,563 @@
48.4 +/*
48.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
48.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
48.7 + *
48.8 + * This code is free software; you can redistribute it and/or modify it
48.9 + * under the terms of the GNU General Public License version 2 only, as
48.10 + * published by the Free Software Foundation. Sun designates this
48.11 + * particular file as subject to the "Classpath" exception as provided
48.12 + * by Sun in the LICENSE file that accompanied this code.
48.13 + *
48.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
48.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
48.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
48.17 + * version 2 for more details (a copy is included in the LICENSE file that
48.18 + * accompanied this code).
48.19 + *
48.20 + * You should have received a copy of the GNU General Public License version
48.21 + * 2 along with this work; if not, write to the Free Software Foundation,
48.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
48.23 + *
48.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
48.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
48.26 + * have any questions.
48.27 + */
48.28 +
48.29 +package sun.dyn.util;
48.30 +
48.31 +import java.dyn.*;
48.32 +import java.dyn.MethodHandles.Lookup;
48.33 +import java.util.EnumMap;
48.34 +import sun.dyn.Access;
48.35 +import sun.dyn.AdapterMethodHandle;
48.36 +import sun.dyn.MethodHandleImpl;
48.37 +
48.38 +public class ValueConversions {
48.39 + private static final Access IMPL_TOKEN = Access.getToken();
48.40 + private static final Lookup IMPL_LOOKUP = MethodHandleImpl.getLookup(IMPL_TOKEN);
48.41 +
48.42 + private static EnumMap<Wrapper, MethodHandle>[] newWrapperCaches(int n) {
48.43 + EnumMap<Wrapper, MethodHandle>[] caches
48.44 + = (EnumMap<Wrapper, MethodHandle>[]) new EnumMap[n]; // unchecked warning expected here
48.45 + for (int i = 0; i < n; i++)
48.46 + caches[i] = new EnumMap<Wrapper, MethodHandle>(Wrapper.class);
48.47 + return caches;
48.48 + }
48.49 +
48.50 + /// Converting references to values.
48.51 +
48.52 + static int unboxInteger(Object x) {
48.53 + if (x == null) return 0; // never NPE
48.54 + return ((Integer) x).intValue();
48.55 + }
48.56 +
48.57 + static byte unboxByte(Object x) {
48.58 + if (x == null) return 0; // never NPE
48.59 + return ((Byte) x).byteValue();
48.60 + }
48.61 +
48.62 + static short unboxShort(Object x) {
48.63 + if (x == null) return 0; // never NPE
48.64 + return ((Short) x).shortValue();
48.65 + }
48.66 +
48.67 + static boolean unboxBoolean(Object x) {
48.68 + if (x == null) return false; // never NPE
48.69 + return ((Boolean) x).booleanValue();
48.70 + }
48.71 +
48.72 + static char unboxCharacter(Object x) {
48.73 + if (x == null) return 0; // never NPE
48.74 + return ((Character) x).charValue();
48.75 + }
48.76 +
48.77 + static long unboxLong(Object x) {
48.78 + if (x == null) return 0; // never NPE
48.79 + return ((Long) x).longValue();
48.80 + }
48.81 +
48.82 + static float unboxFloat(Object x) {
48.83 + if (x == null) return 0; // never NPE
48.84 + return ((Float) x).floatValue();
48.85 + }
48.86 +
48.87 + static double unboxDouble(Object x) {
48.88 + if (x == null) return 0; // never NPE
48.89 + return ((Double) x).doubleValue();
48.90 + }
48.91 +
48.92 + /// Converting references to "raw" values.
48.93 + /// A raw primitive value is always an int or long.
48.94 +
48.95 + static int unboxByteRaw(Object x) {
48.96 + return unboxByte(x);
48.97 + }
48.98 +
48.99 + static int unboxShortRaw(Object x) {
48.100 + return unboxShort(x);
48.101 + }
48.102 +
48.103 + static int unboxBooleanRaw(Object x) {
48.104 + return unboxBoolean(x) ? 1 : 0;
48.105 + }
48.106 +
48.107 + static int unboxCharacterRaw(Object x) {
48.108 + return unboxCharacter(x);
48.109 + }
48.110 +
48.111 + static int unboxFloatRaw(Object x) {
48.112 + return Float.floatToIntBits(unboxFloat(x));
48.113 + }
48.114 +
48.115 + static long unboxDoubleRaw(Object x) {
48.116 + return Double.doubleToRawLongBits(unboxDouble(x));
48.117 + }
48.118 +
48.119 + private static MethodType unboxType(Wrapper wrap, boolean raw) {
48.120 + return MethodType.make(rawWrapper(wrap, raw).primitiveType(), wrap.wrapperType());
48.121 + }
48.122 +
48.123 + private static final EnumMap<Wrapper, MethodHandle>[]
48.124 + UNBOX_CONVERSIONS = newWrapperCaches(4);
48.125 +
48.126 + private static MethodHandle unbox(Wrapper wrap, boolean exact, boolean raw) {
48.127 + EnumMap<Wrapper, MethodHandle> cache = UNBOX_CONVERSIONS[(exact?1:0)+(raw?2:0)];
48.128 + MethodHandle mh = cache.get(wrap);
48.129 + if (mh != null) {
48.130 + return mh;
48.131 + }
48.132 + // slow path
48.133 + switch (wrap) {
48.134 + case OBJECT:
48.135 + mh = IDENTITY; break;
48.136 + case VOID:
48.137 + mh = raw ? ALWAYS_ZERO : IGNORE; break;
48.138 + case INT: case LONG:
48.139 + // these guys don't need separate raw channels
48.140 + if (raw) mh = unbox(wrap, exact, false);
48.141 + break;
48.142 + }
48.143 + if (mh != null) {
48.144 + cache.put(wrap, mh);
48.145 + return mh;
48.146 + }
48.147 + // look up the method
48.148 + String name = "unbox" + wrap.simpleName() + (raw ? "Raw" : "");
48.149 + MethodType type = unboxType(wrap, raw);
48.150 + if (!exact)
48.151 + // actually, type is wrong; the Java method takes Object
48.152 + mh = IMPL_LOOKUP.findStatic(ValueConversions.class, name, type.erase());
48.153 + else
48.154 + mh = retype(type, unbox(wrap, !exact, raw));
48.155 + if (mh != null) {
48.156 + cache.put(wrap, mh);
48.157 + return mh;
48.158 + }
48.159 + throw new IllegalArgumentException("cannot find unbox adapter for " + wrap + (raw ? " (raw)" : ""));
48.160 + }
48.161 +
48.162 + public static MethodHandle unbox(Wrapper type, boolean exact) {
48.163 + return unbox(type, exact, false);
48.164 + }
48.165 +
48.166 + public static MethodHandle unboxRaw(Wrapper type, boolean exact) {
48.167 + return unbox(type, exact, true);
48.168 + }
48.169 +
48.170 + public static MethodHandle unbox(Class<?> type, boolean exact) {
48.171 + return unbox(Wrapper.forPrimitiveType(type), exact, false);
48.172 + }
48.173 +
48.174 + public static MethodHandle unboxRaw(Class<?> type, boolean exact) {
48.175 + return unbox(Wrapper.forPrimitiveType(type), exact, true);
48.176 + }
48.177 +
48.178 + /// Converting primitives to references
48.179 +
48.180 + static Integer boxInteger(int x) {
48.181 + return x;
48.182 + }
48.183 +
48.184 + static Byte boxByte(byte x) {
48.185 + return x;
48.186 + }
48.187 +
48.188 + static Short boxShort(short x) {
48.189 + return x;
48.190 + }
48.191 +
48.192 + static Boolean boxBoolean(boolean x) {
48.193 + return x;
48.194 + }
48.195 +
48.196 + static Character boxCharacter(char x) {
48.197 + return x;
48.198 + }
48.199 +
48.200 + static Long boxLong(long x) {
48.201 + return x;
48.202 + }
48.203 +
48.204 + static Float boxFloat(float x) {
48.205 + return x;
48.206 + }
48.207 +
48.208 + static Double boxDouble(double x) {
48.209 + return x;
48.210 + }
48.211 +
48.212 + /// Converting raw primitives to references
48.213 +
48.214 + static Byte boxByteRaw(int x) {
48.215 + return boxByte((byte)x);
48.216 + }
48.217 +
48.218 + static Short boxShortRaw(int x) {
48.219 + return boxShort((short)x);
48.220 + }
48.221 +
48.222 + static Boolean boxBooleanRaw(int x) {
48.223 + return boxBoolean(x != 0);
48.224 + }
48.225 +
48.226 + static Character boxCharacterRaw(int x) {
48.227 + return boxCharacter((char)x);
48.228 + }
48.229 +
48.230 + static Float boxFloatRaw(int x) {
48.231 + return boxFloat(Float.intBitsToFloat(x));
48.232 + }
48.233 +
48.234 + static Double boxDoubleRaw(long x) {
48.235 + return boxDouble(Double.longBitsToDouble(x));
48.236 + }
48.237 +
48.238 + // a raw void value is (arbitrarily) a garbage int
48.239 + static Void boxVoidRaw(int x) {
48.240 + return null;
48.241 + }
48.242 +
48.243 + private static MethodType boxType(Wrapper wrap, boolean raw) {
48.244 + // be exact, since return casts are hard to compose
48.245 + Class<?> boxType = wrap.wrapperType();
48.246 + return MethodType.make(boxType, rawWrapper(wrap, raw).primitiveType());
48.247 + }
48.248 +
48.249 + private static Wrapper rawWrapper(Wrapper wrap, boolean raw) {
48.250 + if (raw) return wrap.isDoubleWord() ? Wrapper.LONG : Wrapper.INT;
48.251 + return wrap;
48.252 + }
48.253 +
48.254 + private static final EnumMap<Wrapper, MethodHandle>[]
48.255 + BOX_CONVERSIONS = newWrapperCaches(4);
48.256 +
48.257 + private static MethodHandle box(Wrapper wrap, boolean exact, boolean raw) {
48.258 + EnumMap<Wrapper, MethodHandle> cache = BOX_CONVERSIONS[(exact?1:0)+(raw?2:0)];
48.259 + MethodHandle mh = cache.get(wrap);
48.260 + if (mh != null) {
48.261 + return mh;
48.262 + }
48.263 + // slow path
48.264 + switch (wrap) {
48.265 + case OBJECT:
48.266 + mh = IDENTITY; break;
48.267 + case VOID:
48.268 + if (!raw) mh = ZERO_OBJECT;
48.269 + break;
48.270 + case INT: case LONG:
48.271 + // these guys don't need separate raw channels
48.272 + if (raw) mh = box(wrap, exact, false);
48.273 + break;
48.274 + }
48.275 + if (mh != null) {
48.276 + cache.put(wrap, mh);
48.277 + return mh;
48.278 + }
48.279 + // look up the method
48.280 + String name = "box" + wrap.simpleName() + (raw ? "Raw" : "");
48.281 + MethodType type = boxType(wrap, raw);
48.282 + if (exact)
48.283 + mh = IMPL_LOOKUP.findStatic(ValueConversions.class, name, type);
48.284 + else
48.285 + mh = retype(type.erase(), box(wrap, !exact, raw));
48.286 + if (mh != null) {
48.287 + cache.put(wrap, mh);
48.288 + return mh;
48.289 + }
48.290 + throw new IllegalArgumentException("cannot find box adapter for " + wrap + (raw ? " (raw)" : ""));
48.291 + }
48.292 +
48.293 + public static MethodHandle box(Class<?> type, boolean exact) {
48.294 + return box(Wrapper.forPrimitiveType(type), exact, false);
48.295 + }
48.296 +
48.297 + public static MethodHandle boxRaw(Class<?> type, boolean exact) {
48.298 + return box(Wrapper.forPrimitiveType(type), exact, true);
48.299 + }
48.300 +
48.301 + public static MethodHandle box(Wrapper type, boolean exact) {
48.302 + return box(type, exact, false);
48.303 + }
48.304 +
48.305 + public static MethodHandle boxRaw(Wrapper type, boolean exact) {
48.306 + return box(type, exact, true);
48.307 + }
48.308 +
48.309 + /// Kludges for when raw values get accidentally boxed.
48.310 +
48.311 + static Byte reboxRawByte(Object x) {
48.312 + if (x instanceof Byte) return (Byte) x;
48.313 + return boxByteRaw(unboxInteger(x));
48.314 + }
48.315 +
48.316 + static Short reboxRawShort(Object x) {
48.317 + if (x instanceof Short) return (Short) x;
48.318 + return boxShortRaw(unboxInteger(x));
48.319 + }
48.320 +
48.321 + static Boolean reboxRawBoolean(Object x) {
48.322 + if (x instanceof Boolean) return (Boolean) x;
48.323 + return boxBooleanRaw(unboxInteger(x));
48.324 + }
48.325 +
48.326 + static Character reboxRawCharacter(Object x) {
48.327 + if (x instanceof Character) return (Character) x;
48.328 + return boxCharacterRaw(unboxInteger(x));
48.329 + }
48.330 +
48.331 + static Float reboxRawFloat(Object x) {
48.332 + if (x instanceof Float) return (Float) x;
48.333 + return boxFloatRaw(unboxInteger(x));
48.334 + }
48.335 +
48.336 + static Double reboxRawDouble(Object x) {
48.337 + if (x instanceof Double) return (Double) x;
48.338 + return boxDoubleRaw(unboxLong(x));
48.339 + }
48.340 +
48.341 + private static MethodType reboxType(Wrapper wrap) {
48.342 + Class<?> boxType = wrap.wrapperType();
48.343 + return MethodType.make(boxType, Object.class);
48.344 + }
48.345 +
48.346 + private static final EnumMap<Wrapper, MethodHandle>[]
48.347 + REBOX_CONVERSIONS = newWrapperCaches(2);
48.348 +
48.349 + public static MethodHandle rebox(Wrapper wrap, boolean exact) {
48.350 + EnumMap<Wrapper, MethodHandle> cache = REBOX_CONVERSIONS[exact?1:0];
48.351 + MethodHandle mh = cache.get(wrap);
48.352 + if (mh != null) {
48.353 + return mh;
48.354 + }
48.355 + // slow path
48.356 + switch (wrap) {
48.357 + case OBJECT:
48.358 + mh = IDENTITY; break;
48.359 + case VOID:
48.360 + throw new IllegalArgumentException("cannot rebox a void");
48.361 + case INT: case LONG:
48.362 + mh = cast(wrap.wrapperType(), exact);
48.363 + break;
48.364 + }
48.365 + if (mh != null) {
48.366 + cache.put(wrap, mh);
48.367 + return mh;
48.368 + }
48.369 + // look up the method
48.370 + String name = "reboxRaw" + wrap.simpleName();
48.371 + MethodType type = reboxType(wrap);
48.372 + if (exact)
48.373 + mh = IMPL_LOOKUP.findStatic(ValueConversions.class, name, type);
48.374 + else
48.375 + mh = retype(IDENTITY.type(), rebox(wrap, !exact));
48.376 + if (mh != null) {
48.377 + cache.put(wrap, mh);
48.378 + return mh;
48.379 + }
48.380 + throw new IllegalArgumentException("cannot find rebox adapter for " + wrap);
48.381 + }
48.382 +
48.383 + public static MethodHandle rebox(Class<?> type, boolean exact) {
48.384 + return rebox(Wrapper.forPrimitiveType(type), exact);
48.385 + }
48.386 +
48.387 + /// Width-changing conversions between int and long.
48.388 +
48.389 + static long widenInt(int x) {
48.390 + return x;
48.391 + }
48.392 +
48.393 + static int narrowLong(long x) {
48.394 + return (int) x;
48.395 + }
48.396 +
48.397 + /// Constant functions
48.398 +
48.399 + static void ignore(Object x) {
48.400 + // no value to return; this is an unbox of null
48.401 + return;
48.402 + }
48.403 +
48.404 + static void empty() {
48.405 + return;
48.406 + }
48.407 +
48.408 + static Object zeroObject() {
48.409 + return null;
48.410 + }
48.411 +
48.412 + static int zeroInteger() {
48.413 + return 0;
48.414 + }
48.415 +
48.416 + static long zeroLong() {
48.417 + return 0;
48.418 + }
48.419 +
48.420 + static float zeroFloat() {
48.421 + return 0;
48.422 + }
48.423 +
48.424 + static double zeroDouble() {
48.425 + return 0;
48.426 + }
48.427 +
48.428 + private static final EnumMap<Wrapper, MethodHandle>[]
48.429 + ZERO_CONSTANT_FUNCTIONS = newWrapperCaches(1);
48.430 +
48.431 + public static MethodHandle zeroConstantFunction(Wrapper wrap) {
48.432 + EnumMap<Wrapper, MethodHandle> cache = ZERO_CONSTANT_FUNCTIONS[0];
48.433 + MethodHandle mh = cache.get(wrap);
48.434 + if (mh != null) {
48.435 + return mh;
48.436 + }
48.437 + // slow path
48.438 + MethodType type = MethodType.make(wrap.primitiveType());
48.439 + switch (wrap) {
48.440 + case VOID:
48.441 + mh = EMPTY;
48.442 + break;
48.443 + case INT: case LONG: case FLOAT: case DOUBLE:
48.444 + mh = IMPL_LOOKUP.findStatic(ValueConversions.class, "zero"+wrap.simpleName(), type);
48.445 + break;
48.446 + }
48.447 + if (mh != null) {
48.448 + cache.put(wrap, mh);
48.449 + return mh;
48.450 + }
48.451 +
48.452 + // use the raw method
48.453 + Wrapper rawWrap = wrap.rawPrimitive();
48.454 + if (rawWrap != wrap) {
48.455 + mh = retype(type, zeroConstantFunction(rawWrap));
48.456 + }
48.457 + if (mh != null) {
48.458 + cache.put(wrap, mh);
48.459 + return mh;
48.460 + }
48.461 + throw new IllegalArgumentException("cannot find zero constant for " + wrap);
48.462 + }
48.463 +
48.464 + /// Converting references to references.
48.465 +
48.466 + /**
48.467 + * Value-killing function.
48.468 + * @param x an arbitrary reference value
48.469 + * @return a null
48.470 + */
48.471 + static Object alwaysNull(Object x) {
48.472 + return null;
48.473 + }
48.474 +
48.475 + /**
48.476 + * Value-killing function.
48.477 + * @param x an arbitrary reference value
48.478 + * @return a zero
48.479 + */
48.480 + static int alwaysZero(Object x) {
48.481 + return 0;
48.482 + }
48.483 +
48.484 + /**
48.485 + * Identity function.
48.486 + * @param x an arbitrary reference value
48.487 + * @return the same value x
48.488 + */
48.489 + static <T> T identity(T x) {
48.490 + return x;
48.491 + }
48.492 +
48.493 + /**
48.494 + * Identity function, with reference cast.
48.495 + * @param t an arbitrary reference type
48.496 + * @param x an arbitrary reference value
48.497 + * @return the same value x
48.498 + */
48.499 + static <T,U> T castReference(Class<? extends T> t, U x) {
48.500 + return t.cast(x);
48.501 + }
48.502 +
48.503 + private static final MethodHandle IDENTITY, CAST_REFERENCE, ALWAYS_NULL, ALWAYS_ZERO, ZERO_OBJECT, IGNORE, EMPTY;
48.504 + static {
48.505 + try {
48.506 + MethodType idType = MethodType.makeGeneric(1);
48.507 + MethodType castType = idType.insertParameterType(0, Class.class);
48.508 + MethodType alwaysZeroType = idType.changeReturnType(int.class);
48.509 + MethodType ignoreType = idType.changeReturnType(void.class);
48.510 + MethodType zeroObjectType = MethodType.makeGeneric(0);
48.511 + IDENTITY = IMPL_LOOKUP.findStatic(ValueConversions.class, "identity", idType);
48.512 + //CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType);
48.513 + CAST_REFERENCE = IMPL_LOOKUP.findStatic(ValueConversions.class, "castReference", castType);
48.514 + ALWAYS_NULL = IMPL_LOOKUP.findStatic(ValueConversions.class, "alwaysNull", idType);
48.515 + ALWAYS_ZERO = IMPL_LOOKUP.findStatic(ValueConversions.class, "alwaysZero", alwaysZeroType);
48.516 + ZERO_OBJECT = IMPL_LOOKUP.findStatic(ValueConversions.class, "zeroObject", zeroObjectType);
48.517 + IGNORE = IMPL_LOOKUP.findStatic(ValueConversions.class, "ignore", ignoreType);
48.518 + EMPTY = IMPL_LOOKUP.findStatic(ValueConversions.class, "empty", ignoreType.dropParameterType(0));
48.519 + } catch (RuntimeException ex) {
48.520 + throw ex;
48.521 + }
48.522 + }
48.523 +
48.524 + private static final EnumMap<Wrapper, MethodHandle> WRAPPER_CASTS
48.525 + = new EnumMap<Wrapper, MethodHandle>(Wrapper.class);
48.526 +
48.527 + private static final EnumMap<Wrapper, MethodHandle> EXACT_WRAPPER_CASTS
48.528 + = new EnumMap<Wrapper, MethodHandle>(Wrapper.class);
48.529 +
48.530 + /** Return a method that casts its sole argument (an Object) to the given type
48.531 + * and returns it as the given type (if exact is true), or as plain Object (if erase is true).
48.532 + */
48.533 + public static MethodHandle cast(Class<?> type, boolean exact) {
48.534 + if (type.isPrimitive()) throw new IllegalArgumentException("cannot cast primitive type "+type);
48.535 + MethodHandle mh = null;
48.536 + Wrapper wrap = null;
48.537 + EnumMap<Wrapper, MethodHandle> cache = null;
48.538 + if (Wrapper.isWrapperType(type)) {
48.539 + wrap = Wrapper.forWrapperType(type);
48.540 + cache = (exact ? EXACT_WRAPPER_CASTS : WRAPPER_CASTS);
48.541 + mh = cache.get(wrap);
48.542 + if (mh != null) return mh;
48.543 + }
48.544 + if (VerifyType.isNullReferenceConversion(Object.class, type))
48.545 + mh = IDENTITY;
48.546 + else if (VerifyType.isNullType(type))
48.547 + mh = ALWAYS_NULL;
48.548 + else
48.549 + mh = MethodHandles.insertArgument(CAST_REFERENCE, 0, type);
48.550 + if (exact) {
48.551 + MethodType xmt = MethodType.make(type, Object.class);
48.552 + mh = AdapterMethodHandle.makeRawRetypeOnly(IMPL_TOKEN, xmt, mh);
48.553 + }
48.554 + if (cache != null)
48.555 + cache.put(wrap, mh);
48.556 + return mh;
48.557 + }
48.558 +
48.559 + public static MethodHandle identity() {
48.560 + return IDENTITY;
48.561 + }
48.562 +
48.563 + private static MethodHandle retype(MethodType type, MethodHandle mh) {
48.564 + return AdapterMethodHandle.makeRetypeOnly(IMPL_TOKEN, type, mh);
48.565 + }
48.566 +}
49.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
49.2 +++ b/src/share/classes/sun/dyn/util/VerifyAccess.java Tue May 05 23:12:47 2009 -0700
49.3 @@ -0,0 +1,169 @@
49.4 +/*
49.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
49.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
49.7 + *
49.8 + * This code is free software; you can redistribute it and/or modify it
49.9 + * under the terms of the GNU General Public License version 2 only, as
49.10 + * published by the Free Software Foundation. Sun designates this
49.11 + * particular file as subject to the "Classpath" exception as provided
49.12 + * by Sun in the LICENSE file that accompanied this code.
49.13 + *
49.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
49.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
49.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
49.17 + * version 2 for more details (a copy is included in the LICENSE file that
49.18 + * accompanied this code).
49.19 + *
49.20 + * You should have received a copy of the GNU General Public License version
49.21 + * 2 along with this work; if not, write to the Free Software Foundation,
49.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
49.23 + *
49.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
49.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
49.26 + * have any questions.
49.27 + */
49.28 +
49.29 +package sun.dyn.util;
49.30 +
49.31 +import java.dyn.LinkagePermission;
49.32 +import java.lang.reflect.Modifier;
49.33 +import sun.dyn.Access;
49.34 +
49.35 +/**
49.36 + * This class centralizes information about the JVM's linkage access control.
49.37 + * @author jrose
49.38 + */
49.39 +public class VerifyAccess {
49.40 +
49.41 + private VerifyAccess() { } // cannot instantiate
49.42 +
49.43 + /**
49.44 + * Evaluate the JVM linkage rules for access to the given method on behalf of caller.
49.45 + * Return non-null if and only if the given accessing class has at least partial
49.46 + * privileges to invoke the given method. The return value {@code Object.class}
49.47 + * denotes unlimited privileges.
49.48 + * <p>
49.49 + * Some circumstances require an additional check on the
49.50 + * leading parameter (the receiver) of the method, if it is non-static.
49.51 + * In the case of {@code invokespecial} ({@code doDispatch} is false),
49.52 + * the leading parameter must be the accessing class or a subclass.
49.53 + * In the case of a call to a {@code protected} method outside the same
49.54 + * package, the same constraint applies.
49.55 + * @param m the proposed callee
49.56 + * @param doDispatch if false, a non-static m will be invoked as if by {@code invokespecial}
49.57 + * @param lookupClass the class for which the access check is being made
49.58 + * @return null if the method is not accessible, else a receiver type constraint, else {@code Object.class}
49.59 + */
49.60 + public static Class<?> isAccessible(Class<?> defc, int mods,
49.61 + boolean doDispatch, Class<?> lookupClass) {
49.62 + if (!isAccessible(defc, lookupClass))
49.63 + return null;
49.64 + Class<?> constraint = Object.class;
49.65 + if (!doDispatch && !Modifier.isStatic(mods)) {
49.66 + constraint = lookupClass;
49.67 + }
49.68 + if (Modifier.isPublic(mods))
49.69 + return constraint;
49.70 + if (Modifier.isPrivate(mods))
49.71 + return isSamePackageMember(defc, lookupClass) ? constraint : null;
49.72 + if (isSamePackage(defc, lookupClass))
49.73 + return constraint;
49.74 + if (Modifier.isProtected(mods) && defc.isAssignableFrom(lookupClass))
49.75 + return constraint;
49.76 + // else it is private or package scoped, and not close enough
49.77 + return null;
49.78 + }
49.79 +
49.80 + /**
49.81 + * Evaluate the JVM linkage rules for access to the given class on behalf of caller.
49.82 + */
49.83 + public static boolean isAccessible(Class<?> refc, Class<?> lookupClass) {
49.84 + int mods = refc.getModifiers();
49.85 + if (Modifier.isPublic(mods))
49.86 + return true;
49.87 + if (isSamePackage(lookupClass, refc))
49.88 + return true;
49.89 + return false;
49.90 + }
49.91 +
49.92 + /**
49.93 + * Test if two classes have the same class loader and package qualifier.
49.94 + * @param class1
49.95 + * @param class2
49.96 + * @return whether they are in the same package
49.97 + */
49.98 + public static boolean isSamePackage(Class<?> class1, Class<?> class2) {
49.99 + if (class1 == class2)
49.100 + return true;
49.101 + if (loadersAreRelated(class1.getClassLoader(), class2.getClassLoader()))
49.102 + return false;
49.103 + String name1 = class1.getName(), name2 = class2.getName();
49.104 + int dot = name1.lastIndexOf('.');
49.105 + if (dot != name2.lastIndexOf('.'))
49.106 + return false;
49.107 + for (int i = 0; i < dot; i++) {
49.108 + if (name1.charAt(i) != name2.charAt(i))
49.109 + return false;
49.110 + }
49.111 + return true;
49.112 + }
49.113 +
49.114 + /**
49.115 + * Test if two classes are defined as part of the same package member (top-level class).
49.116 + * If this is true, they can share private access with each other.
49.117 + * @param class1
49.118 + * @param class2
49.119 + * @return whether they are identical or nested together
49.120 + */
49.121 + public static boolean isSamePackageMember(Class<?> class1, Class<?> class2) {
49.122 + if (class1 == class2)
49.123 + return true;
49.124 + if (!isSamePackage(class1, class2))
49.125 + return false;
49.126 + if (getOutermostEnclosingClass(class1) != getOutermostEnclosingClass(class2))
49.127 + return false;
49.128 + return true;
49.129 + }
49.130 +
49.131 + private static Class<?> getOutermostEnclosingClass(Class<?> c) {
49.132 + Class<?> pkgmem = c;
49.133 + for (Class<?> enc = c; (enc = enc.getEnclosingClass()) != null; )
49.134 + pkgmem = enc;
49.135 + return pkgmem;
49.136 + }
49.137 +
49.138 + private static boolean loadersAreRelated(ClassLoader loader1, ClassLoader loader2) {
49.139 + if (loader1 == loader2 || loader1 == null || loader2 == null) {
49.140 + return true;
49.141 + }
49.142 + for (ClassLoader scan1 = loader1;
49.143 + scan1 != null; scan1 = scan1.getParent()) {
49.144 + if (scan1 == loader2) return true;
49.145 + }
49.146 + for (ClassLoader scan2 = loader2;
49.147 + scan2 != null; scan2 = scan2.getParent()) {
49.148 + if (scan2 == loader1) return true;
49.149 + }
49.150 + return false;
49.151 + }
49.152 +
49.153 + /**
49.154 + * Ensure the requesting class have privileges to perform invokedynamic
49.155 + * linkage operations on subjectClass. True if requestingClass is
49.156 + * Access.class (meaning the request originates from the JVM) or if the
49.157 + * classes are in the same package and have consistent class loaders.
49.158 + * (The subject class loader must be identical with or be a child of
49.159 + * the requesting class loader.)
49.160 + * @param requestingClass
49.161 + * @param subjectClass
49.162 + */
49.163 + public static void checkBootstrapPrivilege(Class requestingClass, Class subjectClass,
49.164 + String permissionName) {
49.165 + if (requestingClass == Access.class) return;
49.166 + if (requestingClass == subjectClass) return;
49.167 + SecurityManager security = System.getSecurityManager();
49.168 + if (security == null) return; // open season
49.169 + if (isSamePackage(requestingClass, subjectClass)) return;
49.170 + security.checkPermission(new LinkagePermission(permissionName, requestingClass));
49.171 + }
49.172 +}
50.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
50.2 +++ b/src/share/classes/sun/dyn/util/VerifyType.java Tue May 05 23:12:47 2009 -0700
50.3 @@ -0,0 +1,219 @@
50.4 +/*
50.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
50.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
50.7 + *
50.8 + * This code is free software; you can redistribute it and/or modify it
50.9 + * under the terms of the GNU General Public License version 2 only, as
50.10 + * published by the Free Software Foundation. Sun designates this
50.11 + * particular file as subject to the "Classpath" exception as provided
50.12 + * by Sun in the LICENSE file that accompanied this code.
50.13 + *
50.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
50.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
50.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
50.17 + * version 2 for more details (a copy is included in the LICENSE file that
50.18 + * accompanied this code).
50.19 + *
50.20 + * You should have received a copy of the GNU General Public License version
50.21 + * 2 along with this work; if not, write to the Free Software Foundation,
50.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
50.23 + *
50.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
50.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
50.26 + * have any questions.
50.27 + */
50.28 +
50.29 +package sun.dyn.util;
50.30 +
50.31 +import java.dyn.MethodType;
50.32 +
50.33 +/**
50.34 + * This class centralizes information about the JVM verifier
50.35 + * and its requirements about type correctness.
50.36 + * @author jrose
50.37 + */
50.38 +public class VerifyType {
50.39 +
50.40 + private VerifyType() { } // cannot instantiate
50.41 +
50.42 + /**
50.43 + * True if a value can be stacked as the source type and unstacked as the
50.44 + * destination type, without violating the JVM's type consistency.
50.45 + *
50.46 + * @param call the type of a stacked value
50.47 + * @param recv the type by which we'd like to treat it
50.48 + * @return whether the retyping can be done without motion or reformatting
50.49 + */
50.50 + public static boolean isNullConversion(Class<?> src, Class<?> dst) {
50.51 + if (src == dst) return true;
50.52 + // Verifier allows any interface to be treated as Object:
50.53 + if (dst.isInterface()) dst = Object.class;
50.54 + if (src.isInterface()) src = Object.class;
50.55 + if (src == dst) return true; // check again
50.56 + if (dst == void.class) return true; // drop any return value
50.57 + if (isNullType(src)) return !dst.isPrimitive();
50.58 + if (!src.isPrimitive()) return dst.isAssignableFrom(src);
50.59 + // Verifier allows an int to carry byte, short, char, or even boolean:
50.60 + if (dst == int.class) return Wrapper.forPrimitiveType(src).isSubwordOrInt();
50.61 + return false;
50.62 + }
50.63 +
50.64 + /**
50.65 + * Specialization of isNullConversion to reference types.
50.66 +
50.67 + * @param call the type of a stacked value
50.68 + * @param recv the reference type by which we'd like to treat it
50.69 + * @return whether the retyping can be done without a cast
50.70 + */
50.71 + public static boolean isNullReferenceConversion(Class<?> src, Class<?> dst) {
50.72 + assert(!dst.isPrimitive());
50.73 + if (dst.isInterface()) return true; // verifier allows this
50.74 + if (isNullType(src)) return true;
50.75 + return dst.isAssignableFrom(src);
50.76 + }
50.77 +
50.78 + /**
50.79 + * Is the given type either java.lang.Void or java.lang.Null?
50.80 + * These types serve as markers for bare nulls and therefore
50.81 + * may be promoted to any type. This is secure, since
50.82 + */
50.83 + public static boolean isNullType(Class<?> type) {
50.84 + if (type == null) return false;
50.85 + return type == NULL_CLASS_1 || type == NULL_CLASS_2;
50.86 + }
50.87 + private static final Class<?> NULL_CLASS_1, NULL_CLASS_2;
50.88 + static {
50.89 + Class<?> nullClass1 = null, nullClass2 = null;
50.90 + try {
50.91 + nullClass1 = Class.forName("java.lang.Null");
50.92 + } catch (ClassNotFoundException ex) {
50.93 + // OK, we'll cope
50.94 + }
50.95 + NULL_CLASS_1 = nullClass1;
50.96 +
50.97 + // This one may also be used as a null type.
50.98 + // TO DO: Decide if we really want to legitimize it here.
50.99 + // Probably we do, unless java.lang.Null really makes it into Java 7
50.100 + nullClass2 = Void.class;
50.101 + NULL_CLASS_2 = nullClass2;
50.102 + }
50.103 +
50.104 + /**
50.105 + * True if a method handle can receive a call under a slightly different
50.106 + * method type, without moving or reformatting any stack elements.
50.107 + *
50.108 + * @param call the type of call being made
50.109 + * @param recv the type of the method handle receiving the call
50.110 + * @return whether the retyping can be done without motion or reformatting
50.111 + */
50.112 + public static boolean isNullConversion(MethodType call, MethodType recv) {
50.113 + if (call == recv) return true;
50.114 + int len = call.parameterCount();
50.115 + if (len != recv.parameterCount()) return false;
50.116 + for (int i = 0; i < len; i++)
50.117 + if (!isNullConversion(call.parameterType(i), recv.parameterType(i)))
50.118 + return false;
50.119 + return isNullConversion(recv.returnType(), call.returnType());
50.120 + }
50.121 +
50.122 + //TO DO: isRawConversion
50.123 +
50.124 + /**
50.125 + * Determine if the JVM verifier allows a value of type call to be
50.126 + * passed to a formal parameter (or return variable) of type recv.
50.127 + * Returns 1 if the verifier allows the types to match without conversion.
50.128 + * Returns -1 if the types can be made to match by a JVM-supported adapter.
50.129 + * Cases supported are:
50.130 + * <ul><li>checkcast
50.131 + * </li><li>conversion between any two integral types (but not floats)
50.132 + * </li><li>unboxing from a wrapper to its corresponding primitive type
50.133 + * </li><li>conversion in either direction between float and double
50.134 + * </li></ul>
50.135 + * (Autoboxing is not supported here; it must be done via Java code.)
50.136 + * Returns 0 otherwise.
50.137 + */
50.138 + public static int canPassUnchecked(Class<?> src, Class<?> dst) {
50.139 + if (src == dst)
50.140 + return 1;
50.141 +
50.142 + if (dst.isPrimitive()) {
50.143 + if (dst == void.class)
50.144 + // Return anything to a caller expecting void.
50.145 + // This is a property of the implementation, which links
50.146 + // return values via a register rather than via a stack push.
50.147 + // This makes it possible to ignore cleanly.
50.148 + return 1;
50.149 + if (src == void.class)
50.150 + return 0; // void-to-something?
50.151 + if (!src.isPrimitive())
50.152 + // Cannot pass a reference to any primitive type (exc. void).
50.153 + return 0;
50.154 + Wrapper sw = Wrapper.forPrimitiveType(src);
50.155 + Wrapper dw = Wrapper.forPrimitiveType(dst);
50.156 + if (sw.isSubwordOrInt() && dw.isSubwordOrInt()) {
50.157 + if (sw.bitWidth() >= dw.bitWidth())
50.158 + return -1; // truncation may be required
50.159 + if (!dw.isSigned() && sw.isSigned())
50.160 + return -1; // sign elimination may be required
50.161 + }
50.162 + if (src == float.class || dst == float.class) {
50.163 + if (src == double.class || dst == double.class)
50.164 + return -1; // floating conversion may be required
50.165 + else
50.166 + return 0; // other primitive conversions NYI
50.167 + } else {
50.168 + // all fixed-point conversions are supported
50.169 + return 0;
50.170 + }
50.171 + } else if (src.isPrimitive()) {
50.172 + // Cannot pass a primitive to any reference type.
50.173 + // (Maybe allow null.class?)
50.174 + return 0;
50.175 + }
50.176 +
50.177 + // Handle reference types in the rest of the block:
50.178 +
50.179 + // The verifier treats interfaces exactly like Object.
50.180 + if (isNullReferenceConversion(src, dst))
50.181 + // pass any reference to object or an arb. interface
50.182 + return 1;
50.183 + // else it's a definite "maybe" (cast is required)
50.184 + return -1;
50.185 + }
50.186 +
50.187 + public static int canPassRaw(Class<?> src, Class<?> dst) {
50.188 + if (dst.isPrimitive()) {
50.189 + if (dst == void.class)
50.190 + // As above, return anything to a caller expecting void.
50.191 + return 1;
50.192 + if (src == void.class)
50.193 + // Special permission for raw conversions: allow a void
50.194 + // to be captured as a garbage int.
50.195 + // Caller promises that the actual value will be disregarded.
50.196 + return dst == int.class ? 1 : 0;
50.197 + if (!src.isPrimitive())
50.198 + return 0;
50.199 + Wrapper sw = Wrapper.forPrimitiveType(src);
50.200 + Wrapper dw = Wrapper.forPrimitiveType(dst);
50.201 + if (sw.stackSlots() == dw.stackSlots())
50.202 + return 1; // can do a reinterpret-cast on a stacked primitive
50.203 + if (sw.isSubwordOrInt() && dw == Wrapper.VOID)
50.204 + return 1; // can drop an outgoing int value
50.205 + return 0;
50.206 + } else if (src.isPrimitive()) {
50.207 + return 0;
50.208 + }
50.209 +
50.210 + // Both references.
50.211 + if (isNullReferenceConversion(src, dst))
50.212 + return 1;
50.213 + return -1;
50.214 + }
50.215 +
50.216 + public static boolean isSpreadArgType(Class<?> spreadArg) {
50.217 + return spreadArg.isArray();
50.218 + }
50.219 + public static Class<?> spreadArgElementType(Class<?> spreadArg, int i) {
50.220 + return spreadArg.getComponentType();
50.221 + }
50.222 +}
51.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
51.2 +++ b/src/share/classes/sun/dyn/util/Wrapper.java Tue May 05 23:12:47 2009 -0700
51.3 @@ -0,0 +1,467 @@
51.4 +/*
51.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
51.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
51.7 + *
51.8 + * This code is free software; you can redistribute it and/or modify it
51.9 + * under the terms of the GNU General Public License version 2 only, as
51.10 + * published by the Free Software Foundation. Sun designates this
51.11 + * particular file as subject to the "Classpath" exception as provided
51.12 + * by Sun in the LICENSE file that accompanied this code.
51.13 + *
51.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
51.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
51.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
51.17 + * version 2 for more details (a copy is included in the LICENSE file that
51.18 + * accompanied this code).
51.19 + *
51.20 + * You should have received a copy of the GNU General Public License version
51.21 + * 2 along with this work; if not, write to the Free Software Foundation,
51.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
51.23 + *
51.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
51.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
51.26 + * have any questions.
51.27 + */
51.28 +
51.29 +package sun.dyn.util;
51.30 +
51.31 +public enum Wrapper {
51.32 + INT(Integer.class, int.class, 'I', (Integer)(int)0, Format.signed(32)),
51.33 + LONG(Long.class, long.class, 'J', (Long)(long)0, Format.signed(64)),
51.34 + BYTE(Byte.class, byte.class, 'B', (Byte)(byte)0, Format.signed(8)),
51.35 + SHORT(Short.class, short.class, 'S', (Short)(short)0, Format.signed(16)),
51.36 + CHAR(Character.class, char.class, 'C', (Character)(char)0, Format.unsigned(16)),
51.37 + BOOLEAN(Boolean.class, boolean.class, 'Z', (Boolean)false, Format.unsigned(1)),
51.38 + FLOAT(Float.class, float.class, 'F', (Float)(float)0, Format.floating(32)),
51.39 + DOUBLE(Double.class, double.class, 'D', (Double)(double)0, Format.floating(64)),
51.40 + VOID(Void.class, void.class, 'V', null, Format.other(0)),
51.41 + //NULL(Null.class, null.class, 'N', null, Format.other(1)),
51.42 + OBJECT(Object.class, Object.class, 'L', null, Format.other(1)),
51.43 + ;
51.44 +
51.45 + private final Class<?> wrapperType;
51.46 + private final Class<?> primitiveType;
51.47 + private final char basicTypeChar;
51.48 + private final Object zero;
51.49 + private final int format;
51.50 + private final String simpleName;
51.51 +
51.52 + private Wrapper(Class<?> wtype, Class<?> ptype, char tchar, Object zero, int format) {
51.53 + this.wrapperType = wtype;
51.54 + this.primitiveType = ptype;
51.55 + this.basicTypeChar = tchar;
51.56 + this.zero = zero;
51.57 + this.format = format;
51.58 + this.simpleName = wtype.getSimpleName();
51.59 + }
51.60 +
51.61 + private static abstract class Format {
51.62 + static final int SLOT_SHIFT = 0, SIZE_SHIFT = 2, KIND_SHIFT = 12;
51.63 + static final int
51.64 + SIGNED = (-1) << KIND_SHIFT,
51.65 + UNSIGNED = 0 << KIND_SHIFT,
51.66 + FLOATING = 1 << KIND_SHIFT;
51.67 + static final int
51.68 + SLOT_MASK = ((1<<(SIZE_SHIFT-SLOT_SHIFT))-1),
51.69 + SIZE_MASK = ((1<<(KIND_SHIFT-SIZE_SHIFT))-1);
51.70 + static int format(int kind, int size, int slots) {
51.71 + assert(((kind >> KIND_SHIFT) << KIND_SHIFT) == kind);
51.72 + assert((size & (size-1)) == 0); // power of two
51.73 + assert((kind == SIGNED) ? (size > 0) :
51.74 + (kind == UNSIGNED) ? (size > 0) :
51.75 + (kind == FLOATING) ? (size == 32 || size == 64) :
51.76 + false);
51.77 + assert((slots == 2) ? (size == 64) :
51.78 + (slots == 1) ? (size <= 32) :
51.79 + false);
51.80 + return kind | (size << SIZE_SHIFT) | (slots << SLOT_SHIFT);
51.81 + }
51.82 + static int
51.83 + INT = SIGNED | (32 << SIZE_SHIFT) | (1 << SLOT_SHIFT),
51.84 + BOOLEAN = UNSIGNED | (1 << SIZE_SHIFT) | (1 << SLOT_SHIFT),
51.85 + FLOAT = FLOATING | (32 << SIZE_SHIFT) | (1 << SLOT_SHIFT),
51.86 + VOID = UNSIGNED | (0 << SIZE_SHIFT) | (0 << SLOT_SHIFT),
51.87 + NUM_MASK = (-1) << SIZE_SHIFT;
51.88 + static int signed(int size) { return format(SIGNED, size, (size > 32 ? 2 : 1)); }
51.89 + static int unsigned(int size) { return format(UNSIGNED, size, (size > 32 ? 2 : 1)); }
51.90 + static int floating(int size) { return format(FLOATING, size, (size > 32 ? 2 : 1)); }
51.91 + static int other(int slots) { return slots << SLOT_SHIFT; }
51.92 + }
51.93 +
51.94 + /// format queries:
51.95 +
51.96 + /** How many bits are in the wrapped value? Returns 0 for OBJECT or VOID. */
51.97 + public int bitWidth() { return (format >> Format.SIZE_SHIFT) & Format.SIZE_MASK; }
51.98 + /** How many JVM stack slots occupied by the wrapped value? Returns 0 for VOID. */
51.99 + public int stackSlots() { return (format >> Format.SLOT_SHIFT) & Format.SLOT_MASK; }
51.100 + /** Does the wrapped value occupy a single JVM stack slot? */
51.101 + public boolean isSingleWord() { return (format & (1 << Format.SLOT_SHIFT)) != 0; }
51.102 + /** Does the wrapped value occupy two JVM stack slots? */
51.103 + public boolean isDoubleWord() { return (format & (2 << Format.SLOT_SHIFT)) != 0; }
51.104 + /** Is the wrapped type numeric (not void or object)? */
51.105 + public boolean isNumeric() { return (format & Format.NUM_MASK) != 0; }
51.106 + /** Is the wrapped type a primitive other than float, double, or void? */
51.107 + public boolean isIntegral() { return isNumeric() && format < Format.FLOAT; }
51.108 + /** Is the wrapped type one of int, boolean, byte, char, or short? */
51.109 + public boolean isSubwordOrInt() { return isIntegral() && isSingleWord(); }
51.110 + /* Is the wrapped value a signed integral type (one of byte, short, int, or long)? */
51.111 + public boolean isSigned() { return format < Format.VOID; }
51.112 + /* Is the wrapped value an unsigned integral type (one of boolean or char)? */
51.113 + public boolean isUnsigned() { return format >= Format.BOOLEAN && format < Format.FLOAT; }
51.114 + /** Is the wrapped type either float or double? */
51.115 + public boolean isFloating() { return format >= Format.FLOAT; }
51.116 +
51.117 + /** Produce a zero value for the given wrapper type.
51.118 + * This will be a numeric zero for a number or character,
51.119 + * false for a boolean, and null for a reference or void.
51.120 + * The common thread is that this is what is contained
51.121 + * in a default-initialized variable of the given primitive
51.122 + * type. (For void, it is what a reflective method returns
51.123 + * instead of no value at all.)
51.124 + */
51.125 + public Object zero() { return zero; }
51.126 +
51.127 + /** Produce a zero value for the given wrapper type T.
51.128 + * The optinoal argument must a type compatible with this wrapper.
51.129 + * Equivalent to {@code this.cast(this.zero(), type)}.
51.130 + */
51.131 + public <T> T zero(Class<T> type) { return cast(zero, type); }
51.132 +
51.133 +// /** Produce a wrapper for the given wrapper or primitive type. */
51.134 +// public static Wrapper valueOf(Class<?> type) {
51.135 +// if (isPrimitiveType(type))
51.136 +// return forPrimitiveType(type);
51.137 +// else
51.138 +// return forWrapperType(type);
51.139 +// }
51.140 +
51.141 + /** Return the wrapper that wraps values of the given type.
51.142 + * The type may be {@code Object}, meaning the {@code OBJECT} wrapper.
51.143 + * Otherwise, the type must be a primitive.
51.144 + * @throws IllegalArgumentException for unexpected types
51.145 + */
51.146 + public static Wrapper forPrimitiveType(Class<?> type) {
51.147 + Wrapper w = FROM_PRIM[hashPrim(type)];
51.148 + if (w != null && w.primitiveType == type) {
51.149 + return w;
51.150 + }
51.151 + if (type.isPrimitive())
51.152 + throw new InternalError(); // redo hash function
51.153 + throw newIllegalArgumentException("not primitive: "+type);
51.154 + }
51.155 +
51.156 + /** Return the wrapper that wraps values into the given wrapper type.
51.157 + * If it is {@code Object} or an interface, return {@code OBJECT}.
51.158 + * Otherwise, it must be a wrapper type.
51.159 + * The type must not be a primitive type.
51.160 + * @throws IllegalArgumentException for unexpected types
51.161 + */
51.162 + public static Wrapper forWrapperType(Class<?> type) {
51.163 + Wrapper w = findWrapperType(type);
51.164 + if (w != null) return w;
51.165 + for (Wrapper x : values())
51.166 + if (w.wrapperType == type)
51.167 + throw new InternalError(); // redo hash function
51.168 + throw newIllegalArgumentException("not wrapper: "+type);
51.169 + }
51.170 +
51.171 + static Wrapper findWrapperType(Class<?> type) {
51.172 + Wrapper w = FROM_WRAP[hashWrap(type)];
51.173 + if (w != null && w.wrapperType == type) {
51.174 + return w;
51.175 + }
51.176 + if (type.isInterface())
51.177 + return OBJECT;
51.178 + return null;
51.179 + }
51.180 +
51.181 + /** Return the wrapper that corresponds to the given bytecode
51.182 + * signature character. Return {@code OBJECT} for the character 'L'.
51.183 + * @throws IllegalArgumentException for any non-signature character or {@code '['}.
51.184 + */
51.185 + public static Wrapper forBasicType(char type) {
51.186 + Wrapper w = FROM_CHAR[hashChar(type)];
51.187 + if (w != null && w.basicTypeChar == type) {
51.188 + return w;
51.189 + }
51.190 + for (Wrapper x : values())
51.191 + if (w.basicTypeChar == type)
51.192 + throw new InternalError(); // redo hash function
51.193 + throw newIllegalArgumentException("not basic type char: "+type);
51.194 + }
51.195 +
51.196 + /** Return the wrapper for the given type, if it is
51.197 + * a primitive type, else return {@code OBJECT}.
51.198 + */
51.199 + public static Wrapper forBasicType(Class<?> type) {
51.200 + if (type.isPrimitive())
51.201 + return forPrimitiveType(type);
51.202 + return OBJECT; // any reference, including wrappers or arrays
51.203 + }
51.204 +
51.205 + // Note on perfect hashes:
51.206 + // for signature chars c, do (c + (c >> 1)) % 16
51.207 + // for primitive type names n, do (n[0] + n[2]) % 16
51.208 + // The type name hash works for both primitive and wrapper names.
51.209 + // You can add "java/lang/Object" to the primitive names.
51.210 + // But you add the wrapper name Object, use (n[2] + (3*n[1])) % 16.
51.211 + private static final Wrapper[] FROM_PRIM = new Wrapper[16];
51.212 + private static final Wrapper[] FROM_WRAP = new Wrapper[16];
51.213 + private static final Wrapper[] FROM_CHAR = new Wrapper[16];
51.214 + private static int hashPrim(Class<?> x) {
51.215 + String xn = x.getName();
51.216 + if (xn.length() < 3) return 0;
51.217 + return (xn.charAt(0) + xn.charAt(2)) % 16;
51.218 + }
51.219 + private static int hashWrap(Class<?> x) {
51.220 + String xn = x.getName();
51.221 + final int offset = 10; assert(offset == "java.lang.".length());
51.222 + if (xn.length() < offset+3) return 0;
51.223 + return (3*xn.charAt(offset+1) + xn.charAt(offset+2)) % 16;
51.224 + }
51.225 + private static int hashChar(char x) {
51.226 + return (x + (x >> 1)) % 16;
51.227 + }
51.228 + static {
51.229 + for (Wrapper w : values()) {
51.230 + int pi = hashPrim(w.primitiveType);
51.231 + int wi = hashWrap(w.wrapperType);
51.232 + int ci = hashChar(w.basicTypeChar);
51.233 + assert(FROM_PRIM[pi] == null);
51.234 + assert(FROM_WRAP[wi] == null);
51.235 + assert(FROM_CHAR[ci] == null);
51.236 + FROM_PRIM[pi] = w;
51.237 + FROM_WRAP[wi] = w;
51.238 + FROM_CHAR[ci] = w;
51.239 + }
51.240 + //assert(jdk.sun.dyn.util.WrapperTest.test(false));
51.241 + }
51.242 +
51.243 + /** What is the primitive type wrapped by this wrapper? */
51.244 + public Class<?> primitiveType() { return primitiveType; }
51.245 +
51.246 + /** What is the wrapper type for this wrapper? */
51.247 + public Class<?> wrapperType() { return wrapperType; }
51.248 +
51.249 + /** What is the wrapper type for this wrapper?
51.250 + * The example type must be the wrapper type,
51.251 + * or the corresponding primitive type.
51.252 + * The resulting class type has the same type parameter.
51.253 + */
51.254 + public <T> Class<T> wrapperType(Class<T> exampleType) {
51.255 + if (exampleType == wrapperType) {
51.256 + return exampleType;
51.257 + } else if (exampleType == primitiveType ||
51.258 + wrapperType == Object.class ||
51.259 + exampleType.isInterface()) {
51.260 + return forceType(wrapperType, exampleType);
51.261 + }
51.262 + throw new ClassCastException(exampleType + " not <:" + wrapperType);
51.263 + }
51.264 +
51.265 + /** If {@code type} is a primitive type, return the corresponding
51.266 + * wrapper type, else return {@code type} unchanged.
51.267 + */
51.268 + public static <T> Class<T> asWrapperType(Class<T> type) {
51.269 + if (type.isPrimitive()) {
51.270 + return forPrimitiveType(type).wrapperType(type);
51.271 + }
51.272 + return type;
51.273 + }
51.274 +
51.275 + /** If {@code type} is a wrapper type, return the corresponding
51.276 + * primitive type, else return {@code type} unchanged.
51.277 + */
51.278 + public static <T> Class<T> asPrimitiveType(Class<T> type) {
51.279 + Wrapper w = findWrapperType(type);
51.280 + if (w != null) {
51.281 + return forceType(w.primitiveType(), type);
51.282 + }
51.283 + return type;
51.284 + }
51.285 +
51.286 + /** Query: Is the given type a wrapper, such as {@code Integer} or {@code Void}? */
51.287 + public static boolean isWrapperType(Class<?> type) {
51.288 + return findWrapperType(type) != null;
51.289 + }
51.290 +
51.291 + /** Query: Is the given type a primitive, such as {@code int} or {@code void}? */
51.292 + public static boolean isPrimitiveType(Class<?> type) {
51.293 + return type.isPrimitive();
51.294 + }
51.295 +
51.296 + /** What is the bytecode signature character for this wrapper's
51.297 + * primitive type?
51.298 + */
51.299 + public char basicTypeChar() { return basicTypeChar; }
51.300 +
51.301 + /** What is the simple name of the wrapper type?
51.302 + */
51.303 + public String simpleName() { return simpleName; }
51.304 +
51.305 +// /** Wrap a value in the given type, which may be either a primitive or wrapper type.
51.306 +// * Performs standard primitive conversions, including truncation and float conversions.
51.307 +// */
51.308 +// public static <T> T wrap(Object x, Class<T> type) {
51.309 +// return Wrapper.valueOf(type).cast(x, type);
51.310 +// }
51.311 +
51.312 + /** Cast a wrapped value to the given type, which may be either a primitive or wrapper type.
51.313 + * Performs standard primitive conversions, including truncation and float conversions.
51.314 + * The given type must be compatible with this wrapper. That is, it must either
51.315 + * be the wrapper type (or a subtype, in the case of {@code OBJECT} or else
51.316 + * it must be the wrapper's primitive type.
51.317 + * @throws ClassCastException if the given type is not compatible with this wrapper
51.318 + */
51.319 + public <T> T cast(Object x, Class<T> type) {
51.320 + Class<T> wtype = wrapperType(type);
51.321 + if (wtype.isInstance(x))
51.322 + return wtype.cast(x);
51.323 + return wtype.cast(wrap(x));
51.324 + }
51.325 +
51.326 + /** Cast a reference type to another reference type.
51.327 + * If the target type is an interface, perform no runtime check.
51.328 + * (This loophole is safe, and is allowed by the JVM verifier.)
51.329 + * If the target type is a primitive, change it to a wrapper.
51.330 + */
51.331 + static <T> Class<T> forceType(Class<?> type, Class<T> exampleType) {
51.332 + assert(type == exampleType ||
51.333 + type == asWrapperType(exampleType) ||
51.334 + type == Object.class && exampleType.isInterface());
51.335 + Class<T> result = (Class<T>) type; // unchecked warning is expected here
51.336 + return result;
51.337 + }
51.338 +
51.339 + /** Wrap a value in this wrapper's type.
51.340 + * Performs standard primitive conversions, including truncation and float conversions.
51.341 + * Performs returns the unchanged reference for {@code OBJECT}.
51.342 + * Returns null for {@code VOID}.
51.343 + * Returns a zero value for a null input.
51.344 + * @throws ClassCastException if this wrapper is numeric and the operand
51.345 + * is not a number, character, boolean, or null
51.346 + */
51.347 + public Object wrap(Object x) {
51.348 + // do non-numeric wrappers first
51.349 + switch (basicTypeChar) {
51.350 + case 'L': return x;
51.351 + case 'V': return null;
51.352 + }
51.353 + Number xn = numberValue(x);
51.354 + switch (basicTypeChar) {
51.355 + case 'I': return Integer.valueOf(xn.intValue());
51.356 + case 'J': return Long.valueOf(xn.longValue());
51.357 + case 'F': return Float.valueOf(xn.floatValue());
51.358 + case 'D': return Double.valueOf(xn.doubleValue());
51.359 + case 'S': return Short.valueOf((short) xn.intValue());
51.360 + case 'B': return Byte.valueOf((byte) xn.intValue());
51.361 + case 'C': return Character.valueOf((char) xn.intValue());
51.362 + case 'Z': return Boolean.valueOf(boolValue(xn.longValue()));
51.363 + }
51.364 + throw new InternalError("bad wrapper");
51.365 + }
51.366 +
51.367 + /** Wrap a value (an int or smaller value) in this wrapper's type.
51.368 + * Performs standard primitive conversions, including truncation and float conversions.
51.369 + * Produces an {@code Integer} for {@code OBJECT}, although the exact type
51.370 + * of the operand is not known.
51.371 + * Returns null for {@code VOID}.
51.372 + */
51.373 + public Object wrap(int x) {
51.374 + if (basicTypeChar == 'L') return (Integer)x;
51.375 + switch (basicTypeChar) {
51.376 + case 'L': throw newIllegalArgumentException("cannot wrap to object type");
51.377 + case 'V': return null;
51.378 + case 'I': return Integer.valueOf((int)x);
51.379 + case 'J': return Long.valueOf(x);
51.380 + case 'F': return Float.valueOf(x);
51.381 + case 'D': return Double.valueOf(x);
51.382 + case 'S': return Short.valueOf((short) x);
51.383 + case 'B': return Byte.valueOf((byte) x);
51.384 + case 'C': return Character.valueOf((char) x);
51.385 + case 'Z': return Boolean.valueOf(boolValue(x));
51.386 + }
51.387 + throw new InternalError("bad wrapper");
51.388 + }
51.389 +
51.390 + /** Wrap a value (a long or smaller value) in this wrapper's type.
51.391 + * Does not perform floating point conversion.
51.392 + * Produces a {@code Long} for {@code OBJECT}, although the exact type
51.393 + * of the operand is not known.
51.394 + * Returns null for {@code VOID}.
51.395 + */
51.396 + public Object wrapRaw(long x) {
51.397 + switch (basicTypeChar) {
51.398 + case 'F': return Float.valueOf(Float.intBitsToFloat((int)x));
51.399 + case 'D': return Double.valueOf(Double.longBitsToDouble(x));
51.400 + case 'L': // same as 'J':
51.401 + case 'J': return (Long) x;
51.402 + }
51.403 + // Other wrapping operations are just the same, given that the
51.404 + // operand is already promoted to an int.
51.405 + return wrap((int)x);
51.406 + }
51.407 +
51.408 + /** Produce bitwise value which encodes the given wrapped value.
51.409 + * Does not perform floating point conversion.
51.410 + * Returns zero for {@code VOID}.
51.411 + */
51.412 + public long unwrapRaw(Object x) {
51.413 + switch (basicTypeChar) {
51.414 + case 'F': return Float.floatToRawIntBits((Float) x);
51.415 + case 'D': return Double.doubleToRawLongBits((Double) x);
51.416 +
51.417 + case 'L': throw newIllegalArgumentException("cannot unwrap from sobject type");
51.418 + case 'V': return 0;
51.419 + case 'I': return (int)(Integer) x;
51.420 + case 'J': return (long)(Long) x;
51.421 + case 'S': return (short)(Short) x;
51.422 + case 'B': return (byte)(Byte) x;
51.423 + case 'C': return (char)(Character) x;
51.424 + case 'Z': return (boolean)(Boolean) x ? 1 : 0;
51.425 + }
51.426 + throw new InternalError("bad wrapper");
51.427 + }
51.428 +
51.429 + /** Report what primitive type holds this guy's raw value. */
51.430 + public Class<?> rawPrimitiveType() {
51.431 + return rawPrimitive().primitiveType();
51.432 + }
51.433 +
51.434 + /** Report, as a wrapper, what primitive type holds this guy's raw value.
51.435 + * Returns self for INT, LONG, OBJECT; returns LONG for DOUBLE,
51.436 + * else returns INT.
51.437 + */
51.438 + public Wrapper rawPrimitive() {
51.439 + switch (basicTypeChar) {
51.440 + case 'S': case 'B':
51.441 + case 'C': case 'Z':
51.442 + case 'V':
51.443 + case 'F':
51.444 + return INT;
51.445 + case 'D':
51.446 + return LONG;
51.447 + }
51.448 + return this;
51.449 + }
51.450 +
51.451 + private static Number numberValue(Object x) {
51.452 + if (x instanceof Number) return (Number)x;
51.453 + if (x instanceof Character) return (int)(Character)x;
51.454 + if (x instanceof Boolean) return (Boolean)x ? 1 : 0;
51.455 + // Remaining allowed case of void: Must be a null reference.
51.456 + return (Number)x;
51.457 + }
51.458 +
51.459 + private static boolean boolValue(long bits) {
51.460 + //bits &= 1; // simple 31-bit zero extension
51.461 + return (bits != 0);
51.462 + }
51.463 +
51.464 + private static RuntimeException newIllegalArgumentException(String message, Object x) {
51.465 + return newIllegalArgumentException(message + x);
51.466 + }
51.467 + private static RuntimeException newIllegalArgumentException(String message) {
51.468 + return new IllegalArgumentException(message);
51.469 + }
51.470 +}
52.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
52.2 +++ b/src/share/classes/sun/dyn/util/package-info.java Tue May 05 23:12:47 2009 -0700
52.3 @@ -0,0 +1,31 @@
52.4 +/*
52.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
52.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
52.7 + *
52.8 + * This code is free software; you can redistribute it and/or modify it
52.9 + * under the terms of the GNU General Public License version 2 only, as
52.10 + * published by the Free Software Foundation. Sun designates this
52.11 + * particular file as subject to the "Classpath" exception as provided
52.12 + * by Sun in the LICENSE file that accompanied this code.
52.13 + *
52.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
52.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
52.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
52.17 + * version 2 for more details (a copy is included in the LICENSE file that
52.18 + * accompanied this code).
52.19 + *
52.20 + * You should have received a copy of the GNU General Public License version
52.21 + * 2 along with this work; if not, write to the Free Software Foundation,
52.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
52.23 + *
52.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
52.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
52.26 + * have any questions.
52.27 + */
52.28 +
52.29 +/**
52.30 + * Extra support for using JSR 292 RI, package java.dyn.
52.31 + * @author jrose
52.32 + */
52.33 +
52.34 +package sun.dyn.util;
53.1 --- a/src/share/classes/sun/misc/JavaLangAccess.java Tue May 05 09:09:24 2009 -0700
53.2 +++ b/src/share/classes/sun/misc/JavaLangAccess.java Tue May 05 23:12:47 2009 -0700
53.3 @@ -55,6 +55,22 @@
53.4 /** Set thread's blocker field. */
53.5 void blockedOn(Thread t, Interruptible b);
53.6
53.7 - /** register shutdown hook */
53.8 - void registerShutdownHook(int slot, Runnable r);
53.9 + /**
53.10 + * Registers a shutdown hook.
53.11 + *
53.12 + * It is expected that this method with registerShutdownInProgress=true
53.13 + * is only used to register DeleteOnExitHook since the first file
53.14 + * may be added to the delete on exit list by the application shutdown
53.15 + * hooks.
53.16 + *
53.17 + * @params slot the slot in the shutdown hook array, whose element
53.18 + * will be invoked in order during shutdown
53.19 + * @params registerShutdownInProgress true to allow the hook
53.20 + * to be registered even if the shutdown is in progress.
53.21 + * @params hook the hook to be registered
53.22 + *
53.23 + * @throw IllegalStateException if shutdown is in progress and
53.24 + * the slot is not valid to register.
53.25 + */
53.26 + void registerShutdownHook(int slot, boolean registerShutdownInProgress, Runnable hook);
53.27 }
54.1 --- a/src/share/classes/sun/misc/Unsafe.java Tue May 05 09:09:24 2009 -0700
54.2 +++ b/src/share/classes/sun/misc/Unsafe.java Tue May 05 23:12:47 2009 -0700
54.3 @@ -1,5 +1,5 @@
54.4 /*
54.5 - * Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved.
54.6 + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved.
54.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
54.8 *
54.9 * This code is free software; you can redistribute it and/or modify it
54.10 @@ -811,6 +811,25 @@
54.11
54.12 public native Class defineClass(String name, byte[] b, int off, int len);
54.13
54.14 + /**
54.15 + * Define a class but do not make it known to the class loader or system dictionary.
54.16 + * <p>
54.17 + * For each CP entry, the corresponding CP patch must either be null or have
54.18 + * the a format that matches its tag:
54.19 + * <ul>
54.20 + * <li>Integer, Long, Float, Double: the corresponding wrapper object type from java.lang
54.21 + * <li>Utf8: a string (must have suitable syntax if used as signature or name)
54.22 + * <li>Class: any java.lang.Class object
54.23 + * <li>String: any object (not just a java.lang.String)
54.24 + * <li>InterfaceMethodRef: (NYI) a method handle to invoke on that call site's arguments
54.25 + * </ul>
54.26 + * @params hostClass context for linkage, access control, protection domain, and class loader
54.27 + * @params data bytes of a class file
54.28 + * @params cpPatches where non-null entries exist, they replace corresponding CP entries in data
54.29 + */
54.30 + public native Class defineAnonymousClass(Class hostClass, byte[] data, Object[] cpPatches);
54.31 +
54.32 +
54.33 /** Allocate an instance but do not run any constructor.
54.34 Initializes the class if it has not yet been. */
54.35 public native Object allocateInstance(Class cls)
55.1 --- a/src/share/javavm/export/classfile_constants.h Tue May 05 09:09:24 2009 -0700
55.2 +++ b/src/share/javavm/export/classfile_constants.h Tue May 05 23:12:47 2009 -0700
55.3 @@ -1,5 +1,5 @@
55.4 /*
55.5 - * Copyright 2004-2005 Sun Microsystems, Inc. All Rights Reserved.
55.6 + * Copyright 2004-2009 Sun Microsystems, Inc. All Rights Reserved.
55.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
55.8 *
55.9 * This code is free software; you can redistribute it and/or modify it
55.10 @@ -306,7 +306,7 @@
55.11 JVM_OPC_invokespecial = 183,
55.12 JVM_OPC_invokestatic = 184,
55.13 JVM_OPC_invokeinterface = 185,
55.14 - JVM_OPC_xxxunusedxxx = 186,
55.15 + JVM_OPC_invokedynamic = 186,
55.16 JVM_OPC_new = 187,
55.17 JVM_OPC_newarray = 188,
55.18 JVM_OPC_anewarray = 189,
55.19 @@ -515,7 +515,7 @@
55.20 3, /* invokespecial */ \
55.21 3, /* invokestatic */ \
55.22 5, /* invokeinterface */ \
55.23 - 0, /* xxxunusedxxx */ \
55.24 + 5, /* invokedynamic */ \
55.25 3, /* new */ \
55.26 2, /* newarray */ \
55.27 3, /* anewarray */ \
56.1 --- a/src/share/native/common/check_code.c Tue May 05 09:09:24 2009 -0700
56.2 +++ b/src/share/native/common/check_code.c Tue May 05 23:12:47 2009 -0700
56.3 @@ -1,5 +1,5 @@
56.4 /*
56.5 - * Copyright 1994-2008 Sun Microsystems, Inc. All Rights Reserved.
56.6 + * Copyright 1994-2009 Sun Microsystems, Inc. All Rights Reserved.
56.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
56.8 *
56.9 * This code is free software; you can redistribute it and/or modify it
56.10 @@ -1223,16 +1223,20 @@
56.11 case JVM_OPC_invokevirtual:
56.12 case JVM_OPC_invokespecial:
56.13 case JVM_OPC_invokestatic:
56.14 + case JVM_OPC_invokedynamic:
56.15 case JVM_OPC_invokeinterface: {
56.16 /* Make sure the constant pool item is the right type. */
56.17 int key = (code[offset + 1] << 8) + code[offset + 2];
56.18 const char *methodname;
56.19 jclass cb = context->class;
56.20 fullinfo_type clazz_info;
56.21 - int is_constructor, is_internal;
56.22 + int is_constructor, is_internal, is_invokedynamic;
56.23 int kind = (opcode == JVM_OPC_invokeinterface
56.24 ? 1 << JVM_CONSTANT_InterfaceMethodref
56.25 + : opcode == JVM_OPC_invokedynamic
56.26 + ? 1 << JVM_CONSTANT_NameAndType
56.27 : 1 << JVM_CONSTANT_Methodref);
56.28 + is_invokedynamic = opcode == JVM_OPC_invokedynamic;
56.29 /* Make sure the constant pool item is the right type. */
56.30 verify_constant_pool_type(context, key, kind);
56.31 methodname = JVM_GetCPMethodNameUTF(env, cb, key);
56.32 @@ -1241,8 +1245,11 @@
56.33 is_internal = methodname[0] == '<';
56.34 pop_and_free(context);
56.35
56.36 - clazz_info = cp_index_to_class_fullinfo(context, key,
56.37 - JVM_CONSTANT_Methodref);
56.38 + if (is_invokedynamic)
56.39 + clazz_info = context->object_info; // anything will do
56.40 + else
56.41 + clazz_info = cp_index_to_class_fullinfo(context, key,
56.42 + JVM_CONSTANT_Methodref);
56.43 this_idata->operand.i = key;
56.44 this_idata->operand2.fi = clazz_info;
56.45 if (is_constructor) {
56.46 @@ -1304,6 +1311,11 @@
56.47 "Fourth operand byte of invokeinterface must be zero");
56.48 }
56.49 pop_and_free(context);
56.50 + } else if (opcode == JVM_OPC_invokedynamic) {
56.51 + if (code[offset + 3] != 0 || code[offset + 4] != 0) {
56.52 + CCerror(context,
56.53 + "Third and fourth operand bytes of invokedynamic must be zero");
56.54 + }
56.55 } else if (opcode == JVM_OPC_invokevirtual
56.56 || opcode == JVM_OPC_invokespecial)
56.57 set_protected(context, inumber, key, opcode);
56.58 @@ -1990,6 +2002,7 @@
56.59
56.60 case JVM_OPC_invokevirtual: case JVM_OPC_invokespecial:
56.61 case JVM_OPC_invokeinit: /* invokespecial call to <init> */
56.62 + case JVM_OPC_invokedynamic:
56.63 case JVM_OPC_invokestatic: case JVM_OPC_invokeinterface: {
56.64 /* The top stuff on the stack depends on the method signature */
56.65 int operand = this_idata->operand.i;
56.66 @@ -2005,7 +2018,8 @@
56.67 print_formatted_methodname(context, operand);
56.68 }
56.69 #endif
56.70 - if (opcode != JVM_OPC_invokestatic)
56.71 + if (opcode != JVM_OPC_invokestatic &&
56.72 + opcode != JVM_OPC_invokedynamic)
56.73 /* First, push the object */
56.74 *ip++ = (opcode == JVM_OPC_invokeinit ? '@' : 'A');
56.75 for (p = signature + 1; *p != JVM_SIGNATURE_ENDFUNC; ) {
56.76 @@ -2290,6 +2304,7 @@
56.77
56.78 case JVM_OPC_invokevirtual: case JVM_OPC_invokespecial:
56.79 case JVM_OPC_invokeinit:
56.80 + case JVM_OPC_invokedynamic:
56.81 case JVM_OPC_invokeinterface: case JVM_OPC_invokestatic: {
56.82 int operand = this_idata->operand.i;
56.83 const char *signature =
56.84 @@ -2299,7 +2314,8 @@
56.85 int item;
56.86 const char *p;
56.87 check_and_push(context, signature, VM_STRING_UTF);
56.88 - if (opcode == JVM_OPC_invokestatic) {
56.89 + if (opcode == JVM_OPC_invokestatic ||
56.90 + opcode == JVM_OPC_invokedynamic) {
56.91 item = 0;
56.92 } else if (opcode == JVM_OPC_invokeinit) {
56.93 fullinfo_type init_type = this_idata->operand2.fi;
56.94 @@ -2680,6 +2696,7 @@
56.95
56.96 case JVM_OPC_invokevirtual: case JVM_OPC_invokespecial:
56.97 case JVM_OPC_invokeinit:
56.98 + case JVM_OPC_invokedynamic:
56.99 case JVM_OPC_invokestatic: case JVM_OPC_invokeinterface: {
56.100 /* Look to signature to determine correct result. */
56.101 int operand = this_idata->operand.i;
57.1 --- a/src/share/native/common/opcodes.in_out Tue May 05 09:09:24 2009 -0700
57.2 +++ b/src/share/native/common/opcodes.in_out Tue May 05 23:12:47 2009 -0700
57.3 @@ -1,5 +1,5 @@
57.4 /*
57.5 - * Copyright 1998 Sun Microsystems, Inc. All Rights Reserved.
57.6 + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
57.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
57.8 *
57.9 * This code is free software; you can redistribute it and/or modify it
57.10 @@ -210,7 +210,7 @@
57.11 {"?", "?"}, /* invokespecial */
57.12 {"?", "?"}, /* invokestatic */
57.13 {"?", "?"}, /* invokeinterface */
57.14 - {"?", "?"}, /* xxxunusedxxx */
57.15 + {"?", "?"}, /* invokedynamic */
57.16 {"", "A"}, /* new */
57.17 {"I", "A"}, /* newarray */
57.18 {"I", "A"}, /* anewarray */
58.1 --- a/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java Tue May 05 09:09:24 2009 -0700
58.2 +++ b/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java Tue May 05 23:12:47 2009 -0700
58.3 @@ -475,49 +475,40 @@
58.4 // get an OVERLAPPED structure (from the cache or allocate)
58.5 overlapped = ioCache.add(result);
58.6
58.7 - // synchronize on result to allow this thread handle the case
58.8 - // where the read completes immediately.
58.9 - synchronized (result) {
58.10 - int n = read0(handle, numBufs, readBufferArray, overlapped);
58.11 - if (n == IOStatus.UNAVAILABLE) {
58.12 - // I/O is pending
58.13 - pending = true;
58.14 - return;
58.15 + // initiate read
58.16 + int n = read0(handle, numBufs, readBufferArray, overlapped);
58.17 + if (n == IOStatus.UNAVAILABLE) {
58.18 + // I/O is pending
58.19 + pending = true;
58.20 + return;
58.21 + }
58.22 + if (n == IOStatus.EOF) {
58.23 + // input shutdown
58.24 + enableReading();
58.25 + if (scatteringRead) {
58.26 + result.setResult((V)Long.valueOf(-1L));
58.27 + } else {
58.28 + result.setResult((V)Integer.valueOf(-1));
58.29 }
58.30 - // read completed immediately:
58.31 - // 1. update buffer position
58.32 - // 2. reset read flag
58.33 - // 3. release waiters
58.34 - if (n == 0) {
58.35 - n = -1;
58.36 - } else {
58.37 - updateBuffers(n);
58.38 - }
58.39 - enableReading();
58.40 -
58.41 - if (scatteringRead) {
58.42 - result.setResult((V)Long.valueOf(n));
58.43 - } else {
58.44 - result.setResult((V)Integer.valueOf(n));
58.45 - }
58.46 + } else {
58.47 + throw new InternalError("Read completed immediately");
58.48 }
58.49 } catch (Throwable x) {
58.50 - // failed to initiate read:
58.51 - // 1. reset read flag
58.52 - // 2. free resources
58.53 - // 3. release waiters
58.54 + // failed to initiate read
58.55 + // reset read flag before releasing waiters
58.56 enableReading();
58.57 - if (overlapped != 0L)
58.58 - ioCache.remove(overlapped);
58.59 if (x instanceof ClosedChannelException)
58.60 x = new AsynchronousCloseException();
58.61 if (!(x instanceof IOException))
58.62 x = new IOException(x);
58.63 result.setFailure(x);
58.64 } finally {
58.65 - if (prepared && !pending) {
58.66 - // return direct buffer(s) to cache if substituted
58.67 - releaseBuffers();
58.68 + // release resources if I/O not pending
58.69 + if (!pending) {
58.70 + if (overlapped != 0L)
58.71 + ioCache.remove(overlapped);
58.72 + if (prepared)
58.73 + releaseBuffers();
58.74 }
58.75 end();
58.76 }
58.77 @@ -721,7 +712,6 @@
58.78 @Override
58.79 @SuppressWarnings("unchecked")
58.80 public void run() {
58.81 - int n = -1;
58.82 long overlapped = 0L;
58.83 boolean prepared = false;
58.84 boolean pending = false;
58.85 @@ -736,56 +726,34 @@
58.86
58.87 // get an OVERLAPPED structure (from the cache or allocate)
58.88 overlapped = ioCache.add(result);
58.89 -
58.90 - // synchronize on result to allow this thread handle the case
58.91 - // where the read completes immediately.
58.92 - synchronized (result) {
58.93 - n = write0(handle, numBufs, writeBufferArray, overlapped);
58.94 - if (n == IOStatus.UNAVAILABLE) {
58.95 - // I/O is pending
58.96 - pending = true;
58.97 - return;
58.98 - }
58.99 -
58.100 - enableWriting();
58.101 -
58.102 - if (n == IOStatus.EOF) {
58.103 - // special case for shutdown output
58.104 - shutdown = true;
58.105 - throw new ClosedChannelException();
58.106 - }
58.107 -
58.108 - // write completed immediately:
58.109 - // 1. enable writing
58.110 - // 2. update buffer position
58.111 - // 3. release waiters
58.112 - updateBuffers(n);
58.113 -
58.114 - // result is a Long or Integer
58.115 - if (gatheringWrite) {
58.116 - result.setResult((V)Long.valueOf(n));
58.117 - } else {
58.118 - result.setResult((V)Integer.valueOf(n));
58.119 - }
58.120 + int n = write0(handle, numBufs, writeBufferArray, overlapped);
58.121 + if (n == IOStatus.UNAVAILABLE) {
58.122 + // I/O is pending
58.123 + pending = true;
58.124 + return;
58.125 }
58.126 + if (n == IOStatus.EOF) {
58.127 + // special case for shutdown output
58.128 + shutdown = true;
58.129 + throw new ClosedChannelException();
58.130 + }
58.131 + // write completed immediately
58.132 + throw new InternalError("Write completed immediately");
58.133 } catch (Throwable x) {
58.134 + // write failed. Enable writing before releasing waiters.
58.135 enableWriting();
58.136 -
58.137 - // failed to initiate read:
58.138 if (!shutdown && (x instanceof ClosedChannelException))
58.139 x = new AsynchronousCloseException();
58.140 if (!(x instanceof IOException))
58.141 x = new IOException(x);
58.142 result.setFailure(x);
58.143 -
58.144 - // release resources
58.145 - if (overlapped != 0L)
58.146 - ioCache.remove(overlapped);
58.147 -
58.148 } finally {
58.149 - if (prepared && !pending) {
58.150 - // return direct buffer(s) to cache if substituted
58.151 - releaseBuffers();
58.152 + // release resources if I/O not pending
58.153 + if (!pending) {
58.154 + if (overlapped != 0L)
58.155 + ioCache.remove(overlapped);
58.156 + if (prepared)
58.157 + releaseBuffers();
58.158 }
58.159 end();
58.160 }
59.1 --- a/src/windows/native/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.c Tue May 05 09:09:24 2009 -0700
59.2 +++ b/src/windows/native/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.c Tue May 05 23:12:47 2009 -0700
59.3 @@ -157,14 +157,13 @@
59.4 WSABUF* lpWsaBuf = (WSABUF*) jlong_to_ptr(address);
59.5 OVERLAPPED* lpOverlapped = (OVERLAPPED*) jlong_to_ptr(ov);
59.6 BOOL res;
59.7 - DWORD nread = 0;
59.8 DWORD flags = 0;
59.9
59.10 ZeroMemory((PVOID)lpOverlapped, sizeof(OVERLAPPED));
59.11 res = WSARecv(s,
59.12 lpWsaBuf,
59.13 (DWORD)count,
59.14 - &nread,
59.15 + NULL,
59.16 &flags,
59.17 lpOverlapped,
59.18 NULL);
59.19 @@ -175,17 +174,12 @@
59.20 return IOS_UNAVAILABLE;
59.21 }
59.22 if (error == WSAESHUTDOWN) {
59.23 - return 0; // input shutdown
59.24 + return IOS_EOF; // input shutdown
59.25 }
59.26 JNU_ThrowIOExceptionWithLastError(env, "WSARecv failed");
59.27 return IOS_THROWN;
59.28 }
59.29 - if (nread == 0) {
59.30 - // Handle graceful close or bytes not yet available cases
59.31 - // via completion port notification.
59.32 - return IOS_UNAVAILABLE;
59.33 - }
59.34 - return (jint)nread;
59.35 + return IOS_UNAVAILABLE;
59.36 }
59.37
59.38 JNIEXPORT jint JNICALL
59.39 @@ -196,13 +190,12 @@
59.40 WSABUF* lpWsaBuf = (WSABUF*) jlong_to_ptr(address);
59.41 OVERLAPPED* lpOverlapped = (OVERLAPPED*) jlong_to_ptr(ov);
59.42 BOOL res;
59.43 - DWORD nwritten;
59.44
59.45 ZeroMemory((PVOID)lpOverlapped, sizeof(OVERLAPPED));
59.46 res = WSASend(s,
59.47 lpWsaBuf,
59.48 (DWORD)count,
59.49 - &nwritten,
59.50 + NULL,
59.51 0,
59.52 lpOverlapped,
59.53 NULL);
59.54 @@ -218,5 +211,5 @@
59.55 JNU_ThrowIOExceptionWithLastError(env, "WSASend failed");
59.56 return IOS_THROWN;
59.57 }
59.58 - return (jint)nwritten;
59.59 + return IOS_UNAVAILABLE;
59.60 }
60.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
60.2 +++ b/test/java/lang/Runtime/shutdown/ShutdownHooks.java Tue May 05 23:12:47 2009 -0700
60.3 @@ -0,0 +1,69 @@
60.4 +/*
60.5 + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
60.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
60.7 + *
60.8 + * This code is free software; you can redistribute it and/or modify it
60.9 + * under the terms of the GNU General Public License version 2 only, as
60.10 + * published by the Free Software Foundation.
60.11 + *
60.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
60.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
60.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
60.15 + * version 2 for more details (a copy is included in the LICENSE file that
60.16 + * accompanied this code).
60.17 + *
60.18 + * You should have received a copy of the GNU General Public License version
60.19 + * 2 along with this work; if not, write to the Free Software Foundation,
60.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
60.21 + *
60.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
60.23 + * CA 95054 USA or visit www.sun.com if you need additional information or
60.24 + * have any questions.
60.25 + */
60.26 +
60.27 +/*
60.28 + * @bug 6829503
60.29 + * @summary 1) Test Console and DeleteOnExitHook can be initialized
60.30 + * while shutdown is in progress
60.31 + * 2) Test if files that are added by the application shutdown
60.32 + * hook are deleted on exit during shutdown
60.33 + */
60.34 +import java.io.*;
60.35 +public class ShutdownHooks {
60.36 + private static File file;
60.37 + public static void main(String[] args) throws Exception {
60.38 + if (args.length != 2) {
60.39 + throw new IllegalArgumentException("Usage: ShutdownHooks <dir> <filename>");
60.40 + }
60.41 +
60.42 + // Add a shutdown hook
60.43 + Runtime.getRuntime().addShutdownHook(new Cleaner());
60.44 +
60.45 + File dir = new File(args[0]);
60.46 + file = new File(dir, args[1]);
60.47 + // write to file
60.48 + System.out.println("writing to "+ file);
60.49 + PrintWriter pw = new PrintWriter(file);
60.50 + pw.println("Shutdown begins");
60.51 + pw.close();
60.52 + }
60.53 +
60.54 + public static class Cleaner extends Thread {
60.55 + public void run() {
60.56 + // register the Console's shutdown hook while the application
60.57 + // shutdown hook is running
60.58 + Console cons = System.console();
60.59 + // register the DeleteOnExitHook while the application
60.60 + // shutdown hook is running
60.61 + file.deleteOnExit();
60.62 + try {
60.63 + PrintWriter pw = new PrintWriter(file);
60.64 + pw.println("file is being deleted");
60.65 + pw.close();
60.66 + } catch (FileNotFoundException e) {
60.67 + throw new RuntimeException(e);
60.68 + }
60.69 + }
60.70 + }
60.71 +
60.72 +}
61.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
61.2 +++ b/test/java/lang/Runtime/shutdown/ShutdownHooks.sh Tue May 05 23:12:47 2009 -0700
61.3 @@ -0,0 +1,57 @@
61.4 +#!/bin/sh
61.5 +
61.6 +#
61.7 +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
61.8 +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
61.9 +#
61.10 +# This code is free software; you can redistribute it and/or modify it
61.11 +# under the terms of the GNU General Public License version 2 only, as
61.12 +# published by the Free Software Foundation.
61.13 +#
61.14 +# This code is distributed in the hope that it will be useful, but WITHOUT
61.15 +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
61.16 +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
61.17 +# version 2 for more details (a copy is included in the LICENSE file that
61.18 +# accompanied this code).
61.19 +#
61.20 +# You should have received a copy of the GNU General Public License version
61.21 +# 2 along with this work; if not, write to the Free Software Foundation,
61.22 +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
61.23 +#
61.24 +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
61.25 +# CA 95054 USA or visit www.sun.com if you need additional information or
61.26 +# have any questions.
61.27 +#
61.28 +
61.29 +
61.30 +# @test
61.31 +# @bug 6829503
61.32 +# @summary 1) Test Console and DeleteOnExitHook can be initialized
61.33 +# while shutdown is in progress
61.34 +# 2) Test if files that are added by the application shutdown
61.35 +# hook are deleted on exit during shutdown
61.36 +#
61.37 +# @build ShutdownHooks
61.38 +# @run shell ShutdownHooks.sh
61.39 +
61.40 +if [ "${TESTJAVA}" = "" ]
61.41 +then
61.42 + echo "TESTJAVA not set. Test cannot execute. Failed."
61.43 + exit 1
61.44 +fi
61.45 +
61.46 +FILENAME=fileToBeDeleted
61.47 +rm -f ${TESTCLASSES}/${FILENAME}
61.48 +
61.49 +# create the file to be deleted on exit
61.50 +echo "testing shutdown" > ${TESTCLASSES}/${FILENAME}
61.51 +
61.52 +${TESTJAVA}/bin/java ${TESTVMOPTS} -classpath ${TESTCLASSES} ShutdownHooks ${TESTCLASSES} $FILENAME
61.53 +if [ $? != 0 ] ; then
61.54 + echo "Test Failed"; exit 1
61.55 +fi
61.56 +
61.57 +if [ -f ${TESTCLASSES}/${FILENAME} ]; then
61.58 + echo "Test Failed: ${TESTCLASSES}/${FILENAME} not deleted"; exit 2
61.59 +fi
61.60 +echo "ShutdownHooks test passed.";
62.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
62.2 +++ b/test/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java Tue May 05 23:12:47 2009 -0700
62.3 @@ -0,0 +1,183 @@
62.4 +/*
62.5 + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
62.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
62.7 + *
62.8 + * This code is free software; you can redistribute it and/or modify it
62.9 + * under the terms of the GNU General Public License version 2 only, as
62.10 + * published by the Free Software Foundation.
62.11 + *
62.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
62.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
62.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
62.15 + * version 2 for more details (a copy is included in the LICENSE file that
62.16 + * accompanied this code).
62.17 + *
62.18 + * You should have received a copy of the GNU General Public License version
62.19 + * 2 along with this work; if not, write to the Free Software Foundation,
62.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
62.21 + *
62.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
62.23 + * CA 95054 USA or visit www.sun.com if you need additional information or
62.24 + * have any questions.
62.25 + */
62.26 +
62.27 +/* @test
62.28 + * @bug 6834246
62.29 + * @summary Stress test connections through the loopback interface
62.30 + */
62.31 +
62.32 +import java.nio.ByteBuffer;
62.33 +import java.net.*;
62.34 +import java.nio.channels.*;
62.35 +import java.util.Random;
62.36 +import java.io.IOException;
62.37 +
62.38 +public class StressLoopback {
62.39 + static final Random rand = new Random();
62.40 +
62.41 + public static void main(String[] args) throws Exception {
62.42 + // setup listener
62.43 + AsynchronousServerSocketChannel listener =
62.44 + AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(0));
62.45 + int port =((InetSocketAddress)(listener.getLocalAddress())).getPort();
62.46 + InetAddress lh = InetAddress.getLocalHost();
62.47 + SocketAddress remote = new InetSocketAddress(lh, port);
62.48 +
62.49 + // create sources and sinks
62.50 + int count = 2 + rand.nextInt(9);
62.51 + Source[] source = new Source[count];
62.52 + Sink[] sink = new Sink[count];
62.53 + for (int i=0; i<count; i++) {
62.54 + AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
62.55 + ch.connect(remote).get();
62.56 + source[i] = new Source(ch);
62.57 + sink[i] = new Sink(listener.accept().get());
62.58 + }
62.59 +
62.60 + // start the sinks and sources
62.61 + for (int i=0; i<count; i++) {
62.62 + sink[i].start();
62.63 + source[i].start();
62.64 + }
62.65 +
62.66 + // let the test run for a while
62.67 + Thread.sleep(20*1000);
62.68 +
62.69 + // wait until everyone is done
62.70 + boolean failed = false;
62.71 + long total = 0L;
62.72 + for (int i=0; i<count; i++) {
62.73 + long nwrote = source[i].finish();
62.74 + long nread = sink[i].finish();
62.75 + if (nread != nwrote)
62.76 + failed = true;
62.77 + System.out.format("%d -> %d (%s)\n",
62.78 + nwrote, nread, (failed) ? "FAIL" : "PASS");
62.79 + total += nwrote;
62.80 + }
62.81 + if (failed)
62.82 + throw new RuntimeException("Test failed - see log for details");
62.83 + System.out.format("Total sent %d MB\n", total / (1024L * 1024L));
62.84 + }
62.85 +
62.86 + /**
62.87 + * Writes bytes to a channel until "done". When done the channel is closed.
62.88 + */
62.89 + static class Source {
62.90 + private final AsynchronousByteChannel channel;
62.91 + private final ByteBuffer sentBuffer;
62.92 + private volatile long bytesSent;
62.93 + private volatile boolean finished;
62.94 +
62.95 + Source(AsynchronousByteChannel channel) {
62.96 + this.channel = channel;
62.97 + int size = 1024 + rand.nextInt(10000);
62.98 + this.sentBuffer = (rand.nextBoolean()) ?
62.99 + ByteBuffer.allocateDirect(size) : ByteBuffer.allocate(size);
62.100 + }
62.101 +
62.102 + void start() {
62.103 + sentBuffer.position(0);
62.104 + sentBuffer.limit(sentBuffer.capacity());
62.105 + channel.write(sentBuffer, null, new CompletionHandler<Integer,Void> () {
62.106 + public void completed(Integer nwrote, Void att) {
62.107 + bytesSent += nwrote;
62.108 + if (finished) {
62.109 + closeUnchecked(channel);
62.110 + } else {
62.111 + sentBuffer.position(0);
62.112 + sentBuffer.limit(sentBuffer.capacity());
62.113 + channel.write(sentBuffer, null, this);
62.114 + }
62.115 + }
62.116 + public void failed(Throwable exc, Void att) {
62.117 + exc.printStackTrace();
62.118 + closeUnchecked(channel);
62.119 + }
62.120 + public void cancelled(Void att) {
62.121 + }
62.122 + });
62.123 + }
62.124 +
62.125 + long finish() {
62.126 + finished = true;
62.127 + waitUntilClosed(channel);
62.128 + return bytesSent;
62.129 + }
62.130 + }
62.131 +
62.132 + /**
62.133 + * Read bytes from a channel until EOF is received.
62.134 + */
62.135 + static class Sink {
62.136 + private final AsynchronousByteChannel channel;
62.137 + private final ByteBuffer readBuffer;
62.138 + private volatile long bytesRead;
62.139 +
62.140 + Sink(AsynchronousByteChannel channel) {
62.141 + this.channel = channel;
62.142 + int size = 1024 + rand.nextInt(10000);
62.143 + this.readBuffer = (rand.nextBoolean()) ?
62.144 + ByteBuffer.allocateDirect(size) : ByteBuffer.allocate(size);
62.145 + }
62.146 +
62.147 + void start() {
62.148 + channel.read(readBuffer, null, new CompletionHandler<Integer,Void> () {
62.149 + public void completed(Integer nread, Void att) {
62.150 + if (nread < 0) {
62.151 + closeUnchecked(channel);
62.152 + } else {
62.153 + bytesRead += nread;
62.154 + readBuffer.clear();
62.155 + channel.read(readBuffer, null, this);
62.156 + }
62.157 + }
62.158 + public void failed(Throwable exc, Void att) {
62.159 + exc.printStackTrace();
62.160 + closeUnchecked(channel);
62.161 + }
62.162 + public void cancelled(Void att) {
62.163 + }
62.164 + });
62.165 + }
62.166 +
62.167 + long finish() {
62.168 + waitUntilClosed(channel);
62.169 + return bytesRead;
62.170 + }
62.171 + }
62.172 +
62.173 + static void waitUntilClosed(Channel c) {
62.174 + while (c.isOpen()) {
62.175 + try {
62.176 + Thread.sleep(100);
62.177 + } catch (InterruptedException ignore) { }
62.178 + }
62.179 + }
62.180 +
62.181 + static void closeUnchecked(Channel c) {
62.182 + try {
62.183 + c.close();
62.184 + } catch (IOException ignore) { }
62.185 + }
62.186 +}