meth, indy: rebase to bsd-port and latest JVM changes; pull indy changes out of meth
--- a/indy.patch Sat Mar 21 23:59:57 2009 -0700
+++ b/indy.patch Fri Apr 03 02:34:37 2009 -0700
@@ -1,34 +1,822 @@ diff --git a/src/share/classes/java/dyn/
-diff --git a/src/share/classes/java/dyn/CallSite.java b/src/share/classes/java/dyn/CallSite.java
+diff --git a/src/share/classes/impl/java/dyn/CallSiteImpl.java b/src/share/classes/impl/java/dyn/CallSiteImpl.java
new file mode 100644
--- /dev/null
-+++ b/src/share/classes/java/dyn/CallSite.java
-@@ -0,0 +1,116 @@
++++ b/src/share/classes/impl/java/dyn/CallSiteImpl.java
+@@ -0,0 +1,65 @@
+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-+ *
++ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
-+ *
++ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
-+ *
++ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
++ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
++package impl.java.dyn;
++
++import java.dyn.*;
++
++/**
++ * The CallSite privately created by the JVM at every invokedynamic instruction.
++ * @author jrose
++ */
++class CallSiteImpl extends CallSite {
++ // Fields used only by the JVM. Do not use or change.
++ private Object vmmethod;
++
++ // Values supplied by the JVM:
++ final int callerMID, callerBCI;
++
++ private CallSiteImpl(Class<?> caller, String name, MethodType type,
++ int callerMID, int callerBCI) {
++ super(caller, name, type);
++ this.callerMID = callerMID;
++ this.callerBCI = callerBCI;
++ }
++
++ @Override
++ public void setTarget(MethodHandle mh) {
++ checkTarget(mh);
++ if (MethodHandleNatives.JVM_SUPPORT)
++ MethodHandleNatives.linkCallSite(this, (MethodHandle) mh);
++ else
++ super.setTarget(mh);
++ }
++
++ // this is the up-call from the JVM:
++ static CallSiteImpl makeSite(Class<?> caller, String name, MethodType type,
++ int callerMID, int callerBCI) {
++ CallSiteImpl site = new CallSiteImpl(caller, name, type,
++ callerMID, callerBCI);
++ System.out.println("DynCallSite: "+site); // %%% REMOVE
++ return site;
++ }
++}
+diff --git a/src/share/classes/impl/java/dyn/util/BytecodeName.java b/src/share/classes/impl/java/dyn/util/BytecodeName.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/impl/java/dyn/util/BytecodeName.java
+@@ -0,0 +1,711 @@
++/*
++ * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation. Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ */
++
++package impl.java.dyn.util;
++
++/**
++ * Utility routines for dealing with bytecode-level names.
++ * Includes universal mangling rules for the JVM.
++ *
++ * <h3>Avoiding Dangerous Characters </h3>
++ *
++ * <p>
++ * The JVM defines a very small set of characters which are illegal
++ * in name spellings. We will slightly extend and regularize this set
++ * into a group of <cite>dangerous characters</cite>.
++ * These characters will then be replaced, in mangled names, by escape sequences.
++ * In addition, accidental escape sequences must be further escaped.
++ * Finally, a special prefix will be applied if and only if
++ * the mangling would otherwise fail to begin with the escape character.
++ * This happens to cover the corner case of the null string,
++ * and also clearly marks symbols which need demangling.
++ * </p>
++ * <p>
++ * Dangerous characters are the union of all characters forbidden
++ * or otherwise restricted by the JVM specification,
++ * plus their mates, if they are brackets
++ * (<code><big><b>[</b></big></code> and <code><big><b>]</b></big></code>,
++ * <code><big><b><</b></big></code> and <code><big><b>></b></big></code>),
++ * plus, arbitrarily, the colon character <code><big><b>:</b></big></code>.
++ * There is no distinction between type, method, and field names.
++ * This makes it easier to convert between mangled names of different
++ * types, since they do not need to be decoded (demangled).
++ * </p>
++ * <p>
++ * The escape character is backslash <code><big><b>\</b></big></code>
++ * (also known as reverse solidus).
++ * This character is, until now, unheard of in bytecode names,
++ * but traditional in the proposed role.
++ *
++ * </p>
++ * <h3> Replacement Characters </h3>
++ *
++ *
++ * <p>
++ * Every escape sequence is two characters
++ * (in fact, two UTF8 bytes) beginning with
++ * the escape character and followed by a
++ * <cite>replacement character</cite>.
++ * (Since the replacement character is never a backslash,
++ * iterated manglings do not double in size.)
++ * </p>
++ * <p>
++ * Each dangerous character has some rough visual similarity
++ * to its corresponding replacement character.
++ * This makes mangled symbols easier to recognize by sight.
++ * </p>
++ * <p>
++ * The dangerous characters are
++ * <code><big><b>/</b></big></code> (forward slash, used to delimit package components),
++ * <code><big><b>.</b></big></code> (dot, also a package delimiter),
++ * <code><big><b>;</b></big></code> (semicolon, used in signatures),
++ * <code><big><b>$</b></big></code> (dollar, used in inner classes and synthetic members),
++ * <code><big><b><</b></big></code> (left angle),
++ * <code><big><b>></b></big></code> (right angle),
++ * <code><big><b>[</b></big></code> (left square bracket, used in array types),
++ * <code><big><b>]</b></big></code> (right square bracket, reserved in this scheme for language use),
++ * and <code><big><b>:</b></big></code> (colon, reserved in this scheme for language use).
++ * Their replacements are, respectively,
++ * <code><big><b>|</b></big></code> (vertical bar),
++ * <code><big><b>,</b></big></code> (comma),
++ * <code><big><b>?</b></big></code> (question mark),
++ * <code><big><b>%</b></big></code> (percent),
++ * <code><big><b>^</b></big></code> (caret),
++ * <code><big><b>_</b></big></code> (underscore), and
++ * <code><big><b>{</b></big></code> (left curly bracket),
++ * <code><big><b>}</b></big></code> (right curly bracket),
++ * <code><big><b>!</b></big></code> (exclamation mark).
++ * In addition, the replacement character for the escape character itself is
++ * <code><big><b>-</b></big></code> (hyphen),
++ * and the replacement character for the null prefix is
++ * <code><big><b>=</b></big></code> (equal sign).
++ * </p>
++ * <p>
++ * An escape character <code><big><b>\</b></big></code>
++ * followed by any of these replacement characters
++ * is an escape sequence, and there are no other escape sequences.
++ * An equal sign is only part of an escape sequence
++ * if it is the second character in the whole string, following a backslash.
++ * Two consecutive backslashes do <em>not</em> form an escape sequence.
++ * </p>
++ * <p>
++ * Each escape sequence replaces a so-called <cite>original character</cite>
++ * which is either one of the dangerous characters or the escape character.
++ * A null prefix replaces an initial null string, not a character.
++ * </p>
++ * <p>
++ * All this implies that escape sequences cannot overlap and may be
++ * determined all at once for a whole string. Note that a spelling
++ * string can contain <cite>accidental escapes</cite>, apparent escape
++ * sequences which must not be interpreted as manglings.
++ * These are disabled by replacing their leading backslash with an
++ * escape sequence (<code><big><b>\-</b></big></code>). To mangle a string, three logical steps
++ * are required, though they may be carried out in one pass:
++ * </p>
++ * <ol>
++ * <li>In each accidental escape, replace the backslash with an escape sequence
++ * (<code><big><b>\-</b></big></code>).</li>
++ * <li>Replace each dangerous character with an escape sequence
++ * (<code><big><b>\|</b></big></code> for <code><big><b>/</b></big></code>, etc.).</li>
++ * <li>If the first two steps introduced any change, <em>and</em>
++ * if the string does not already begin with a backslash, prepend a null prefix (<code><big><b>\=</b></big></code>).</li>
++ * </ol>
++ *
++ * To demangle a mangled string that begins with an escape,
++ * remove any null prefix, and then replace (in parallel)
++ * each escape sequence by its original character.
++ * <p>Spelling strings which contain accidental
++ * escapes <em>must</em> have them replaced, even if those
++ * strings do not contain dangerous characters.
++ * This restriction means that mangling a string always
++ * requires a scan of the string for escapes.
++ * But then, a scan would be required anyway,
++ * to check for dangerous characters.
++ *
++ * </p>
++ * <h3> Nice Properties </h3>
++ *
++ * <p>
++ * If a bytecode name does not contain any escape sequence,
++ * demangling is a no-op: The string demangles to itself.
++ * Such a string is called <cite>self-mangling</cite>.
++ * Almost all strings are self-mangling.
++ * In practice, to demangle almost any name “found in nature”,
++ * simply verify that it does not begin with a backslash.
++ * </p>
++ * <p>
++ * Mangling is a one-to-one function, while demangling
++ * is a many-to-one function.
++ * A mangled string is defined as <cite>validly mangled</cite> if
++ * it is in fact the unique mangling of its spelling string.
++ * Three examples of invalidly mangled strings are <code><big><b>\=foo</b></big></code>,
++ * <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
++ * <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>.
++ * If a language back-end or runtime is using mangled names,
++ * it should never present an invalidly mangled bytecode
++ * name to the JVM. If the runtime encounters one,
++ * it should also report an error, since such an occurrence
++ * probably indicates a bug in name encoding which
++ * will lead to errors in linkage.
++ * However, this note does not propose that the JVM verifier
++ * detect invalidly mangled names.
++ * </p>
++ * <p>
++ * As a result of these rules, it is a simple matter to
++ * compute validly mangled substrings and concatenations
++ * of validly mangled strings, and (with a little care)
++ * these correspond to corresponding operations on their
++ * spelling strings.
++ * </p>
++ * <ul>
++ * <li>Any prefix of a validly mangled string is also validly mangled,
++ * although a null prefix may need to be removed.</li>
++ * <li>Any suffix of a validly mangled string is also validly mangled,
++ * although a null prefix may need to be added.</li>
++ * <li>Two validly mangled strings, when concatenated,
++ * are also validly mangled, although any null prefix
++ * must be removed from the second string,
++ * and a trailing backslash on the first string may need escaping,
++ * if it would participate in an accidental escape when followed
++ * by the first character of the second string.</li>
++ * </ul>
++ * <p>If languages that include non-Java symbol spellings use this
++ * mangling convention, they will enjoy the following advantages:
++ * </p>
++ * <ul>
++ * <li>They can interoperate via symbols they share in common.</li>
++ * <li>Low-level tools, such as backtrace printers, will have readable displays.</li>
++ * <li>Future JVM and language extensions can safely use the dangerous characters
++ * for structuring symbols, but will never interfere with valid spellings.</li>
++ * <li>Runtimes and compilers can use standard libraries for mangling and demangling.</li>
++ * <li>Occasional transliterations and name composition will be simple and regular,
++ * for classes, methods, and fields.</li>
++ * <li>Bytecode names will continue to be compact.
++ * When mangled, spellings will at most double in length, either in
++ * UTF8 or UTF16 format, and most will not change at all.</li>
++ * </ul>
++ *
++ *
++ * <h3> Suggestions for Human Readable Presentations </h3>
++ *
++ *
++ * <p>
++ * For human readable displays of symbols,
++ * it will be better to present a string-like quoted
++ * representation of the spelling, because JVM users
++ * are generally familiar with such tokens.
++ * We suggest using single or double quotes before and after
++ * mangled symbols which are not valid Java identifiers,
++ * with quotes, backslashes, and non-printing characters
++ * escaped as if for literals in the Java language.
++ * </p>
++ * <p>
++ * For example, an HTML-like spelling
++ * <code><big><b><pre></b></big></code> mangles to
++ * <code><big><b>\^pre\_</b></big></code> and could
++ * display more cleanly as
++ * <code><big><b>'<pre>'</b></big></code>,
++ * with the quotes included.
++ * Such string-like conventions are <em>not</em> suitable
++ * for mangled bytecode names, in part because
++ * dangerous characters must be eliminated, rather
++ * than just quoted. Otherwise internally structured
++ * strings like package prefixes and method signatures
++ * could not be reliably parsed.
++ * </p>
++ * <p>
++ * In such human-readable displays, invalidly mangled
++ * names should <em>not</em> be demangled and quoted,
++ * for this would be misleading. Likewise, JVM symbols
++ * which contain dangerous characters (like dots in field
++ * names or brackets in method names) should not be
++ * simply quoted. The bytecode names
++ * <code><big><b>\=phase\,1</b></big></code> and
++ * <code><big><b>phase.1</b></big></code> are distinct,
++ * and in demangled displays they should be presented as
++ * <code><big><b>'phase.1'</b></big></code> and something like
++ * <code><big><b>'phase'.1</b></big></code>, respectively.
++ * </p>
++ *
++ * @author John Rose
++ * @version 1.2, 02/06/2008
++ * @see http://blogs.sun.com/jrose/entry/symbolic_freedom_in_the_vm
++ */
++public class BytecodeName {
++ private BytecodeName() { } // static only class
++
++ /** Given a source name, produce the corresponding bytecode name.
++ * The source name should not be qualified, because any syntactic
++ * markers (dots, slashes, dollar signs, colons, etc.) will be mangled.
++ * @param s the source name
++ * @return a valid bytecode name which represents the source name
++ */
++ public static String toBytecodeName(String s) {
++ String bn = mangle(s);
++ assert((Object)bn == s || looksMangled(bn)) : bn;
++ assert(s.equals(toSourceName(bn))) : s;
++ return bn;
++ }
++
++ /** Given an unqualified bytecode name, produce the corresponding source name.
++ * The bytecode name must not contain dangerous characters.
++ * In particular, it must not be qualified or segmented by colon {@code ':'}.
++ * @param s the bytecode name
++ * @return the source name, which may possibly have unsafe characters
++ * @throws IllegalArgumentException if the bytecode name is not {@link #isSafeBytecodeName safe}
++ * @see #isSafeBytecodeName(java.lang.String)
++ */
++ public static String toSourceName(String s) {
++ checkSafeBytecodeName(s);
++ String sn = s;
++ if (looksMangled(s)) {
++ sn = demangle(s);
++ assert(s.equals(mangle(sn))) : s+" => "+sn+" => "+mangle(sn);
++ }
++ return sn;
++ }
++
++ /**
++ * Given a bytecode name from a classfile, separate it into
++ * components delimited by dangerous characters.
++ * Each resulting array element will be either a dangerous character,
++ * or else a safe bytecode name.
++ * (The safe name might possibly be mangled to hide further dangerous characters.)
++ * For example, the qualified class name {@code java/lang/String}
++ * will be parsed into the array {@code {"java", '/', "lang", '/', "String"}}.
++ * The name {@code <init>} will be parsed into { '<', "init", '>'}}
++ * The name {@code foo/bar$:baz} will be parsed into
++ * {@code {"foo", '/', "bar", '$', ':', "baz"}}.
++ */
++ public static Object[] parseBytecodeName(String s) {
++ int slen = s.length();
++ Object[] res = null;
++ for (int pass = 0; pass <= 1; pass++) {
++ int fillp = 0;
++ int lasti = 0;
++ for (int i = 0; i <= slen; i++) {
++ int whichDC = -1;
++ if (i < slen) {
++ whichDC = DANGEROUS_CHARS.indexOf(s.charAt(i));
++ if (whichDC < DANGEROUS_CHAR_FIRST_INDEX) continue;
++ }
++ // got to end of string or next dangerous char
++ if (lasti < i) {
++ // normal component
++ if (pass != 0)
++ res[fillp] = s.substring(lasti, i);
++ fillp++;
++ lasti = i+1;
++ }
++ if (whichDC >= DANGEROUS_CHAR_FIRST_INDEX) {
++ if (pass != 0)
++ res[fillp] = DANGEROUS_CHARS_CA[whichDC];
++ fillp++;
++ }
++ }
++ if (pass != 0) break;
++ // between passes, build the result array
++ res = new String[fillp];
++ if (fillp <= 1) {
++ if (fillp != 0) res[0] = s;
++ break;
++ }
++ }
++ return res;
++ }
++
++ /**
++ * Given a series of components, create a bytecode name for a classfile.
++ * This is the inverse of {@link #parseBytecodeName(java.lang.String)}.
++ * Each component must either be an interned one-character string of
++ * a dangerous character, or else a safe bytecode name.
++ * @param components a series of name components
++ * @return the concatenation of all components
++ * @throws IllegalArgumentException if any component contains an unsafe
++ * character, and is not an interned one-character string
++ * @throws NullPointerException if any component is null
++ */
++ public static String unparseBytecodeName(Object[] components) {
++ for (Object c : components) {
++ if (c instanceof String)
++ checkSafeBytecodeName((String) c); // may fail
++ }
++ return appendAll(components);
++ }
++ private static String appendAll(Object[] components) {
++ if (components.length <= 1) {
++ if (components.length == 1) {
++ return String.valueOf(components[0]);
++ }
++ return "";
++ }
++ int slen = 0;
++ for (Object c : components) {
++ if (c instanceof String)
++ slen += String.valueOf(c).length();
++ else
++ slen += 1;
++ }
++ StringBuilder sb = new StringBuilder(slen);
++ for (Object c : components) {
++ sb.append(c);
++ }
++ return sb.toString();
++ }
++
++ /**
++ * Given a bytecode name, produce the corresponding display name.
++ * This is the source name, plus quotes if needed.
++ * If the bytecode name contains dangerous characters,
++ * assume that they are being used as punctuation,
++ * and pass them through unchanged.
++ * @param s the original bytecode name (which may be qualified)
++ * @return a human-readable presentation
++ */
++ public static String toDisplayName(String s) {
++ Object[] components = parseBytecodeName(s);
++ for (int i = 0; i < components.length; i++) {
++ if (!(components[i] instanceof String))
++ continue;
++ String c = (String) components[i];
++ // pretty up the name by demangling it
++ String sn = toSourceName(c);
++ if ((Object)sn != c || !isJavaIdent(sn)) {
++ components[i] = quoteDisplay(sn);
++ }
++ }
++ return appendAll(components);
++ }
++ private static boolean isJavaIdent(String s) {
++ int slen = s.length();
++ if (slen == 0) return false;
++ if (!Character.isUnicodeIdentifierStart(s.charAt(0)))
++ return false;
++ for (int i = 1; i < slen; i++) {
++ if (!Character.isUnicodeIdentifierPart(s.charAt(0)))
++ return false;
++ }
++ return true;
++ }
++ private static String quoteDisplay(String s) {
++ // TO DO: Replace wierd characters in s by C-style escapes.
++ return "'"+s.replaceAll("['\\\\]", "\\\\$0")+"'";
++ }
++
++ private static void checkSafeBytecodeName(String s)
++ throws IllegalArgumentException {
++ if (!isSafeBytecodeName(s)) {
++ throw new IllegalArgumentException(s);
++ }
++ }
++
++ /**
++ * Report whether a simple name is safe as a bytecode name.
++ * Such names are acceptable in class files as class, method, and field names.
++ * Additionally, they are free of "dangerous" characters, even if those
++ * characters are legal in some (or all) names in class files.
++ * @param s the proposed bytecode name
++ * @return true if the name is non-empty and all of its characters are safe
++ */
++ public static boolean isSafeBytecodeName(String s) {
++ if (s.length() == 0) return false;
++ // check occurrences of each DANGEROUS char
++ for (char xc : DANGEROUS_CHARS_A) {
++ if (xc == ESCAPE_C) continue; // not really that dangerous
++ if (s.indexOf(xc) >= 0) return false;
++ }
++ return true;
++ }
++
++ /**
++ * Report whether a character is safe in a bytecode name.
++ * This is true of any unicode character except the following
++ * <em>dangerous characters</em>: {@code ".;:$[]<>/"}.
++ * @param s the proposed character
++ * @return true if the character is safe to use in classfiles
++ */
++ public static boolean isSafeBytecodeChar(char c) {
++ return DANGEROUS_CHARS.indexOf(c) < DANGEROUS_CHAR_FIRST_INDEX;
++ }
++
++ private static boolean looksMangled(String s) {
++ return s.charAt(0) == ESCAPE_C;
++ }
++
++ private static String mangle(String s) {
++ if (s.length() == 0)
++ return NULL_ESCAPE;
++
++ // build this lazily, when we first need an escape:
++ StringBuilder sb = null;
++
++ for (int i = 0, slen = s.length(); i < slen; i++) {
++ char c = s.charAt(i);
++
++ boolean needEscape = false;
++ if (c == ESCAPE_C) {
++ if (i+1 < slen) {
++ char c1 = s.charAt(i+1);
++ if ((i == 0 && c1 == NULL_ESCAPE_C)
++ || c1 != originalOfReplacement(c1)) {
++ // an accidental escape
++ needEscape = true;
++ }
++ }
++ } else {
++ needEscape = isDangerous(c);
++ }
++
++ if (!needEscape) {
++ if (sb != null) sb.append(c);
++ continue;
++ }
++
++ // build sb if this is the first escape
++ if (sb == null) {
++ sb = new StringBuilder(s.length()+10);
++ // mangled names must begin with a backslash:
++ if (s.charAt(0) != ESCAPE_C && i > 0)
++ sb.append(NULL_ESCAPE);
++ // append the string so far, which is unremarkable:
++ sb.append(s.substring(0, i));
++ }
++
++ // rewrite \ to \-, / to \|, etc.
++ sb.append(ESCAPE_C);
++ sb.append(replacementOf(c));
++ }
++
++ if (sb != null) return sb.toString();
++
++ return s;
++ }
++
++ private static String demangle(String s) {
++ // build this lazily, when we first meet an escape:
++ StringBuilder sb = null;
++
++ int stringStart = 0;
++ if (s.startsWith(NULL_ESCAPE))
++ stringStart = 2;
++
++ for (int i = stringStart, slen = s.length(); i < slen; i++) {
++ char c = s.charAt(i);
++
++ if (c == ESCAPE_C && i+1 < slen) {
++ // might be an escape sequence
++ char rc = s.charAt(i+1);
++ char oc = originalOfReplacement(rc);
++ if (oc != rc) {
++ // build sb if this is the first escape
++ if (sb == null) {
++ sb = new StringBuilder(s.length());
++ // append the string so far, which is unremarkable:
++ sb.append(s.substring(stringStart, i));
++ }
++ ++i; // skip both characters
++ c = oc;
++ }
++ }
++
++ if (sb != null)
++ sb.append(c);
++ }
++
++ if (sb != null) return sb.toString();
++
++ return s.substring(stringStart);
++ }
++
++ static char ESCAPE_C = '\\';
++ // empty escape sequence to avoid a null name or illegal prefix
++ static char NULL_ESCAPE_C = '=';
++ static String NULL_ESCAPE = ESCAPE_C+""+NULL_ESCAPE_C;
++
++ static final String DANGEROUS_CHARS = "\\/.;:$[]<>"; // \\ must be first
++ static final String REPLACEMENT_CHARS = "-|,?!%{}^_";
++ static final int DANGEROUS_CHAR_FIRST_INDEX = 1; // index after \\
++ static char[] DANGEROUS_CHARS_A = DANGEROUS_CHARS.toCharArray();
++ static char[] REPLACEMENT_CHARS_A = REPLACEMENT_CHARS.toCharArray();
++ static final Character[] DANGEROUS_CHARS_CA;
++ static {
++ Character[] dcca = new Character[DANGEROUS_CHARS.length()];
++ for (int i = 0; i < dcca.length; i++)
++ dcca[i] = Character.valueOf(DANGEROUS_CHARS.charAt(i));
++ DANGEROUS_CHARS_CA = dcca;
++ }
++
++ static final long[] SPECIAL_BITMAP = new long[2]; // 128 bits
++ static {
++ String SPECIAL = DANGEROUS_CHARS + REPLACEMENT_CHARS;
++ //System.out.println("SPECIAL = "+SPECIAL);
++ for (char c : SPECIAL.toCharArray()) {
++ SPECIAL_BITMAP[c >>> 6] |= 1L << c;
++ }
++ }
++ static boolean isSpecial(char c) {
++ if ((c >>> 6) < SPECIAL_BITMAP.length)
++ return ((SPECIAL_BITMAP[c >>> 6] >> c) & 1) != 0;
++ else
++ return false;
++ }
++ static char replacementOf(char c) {
++ if (!isSpecial(c)) return c;
++ int i = DANGEROUS_CHARS.indexOf(c);
++ if (i < 0) return c;
++ return REPLACEMENT_CHARS.charAt(i);
++ }
++ static char originalOfReplacement(char c) {
++ if (!isSpecial(c)) return c;
++ int i = REPLACEMENT_CHARS.indexOf(c);
++ if (i < 0) return c;
++ return DANGEROUS_CHARS.charAt(i);
++ }
++ static boolean isDangerous(char c) {
++ if (!isSpecial(c)) return false;
++ return (DANGEROUS_CHARS.indexOf(c) >= DANGEROUS_CHAR_FIRST_INDEX);
++ }
++ static int indexOfDangerousChar(String s, int from) {
++ for (int i = from, slen = s.length(); i < slen; i++) {
++ if (isDangerous(s.charAt(i)))
++ return i;
++ }
++ return -1;
++ }
++ static int lastIndexOfDangerousChar(String s, int from) {
++ for (int i = Math.min(from, s.length()-1); i >= 0; i--) {
++ if (isDangerous(s.charAt(i)))
++ return i;
++ }
++ return -1;
++ }
++
++ // test driver
++ static void main(String[] av) {
++ // If verbose is enabled, quietly check everything.
++ // Otherwise, print the output for the user to check.
++ boolean verbose = false;
++
++ int maxlen = 0;
++
++ while (av.length > 0 && av[0].startsWith("-")) {
++ String flag = av[0].intern();
++ av = java.util.Arrays.copyOfRange(av, 1, av.length); // Java 1.6 or later
++ if (flag == "-" || flag == "--") break;
++ else if (flag == "-q")
++ verbose = false;
++ else if (flag == "-v")
++ verbose = true;
++ else if (flag.startsWith("-l"))
++ maxlen = Integer.valueOf(flag.substring(2));
++ else
++ throw new Error("Illegal flag argument: "+flag);
++ }
++
++ if (maxlen == 0)
++ maxlen = (verbose ? 2 : 4);
++ if (verbose) System.out.println("Note: maxlen = "+maxlen);
++
++ switch (av.length) {
++ case 0: av = new String[] {
++ DANGEROUS_CHARS.substring(0) +
++ REPLACEMENT_CHARS.substring(0, 1) +
++ NULL_ESCAPE + "x"
++ }; // and fall through:
++ case 1:
++ char[] cv = av[0].toCharArray();
++ av = new String[cv.length];
++ int avp = 0;
++ for (char c : cv) {
++ String s = String.valueOf(c);
++ if (c == 'x') s = "foo"; // tradition...
++ av[avp++] = s;
++ }
++ }
++ if (verbose)
++ System.out.println("Note: Verbose output mode enabled. Use '-q' to suppress.");
++ Tester t = new Tester();
++ t.maxlen = maxlen;
++ t.verbose = verbose;
++ t.tokens = av;
++ t.test("", 0);
++ }
++
++ static class Tester {
++ boolean verbose;
++ int maxlen;
++ java.util.Map<String,String> map = new java.util.HashMap<String,String>();
++ String[] tokens;
++
++ void test(String stringSoFar, int tokensSoFar) {
++ test(stringSoFar);
++ if (tokensSoFar <= maxlen) {
++ for (String token : tokens) {
++ if (token.length() == 0) continue; // skip empty tokens
++ if (stringSoFar.indexOf(token) != stringSoFar.lastIndexOf(token))
++ continue; // there are already two occs. of this token
++ if (token.charAt(0) == ESCAPE_C && token.length() == 1 && maxlen < 4)
++ test(stringSoFar+token, tokensSoFar); // want lots of \'s
++ else if (tokensSoFar < maxlen)
++ test(stringSoFar+token, tokensSoFar+1);
++ }
++ }
++ }
++
++ void test(String s) {
++ // for small batches, do not test the null string
++ if (s.length() == 0 && maxlen >=1 && maxlen <= 2) return;
++ String bn = testSourceName(s);
++ if (bn == null) return;
++ if (bn == s) {
++ //if (verbose) System.out.println(s+" == id");
++ } else {
++ if (verbose) System.out.println(s+" => "+bn+" "+toDisplayName(bn));
++ String bnbn = testSourceName(bn);
++ if (bnbn == null) return;
++ if (verbose) System.out.println(bn+" => "+bnbn+" "+toDisplayName(bnbn));
++ /*
++ String bn3 = testSourceName(bnbn);
++ if (bn3 == null) return;
++ if (verbose) System.out.println(bnbn+" => "+bn3);
++ */
++ }
++ }
++
++ String testSourceName(String s) {
++ if (map.containsKey(s)) return null;
++ String bn = toBytecodeName(s);
++ map.put(s, bn);
++ String sn = toSourceName(bn);
++ if (!sn.equals(s)) {
++ String bad = (s+" => "+bn+" != "+sn);
++ if (!verbose) throw new Error("Bad mangling: "+bad);
++ System.out.println("*** "+bad);
++ return null;
++ }
++ return bn;
++ }
++ }
++}
+diff --git a/src/share/classes/java/dyn/CallSite.java b/src/share/classes/java/dyn/CallSite.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/CallSite.java
+@@ -0,0 +1,176 @@
++/*
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation. Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ */
++
+package java.dyn;
++
++import impl.java.dyn.util.BytecodeName;
+
+/**
+ * An <code>invokedynamic</code> call site, as reified to the bootstrap method.
@@ -43,7 +831,7 @@ new file mode 100644
+ * to finish the execution of the call site, and optionally to link
+ * the call site.
+ * <p>
-+ * @author jrose
++ * @author John Rose, JSR 292 EG
+ */
+public abstract class CallSite {
+ protected MethodHandle target;
@@ -60,7 +848,19 @@ new file mode 100644
+ /**
+ * Report the current linkage state of the call site. (This is mutable.)
+ * The value is null if and only if the call site is currently unlinked.
++ * When a linked call site is invoked, the target method is used directly.
++ * When an unlinked call site is invoked, its bootstrap method receives
++ * the call, as if via {@link Linkage#bootstrapInvokeDynamic}.
++ * <p>
++ * The interactions of {@code getTarget} with memory are the same
++ * as of a read from an ordinary variable, such as an array element or a
++ * non-volatile, non-final field.
++ * <p>
++ * In particular, the current thread may choose to reuse the result
++ * of a previous read of the target from memory, and may fail to see
++ * a recent update to the target by another thread.
+ * @return the current linkage state of the call site
++ * @see #setTarget
+ */
+ public MethodHandle getTarget() {
+ return target;
@@ -68,9 +868,19 @@ new file mode 100644
+
+ /**
+ * Link or relink the call site, by setting its target method.
++ * <p>
++ * The interactions of {@code setTarget} with memory are the same
++ * as of a write to an ordinary variable, such as an array element or a
++ * non-volatile, non-final field.
++ * <p>
++ * In particular, unrelated threads may fail to see the updated target
++ * until they perform a read from memory.
++ * Stronger guarantees can be created by putting appropriate operations
++ * into the bootstrap method and/or the target methods used
++ * at any given call site.
+ * @param target the new target, or null if it is to be unlinked
+ * @throws WrongMethodTypeException if the new target is not null
-+ * and has a method type that differs from the call site type
++ * and has a method type that differs from the call site's {@link #type}
+ */
+ public void setTarget(MethodHandle target) {
+ checkTarget(target);
@@ -98,15 +908,51 @@ new file mode 100644
+ /**
+ * Report the method name specified in the {@code invokedynamic} instruction.
+ * This is immutable static context.
++ * <p>
++ * Note that the name is a JVM bytecode name, and as such can be any
++ * non-empty string, as long as it does not contain certain "dangerous"
++ * characters such as slash {@code '/'} and dot {@code '.'}.
++ * See the Java Virtual Machine specification for more details.
++ * <p>
++ * Application such as a language runtimes may need to encode
++ * arbitrary program element names and other configuration information
++ * into the name. A standard convention for doing this is
++ * <a href="http://blogs.sun.com/jrose/entry/symbolic_freedom_in_the_vm">specified here</a>.
+ * @return method name specified by the call site
+ */
+ public String name() {
+ return name;
+ }
+
-+ /*
-+ * Report the result and parameter types, derived from the invocation descriptor, and resolved
-+ * against the calling class's class loader.
++ /**
++ * Report the method name specified in the {@code invokedynamic} instruction,
++ * as a series of components, individually demangled according to
++ * the standard convention
++ * <a href="http://blogs.sun.com/jrose/entry/symbolic_freedom_in_the_vm">specified here</a>.
++ * <p>
++ * Non-empty runs of characters between dangerous characters are demangled.
++ * Each component is either a completely arbitrary demangled string,
++ * or else a character constant for a punctuation character, typically ':'.
++ * (In principle, the character can be any dangerous character that the
++ * JVM lets through in a method name, such as '$' or ']'.
++ * Runtime implementors are encouraged to use colon ':' for building
++ * structured names.)
++ * <p>
++ * In the common case where the name contains no dangerous characters,
++ * the result is an array whose only element array is the demangled
++ * name at the call site. Such a demangled name can be any sequence
++ * of any number of any unicode characters.
++ * @return method name components specified by the call site
++ */
++ public Object[] nameComponents() {
++ return BytecodeName.parseBytecodeName(name);
++ }
++
++ /**
++ * Report the resolved result and parameter types of this call site,
++ * which are derived from its bytecode-level invocation descriptor.
++ * The types are packaged into a {@link MethodType}.
++ * Any linked target of this call site must be exactly this method type.
+ * This is immutable static context.
+ * @return method type specified by the call site
+ */
@@ -123,9 +969,9 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/share/classes/java/dyn/Dynamic.java
-@@ -0,0 +1,37 @@
+@@ -0,0 +1,50 @@
+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
@@ -152,22 +998,93 @@ new file mode 100644
+package java.dyn;
+
+/**
-+ * Syntactic marker interface for {@code invokedynamic} instructions.
++ * Syntactic marker interface to request javac to emit an {@code invokedynamic} instruction.
++ * A language compiler might use this interface to express invokedynamic instructions as follows:
++ * <blockquote><pre>
++ * Dynamic.greet("hello world", 123);
++ * // previous line generates invokedynamic "greet" "(Ljava/lang/String;I)Ljava/lang/Object;"
++ * Dynamic.>void<println(123);
++ * // previous line generates invokedynamic "println" "(I)V"
++ * Dynamic.#"long:strange:name"();
++ * // previous line generates invokedynamic "long:strange:name" "()Ljava/lang/Object;"
++ * </pre></blockquote>
++ * <p>
+ * This type has no particular meaning as a class or interface supertype, and need never be implemented by any class.
+ * Logically, it denotes a dynamically typed reference to any object.
+ * As such it may be viewed as logically containing all methods on any of those types.
-+ * @author jrose
++ * <p>
++ * This type may be used as a marker interface for arguments to method handles, in order
++ * to distinguish the static type {@code Object} from a dynamically typed reference.
++ * @author John Rose, JSR 292 EG
+ */
+public interface Dynamic {
+ // no methods
++}
+diff --git a/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java b/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java
+@@ -0,0 +1,53 @@
++/*
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation. Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ */
++
++package java.dyn;
++
++/**
++ * Thrown to indicate that an {@code invokedynamic} instruction has
++ * failed to find its bootstrap method.
++ * This must have been declared during a class's initialization
++ * by a call to {@link Linkage#registerBootstrapMethod}.
++ *
++ * @author John Rose, JSR 292 EG
++ */
++public class InvokeDynamicBootstrapError extends LinkageError {
++ /**
++ * Constructs a {@code InvokeDynamicBootstrapError} with no detail message.
++ */
++ public InvokeDynamicBootstrapError() {
++ super();
++ }
++
++ /**
++ * Constructs a {@code InvokeDynamicBootstrapError} with the specified
++ * detail message.
++ *
++ * @param s the detail message.
++ */
++ public InvokeDynamicBootstrapError(String s) {
++ super(s);
++ }
+}
diff --git a/src/share/classes/java/dyn/Linkage.java b/src/share/classes/java/dyn/Linkage.java
new file mode 100644
--- /dev/null
+++ b/src/share/classes/java/dyn/Linkage.java
-@@ -0,0 +1,209 @@
+@@ -0,0 +1,252 @@
+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
@@ -193,15 +1110,17 @@ new file mode 100644
+
+package java.dyn;
+
-+import java.dyn.util.MethodHandleInvoker;
++import impl.java.dyn.util.MethodHandleInvoker;
+import java.util.WeakHashMap;
+import sun.reflect.Reflection;
+
+/**
-+ *
-+ * @author jrose
++ * Static methods which control the linkage of invokedynamic call sites.
++ * @author John Rose, JSR 292 EG
+ */
+public class Linkage {
++ private Linkage() {} // do not instantiate
++
+ /**
+ * Register a bootstrap method for use for a given caller class.
+ * The method handle must be of a type equivalent to {@link Linkage#bootstrapInvokeDynamic}.
@@ -210,7 +1129,7 @@ new file mode 100644
+ * <ul>
+ * <li>The caller of this method is in a different package than the {@code callerClass},
+ * and there is a security manager, and its {@code checkPermission} call throws
-+ * when passed {@link LinkagePermission("registerBootstrapMethod",callerClass)}.
++ * when passed {@link LinkagePermission}("registerBootstrapMethod",callerClass).
+ * <li>The given class already has a bootstrap method, either from an embedded
+ * {@code BootstrapInvokeDynamic} classfile attribute, or from a previous
+ * call to this method.
@@ -232,6 +1151,23 @@ new file mode 100644
+ bootstrapMethods.put(callerClass, mh);
+ }
+ }
++
++ /**
++ * Simplified version of registerBootstrapMethod for self-registration,
++ * to be called from a static initializer.
++ * Finds a static method of type (CallSite, Object[]) -> Object in the
++ * caller's class, and installs it on the caller.
++ * @throws IllegalArgumentException if there is no such method
++ */
++ public static
++ void registerBootstrapMethod(String name) {
++ Class callc = Reflection.getCallerClass(2);
++ MethodHandle bootstrapMethod =
++ MethodHandles.findStaticFrom(callc, callc, name, BOOTSTRAP_METHOD_TYPE);
++ if (bootstrapMethod == null)
++ throw new IllegalArgumentException("cannot find bootstrap method: "+name);
++ Linkage.registerBootstrapMethod(callc, bootstrapMethod);
++ }
+
+ /**
+ * Report the bootstrap method registered for a given class.
@@ -239,7 +1175,7 @@ new file mode 100644
+ * or if the class has explicitly registered a null bootstrap method.
+ * Only callers privileged to set the bootstrap method may inquire
+ * about it, because a bootstrap method is potentially a back-door entry
-+ * points to its class.
++ * point into its class.
+ */
+ public static
+ MethodHandle getBootstrapMethod(Class callerClass) {
@@ -255,18 +1191,42 @@ new file mode 100644
+ */
+ public static final MethodType BOOTSTRAP_METHOD_TYPE
+ = MethodType.make(Object.class,
-+ CallSite.class, Object[].class).newVarArgs(true);
++ CallSite.class, Object[].class);
+
+ private static MethodHandleInvoker bootstrapMethodInvoker;
+
+ private static final WeakHashMap<Class, MethodHandle> bootstrapMethods =
+ new WeakHashMap<Class, MethodHandle>();
+
-+ /** Determine if the caller class has declared or registered its own bootstrap method.
-+ * If so, delegate this call to it. Otherwise, throw an IncompatibleClassChangeError.
++ /**
++ * Determine if the caller class has declared or registered its own bootstrap method.
++ * If so, delegate this call to it. Otherwise, throw an IncompatibleClassChangeError.
++ * <p>
++ * This routine, or an equivalent sequence of actions, is called from the
++ * JVM when an {@code invokedynamic} instruction is executed
++ * but its call site is unlinked (has a null target method).
++ * <p>
++ * This routine can be called from Java code whether or not the call site
++ * currently has a target, and will invoke the bootstrap method regardless
++ * of he call site's linkage state.
++ * <p>
++ * Although invoking the bootstrap method does not in and of itself cause
++ * state change in the call site, the actions eventually performed by
++ * the bootstrap method may include installed a new target on the call site.
++ * <p>
++ * Note that linkage state changes are individually atomic, but are not
++ * serialized in any way with respect to calls to the bootstrap method,
++ * or executions of the {@code invokedynamic} instruction. Therefore,
++ * an {@code invokedynamic} call site may be linked several times if
++ * several threads concurrently execute it in an unlinked state.
++ * It is up to the user-defined bootstrap method to make sure this
++ * race condition is resolved safely, either by performing linkage
++ * decisions under suitable locks (as the JVM does) or by ensuring
++ * that all racing threads come to the same conclusion, and independently
++ * install equivalent target methods.
+ */
+ public static
-+ Object bootstrapInvokeDynamic(CallSite site, Object... receiverAndArguments) {
++ Object bootstrapInvokeDynamic(CallSite site, Object... arguments) {
+ Class callerClass = site.callerClass();
+ MethodHandle mh;
+ synchronized (bootstrapMethods) {
@@ -275,10 +1235,10 @@ new file mode 100644
+ if (mh == null)
+ throw new IllegalStateException("no bootstrap method declared in "+callerClass);
+
-+ System.out.println(site+": calling bootstrap "+mh);
++ System.out.println(site+": calling bootstrap "+mh); // FIXME
+ if (bootstrapMethodInvoker == null)
+ bootstrapMethodInvoker = MethodHandleInvoker.make(BOOTSTRAP_METHOD_TYPE);
-+ return bootstrapMethodInvoker.invoke_LLL(mh, site, receiverAndArguments);
++ return bootstrapMethodInvoker.invoke(mh, site, arguments);
+ }
+
+ /**
@@ -297,10 +1257,10 @@ new file mode 100644
+ */
+ public static
+ Object invalidateAll() {
-+ SecurityManager security = System.getSecurityManager();
-+ if (security != null) {
-+ security.checkPermission(new LinkagePermission("invalidateAll"));
-+ }
++ SecurityManager security = System.getSecurityManager();
++ if (security != null) {
++ security.checkPermission(new LinkagePermission("invalidateAll"));
++ }
+ throw new UnsupportedOperationException("NYI");
+ }
+
@@ -318,10 +1278,10 @@ new file mode 100644
+ */
+ public static
+ Object invalidateCallerClass(Class<?> callerClass) {
-+ SecurityManager security = System.getSecurityManager();
-+ if (security != null) {
-+ security.checkPermission(new LinkagePermission("invalidateAll", callerClass));
-+ }
++ SecurityManager security = System.getSecurityManager();
++ if (security != null) {
++ security.checkPermission(new LinkagePermission("invalidateAll", callerClass));
++ }
+ throw new UnsupportedOperationException("NYI");
+ }
+
@@ -334,8 +1294,8 @@ new file mode 100644
+ * the requesting class loader.)
+ * @param requestingClass
+ * @param subjectClass
-+ * @return
-+ */
++ */
++ // FIXME: factor this logic into impl.java.dyn.util.VerifyAccess
+ static void checkPackagePrivilege(Class requestingClass, Class subjectClass,
+ String permissionName) {
+ if (requestingClass == null) return;
@@ -357,7 +1317,7 @@ new file mode 100644
+ MethodHandle findBootstrapMethod(Class callerClass, Class searchBootstrapClass) {
+ if (searchBootstrapClass != null) throw new UnsupportedOperationException("NYI");
+ MethodHandle mh = getBootstrapMethod(callerClass);
-+ System.out.println("reporting bootstrap method to JVM: "+mh);
++ System.out.println("reporting bootstrap method to JVM: "+mh); //FIXME
+ return mh;
+ }
+
@@ -381,7 +1341,7 @@ new file mode 100644
+++ b/src/share/classes/java/dyn/LinkagePermission.java
@@ -0,0 +1,111 @@
+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
@@ -463,7 +1423,7 @@ new file mode 100644
+ * @see java.security.BasicPermission
+ * @see java.lang.SecurityManager
+ *
-+ * @author jrose
++ * @author John Rose, JSR 292 EG
+ */
+
+public final class LinkagePermission extends BasicPermission {
@@ -491,68 +1451,3 @@ new file mode 100644
+ super(name + "." + clazz.getName());
+ }
+}
-diff --git a/src/share/classes/java/dyn/impl/DynCallSite.java b/src/share/classes/java/dyn/impl/DynCallSite.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/java/dyn/impl/DynCallSite.java
-@@ -0,0 +1,60 @@
-+/*
-+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
-+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-+ *
-+ * This code is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 only, as
-+ * published by the Free Software Foundation. Sun designates this
-+ * particular file as subject to the "Classpath" exception as provided
-+ * by Sun in the LICENSE file that accompanied this code.
-+ *
-+ * This code is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-+ * version 2 for more details (a copy is included in the LICENSE file that
-+ * accompanied this code).
-+ *
-+ * You should have received a copy of the GNU General Public License version
-+ * 2 along with this work; if not, write to the Free Software Foundation,
-+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
-+ * CA 95054 USA or visit www.sun.com if you need additional information or
-+ * have any questions.
-+ */
-+
-+package java.dyn.impl;
-+
-+import java.dyn.*;
-+
-+/**
-+ * The CallSite privately created by the JVM at every invokedynamic instruction.
-+ * @author jrose
-+ */
-+class DynCallSite extends CallSite {
-+ // Fields used only by the JVM. Do not use or change.
-+ Object vmref;
-+ long vmdata;
-+
-+ private DynCallSite(Class<?> caller, String name, MethodType type) {
-+ super(caller, name, type);
-+ }
-+
-+ @Override
-+ public void setTarget(MethodHandle mh) {
-+ checkTarget(mh);
-+ if (MH.JVM_SUPPORT)
-+ MH.linkCallSite(this, mh);
-+ else
-+ super.setTarget(mh);
-+ }
-+
-+ // this is the up-call from the JVM:
-+ static DynCallSite makeSite(Class<?> caller, String name, MethodType type,
-+ long vmdata) {
-+ DynCallSite site = new DynCallSite(caller, name, type);
-+ site.vmdata = vmdata;
-+ System.out.println("DynCallSite: "+site);
-+ return site;
-+ }
-+}
--- a/meth.patch Sat Mar 21 23:59:57 2009 -0700
+++ b/meth.patch Fri Apr 03 02:34:37 2009 -0700
@@ -1,3 +1,100 @@ diff --git a/src/share/classes/impl/java
+diff --git a/make/Makefile b/make/Makefile
+--- a/make/Makefile
++++ b/make/Makefile
+@@ -1,5 +1,5 @@
+ #
+-# Copyright 1995-2007 Sun Microsystems, Inc. All Rights Reserved.
++# Copyright 1995-2009 Sun Microsystems, Inc. All Rights Reserved.
+ # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ #
+ # This code is free software; you can redistribute it and/or modify it
+@@ -239,7 +239,7 @@
+
+ all build:: sanity-all post-sanity-all
+
+-SUBDIRS = tools java javax org sun sunw com jpda mkdemo mksample launchers
++SUBDIRS = tools java javax org impl sun sunw com jpda mkdemo mksample launchers
+ all build::
+ $(SUBDIRS-loop)
+
+diff --git a/make/docs/CORE_PKGS.gmk b/make/docs/CORE_PKGS.gmk
+--- a/make/docs/CORE_PKGS.gmk
++++ b/make/docs/CORE_PKGS.gmk
+@@ -1,5 +1,5 @@
+ #
+-# Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved.
++# Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved.
+ # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ #
+ # This code is free software; you can redistribute it and/or modify it
+@@ -55,6 +55,9 @@
+ # This is a list of regular expressions. So foo.* matches "foo" and "foo.bar".
+ #
+ ACTIVE_JSR_PKGS= \
++ impl.java.dyn \
++ impl.java.dyn.util \
++ java.dyn \
+ java.sql \
+ javax.activation \
+ javax.annotation.* \
+diff --git a/make/java/Makefile b/make/java/Makefile
+--- a/make/java/Makefile
++++ b/make/java/Makefile
+@@ -1,5 +1,5 @@
+ #
+-# Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved.
++# Copyright 1995-2009 Sun Microsystems, Inc. All Rights Reserved.
+ # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ #
+ # This code is free software; you can redistribute it and/or modify it
+@@ -39,7 +39,7 @@
+ # Others
+ # Note: java_crw_demo java_hprof_demo are demos but must be delivered built in sdk
+ SUBDIRS += security npt java_crw_demo java_hprof_demo \
+- math awt util text applet net nio \
++ math awt util text applet net nio dyn \
+ sql rmi jar beans logging management instrument
+
+
+diff --git a/make/java/dyn/Makefile b/make/java/dyn/Makefile
+new file mode 100644
+--- /dev/null
++++ b/make/java/dyn/Makefile
+@@ -0,0 +1,34 @@
++#
++# Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
++# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++#
++# This code is free software; you can redistribute it and/or modify it
++# under the terms of the GNU General Public License version 2 only, as
++# published by the Free Software Foundation. Sun designates this
++# particular file as subject to the "Classpath" exception as provided
++# by Sun in the LICENSE file that accompanied this code.
++#
++# This code is distributed in the hope that it will be useful, but WITHOUT
++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++# version 2 for more details (a copy is included in the LICENSE file that
++# accompanied this code).
++#
++# You should have received a copy of the GNU General Public License version
++# 2 along with this work; if not, write to the Free Software Foundation,
++# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++#
++# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++# CA 95054 USA or visit www.sun.com if you need additional information or
++# have any questions.
++#
++
++BUILDDIR = ../..
++
++PACKAGE = java.dyn
++PRODUCT = java
++include $(BUILDDIR)/common/Defs.gmk
++
++AUTO_FILES_JAVA_DIRS = java/dyn impl/java/dyn impl/java/dyn/util
++
++include $(BUILDDIR)/common/Classes.gmk
diff --git a/src/share/classes/impl/java/dyn/Access.java b/src/share/classes/impl/java/dyn/Access.java
new file mode 100644
--- /dev/null
@@ -100,7 +197,7 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/share/classes/impl/java/dyn/AdapterMethodHandle.java
-@@ -0,0 +1,541 @@
+@@ -0,0 +1,599 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -142,6 +239,7 @@ new file mode 100644
+ * @author jrose
+ */
+public class AdapterMethodHandle extends BoundMethodHandle {
++
+ //MethodHandle vmtarget; // next AMH or BMH in chain or final DMH
+ //Object argument; // parameter to the conversion if needed
+ //int vmargslot; // which argument slot is affected
@@ -166,6 +264,53 @@ new file mode 100644
+
+ // TO DO: When adapting another MH with a null conversion, clone
+ // the target and change its type, instead of adding another layer.
++
++ /** Can a JVM-level adapter directly implement the proposed
++ * argument conversions, as if by MethodHandles.convertArguments?
++ */
++ public static boolean canPairwiseConvert(MethodType newType, MethodType oldType) {
++ // same number of args, of course
++ int len = newType.parameterCount();
++ if (len != oldType.parameterCount())
++ return false;
++
++ // Check return type. (Not much can be done with it.)
++ Class<?> exp = newType.returnType();
++ Class<?> ret = oldType.returnType();
++ if (!VerifyType.isNullConversion(ret, exp))
++ return false;
++
++ // Check args pairwise.
++ for (int i = 0; i < len; i++) {
++ Class<?> src = newType.parameterType(i); // source type
++ Class<?> dst = oldType.parameterType(i); // destination type
++ if (!canConvertArgument(src, dst))
++ return false;
++ }
++
++ return true;
++ }
++
++ /** Can a JVM-level adapter directly implement the proposed
++ * argument conversion, as if by MethodHandles.convertArguments?
++ */
++ public static boolean canConvertArgument(Class<?> src, Class<?> dst) {
++ // ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes,
++ // so we don't need to repeat so much decision making.
++ if (VerifyType.isNullConversion(src, dst)) {
++ return true;
++ } else if (src.isPrimitive()) {
++ if (dst.isPrimitive())
++ return canPrimCast(src, dst);
++ else
++ return canBoxArgument(src, dst);
++ } else {
++ if (dst.isPrimitive())
++ return canUnboxArgument(src, dst);
++ else
++ return true; // any two refs can be interconverted
++ }
++ }
+
+ /**
+ * Create a JVM-level adapter method handle to conform the given method
@@ -183,27 +328,21 @@ new file mode 100644
+ * @throws IllegalArgumentException if the adaptation cannot be made
+ * directly by a JVM-level adapter, without help from Java code
+ */
-+ public static MethodHandle makePairwiseConversion(Access token,
++ public static MethodHandle makePairwiseConvert(Access token,
+ MethodType newType, MethodHandle target) {
+ Access.check(token);
-+ int len = newType.parameterCount();
+ MethodType oldType = target.type();
+ if (newType == oldType) return target;
-+ if (len != oldType.parameterCount())
-+ throw newIllegalArgumentException("wrong number of arguments in "+newType);
-+
-+ // Check return type. (Not much can be done with it.)
-+ Class<?> exp = newType.returnType();
-+ Class<?> ret = oldType.returnType();
-+ if (!VerifyType.isNullConversion(ret, exp))
-+ throw newIllegalArgumentException("bad return conversion for "+newType);
-+
-+ // Find last non-trivial conversion.
-+ int lastConv = len-1;
++
++ // caller responsibility:
++ assert(canPairwiseConvert(newType, oldType));
++
++ // Find last non-trivial conversion (if any).
++ int lastConv = newType.parameterCount()-1;
+ while (lastConv >= 0) {
+ Class<?> src = newType.parameterType(lastConv); // source type
+ Class<?> dst = oldType.parameterType(lastConv); // destination type
-+ if (src == dst || VerifyType.isNullConversion(src, dst)) {
++ if (VerifyType.isNullConversion(src, dst)) {
+ --lastConv;
+ } else {
+ break;
@@ -211,11 +350,11 @@ new file mode 100644
+ }
+ // Now build a chain of one or more adapters.
+ MethodHandle adapter = target;
-+ MethodType midType = oldType.changeReturnType(exp);
++ MethodType midType = oldType.changeReturnType(newType.returnType());
+ for (int i = 0; i <= lastConv; i++) {
+ Class<?> src = newType.parameterType(i); // source type
+ Class<?> dst = midType.parameterType(i); // destination type
-+ if (src == dst || VerifyType.isNullConversion(src, dst)) {
++ if (VerifyType.isNullConversion(src, dst)) {
+ // do nothing: difference is trivial
+ continue;
+ }
@@ -228,28 +367,31 @@ new file mode 100644
+ assert(VerifyType.isNullConversion(newType, midType.changeParameterType(i, src)));
+ midType = newType;
+ }
++
+ // Tricky case analysis follows.
-+ boolean srcPrim = src.isPrimitive();
-+ boolean dstPrim = dst.isPrimitive();
-+ if (!srcPrim && !dstPrim && canCheckCast(src, dst)) {
-+ // Simple reference conversion.
-+ // Note: Do not check for a class hierarchy relation
-+ // between src and dst. In all cases a 'null' argument
-+ // will pass the cast conversion.
-+ adapter = makeCheckCast(token, midType, adapter, i, dst);
-+ } else if (srcPrim && dstPrim && canPrimCast(src, dst)) {
-+ // Convert a primitive to a primitive, if the JVM supports it.
-+ adapter = makePrimCast(token, midType, adapter, i, dst);
-+ } else if (!srcPrim && dstPrim && canUnboxArgument(src, dst)) {
-+ // Caller has boxed a primitive. Unbox it for the target.
-+ // The box type must correspond exactly to the primitive type.
-+ // This is simpler than the powerful set of widening
-+ // conversions supported by reflect.Method.invoke.
-+ // Those conversions require a big nest of if/then/else logic,
-+ // which we prefer to make a user responsibility.
-+ adapter = makeUnboxArgument(token, midType, adapter, i, dst);
++ // It parallels canConvertArgument() above.
++ if (src.isPrimitive()) {
++ if (dst.isPrimitive()) {
++ adapter = makePrimCast(token, midType, adapter, i, dst);
++ } else {
++ adapter = makeBoxArgument(token, midType, adapter, i, dst);
++ }
+ } else {
-+ throw newIllegalArgumentException("bad argument #"+i+" conversion in "+newType);
++ if (dst.isPrimitive()) {
++ // Caller has boxed a primitive. Unbox it for the target.
++ // The box type must correspond exactly to the primitive type.
++ // This is simpler than the powerful set of widening
++ // conversions supported by reflect.Method.invoke.
++ // Those conversions require a big nest of if/then/else logic,
++ // which we prefer to make a user responsibility.
++ adapter = makeUnboxArgument(token, midType, adapter, i, dst);
++ } else {
++ // Simple reference conversion.
++ // Note: Do not check for a class hierarchy relation
++ // between src and dst. In all cases a 'null' argument
++ // will pass the cast conversion.
++ adapter = makeCheckCast(token, midType, adapter, i, dst);
++ }
+ }
+ assert(adapter.type() == midType);
+ }
@@ -292,7 +434,7 @@ new file mode 100644
+ if (argumentMap.length != oldType.parameterCount())
+ throw newIllegalArgumentException("bad permutation: "+Arrays.toString(argumentMap));
+ if (nullPermutation)
-+ return makePairwiseConversion(token, newType, target); // well, that was easy
++ return makePairwiseConvert(token, newType, target); // well, that was easy
+
+ // Check return type. (Not much can be done with it.)
+ Class<?> exp = newType.returnType();
@@ -588,7 +730,20 @@ new file mode 100644
+ return makeCheckCast(token, newType, adapter, arg, boxType);
+ }
+
-+ // TO DO: makeBoxArgument, makeSwapArguments, makeRotateArguments, makeDuplicateArguments
++ /** Can an primitive boxing adapter validly convert src to dst? */
++ public static boolean canBoxArgument(Class<?> src, Class<?> dst) {
++ return false; // PRIM_TO_REF NYI
++ }
++
++ /** Factory method: Unbox the given argument. */
++ public static MethodHandle makeBoxArgument(Access token,
++ MethodType newType, MethodHandle target,
++ int arg, Class<?> convType) {
++ // this is difficult to do in the JVM because it must GC
++ throw new InternalError("PRIM_TO_REF NYI");
++ }
++
++ // TO DO: makeSwapArguments, makeRotateArguments, makeDuplicateArguments
+
+ /** Can an adapter simply drop arguments to convert the target to newType? */
+ public static boolean canDropArguments(MethodType newType, MethodType targetType,
@@ -693,7 +848,7 @@ new file mode 100644
+ * The JVM will pre-dispatch the MH if it is not already static.
+ */
+ BoundMethodHandle(DirectMethodHandle mh, Object argument) {
-+ super(Access.TOKEN, mh.type().deleteParameterType(0));
++ super(Access.TOKEN, mh.type().dropParameterType(0));
+ // check the type now, once for all:
+ this.argument = mh.type().parameterType(0).cast(argument);
+ this.vmargslot = this.type().parameterSlotCount();
@@ -709,7 +864,7 @@ new file mode 100644
+ * If argnum is zero, inserts the first argument, etc.
+ */
+ BoundMethodHandle(MethodHandle mh, Object argument, int argnum) {
-+ super(Access.TOKEN, mh.type().deleteParameterType(argnum));
++ super(Access.TOKEN, mh.type().dropParameterType(argnum));
+ this.argument = mh.type().parameterType(argnum).cast(argument);
+ this.vmargslot = this.type().parameterSlot(argnum-1);
+ System.out.println("init BMH type="+type()+" argnum="+argnum+" vmargslot="+vmargslot);
@@ -733,71 +888,6 @@ new file mode 100644
+ @Override
+ public String toString() {
+ return "Bound[" + super.toString() + "]";
-+ }
-+}
-diff --git a/src/share/classes/impl/java/dyn/CallSiteImpl.java b/src/share/classes/impl/java/dyn/CallSiteImpl.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/impl/java/dyn/CallSiteImpl.java
-@@ -0,0 +1,60 @@
-+/*
-+ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
-+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-+ *
-+ * This code is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 only, as
-+ * published by the Free Software Foundation. Sun designates this
-+ * particular file as subject to the "Classpath" exception as provided
-+ * by Sun in the LICENSE file that accompanied this code.
-+ *
-+ * This code is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-+ * version 2 for more details (a copy is included in the LICENSE file that
-+ * accompanied this code).
-+ *
-+ * You should have received a copy of the GNU General Public License version
-+ * 2 along with this work; if not, write to the Free Software Foundation,
-+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
-+ * CA 95054 USA or visit www.sun.com if you need additional information or
-+ * have any questions.
-+ */
-+
-+package impl.java.dyn;
-+
-+import java.dyn.*;
-+
-+/**
-+ * The CallSite privately created by the JVM at every invokedynamic instruction.
-+ * @author jrose
-+ */
-+class CallSiteImpl extends CallSite {
-+ // Fields used only by the JVM. Do not use or change.
-+ Object vmref;
-+ long vmdata;
-+
-+ private CallSiteImpl(Class<?> caller, String name, MethodType type) {
-+ super(caller, name, type);
-+ }
-+
-+ @Override
-+ public void setTarget(MethodHandle mh) {
-+ checkTarget(mh);
-+ if (MethodHandleNatives.JVM_SUPPORT)
-+ MethodHandleNatives.linkCallSite(this, (MethodHandle) mh);
-+ else
-+ super.setTarget(mh);
-+ }
-+
-+ // this is the up-call from the JVM:
-+ static CallSiteImpl makeSite(Class<?> caller, String name, MethodType type,
-+ long vmdata) {
-+ CallSiteImpl site = new CallSiteImpl(caller, name, type);
-+ site.vmdata = vmdata;
-+ System.out.println("DynCallSite: "+site);
-+ return site;
+ }
+}
diff --git a/src/share/classes/impl/java/dyn/DirectMethodHandle.java b/src/share/classes/impl/java/dyn/DirectMethodHandle.java
@@ -1447,7 +1537,7 @@ new file mode 100644
+
+package impl.java.dyn;
+
-+import impl.java.dyn.util.Signatures;
++import impl.java.dyn.util.BytecodeSignature;
+import java.dyn.*;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
@@ -1577,9 +1667,9 @@ new file mode 100644
+ if (type instanceof String)
+ return (String) type;
+ if (isInvocable())
-+ return Signatures.unparse(getMethodType());
++ return BytecodeSignature.unparse(getMethodType());
+ else
-+ return Signatures.unparse(getFieldType());
++ return BytecodeSignature.unparse(getFieldType());
+ }
+
+ public int getModifiers() {
@@ -1858,7 +1948,7 @@ new file mode 100644
+ matchFlags &= ALLOWED_FLAGS;
+ String matchSig = null;
+ if (matchType != null) {
-+ matchSig = Signatures.unparse(matchType);
++ matchSig = BytecodeSignature.unparse(matchType);
+ if (matchSig.startsWith("("))
+ matchFlags &= ~(ALL_KINDS & ~IS_INVOCABLE);
+ else
@@ -1975,7 +2065,7 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/share/classes/impl/java/dyn/MethodHandleImpl.java
-@@ -0,0 +1,266 @@
+@@ -0,0 +1,269 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -2009,6 +2099,7 @@ new file mode 100644
+import impl.java.dyn.JavaMethodHandle;
+import impl.java.dyn.util.MethodHandleInvoker;
+import java.dyn.NoAccessException;
++import org.omg.PortableInterceptor.AdapterManagerIdHelper;
+import static impl.java.dyn.MemberName.newIllegalArgumentException;
+import static impl.java.dyn.MemberName.newNoAccessException;
+
@@ -2160,7 +2251,9 @@ new file mode 100644
+ MethodType oldType, boolean oldVarargs,
+ String permutationOrNull) {
+ Access.check(token);
-+ throw new UnsupportedOperationException("Not yet implemented");
++ if (AdapterMethodHandle.canPairwiseConvert(newType, oldType))
++ return AdapterMethodHandle.makePairwiseConvert(token, newType, target);
++ throw new UnsupportedOperationException("NYI");
+ }
+
+ public static
@@ -2221,7 +2314,7 @@ new file mode 100644
+ }
+
+ public static
-+ MethodHandle checkArguments(Access token, MethodHandle target, MethodHandle checker, int pos) {
++ MethodHandle combineArguments(Access token, MethodHandle target, MethodHandle checker, int pos) {
+ Access.check(token);
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
@@ -2379,12 +2472,12 @@ new file mode 100644
+ JVM_SUPPORT_ = false;
+ JVM_PUSH_LIMIT_ = 3; // arbitrary
+ JVM_STACK_MOVE_UNIT_ = -1; // arbitrary
++ System.out.println("Warning: Running with JVM_SUPPORT=false");
++ System.out.println(ee);
+ }
+ JVM_SUPPORT = JVM_SUPPORT_;
+ JVM_PUSH_LIMIT = JVM_PUSH_LIMIT_;
+ JVM_STACK_MOVE_UNIT = JVM_STACK_MOVE_UNIT_;
-+ if (!JVM_SUPPORT)
-+ System.out.println("Warning: Running with JVM_SUPPORT=false");
+ }
+
+ // All compile-time constants go here.
@@ -2527,6 +2620,148 @@ new file mode 100644
+ */
+
+package impl.java.dyn;
+diff --git a/src/share/classes/impl/java/dyn/util/BytecodeSignature.java b/src/share/classes/impl/java/dyn/util/BytecodeSignature.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/impl/java/dyn/util/BytecodeSignature.java
+@@ -0,0 +1,137 @@
++/*
++ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation. Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ */
++
++package impl.java.dyn.util;
++
++import java.dyn.MethodType;
++import java.util.ArrayList;
++import java.util.List;
++
++/**
++ * Utility routines for dealing with bytecode-level signatures.
++ * @author jrose
++ */
++public class BytecodeSignature {
++
++ private BytecodeSignature() { } // cannot instantiate
++
++ public static List<Class<?>> parseMethod(String bytecodeSignature, ClassLoader loader) {
++ return parseMethod(bytecodeSignature, 0, bytecodeSignature.length(), loader);
++ }
++
++ static List<Class<?>> parseMethod(String bytecodeSignature,
++ int start, int end, ClassLoader loader) {
++ if (loader == null)
++ loader = ClassLoader.getSystemClassLoader();
++ String str = bytecodeSignature;
++ int[] i = {start};
++ ArrayList<Class<?>> ptypes = new ArrayList<Class<?>>();
++ if (i[0] < end && str.charAt(i[0]) == '(') {
++ ++i[0]; // skip '('
++ while (i[0] < end && str.charAt(i[0]) != ')') {
++ Class<?> pt = parseSig(str, i, end, loader);
++ if (pt == null || pt == void.class)
++ parseError(str, "bad argument type");
++ ptypes.add(pt);
++ }
++ ++i[0]; // skip ')'
++ } else {
++ parseError(str, "not a method type");
++ }
++ Class<?> rtype = parseSig(str, i, end, loader);
++ if (rtype == null || i[0] != end)
++ parseError(str, "bad return type");
++ ptypes.add(rtype);
++ return ptypes;
++ }
++
++ static private void parseError(String str, String msg) {
++ throw new IllegalArgumentException("bad signature: "+str+": "+msg);
++ }
++
++ static private Class<?> parseSig(String str, int[] i, int end, ClassLoader loader) {
++ if (i[0] == end) return null;
++ char c = str.charAt(i[0]++);
++ if (c == 'L') {
++ int begc = i[0], endc = str.indexOf(';', begc);
++ if (endc < 0) return null;
++ i[0] = endc+1;
++ String name = str.substring(begc, endc).replace('/', '.');
++ try {
++ return loader.loadClass(name);
++ } catch (ClassNotFoundException ex) {
++ throw new TypeNotPresentException(name, ex);
++ }
++ } else if (c == '[') {
++ Class<?> t = parseSig(str, i, end, loader);
++ if (t != null)
++ t = java.lang.reflect.Array.newInstance(t, 0).getClass();
++ return t;
++ } else {
++ return Wrappers.basicTypeFromChar(c);
++ }
++ }
++
++ public static String unparse(Class<?> type) {
++ StringBuilder sb = new StringBuilder();
++ unparseSig(type, sb);
++ return sb.toString();
++ }
++
++ public static String unparse(MethodType type) {
++ return unparseMethod(type.returnType(), type.parameterList());
++ }
++
++ public static String unparse(Object type) {
++ if (type instanceof Class<?>)
++ return unparse((Class<?>) type);
++ if (type instanceof MethodType)
++ return unparse((MethodType) type);
++ return (String) type;
++ }
++
++ public static String unparseMethod(Class<?> rtype, List<Class<?>> ptypes) {
++ StringBuilder sb = new StringBuilder();
++ sb.append('(');
++ for (Class<?> pt : ptypes)
++ unparseSig(pt, sb);
++ sb.append(')');
++ unparseSig(rtype, sb);
++ return sb.toString();
++ }
++
++ static private void unparseSig(Class<?> t, StringBuilder sb) {
++ char c = Wrappers.basicTypeChar(t);
++ if (c != 'L') {
++ sb.append(c);
++ } else {
++ boolean lsemi = (!t.isArray());
++ if (lsemi) sb.append('L');
++ sb.append(t.getName().replace('.', '/'));
++ if (lsemi) sb.append(';');
++ }
++ }
++
++}
diff --git a/src/share/classes/impl/java/dyn/util/MethodHandleInvoker.java b/src/share/classes/impl/java/dyn/util/MethodHandleInvoker.java
new file mode 100644
--- /dev/null
@@ -2622,7 +2857,7 @@ new file mode 100644
+ throw new IllegalArgumentException("too many long arguments in "+exactType);
+ MethodHandle invoker = MethodHandles.findVirtual(MethodHandle.class, "invoke", exactType);
+ MethodType adapterType = approxType.insertParameterType(0, MethodHandle.class);
-+ return AdapterMethodHandle.makePairwiseConversion(IMPL_TOKEN, adapterType, invoker);
++ return AdapterMethodHandle.makePairwiseConvert(IMPL_TOKEN, adapterType, invoker);
+ }
+
+ public Object invoke_0(MethodHandle mh)
@@ -2986,144 +3221,6 @@ new file mode 100644
+ throw wrongType(mh);
+ }
+}
-diff --git a/src/share/classes/impl/java/dyn/util/Signatures.java b/src/share/classes/impl/java/dyn/util/Signatures.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/impl/java/dyn/util/Signatures.java
-@@ -0,0 +1,133 @@
-+/*
-+ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
-+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-+ *
-+ * This code is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 only, as
-+ * published by the Free Software Foundation. Sun designates this
-+ * particular file as subject to the "Classpath" exception as provided
-+ * by Sun in the LICENSE file that accompanied this code.
-+ *
-+ * This code is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-+ * version 2 for more details (a copy is included in the LICENSE file that
-+ * accompanied this code).
-+ *
-+ * You should have received a copy of the GNU General Public License version
-+ * 2 along with this work; if not, write to the Free Software Foundation,
-+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
-+ * CA 95054 USA or visit www.sun.com if you need additional information or
-+ * have any questions.
-+ */
-+
-+package impl.java.dyn.util;
-+
-+import java.dyn.MethodType;
-+import java.util.ArrayList;
-+import java.util.List;
-+
-+public class Signatures {
-+
-+ private Signatures() { } // cannot instantiate
-+
-+ public static List<Class<?>> parseMethod(String bytecodeSignature, ClassLoader loader) {
-+ return parseMethod(bytecodeSignature, 0, bytecodeSignature.length(), loader);
-+ }
-+
-+ public static List<Class<?>> parseMethod(String bytecodeSignature,
-+ int start, int end, ClassLoader loader) {
-+ if (loader == null)
-+ loader = ClassLoader.getSystemClassLoader();
-+ String str = bytecodeSignature;
-+ int[] i = {start};
-+ ArrayList<Class<?>> ptypes = new ArrayList<Class<?>>();
-+ if (i[0] < end && str.charAt(i[0]) == '(') {
-+ ++i[0]; // skip '('
-+ while (i[0] < end && str.charAt(i[0]) != ')') {
-+ Class<?> pt = parseSig(str, i, end, loader);
-+ if (pt == null || pt == void.class)
-+ parseError(str, "bad argument type");
-+ ptypes.add(pt);
-+ }
-+ ++i[0]; // skip ')'
-+ } else {
-+ parseError(str, "not a method type");
-+ }
-+ Class<?> rtype = parseSig(str, i, end, loader);
-+ if (rtype == null || i[0] != end)
-+ parseError(str, "bad return type");
-+ ptypes.add(rtype);
-+ return ptypes;
-+ }
-+
-+ static private void parseError(String str, String msg) {
-+ throw new IllegalArgumentException("bad signature: "+str+": "+msg);
-+ }
-+
-+ static private Class<?> parseSig(String str, int[] i, int end, ClassLoader loader) {
-+ if (i[0] == end) return null;
-+ char c = str.charAt(i[0]++);
-+ if (c == 'L') {
-+ int begc = i[0], endc = str.indexOf(';', begc);
-+ if (endc < 0) return null;
-+ i[0] = endc+1;
-+ String name = str.substring(begc, endc).replace('/', '.');
-+ try {
-+ return loader.loadClass(name);
-+ } catch (ClassNotFoundException ex) {
-+ throw new TypeNotPresentException(name, ex);
-+ }
-+ } else if (c == '[') {
-+ Class<?> t = parseSig(str, i, end, loader);
-+ if (t != null)
-+ t = java.lang.reflect.Array.newInstance(t, 0).getClass();
-+ return t;
-+ } else {
-+ return Wrappers.basicTypeFromChar(c);
-+ }
-+ }
-+
-+ public static String unparse(Class<?> type) {
-+ StringBuilder sb = new StringBuilder();
-+ unparseSig(type, sb);
-+ return sb.toString();
-+ }
-+
-+ public static String unparse(MethodType type) {
-+ return unparseMethod(type.returnType(), type.parameterList());
-+ }
-+
-+ public static String unparse(Object type) {
-+ if (type instanceof Class<?>)
-+ return unparse((Class<?>) type);
-+ if (type instanceof MethodType)
-+ return unparse((MethodType) type);
-+ return (String) type;
-+ }
-+
-+ public static String unparseMethod(Class<?> rtype, List<Class<?>> ptypes) {
-+ StringBuilder sb = new StringBuilder();
-+ sb.append('(');
-+ for (Class<?> pt : ptypes)
-+ unparseSig(pt, sb);
-+ sb.append(')');
-+ unparseSig(rtype, sb);
-+ return sb.toString();
-+ }
-+
-+ static private void unparseSig(Class<?> t, StringBuilder sb) {
-+ char c = Wrappers.basicTypeChar(t);
-+ if (c != 'L') {
-+ sb.append(c);
-+ } else {
-+ boolean lsemi = (!t.isArray());
-+ if (lsemi) sb.append('L');
-+ sb.append(t.getName().replace('.', '/'));
-+ if (lsemi) sb.append(';');
-+ }
-+ }
-+
-+}
diff --git a/src/share/classes/impl/java/dyn/util/VerifyAccess.java b/src/share/classes/impl/java/dyn/util/VerifyAccess.java
new file mode 100644
--- /dev/null
@@ -3722,572 +3819,6 @@ new file mode 100644
+ */
+
+package impl.java.dyn.util;
-diff --git a/src/share/classes/java/dyn/CallSite.java b/src/share/classes/java/dyn/CallSite.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/java/dyn/CallSite.java
-@@ -0,0 +1,116 @@
-+/*
-+ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
-+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-+ *
-+ * This code is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 only, as
-+ * published by the Free Software Foundation. Sun designates this
-+ * particular file as subject to the "Classpath" exception as provided
-+ * by Sun in the LICENSE file that accompanied this code.
-+ *
-+ * This code is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-+ * version 2 for more details (a copy is included in the LICENSE file that
-+ * accompanied this code).
-+ *
-+ * You should have received a copy of the GNU General Public License version
-+ * 2 along with this work; if not, write to the Free Software Foundation,
-+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
-+ * CA 95054 USA or visit www.sun.com if you need additional information or
-+ * have any questions.
-+ */
-+
-+package java.dyn;
-+
-+/**
-+ * An <code>invokedynamic</code> call site, as reified to the bootstrap method.
-+ * Every instance of a call site corresponds to a distinct instance
-+ * of the <code>invokedynamic</code> instruction.
-+ * Call sites have state, one reference word, called the <code>target</code>,
-+ * and typed as a {@link MethodHandle}. When this state is null (as it is
-+ * initially) the call site is in the unlinked state. Otherwise, it is said
-+ * to be linked to its target.
-+ * <p>
-+ * When an unlinked call site is executed, a bootstrap routine is called
-+ * to finish the execution of the call site, and optionally to link
-+ * the call site.
-+ * <p>
-+ * @author John Rose, JSR 292 EG
-+ */
-+public abstract class CallSite {
-+ protected MethodHandle target;
-+ protected final Object caller; // usually a class
-+ protected final String name;
-+ protected final MethodType type;
-+
-+ protected CallSite(Object caller, String name, MethodType type) {
-+ this.caller = caller;
-+ this.name = name;
-+ this.type = type;
-+ }
-+
-+ /**
-+ * Report the current linkage state of the call site. (This is mutable.)
-+ * The value is null if and only if the call site is currently unlinked.
-+ * @return the current linkage state of the call site
-+ */
-+ public MethodHandle getTarget() {
-+ return target;
-+ }
-+
-+ /**
-+ * Link or relink the call site, by setting its target method.
-+ * @param target the new target, or null if it is to be unlinked
-+ * @throws WrongMethodTypeException if the new target is not null
-+ * and has a method type that differs from the call site type
-+ */
-+ public void setTarget(MethodHandle target) {
-+ checkTarget(target);
-+ this.target = target;
-+ }
-+
-+ protected void checkTarget(MethodHandle target) {
-+ if (!canSetTarget(target))
-+ throw new WrongMethodTypeException(String.valueOf(target));
-+ }
-+
-+ protected boolean canSetTarget(MethodHandle target) {
-+ return (target == null || target.type() == type());
-+ }
-+
-+ /**
-+ * Report the class containing the call site.
-+ * This is immutable static context.
-+ * @return class containing the call site
-+ */
-+ public Class<?> callerClass() {
-+ return (Class) caller;
-+ }
-+
-+ /**
-+ * Report the method name specified in the {@code invokedynamic} instruction.
-+ * This is immutable static context.
-+ * @return method name specified by the call site
-+ */
-+ public String name() {
-+ return name;
-+ }
-+
-+ /*
-+ * Report the result and parameter types, derived from the invocation descriptor, and resolved
-+ * against the calling class's class loader.
-+ * This is immutable static context.
-+ * @return method type specified by the call site
-+ */
-+ public MethodType type() {
-+ return type;
-+ }
-+
-+ @Override
-+ public String toString() {
-+ return "CallSite#"+hashCode()+"["+name+type+" => "+target+"]";
-+ }
-+}
-diff --git a/src/share/classes/java/dyn/Dynamic.java b/src/share/classes/java/dyn/Dynamic.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/java/dyn/Dynamic.java
-@@ -0,0 +1,50 @@
-+/*
-+ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
-+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-+ *
-+ * This code is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 only, as
-+ * published by the Free Software Foundation. Sun designates this
-+ * particular file as subject to the "Classpath" exception as provided
-+ * by Sun in the LICENSE file that accompanied this code.
-+ *
-+ * This code is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-+ * version 2 for more details (a copy is included in the LICENSE file that
-+ * accompanied this code).
-+ *
-+ * You should have received a copy of the GNU General Public License version
-+ * 2 along with this work; if not, write to the Free Software Foundation,
-+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
-+ * CA 95054 USA or visit www.sun.com if you need additional information or
-+ * have any questions.
-+ */
-+
-+package java.dyn;
-+
-+/**
-+ * Syntactic marker interface to request javac to emit an {@code invokedynamic} instruction.
-+ * A language compiler might use this interface to express invokedynamic instructions as follows:
-+ * <blockquote><pre>
-+ * Dynamic.greet("hello world", 123);
-+ * // previous line generates invokedynamic "greet" "(Ljava/lang/String;I)Ljava/lang/Object;"
-+ * Dynamic.<void>println(123);
-+ * // previous line generates invokedynamic "println" "(I)V"
-+ * Dynamic.#"long:strange:name"();
-+ * // previous line generates invokedynamic "long:strange:name" "()Ljava/lang/Object;"
-+ * </pre></blockquote>
-+ * <p>
-+ * This type has no particular meaning as a class or interface supertype, and need never be implemented by any class.
-+ * Logically, it denotes a dynamically typed reference to any object.
-+ * As such it may be viewed as logically containing all methods on any of those types.
-+ * <p>
-+ * This type may be used as a marker interface for arguments to method handles, in order
-+ * to distinguish the static type {@code Object} from a dynamically typed reference.
-+ * @author John Rose, JSR 292 EG
-+ */
-+public interface Dynamic {
-+ // no methods
-+}
-diff --git a/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java b/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java
-@@ -0,0 +1,53 @@
-+/*
-+ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
-+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-+ *
-+ * This code is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 only, as
-+ * published by the Free Software Foundation. Sun designates this
-+ * particular file as subject to the "Classpath" exception as provided
-+ * by Sun in the LICENSE file that accompanied this code.
-+ *
-+ * This code is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-+ * version 2 for more details (a copy is included in the LICENSE file that
-+ * accompanied this code).
-+ *
-+ * You should have received a copy of the GNU General Public License version
-+ * 2 along with this work; if not, write to the Free Software Foundation,
-+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
-+ * CA 95054 USA or visit www.sun.com if you need additional information or
-+ * have any questions.
-+ */
-+
-+package java.dyn;
-+
-+/**
-+ * Thrown to indicate that an {@code invokedynamic} instruction has
-+ * failed to find its bootstrap method.
-+ * This must have been declared during a class's initialization
-+ * by a call to {@link Linkage#registerBootstrapMethod}.
-+ *
-+ * @author John Rose, JSR 292 EG
-+ */
-+public class InvokeDynamicBootstrapError extends LinkageError {
-+ /**
-+ * Constructs a {@code InvokeDynamicBootstrapError} with no detail message.
-+ */
-+ public InvokeDynamicBootstrapError() {
-+ super();
-+ }
-+
-+ /**
-+ * Constructs a {@code InvokeDynamicBootstrapError} with the specified
-+ * detail message.
-+ *
-+ * @param s the detail message.
-+ */
-+ public InvokeDynamicBootstrapError(String s) {
-+ super(s);
-+ }
-+}
-diff --git a/src/share/classes/java/dyn/Linkage.java b/src/share/classes/java/dyn/Linkage.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/java/dyn/Linkage.java
-@@ -0,0 +1,211 @@
-+/*
-+ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
-+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-+ *
-+ * This code is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 only, as
-+ * published by the Free Software Foundation. Sun designates this
-+ * particular file as subject to the "Classpath" exception as provided
-+ * by Sun in the LICENSE file that accompanied this code.
-+ *
-+ * This code is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-+ * version 2 for more details (a copy is included in the LICENSE file that
-+ * accompanied this code).
-+ *
-+ * You should have received a copy of the GNU General Public License version
-+ * 2 along with this work; if not, write to the Free Software Foundation,
-+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
-+ * CA 95054 USA or visit www.sun.com if you need additional information or
-+ * have any questions.
-+ */
-+
-+package java.dyn;
-+
-+import impl.java.dyn.util.MethodHandleInvoker;
-+import java.util.WeakHashMap;
-+import sun.reflect.Reflection;
-+
-+/**
-+ * Static methods which control the linkage of invokedynamic call sites.
-+ * @author John Rose, JSR 292 EG
-+ */
-+public class Linkage {
-+ private Linkage() {} // do not instantiate
-+
-+ /**
-+ * Register a bootstrap method for use for a given caller class.
-+ * The method handle must be of a type equivalent to {@link Linkage#bootstrapInvokeDynamic}.
-+ * <p>
-+ * The operation will fail with an exception if any of the following conditions hold:
-+ * <ul>
-+ * <li>The caller of this method is in a different package than the {@code callerClass},
-+ * and there is a security manager, and its {@code checkPermission} call throws
-+ * when passed {@link LinkagePermission}("registerBootstrapMethod",callerClass).
-+ * <li>The given class already has a bootstrap method, either from an embedded
-+ * {@code BootstrapInvokeDynamic} classfile attribute, or from a previous
-+ * call to this method.
-+ * <li>The given class is already fully initialized.
-+ * <li>The given class is in the process of initialization, in another thread.
-+ * </ul>
-+ * Because of these rules, a class may install its own bootstrap method in
-+ * a static initializer.
-+ */
-+ public static
-+ void registerBootstrapMethod(Class callerClass, MethodHandle mh) {
-+ Class callc = Reflection.getCallerClass(2);
-+ checkPackagePrivilege(callc, callerClass, "registerBootstrapMethod");
-+ if (mh != null && mh.type() != BOOTSTRAP_METHOD_TYPE)
-+ throw new WrongMethodTypeException(mh.type().toString());
-+ synchronized (bootstrapMethods) {
-+ if (bootstrapMethods.containsKey(callerClass))
-+ throw new IllegalStateException("bootstrap method already declared in "+callerClass);
-+ bootstrapMethods.put(callerClass, mh);
-+ }
-+ }
-+
-+ /**
-+ * Report the bootstrap method registered for a given class.
-+ * Returns null if the class has never yet registered a bootstrap method,
-+ * or if the class has explicitly registered a null bootstrap method.
-+ * Only callers privileged to set the bootstrap method may inquire
-+ * about it, because a bootstrap method is potentially a back-door entry
-+ * points to its class.
-+ */
-+ public static
-+ MethodHandle getBootstrapMethod(Class callerClass) {
-+ Class callc = Reflection.getCallerClass(2);
-+ checkPackagePrivilege(callc, callerClass, "registerBootstrapMethod");
-+ synchronized (bootstrapMethods) {
-+ return bootstrapMethods.get(callerClass);
-+ }
-+ }
-+
-+ /** The type of any bootstrap method is (CallSite,Object...)Object.
-+ * The varargs marker is required.
-+ */
-+ public static final MethodType BOOTSTRAP_METHOD_TYPE
-+ = MethodType.make(Object.class,
-+ CallSite.class, Object[].class);
-+
-+ private static MethodHandleInvoker bootstrapMethodInvoker;
-+
-+ private static final WeakHashMap<Class, MethodHandle> bootstrapMethods =
-+ new WeakHashMap<Class, MethodHandle>();
-+
-+ /** Determine if the caller class has declared or registered its own bootstrap method.
-+ * If so, delegate this call to it. Otherwise, throw an IncompatibleClassChangeError.
-+ */
-+ public static
-+ Object bootstrapInvokeDynamic(CallSite site, Object... receiverAndArguments) {
-+ Class callerClass = site.callerClass();
-+ MethodHandle mh;
-+ synchronized (bootstrapMethods) {
-+ mh = bootstrapMethods.get(callerClass);
-+ }
-+ if (mh == null)
-+ throw new IllegalStateException("no bootstrap method declared in "+callerClass);
-+
-+ System.out.println(site+": calling bootstrap "+mh);
-+ if (bootstrapMethodInvoker == null)
-+ bootstrapMethodInvoker = MethodHandleInvoker.make(BOOTSTRAP_METHOD_TYPE);
-+ return bootstrapMethodInvoker.invoke(mh, site, receiverAndArguments);
-+ }
-+
-+ /**
-+ * Invalidate all <code>invokedynamic</code> call sites everywhere.
-+ * <p>
-+ * When this method returns, every <code>invokedynamic</code> instruction
-+ * will invoke its bootstrap method on next call.
-+ * <p>
-+ * It is unspecified whether call sites already known to the Java
-+ * code will continue to be associated with <code>invokedynamic</code>
-+ * instructions. If any call site is still so associated, its
-+ * {@link CallSite#getTarget()} method is guaranteed to return null
-+ * the invalidation operation completes.
-+ * <p>
-+ * Invalidation operations are likely to be slow. Use them sparingly.
-+ */
-+ public static
-+ Object invalidateAll() {
-+ SecurityManager security = System.getSecurityManager();
-+ if (security != null) {
-+ security.checkPermission(new LinkagePermission("invalidateAll"));
-+ }
-+ throw new UnsupportedOperationException("NYI");
-+ }
-+
-+ /**
-+ * Invalidate all <code>invokedynamic</code> call sites associated
-+ * with the given class.
-+ * (These are exactly those sites which report the given class
-+ * via the {@link CallSite#callerClass()} method.)
-+ * <p>
-+ * When this method returns, every matching <code>invokedynamic</code>
-+ * instruction will invoke its bootstrap method on next call.
-+ * <p>
-+ * For additional semantics of call site invalidation,
-+ * see {@link #invalidateAll()}.
-+ */
-+ public static
-+ Object invalidateCallerClass(Class<?> callerClass) {
-+ SecurityManager security = System.getSecurityManager();
-+ if (security != null) {
-+ security.checkPermission(new LinkagePermission("invalidateAll", callerClass));
-+ }
-+ throw new UnsupportedOperationException("NYI");
-+ }
-+
-+ /**
-+ * Ensure the requesting class have privileges to perform invokedynamic
-+ * linkage operations on subjectClass. True if requestingClass is
-+ * null (meaning the request originates from the JVM) or if the
-+ * classes are in the same package and have consistent class loaders.
-+ * (The subject class loader must be identical with or be a child of
-+ * the requesting class loader.)
-+ * @param requestingClass
-+ * @param subjectClass
-+ * @return
-+ */
-+ static void checkPackagePrivilege(Class requestingClass, Class subjectClass,
-+ String permissionName) {
-+ if (requestingClass == null) return;
-+ if (requestingClass == subjectClass) return;
-+ SecurityManager security = System.getSecurityManager();
-+ if (security == null) return; // open season
-+ ClassLoader rcl = requestingClass.getClassLoader();
-+ ClassLoader scl = subjectClass.getClassLoader();
-+ if (isParent(rcl, scl)) {
-+ String rn = requestingClass.getName();
-+ if (rn.startsWith("java.dyn.")) return;
-+ String sn = subjectClass.getName();
-+ if (samePackage(rn, sn)) return;
-+ }
-+ security.checkPermission(new LinkagePermission(permissionName, requestingClass));
-+ }
-+
-+ static
-+ MethodHandle findBootstrapMethod(Class callerClass, Class searchBootstrapClass) {
-+ if (searchBootstrapClass != null) throw new UnsupportedOperationException("NYI");
-+ MethodHandle mh = getBootstrapMethod(callerClass);
-+ System.out.println("reporting bootstrap method to JVM: "+mh);
-+ return mh;
-+ }
-+
-+ private static boolean isParent(ClassLoader rcl, ClassLoader scl) {
-+ while (scl != null && scl != rcl)
-+ scl = scl.getParent();
-+ return (scl == rcl);
-+ }
-+
-+ private static boolean samePackage(String rn, String sn) {
-+ assert((rn.indexOf('/') & sn.indexOf('/')) < 0); // no bytecode names
-+ int lastDot = rn.lastIndexOf('.');
-+ if (lastDot != sn.lastIndexOf('.')) return false;
-+ return rn.startsWith(sn.substring(0, lastDot+1));
-+ }
-+
-+}
-diff --git a/src/share/classes/java/dyn/LinkagePermission.java b/src/share/classes/java/dyn/LinkagePermission.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/java/dyn/LinkagePermission.java
-@@ -0,0 +1,111 @@
-+/*
-+ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
-+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-+ *
-+ * This code is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 only, as
-+ * published by the Free Software Foundation. Sun designates this
-+ * particular file as subject to the "Classpath" exception as provided
-+ * by Sun in the LICENSE file that accompanied this code.
-+ *
-+ * This code is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-+ * version 2 for more details (a copy is included in the LICENSE file that
-+ * accompanied this code).
-+ *
-+ * You should have received a copy of the GNU General Public License version
-+ * 2 along with this work; if not, write to the Free Software Foundation,
-+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
-+ * CA 95054 USA or visit www.sun.com if you need additional information or
-+ * have any questions.
-+ */
-+
-+package java.dyn;
-+
-+import java.security.*;
-+import java.util.Enumeration;
-+import java.util.Hashtable;
-+import java.util.StringTokenizer;
-+
-+/**
-+ * This class is for runtime permissions. A RuntimePermission
-+ * contains a name (also referred to as a "target name") but
-+ * no actions list; you either have the named permission
-+ * or you don't.
-+ *
-+ * <P>
-+ * The target name is the name of the runtime permission (see below). The
-+ * naming convention follows the hierarchical property naming convention.
-+ * Also, an asterisk
-+ * may appear at the end of the name, following a ".", or by itself, to
-+ * signify a wildcard match. For example: "loadLibrary.*" or "*" is valid,
-+ * "*loadLibrary" or "a*b" is not valid.
-+ * <P>
-+ * The following table lists all the possible RuntimePermission target names,
-+ * and for each provides a description of what the permission allows
-+ * and a discussion of the risks of granting code the permission.
-+ * <P>
-+ *
-+ * <table border=1 cellpadding=5 summary="permission target name,
-+ * what the target allows,and associated risks">
-+ * <tr>
-+ * <th>Permission Target Name</th>
-+ * <th>What the Permission Allows</th>
-+ * <th>Risks of Allowing this Permission</th>
-+ * </tr>
-+ *
-+ * <tr>
-+ * <td>registerBootstrapMethod.{class name}</td>
-+ * <td>Specifying a bootstrap method for invokedynamic, within a class of the given name</td>
-+ * <td>An attacker could attempt to attach a bootstrap method to a class which
-+ * has just been loaded, thus gaining control of its invokedynamic calls.</td>
-+ * </tr>
-+ *
-+ * <tr>
-+ * <td>invalidateAll</td>
-+ * <td>Force the relinking of invokedynamic call sites everywhere.</td>
-+ * <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>
-+ * </tr>
-+ *
-+ *
-+ * <tr>
-+ * <td>invalidateCallerClass.{class name}</td>
-+ * <td>Force the relinking of invokedynamic call sites in the given class.</td>
-+ * <td>See {@code invalidateAll}.</td>
-+ * </tr>
-+ * </table>
-+ *
-+ * @see java.security.BasicPermission
-+ * @see java.lang.SecurityManager
-+ *
-+ * @author John Rose, JSR 292 EG
-+ */
-+
-+public final class LinkagePermission extends BasicPermission {
-+ /**
-+ * Create a new LinkagePermission with the given name.
-+ * The name is the symbolic name of the LinkagePermission, such as
-+ * "registerBootstrapMethod", "invalidateClass.*", etc. An asterisk
-+ * may appear at the end of the name, following a ".", or by itself, to
-+ * signify a wildcard match.
-+ *
-+ * @param name the name of the LinkagePermission
-+ */
-+ public LinkagePermission(String name) {
-+ super(name);
-+ }
-+
-+ /**
-+ * Create a new LinkagePermission with the given name on the given class.
-+ * Equivalent to {@code LinkagePermission(name+"."+clazz.getName())}.
-+ *
-+ * @param name the name of the LinkagePermission
-+ * @param clazz the class affected by the permission
-+ */
-+ public LinkagePermission(String name, Class<?> clazz) {
-+ super(name + "." + clazz.getName());
-+ }
-+}
diff --git a/src/share/classes/java/dyn/MethodHandle.java b/src/share/classes/java/dyn/MethodHandle.java
new file mode 100644
--- /dev/null
@@ -4426,7 +3957,7 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/share/classes/java/dyn/MethodHandles.java
-@@ -0,0 +1,938 @@
+@@ -0,0 +1,1041 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -4514,6 +4045,17 @@ new file mode 100644
+ return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, caller);
+ }
+
++ // TODO: Factor this correctly.
++ // We need to make a suitably access-checked MethodHandleFactory class that "knows" the caller class, if appropriate.
++ // Then we can limit the getCallerClass hack to one or two places. (It is convenient but fatally inflexible.)
++ static /*must not be public*/
++ MethodHandle findStaticFrom(Class<?> caller,
++ Class<?> defc, String name, MethodType type) throws NoAccessException {
++ MemberName method = IMPL_LOOKUP.resolveOrFail(new MemberName(defc, name, type, Modifier.STATIC), true, caller);
++ checkStatic(true, method, caller);
++ return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, caller);
++ }
++
+ private static void checkStatic(boolean wantStatic, MemberName m, Class<?> caller) {
+ if (wantStatic != m.isStatic()) {
+ String message = wantStatic ? "expected a static method" : "expected a non-static method";
@@ -4791,36 +4333,117 @@ new file mode 100644
+
+ /**
+ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
-+ * Call the {@code invoke} method of a given method handle.
-+ * The given arguments must exactly match the parameter types of the method handle.
-+ * <em>TBD: Fill in the details.</em>
-+ * No conversions are performed except reference casting and unboxing of primitives.
-+ * @param target method handle to invoke
-+ * @param arguments arguments to pass to the target (with any primitives wrapped)
-+ * @return the result of the method (with any primitive wrapped)
++ * Call the {@code invoke} method of a given method handle,
++ * with arguments that exactly match the parameter types of the method handle.
++ * The length of the arguments array must equal the parameter count
++ * of the target's type.
++ * The arguments array is spread into separate arguments, and
++ * basic reference and unboxing conversions are applied.
++ * <p>
++ * In order to match the type of the target, the following argument
++ * conversions are applied as necessary:
++ * <ul>
++ * <li>reference casting
++ * <li>unboxing
++ * </ul>
++ * The following conversions are not applied:
++ * <ul>
++ * <li>primitive conversions (e.g., {@code byte} to {@code int}
++ * <li>varargs conversions other than the initial spread
++ * <li>any application-specific conversions (e.g., string to number)
++ * </ul>
++ * The result returned by the call is boxed if it is a primitive,
++ * or forced to null if the return type is void.
++ * <p>
++ * This call is a convenience method for the following code:
++ * <pre>
++ * MethodHandle invoker = MethodHandles.genericInvoker(target.type(), 0, true);
++ * Object result = invoker.invoke(arguments);
++ * </pre>
++ * @param target the method handle to invoke
++ * @param arguments the arguments to pass to the target
++ * @return the result returned by the target
+ */
+ public static
+ Object invoke(MethodHandle target, Object... arguments) {
-+ // TO DO: Remove this checking logic; must be part of the invoker anyway.
-+ int length = arguments.length;
-+ MethodType type = target.type();
-+ if (type.parameterCount() != length)
-+ throw new WrongMethodTypeException("wrong number of arguments");
-+ for (int i = 0; i < length; i++) {
-+ Object argument = arguments[i];
-+ Class<?> ptype = type.parameterType(i);
-+ if (ptype.isPrimitive()) {
-+ argument.getClass(); // provoke NPE if null
-+ ptype = Wrappers.asWrapperType(ptype);
-+ } else if (ptype.isInterface()) {
-+ ptype = Object.class; // no check
-+ }
-+ if (ptype != Object.class) {
-+ ptype.cast(argument);
-+ }
-+ }
-+ // End of checking logic.
+ return MethodHandleInvoker.make(target.type()).invoke(target, arguments);
++ //MethodHandle invoker = MethodHandles.genericInvoker(target.type(), 0, true);
++ //return invoker.invoke(arguments);
++ }
++
++ public static
++ Object invoke_1(MethodHandle target, Object argument0, Object... arguments) {
++ int narguments = (arguments == null ? 0 : arguments.length);
++ Object[] args1 = new Object[1 + narguments];
++ args1[0] = argument0;
++ System.arraycopy(arguments, 0, args1, 1, narguments);
++ return MethodHandleInvoker.make(target.type()).invoke(target, args1);
++ //MethodHandle invoker = MethodHandles.genericInvoker(target.type(), 0, true);
++ //return invoker.invoke(arguments);
++ }
++
++ /**
++ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
++ * Give a method handle which will invoke any method handle of the
++ * given type on a standard set of {@code Object} type arguments.
++ * The the resulting invoker will be a method handle with the following
++ * arguments:
++ * <ul>
++ * <li>a single {@code MethodHandle} target
++ * <li>zero or more {@code Object} values
++ * <li>an optional {@code Object[]} array containing more arguments
++ * </ul>
++ * The invoker will spread the varargs array (if present), apply
++ * reference casts as necessary, and unbox primitive arguments.
++ * The return value of the invoker will be an {@code Object} reference,
++ * boxing a primitive value if the original type returns a primitive,
++ * and always null if the original type returns void.
++ * <p>
++ * This is a convenience method equivalent to the following code:
++ * <pre>
++ * MethodHandle invoker = exactInvoker(type);
++ * MethodType genericType = MethodType.makeGeneric(objectArgCount, varargs);
++ * genericType = genericType.insertParameterType(0, MethodHandle.class);
++ * if (!varargs)
++ * return convertArguments(invoker, genericType);
++ * else
++ * return spreadArguments(invoker, genericType);
++ * </pre>
++ * @param type the desired target type
++ * @param objectArgCount number of fixed (non-varargs) {@code Object} arguments
++ * @param varargs if true, the invoker will accept a final {@code Object[]} argument
++ * @return a method handle suitable for invoking any method handle of the given type
++ */
++ static public
++ MethodHandle genericInvoker(MethodType type, int objectArgCount, boolean varargs) {
++ MethodHandle invoker = exactInvoker(type);
++ MethodType genericType = MethodType.makeGeneric(objectArgCount, varargs);
++ genericType = genericType.insertParameterType(0, MethodHandle.class);
++ if (!varargs)
++ return convertArguments(invoker, genericType);
++ else
++ return spreadArguments(invoker, genericType);
++ }
++
++ /**
++ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
++ * Give a method handle which will take a invoke any method handle of the
++ * given type. The resulting invoker will have a type which is
++ * exactly equal to the desired type, except that it will accept
++ * an additional leading argument of type {@code MethodHandle}.
++ * <p>
++ * This is a convenience method equivalent to the following code:
++ * <pre>
++ * return findVirtual(MethodHandle.class, "invoke", type);
++ * </pre>
++ * @param type the desired target type
++ * @return a method handle suitable for invoking any method handle of the given type
++ */
++ static public
++ MethodHandle exactInvoker(MethodType type) {
++ MethodHandle invoker = findVirtual(MethodHandle.class, "invoke", type);
++ if (invoker == null) throw new InternalError("JVM cannot find invoker");
++ return invoker;
+ }
+
+ /**
@@ -4985,6 +4608,7 @@ new file mode 100644
+ * @return a method handle which delegates to {@code target} after performing
+ * any necessary argument conversions, and arranges for any
+ * necessary return value conversions
++ * @throws WrongMethodTypeException if the conversion cannot be made
+ */
+ public static
+ MethodHandle convertArguments(MethodHandle target, MethodType newType) {
@@ -4992,7 +4616,7 @@ new file mode 100644
+ if (oldType.equals(newType))
+ return target;
+ return MethodHandleImpl.convertArguments(IMPL_TOKEN, target,
-+ newType,false, target.type(), false, null);
++ newType, false, oldType, false, null);
+ }
+
+ /**
@@ -5025,7 +4649,7 @@ new file mode 100644
+ MethodHandle permuteArguments(MethodHandle target, MethodType newType, String permutation) {
+ MethodType oldType = target.type();
+ return MethodHandleImpl.convertArguments(IMPL_TOKEN, target,
-+ newType,false, target.type(), false,
++ newType, false, oldType, false,
+ permutation);
+ }
+
@@ -5243,34 +4867,44 @@ new file mode 100644
+ if (target.type().changeReturnType(boolean.class) != test.type())
+ throw newIllegalArgumentException("target and test types do not match");
+ /* {
-+ MethodHandle choose(boolean z, MethodHandle t, MethodHandle f) {
++ MethodHandle invoke = findVirtual(MethodHandle.class, "invoke", target.type());
++ static MethodHandle choose(boolean z, MethodHandle t, MethodHandle f) {
+ return z ? t : f;
+ }
++ static MethodHandle compose(MethodHandle f, MethodHandle g) {
++ Class<?> initargs = g.type().parameterArray();
++ f = dropArguments(f, 1, initargs); // ignore 2nd copy of args
++ return combineArguments(f, g);
++ }
++ // choose = \z.(z ? target : fallback)
+ MethodHandle choose = findVirtual(MethodHandles.class, "choose",
+ MethodType.make(boolean.class, MethodHandle.class, MethodHandle.class));
+ choose = appendArgument(choose, target);
+ choose = appendArgument(choose, fallback);
-+ choose = combineArguments(choose, test);
-+ MethodHandle invoke = findVirtual(MethodHandle.class, "invoke", target.type());
-+ return checkArguments(invoke, choose, 0);
++ MethodHandle dispatch = compose(choose, test);
++ // dispatch = \(a...).(test(a...) ? target : fallback)
++ return combineArguments(invoke, dispatch, 0);
++ // return \(a...).((test(a...) ? target : fallback).invoke(a...))
+ } */
+ return MethodHandleImpl.makeGuardWithTest(IMPL_TOKEN, test, target, fallback);
+ }
+
+ /**
+ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
-+ * Adapt a target method handle {@code target} by first checking its arguments,
-+ * and then calling the target.
-+ * The check is performed by a second method handle, the {@code checker}.
-+ * After this, control passes to the target method handle, with the same
-+ * arguments.
++ * Adapt a target method handle {@code target} by first processing
++ * its arguments, and then calling the target.
++ * The initial processing is performed by a second method handle, the {@code combiner}.
++ * After this, control passes to the {@code target}, with the same arguments.
+ * <p>
-+ * The return value of the checker is inserted into the argument list
-+ * for {@code target} at the indicated position {@code pos}, if it is non-negative.
++ * The return value of the {@code combiner} is inserted into the argument list
++ * for the {@code target} at the indicated position {@code pos}, if it is non-negative.
+ * Except for this inserted argument (if any), the argument types of
-+ * the target {@code target} and the {@code checker} must be identical.
++ * the target {@code target} and the {@code combiner} must be identical.
+ * <p>
-+ * The checker handle must have the same argument types as the
++ * (Note that {@link #dropArguments} can be used to remove any arguments
++ * that either the {@code combiner} or {@code target} does not wish to receive.)
++ * <p>
++ * The combiner handle must have the same argument types as the
+ * target handle, but must return {@link MethodHandle} instead of
+ * the ultimate return type. The returned method handle, in turn,
+ * is required to have exactly the given final method type.
@@ -5278,44 +4912,44 @@ new file mode 100644
+ * <blockquote><pre>
+ * signature V(A[pos]..., B...);
+ * signature T(A[pos]..., V, B...);
-+ * T target(A... a, V, B... b);
-+ * U checker(A..., B...);
++ * T target(A... a, V v, B... b);
++ * V combiner(A..., B...);
+ * T adapter(A... a, B... b) {
-+ * V v = checker(a..., b...);
++ * V v = combiner(a..., b...);
+ * return target(a..., v, b...);
+ * }
+ * </pre></blockquote>
-+ * @param target the method handle to invoke after arguments are checked
-+ * @param checker method handle to call initially on the incoming arguments
-+ * @param pos where the return value of {@code checker} is to
++ * @param target the method handle to invoke after arguments are combined
++ * @param combiner method handle to call initially on the incoming arguments
++ * @param pos where the return value of {@code combiner} is to
+ * be inserted as an argument to {@code target}
+ * @return method handle which incorporates the specified dispatch logic
-+ * @throws IllegalArgumentException if {@code checker} does not itself
++ * @throws IllegalArgumentException if {@code combiner} does not itself
+ * return either void or the {@code pos}-th argument of {@code target},
+ * or does not have the same argument types as {@code target}
+ * (minus the inserted argument)
+ */
+ public static
-+ MethodHandle checkArguments(MethodHandle target, MethodHandle checker, int pos) {
++ MethodHandle combineArguments(MethodHandle target, MethodHandle combiner, int pos) {
+ MethodType mhType = target.type();
-+ Class<?> checkType = checker.type().returnType();
++ Class<?> combinType = combiner.type().returnType();
+ MethodType incomingArgs;
+ if (pos < 0) {
-+ // No inserted argument; target & checker must have same argument types.
++ // No inserted argument; target & combiner must have same argument types.
+ incomingArgs = mhType;
-+ if (!incomingArgs.changeReturnType(checkType).equals(checker.type()))
-+ throw newIllegalArgumentException("target and checker types do not match");
++ if (!incomingArgs.changeReturnType(combinType).equals(combiner.type()))
++ throw newIllegalArgumentException("target and combiner types do not match");
+ } else {
+ // Inserted argument.
+ if (pos >= mhType.parameterCount()
-+ || mhType.parameterType(pos) != checkType)
-+ throw newIllegalArgumentException("inserted checker argument does not match target");
-+ incomingArgs = mhType.deleteParameterType(pos);
-+ }
-+ if (!incomingArgs.changeReturnType(checkType).equals(checker.type())) {
-+ throw newIllegalArgumentException("target and checker types do not match");
-+ }
-+ return MethodHandleImpl.checkArguments(IMPL_TOKEN, target, checker, pos);
++ || mhType.parameterType(pos) != combinType)
++ throw newIllegalArgumentException("inserted combiner argument does not match target");
++ incomingArgs = mhType.dropParameterType(pos);
++ }
++ if (!incomingArgs.changeReturnType(combinType).equals(combiner.type())) {
++ throw newIllegalArgumentException("target and combiner types do not match");
++ }
++ return MethodHandleImpl.combineArguments(IMPL_TOKEN, target, combiner, pos);
+ }
+
+ /// standard method handles
@@ -5369,7 +5003,7 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/share/classes/java/dyn/MethodType.java
-@@ -0,0 +1,529 @@
+@@ -0,0 +1,536 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -5402,7 +5036,7 @@ new file mode 100644
+import java.util.HashMap;
+import java.util.List;
+import impl.java.dyn.*;
-+import impl.java.dyn.util.Signatures;
++import impl.java.dyn.util.BytecodeSignature;
+import static impl.java.dyn.MemberName.newIllegalArgumentException;
+
+/**
@@ -5538,6 +5172,12 @@ new file mode 100644
+ return mt1;
+ }
+
++ // Entry point from JVM. TODO: Change the name & signature.
++ private static MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes,
++ boolean ignore1, boolean ignore2) {
++ return makeImpl(rtype, ptypes, true);
++ }
++
+ private static final MethodType[] objectOnlyTypes = new MethodType[20];
+
+ /**
@@ -5607,7 +5247,7 @@ new file mode 100644
+ * @param num the index (zero-based) of the parameter type to remove
+ * @return the same type, except with the selected parameter removed
+ */
-+ public MethodType deleteParameterType(int num) {
++ public MethodType dropParameterType(int num) {
+ int len = ptypes.length;
+ Class<?>[] nptypes;
+ if (num == 0) {
@@ -5792,6 +5432,7 @@ new file mode 100644
+ sb.append("(");
+ for (int i = 0; i < ptypes.length; i++) {
+ if (i > 0) sb.append(",");
++ putName(sb, ptypes[i]);
+ }
+ sb.append(")");
+ putName(sb, rtype);
@@ -5882,7 +5523,7 @@ new file mode 100644
+ public static MethodType fromBytecodeString(String bytecodeSignature, ClassLoader loader)
+ throws IllegalArgumentException, TypeNotPresentException
+ {
-+ List<Class<?>> types = Signatures.parseMethod(bytecodeSignature, loader);
++ List<Class<?>> types = BytecodeSignature.parseMethod(bytecodeSignature, loader);
+ Class<?> rtype = types.remove(types.size() - 1);
+ Class<?>[] ptypes = types.toArray(NO_PTYPES);
+ return makeImpl(rtype, ptypes, true);
@@ -5896,7 +5537,7 @@ new file mode 100644
+ * @return the bytecode signature representation
+ */
+ public String toBytecodeString() {
-+ return Signatures.unparse(this);
++ return BytecodeSignature.unparse(this);
+ }
+}
diff --git a/src/share/classes/java/dyn/MethodTypeForm.java b/src/share/classes/java/dyn/MethodTypeForm.java
--- a/series Sat Mar 21 23:59:57 2009 -0700
+++ b/series Fri Apr 03 02:34:37 2009 -0700
@@ -1,6 +1,6 @@
-# base = d8eb2738db6b in http://hg.openjdk.java.net/jdk7/hotspot/jdk
-anonk.patch #-/anonk #+d8eb2738db6b #+jdk7-b44
-meth.patch #-/meth #+d8eb2738db6b #+jdk7-b44
-indy.patch #-/indy #+jdk7-b34 #-testable
+# base = 940223097cb1 in http://hg.openjdk.java.net/bsd-port/bsd-port/jdk
+anonk.patch #-/anonk #+940223097cb1
+meth.patch #-/meth #+940223097cb1
+indy.patch #-/indy #+940223097cb1
#inti.patch #-/inti #+jdk7-b34 #-buildable
callcc.patch #-/callcc #+jdk7-b30 #-testable