--- a/anonk.proj.patch Wed Dec 24 19:53:52 2008 -0800
+++ b/anonk.proj.patch Mon Jan 19 23:50:00 2009 -0800
@@ -1,7 +1,7 @@ diff --git a/src/share/projects/Anonymou
-diff --git a/src/share/projects/AnonymousClass/build.xml b/src/share/projects/AnonymousClass/build.xml
+diff --git a/src/share/projects/anonk/build.xml b/src/share/projects/anonk/build.xml
new file mode 100644
--- /dev/null
-+++ b/src/share/projects/AnonymousClass/build.xml
++++ b/src/share/projects/anonk/build.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- You may freely edit this file. See commented blocks below for -->
@@ -72,10 +72,10 @@ new file mode 100644
+
+ -->
+</project>
-diff --git a/src/share/projects/AnonymousClass/nbproject/project.properties b/src/share/projects/AnonymousClass/nbproject/project.properties
+diff --git a/src/share/projects/anonk/nbproject/project.properties b/src/share/projects/anonk/nbproject/project.properties
new file mode 100644
--- /dev/null
-+++ b/src/share/projects/AnonymousClass/nbproject/project.properties
++++ b/src/share/projects/anonk/nbproject/project.properties
@@ -0,0 +1,63 @@
+application.title=AnonymousClass
+application.vendor=jrose
@@ -140,10 +140,10 @@ new file mode 100644
+file.reference.davinci.sources.jdk=${file.reference.projects}/davinci/sources/jdk
+src.src.dir=src
+test.src.dir=test
-diff --git a/src/share/projects/AnonymousClass/nbproject/project.xml b/src/share/projects/AnonymousClass/nbproject/project.xml
+diff --git a/src/share/projects/anonk/nbproject/project.xml b/src/share/projects/anonk/nbproject/project.xml
new file mode 100644
--- /dev/null
-+++ b/src/share/projects/AnonymousClass/nbproject/project.xml
++++ b/src/share/projects/anonk/nbproject/project.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://www.netbeans.org/ns/project/1">
@@ -161,10 +161,2783 @@ new file mode 100644
+ </data>
+ </configuration>
+</project>
-diff --git a/src/share/projects/AnonymousClass/test/jdk/java/dyn/AnonymousTest.java b/src/share/projects/AnonymousClass/test/jdk/java/dyn/AnonymousTest.java
+diff --git a/src/share/projects/anonk/src/java/dyn/AnonymousClassLoader.java b/src/share/projects/anonk/src/java/dyn/AnonymousClassLoader.java
new file mode 100644
--- /dev/null
-+++ b/src/share/projects/AnonymousClass/test/jdk/java/dyn/AnonymousTest.java
++++ b/src/share/projects/anonk/src/java/dyn/AnonymousClassLoader.java
+@@ -0,0 +1,297 @@
++/*
++ * 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;
++
++import java.io.IOException;
++import java.io.InputStream;
++import java.lang.reflect.InvocationTargetException;
++import java.lang.reflect.Method;
++
++/**
++ * Anonymous class loader. Will load any valid classfile, producing
++ * a {@link Class} metaobject, without installing that class in the
++ * system dictionary. Therefore, {@link Class#forName(String)} will never
++ * produce a reference to an anonymous class.
++ * <p>
++ * The access permissions of the anonymous class are borrowed from
++ * a <em>host class</em>. The new class behaves as if it were an
++ * inner class of the host class. It can access the host's private
++ * members, if the creator of the class loader has permission to
++ * do so (or to create accessible reflective objects).
++ * <p>
++ * When the anonymous class is loaded, elements of its constant pool
++ * can be patched to new values. This provides a hook to pre-resolve
++ * named classes in the constant pool to other classes, including
++ * anonymous ones. Also, string constants can be pre-resolved to
++ * any reference. (The verifier treats non-string, non-class reference
++ * constants as plain objects.)
++ * <p>
++ * Why include the patching function? It makes some use cases much easier.
++ * Second, the constant pool needed some internal patching anyway,
++ * to anonymize the loaded class itself. Finally, if you are going
++ * to use this seriously, you'll want to build anonymous classes
++ * on top of pre-existing anonymous classes, and that requires patching.
++ *
++ * <p>%%% TO-DO:
++ * <ul>
++ * <li>needs better documentation</li>
++ * <li>needs more security work (for safe delegation)</li>
++ * <li>needs a clearer story about error processing</li>
++ * <li>patch member references also (use ';' as delimiter char)</li>
++ * <li>patch method references to (conforming) method handles</li>
++ * </ul>
++ *
++ * @author jrose
++ * @author Remi Forax
++ * @see <a href="http://blogs.sun.com/jrose/entry/anonymous_classes_in_the_vm">
++ * http://blogs.sun.com/jrose/entry/anonymous_classes_in_the_vm</a>
++ */
++
++public class AnonymousClassLoader {
++ final Class<?> hostClass;
++
++ // Note: Do not refactor the calls to checkHostClass unless you
++ // also adjust this constant:
++ private static int CHC_CALLERS = 3;
++
++ public AnonymousClassLoader() {
++ this.hostClass = checkHostClass(null);
++ }
++ public AnonymousClassLoader(Class<?> hostClass) {
++ this.hostClass = checkHostClass(hostClass);
++ }
++
++ private static Class<?> getTopLevelClass(Class<?> clazz) {
++ for(Class<?> outer = clazz.getDeclaringClass(); outer != null;
++ outer = outer.getDeclaringClass()) {
++ clazz = outer;
++ }
++ return clazz;
++ }
++
++ private static Class<?> checkHostClass(Class<?> hostClass) {
++ // called only from the constructor
++ // does a context-sensitive check on caller class
++ // CC[0..3] = {Reflection, this.checkHostClass, this.<init>, caller}
++ Class<?> caller = sun.reflect.Reflection.getCallerClass(CHC_CALLERS);
++
++ if (caller == null) {
++ // called from the JVM directly
++ if (hostClass == null)
++ return AnonymousClassLoader.class; // anything central will do
++ return hostClass;
++ }
++
++ if (hostClass == null)
++ hostClass = caller; // default value is caller itself
++
++ // anonymous class will access hostClass on behalf of caller
++ Class<?> callee = hostClass;
++
++ if (caller == callee)
++ // caller can always nominate itself to grant caller's own access rights
++ return hostClass;
++
++ // normalize caller and callee to their top-level classes:
++ caller = getTopLevelClass(caller);
++ callee = getTopLevelClass(callee);
++ if (caller == callee)
++ return caller;
++
++ ClassLoader callerCL = caller.getClassLoader();
++ if (callerCL == null) {
++ // caller is trusted code, so accept the proposed hostClass
++ return hostClass;
++ }
++
++ // %%% should do something with doPrivileged, because trusted
++ // code should have a way to execute on behalf of
++ // partially-trusted clients
++
++ // Does the caller have the right to access the private
++ // members of the callee? If not, raise an error.
++ final int ACC_PRIVATE = 2;
++ try {
++ sun.reflect.Reflection.ensureMemberAccess(caller, callee, null, ACC_PRIVATE);
++ } catch (IllegalAccessException ee) {
++ throw new IllegalArgumentException(ee);
++ }
++
++ return hostClass;
++ }
++
++ public Class<?> loadClass(byte[] classFile) {
++ if (defineAnonymousClass == null) {
++ // no JVM support; try to fake an approximation
++ try {
++ return fakeLoadClass(new ConstantPoolParser(classFile).createPatch());
++ } catch (InvalidConstantPoolFormatException ee) {
++ throw new IllegalArgumentException(ee);
++ }
++ }
++ return loadClass(classFile, null);
++ }
++
++ public Class<?> loadClass(ConstantPoolPatch classPatch) {
++ if (defineAnonymousClass == null) {
++ // no JVM support; try to fake an approximation
++ return fakeLoadClass(classPatch);
++ }
++ Object[] patches = classPatch.patchArray;
++ // Convert class names (this late in the game)
++ // to use slash '/' instead of dot '.'.
++ // Java likes dots, but the JVM likes slashes.
++ for (int i = 0; i < patches.length; i++) {
++ Object value = patches[i];
++ if (value != null) {
++ byte tag = classPatch.getTag(i);
++ switch (tag) {
++ case ConstantPoolVisitor.CONSTANT_Class:
++ if (value instanceof String) {
++ if (patches == classPatch.patchArray)
++ patches = patches.clone();
++ patches[i] = ((String)value).replace('.', '/');
++ }
++ break;
++ case ConstantPoolVisitor.CONSTANT_Fieldref:
++ case ConstantPoolVisitor.CONSTANT_Methodref:
++ case ConstantPoolVisitor.CONSTANT_InterfaceMethodref:
++ case ConstantPoolVisitor.CONSTANT_NameAndType:
++ // When/if the JVM supports these patches,
++ // we'll probably need to reformat them also.
++ // Meanwhile, let the class loader create the error.
++ break;
++ }
++ }
++ }
++ return loadClass(classPatch.outer.classFile, classPatch.patchArray);
++ }
++
++ private Class<?> loadClass(byte[] classFile, Object[] patchArray) {
++ try {
++ return (Class<?>)
++ defineAnonymousClass.invoke(unsafe,
++ hostClass, classFile, patchArray);
++ } catch (Exception ex) {
++ throwReflectedException(ex);
++ throw new RuntimeException("error loading into "+hostClass, ex);
++ }
++ }
++
++ private static void throwReflectedException(Exception ex) {
++ if (ex instanceof InvocationTargetException) {
++ Throwable tex = ((InvocationTargetException)ex).getTargetException();
++ if (tex instanceof Error)
++ throw (Error) tex;
++ ex = (Exception) tex;
++ }
++ if (ex instanceof RuntimeException) {
++ throw (RuntimeException) ex;
++ }
++ }
++
++ private Class<?> fakeLoadClass(ConstantPoolPatch classPatch) {
++ // Implementation:
++ // 1. Make up a new name nobody has used yet.
++ // 2. Inspect the tail-header of the class to find the this_class index.
++ // 3. Patch the CONSTANT_Class for this_class to the new name.
++ // 4. Add other CP entries required by (e.g.) string patches.
++ // 5. Flatten Class constants down to their names, making sure that
++ // the host class loader can pick them up again accurately.
++ // 6. Generate the edited class file bytes.
++ //
++ // Potential limitations:
++ // * The class won't be truly anonymous, and may interfere with others.
++ // * Flattened class constants might not work, because of loader issues.
++ // * Pseudo-string constants will not flatten down to real strings.
++ // * Method handles will (of course) fail to flatten to linkage strings.
++ if (true) throw new UnsupportedOperationException("NYI");
++ Object[] cpArray;
++ try {
++ cpArray = classPatch.getOriginalCP();
++ } catch (InvalidConstantPoolFormatException ex) {
++ throw new RuntimeException(ex);
++ }
++ int thisClassIndex = classPatch.getParser().getThisClassIndex();
++ String thisClassName = (String) cpArray[thisClassIndex];
++ synchronized (AnonymousClassLoader.class) {
++ thisClassName = thisClassName+"\\|"+(++fakeNameCounter);
++ }
++ classPatch.putUTF8(thisClassIndex, thisClassName);
++ byte[] classFile = null;
++ return unsafe.defineClass(null, classFile, 0, classFile.length,
++ hostClass.getClassLoader(),
++ hostClass.getProtectionDomain());
++ }
++ private static int fakeNameCounter = 99999;
++
++ // ignore two warnings on this line:
++ static sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
++ // preceding line requires that this class be on the boot class path
++
++ static private final Method defineAnonymousClass;
++ static {
++ Method dac = null;
++ Class<? extends sun.misc.Unsafe> unsafeClass = unsafe.getClass();
++ try {
++ dac = unsafeClass.getMethod("defineAnonymousClass",
++ Class.class,
++ byte[].class,
++ Object[].class);
++ } catch (Exception ee) {
++ dac = null;
++ }
++ defineAnonymousClass = dac;
++ }
++
++ private static void noJVMSupport() {
++ throw new UnsupportedOperationException("no JVM support for anonymous classes");
++ }
++
++
++ private static native Class<?> loadClassInternal(Class<?> hostClass,
++ byte[] classFile,
++ Object[] patchArray);
++
++ public static byte[] readClassFile(Class<?> templateClass) throws IOException {
++ String templateName = templateClass.getName();
++ int lastDot = templateName.lastIndexOf('.');
++ java.net.URL url = templateClass.getResource(templateName.substring(lastDot+1)+".class");
++ java.net.URLConnection connection = url.openConnection();
++ int contentLength = connection.getContentLength();
++ if (contentLength < 0)
++ throw new IOException("invalid content length "+contentLength);
++
++ byte[] classFile = new byte[contentLength];
++ InputStream tcs = connection.getInputStream();
++ for (int fill = 0, nr; fill < classFile.length; fill += nr) {
++ nr = tcs.read(classFile, fill, classFile.length - fill);
++ if (nr < 0)
++ throw new IOException("premature end of file");
++ }
++ return classFile;
++ }
++}
+diff --git a/src/share/projects/anonk/src/java/dyn/ConstantPoolParser.java b/src/share/projects/anonk/src/java/dyn/ConstantPoolParser.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/projects/anonk/src/java/dyn/ConstantPoolParser.java
+@@ -0,0 +1,368 @@
++/*
++ * 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;
++
++import java.io.IOException;
++import java.io.OutputStream;
++import java.nio.BufferUnderflowException;
++import java.nio.ByteBuffer;
++
++import static java.dyn.ConstantPoolVisitor.*;
++
++/** A constant pool parser.
++ */
++public class ConstantPoolParser {
++ final byte[] classFile;
++ final byte[] tags;
++ final char[] firstHeader; // maghi, maglo, minor, major, cplen
++
++ // these are filled in on first parse:
++ int endOffset;
++ char[] secondHeader; // flags, this_class, super_class, intlen
++
++ // used to decode UTF8 array
++ private char[] charArray = new char[80];
++
++ /** Creates a constant pool parser.
++ * @param classFile an array of bytes containing a class.
++ * @throws InvalidConstantPoolFormatException if the header of the class has errors.
++ */
++ public ConstantPoolParser(byte[] classFile) throws InvalidConstantPoolFormatException {
++ this.classFile = classFile;
++ this.firstHeader = parseHeader(classFile);
++ this.tags = new byte[firstHeader[4]];
++ }
++
++ /** Create a constant pool parser by loading the bytecodes of the
++ * class taken as argument.
++ *
++ * @param templateClass the class to parse.
++ *
++ * @throws IOException raised if an I/O occurs when loading
++ * the bytecode of the template class.
++ * @throws InvalidConstantPoolFormatException if the header of the class has errors.
++ *
++ * @see #ConstantPoolParser(byte[])
++ * @see AnonymousClassLoader#readClassFile(Class)
++ */
++ public ConstantPoolParser(Class<?> templateClass) throws IOException, InvalidConstantPoolFormatException {
++ this(AnonymousClassLoader.readClassFile(templateClass));
++ }
++
++ /** Creates an empty patch to patch the class file
++ * used by the current parser.
++ * @return a new class patch.
++ */
++ public ConstantPoolPatch createPatch() {
++ return new ConstantPoolPatch(this);
++ }
++
++ /** Report the tag of the indicated CP entry.
++ * @param index
++ * @return one of {@link ConstantPoolVisitor#CONSTANT_Utf8}, etc.
++ */
++ public byte getTag(int index) {
++ getEndOffset(); // trigger an exception if we haven't parsed yet
++ return tags[index];
++ }
++
++ /** Report the length of the constant pool. */
++ public int getLength() {
++ return firstHeader[4];
++ }
++
++ /** Report the offset, within the class file, of the start of the constant pool. */
++ public int getStartOffset() {
++ return firstHeader.length * 2;
++ }
++
++ /** Report the offset, within the class file, of the end of the constant pool. */
++ public int getEndOffset() {
++ if (endOffset == 0)
++ throw new IllegalStateException("class file has not yet been parsed");
++ return endOffset;
++ }
++
++ /** Report the CP index of this class's own name. */
++ public int getThisClassIndex() {
++ getEndOffset(); // provoke exception if not yet parsed
++ return secondHeader[1];
++ }
++
++ /** Report the total size of the class file. */
++ public int getTailLength() {
++ return classFile.length - getEndOffset();
++ }
++
++ /** Write the head (header plus constant pool)
++ * of the class file to the indicated stream.
++ */
++ public void writeHead(OutputStream out) throws IOException {
++ out.write(classFile, 0, getEndOffset());
++ }
++
++ /** Write the head (header plus constant pool)
++ * of the class file to the indicated stream,
++ * incorporating the non-null entries of the given array
++ * as patches.
++ */
++ void writePatchedHead(OutputStream out, Object[] patchArray) {
++ // this will be useful to partially emulate the class loader on old JVMs
++ throw new UnsupportedOperationException("Not yet implemented");
++ }
++
++ /** Write the tail (everything after the constant pool)
++ * of the class file to the indicated stream.
++ */
++ public void writeTail(OutputStream out) throws IOException {
++ out.write(classFile, getEndOffset(), getTailLength());
++ }
++
++ private static char[] parseHeader(byte[] classFile) throws InvalidConstantPoolFormatException {
++ char[] result = new char[5];
++ ByteBuffer buffer = ByteBuffer.wrap(classFile);
++ for (int i = 0; i < result.length; i++)
++ result[i] = (char) getUnsignedShort(buffer);
++ int magic = result[0] << 16 | result[1] << 0;
++ if (magic != 0xCAFEBABE)
++ throw new InvalidConstantPoolFormatException("invalid magic number "+magic);
++ // skip major, minor version
++ int len = result[4];
++ if (len < 1)
++ throw new InvalidConstantPoolFormatException("constant pool length < 1");
++ return result;
++ }
++
++ /** Parse the constant pool of the class
++ * calling a method visit* each time a constant pool entry is parsed.
++ *
++ * The order of the calls to visit* is not guaranteed to be the same
++ * than the order of the constant pool entry in the bytecode array.
++ *
++ * @param visitor
++ * @throws InvalidConstantPoolFormatException
++ */
++ public void parse(ConstantPoolVisitor visitor) throws InvalidConstantPoolFormatException {
++ ByteBuffer buffer = ByteBuffer.wrap(classFile);
++ buffer.position(getStartOffset()); //skip header
++
++ Object[] values = new Object[getLength()];
++ try {
++ parseConstantPool(buffer, values, visitor);
++ } catch(BufferUnderflowException e) {
++ throw new InvalidConstantPoolFormatException(e);
++ }
++ if (endOffset == 0) {
++ endOffset = buffer.position();
++ secondHeader = new char[4];
++ for (int i = 0; i < secondHeader.length; i++) {
++ secondHeader[i] = (char) getUnsignedShort(buffer);
++ }
++ }
++ resolveConstantPool(values, visitor);
++ }
++
++ private char[] getCharArray(int utfLength) {
++ if (utfLength <= charArray.length)
++ return charArray;
++ return charArray = new char[utfLength];
++ }
++
++ private void parseConstantPool(ByteBuffer buffer, Object[] values, ConstantPoolVisitor visitor) throws InvalidConstantPoolFormatException {
++ for (int i = 1; i < tags.length; ) {
++ byte tag = (byte) getUnsignedByte(buffer);
++ assert(tags[i] == 0 || tags[i] == tag);
++ tags[i] = tag;
++ switch (tag) {
++ case CONSTANT_Utf8:
++ int utfLen = getUnsignedShort(buffer);
++ String value = getUTF8(buffer, utfLen, getCharArray(utfLen));
++ visitor.visitUTF8(i, CONSTANT_Utf8, value);
++ tags[i] = tag;
++ values[i++] = value;
++ break;
++ case CONSTANT_Integer:
++ visitor.visitConstantValue(i, tag, buffer.getInt());
++ i++;
++ break;
++ case CONSTANT_Float:
++ visitor.visitConstantValue(i, tag, buffer.getFloat());
++ i++;
++ break;
++ case CONSTANT_Long:
++ visitor.visitConstantValue(i, tag, buffer.getLong());
++ i+=2;
++ break;
++ case CONSTANT_Double:
++ visitor.visitConstantValue(i, tag, buffer.getDouble());
++ i+=2;
++ break;
++
++ case CONSTANT_Class: // fall through:
++ case CONSTANT_String:
++ tags[i] = tag;
++ values[i++] = new int[] { getUnsignedShort(buffer) };
++ break;
++
++ case CONSTANT_Fieldref: // fall through:
++ case CONSTANT_Methodref: // fall through:
++ case CONSTANT_InterfaceMethodref: // fall through:
++ case CONSTANT_NameAndType:
++ tags[i] = tag;
++ values[i++] = new int[] { getUnsignedShort(buffer), getUnsignedShort(buffer) };
++ break;
++ default:
++ throw new AssertionError("invalid constant "+tag);
++ }
++ }
++ }
++
++ private void resolveConstantPool(Object[] values, ConstantPoolVisitor visitor) {
++ // clean out the int[] values, which are temporary
++ for (int beg = 1, end = values.length-1, beg2, end2;
++ beg <= end;
++ beg = beg2, end = end2) {
++ beg2 = end; end2 = beg-1;
++ //System.out.println("CP resolve pass: "+beg+".."+end);
++ for (int i = beg; i <= end; i++) {
++ Object value = values[i];
++ if (!(value instanceof int[]))
++ continue;
++ int[] array = (int[]) value;
++ byte tag = tags[i];
++ switch (tag) {
++ case CONSTANT_String:
++ String stringBody = (String) values[array[0]];
++ visitor.visitConstantString(i, tag, stringBody, array[0]);
++ values[i] = null;
++ break;
++ case CONSTANT_Class: {
++ String className = (String) values[array[0]];
++ // use the external form favored by Class.forName:
++ className = className.replace('/', '.');
++ visitor.visitConstantString(i, tag, className, array[0]);
++ values[i] = className;
++ break;
++ }
++ case CONSTANT_NameAndType: {
++ String memberName = (String) values[array[0]];
++ String signature = (String) values[array[1]];
++ visitor.visitDescriptor(i, tag, memberName, signature,
++ array[0], array[1]);
++ values[i] = new String[] {memberName, signature};
++ break;
++ }
++ case CONSTANT_Fieldref: // fall through:
++ case CONSTANT_Methodref: // fall through:
++ case CONSTANT_InterfaceMethodref: {
++ Object className = values[array[0]];
++ Object nameAndType = values[array[1]];
++ if (!(className instanceof String) ||
++ !(nameAndType instanceof String[])) {
++ // one more pass is needed
++ if (beg2 > i) beg2 = i;
++ if (end2 < i) end2 = i;
++ continue;
++ }
++ String[] nameAndTypeArray = (String[]) nameAndType;
++ visitor.visitMemberRef(i, tag,
++ (String)className,
++ nameAndTypeArray[0],
++ nameAndTypeArray[1],
++ array[0], array[1]);
++ values[i] = null;
++ }
++ break;
++ default:
++ continue;
++ }
++ }
++ }
++ }
++
++ private static int getUnsignedByte(ByteBuffer buffer) {
++ return buffer.get() & 0xFF;
++ }
++
++ private static int getUnsignedShort(ByteBuffer buffer) {
++ int b1 = getUnsignedByte(buffer);
++ int b2 = getUnsignedByte(buffer);
++ return (b1 << 8) + (b2 << 0);
++ }
++
++ private static String getUTF8(ByteBuffer buffer, int utfLen, char[] charArray) throws InvalidConstantPoolFormatException {
++ int utfLimit = buffer.position() + utfLen;
++ int index = 0;
++ while (buffer.position() < utfLimit) {
++ int c = buffer.get() & 0xff;
++ if (c > 127) {
++ buffer.position(buffer.position() - 1);
++ return getUTF8Extended(buffer, utfLimit, charArray, index);
++ }
++ charArray[index++] = (char)c;
++ }
++ return new String(charArray, 0, index);
++ }
++
++ private static String getUTF8Extended(ByteBuffer buffer, int utfLimit, char[] charArray, int index) throws InvalidConstantPoolFormatException {
++ int c, c2, c3;
++ while (buffer.position() < utfLimit) {
++ c = buffer.get() & 0xff;
++ switch (c >> 4) {
++ case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
++ /* 0xxxxxxx*/
++ charArray[index++] = (char)c;
++ break;
++ case 12: case 13:
++ /* 110x xxxx 10xx xxxx*/
++ c2 = buffer.get();
++ if ((c2 & 0xC0) != 0x80)
++ throw new InvalidConstantPoolFormatException(
++ "malformed input around byte " + buffer.position());
++ charArray[index++] = (char)(((c & 0x1F) << 6) |
++ (c2 & 0x3F));
++ break;
++ case 14:
++ /* 1110 xxxx 10xx xxxx 10xx xxxx */
++ c2 = buffer.get();
++ c3 = buffer.get();
++ if (((c2 & 0xC0) != 0x80) || ((c3 & 0xC0) != 0x80))
++ throw new InvalidConstantPoolFormatException(
++ "malformed input around byte " + (buffer.position()));
++ charArray[index++] = (char)(((c & 0x0F) << 12) |
++ ((c2 & 0x3F) << 6) |
++ ((c3 & 0x3F) << 0));
++ break;
++ default:
++ /* 10xx xxxx, 1111 xxxx */
++ throw new InvalidConstantPoolFormatException(
++ "malformed input around byte " + buffer.position());
++ }
++ }
++ // The number of chars produced may be less than utflen
++ return new String(charArray, 0, index);
++ }
++}
+diff --git a/src/share/projects/anonk/src/java/dyn/ConstantPoolPatch.java b/src/share/projects/anonk/src/java/dyn/ConstantPoolPatch.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/projects/anonk/src/java/dyn/ConstantPoolPatch.java
+@@ -0,0 +1,503 @@
++/*
++ * 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;
++
++import java.io.IOException;
++import java.io.OutputStream;
++import java.util.Arrays;
++import java.util.HashSet;
++import java.util.IdentityHashMap;
++import java.util.Map;
++
++import static java.dyn.ConstantPoolVisitor.*;
++
++/** A class and its patched constant pool.
++ *
++ * This class allow to modify (patch) a constant pool
++ * by changing the value of its entry.
++ * Entry are referenced using index that can be get
++ * by parsing the constant pool using
++ * {@link ConstantPoolParser#parse(ConstantPoolVisitor)}.
++ *
++ * @see ConstantPoolVisitor
++ * @see ConstantPoolParser#createPatch()
++ */
++public class ConstantPoolPatch {
++ final ConstantPoolParser outer;
++ final Object[] patchArray;
++
++ ConstantPoolPatch(ConstantPoolParser outer) {
++ this.outer = outer;
++ this.patchArray = new Object[outer.getLength()];
++ }
++
++ /** Create a {@link ConstantPoolParser} and
++ * a {@link ConstantPoolPatch} in one step.
++ * Equivalent to {@code new ConstantPoolParser(classFile).createPatch()}.
++ *
++ * @param classFile an array of bytes containing a class.
++ * @see #ConstantPoolParser(Class)
++ */
++ public ConstantPoolPatch(byte[] classFile) throws InvalidConstantPoolFormatException {
++ this(new ConstantPoolParser(classFile));
++ }
++
++ /** Create a {@link ConstantPoolParser} and
++ * a {@link ConstantPoolPatch} in one step.
++ * Equivalent to {@code new ConstantPoolParser(templateClass).createPatch()}.
++ *
++ * @param templateClass the class to parse.
++ * @see #ConstantPoolParser(Class)
++ */
++ public ConstantPoolPatch(Class<?> templateClass) throws IOException, InvalidConstantPoolFormatException {
++ this(new ConstantPoolParser(templateClass));
++ }
++
++
++ /** Creates a patch from an existing patch.
++ * All changes are copied from that patch.
++ * @param patch a patch
++ *
++ * @see ConstantPoolParser#createPatch()
++ */
++ public ConstantPoolPatch(ConstantPoolPatch patch) {
++ outer = patch.outer;
++ patchArray = patch.patchArray.clone();
++ }
++
++ /** Which parser built this patch? */
++ public ConstantPoolParser getParser() {
++ return outer;
++ }
++
++ /** Report the tag at the given index in the constant pool. */
++ public byte getTag(int index) {
++ return outer.getTag(index);
++ }
++
++ /** Report the current patch at the given index of the constant pool.
++ * Null means no patch will be made.
++ * To observe the unpatched entry at the given index, use
++ * {@link #getParser()}{@code .}@link ConstantPoolParser#parse(ConstantPoolVisitor)}
++ */
++ public Object getPatch(int index) {
++ Object value = patchArray[index];
++ if (value == null) return null;
++ switch (getTag(index)) {
++ case CONSTANT_Fieldref:
++ case CONSTANT_Methodref:
++ case CONSTANT_InterfaceMethodref:
++ if (value instanceof String)
++ value = stripSemis(2, (String) value);
++ break;
++ case CONSTANT_NameAndType:
++ if (value instanceof String)
++ value = stripSemis(1, (String) value);
++ break;
++ }
++ return value;
++ }
++
++ /** Clear all patches. */
++ public void clear() {
++ Arrays.fill(patchArray, null);
++ }
++
++ /** Clear one patch. */
++ public void clear(int index) {
++ patchArray[index] = null;
++ }
++
++ /** Produce the patches as an array. */
++ public Object[] getPatches() {
++ return patchArray.clone();
++ }
++
++ /** Produce the original constant pool as an array. */
++ public Object[] getOriginalCP() throws InvalidConstantPoolFormatException {
++ return getOriginalCP(0, patchArray.length, -1);
++ }
++
++ /** Walk the constant pool, applying patches using the given map.
++ *
++ * @param utf8Map Utf8 strings to modify, if encountered
++ * @param classMap Classes (or their names) to modify, if encountered
++ * @param valueMap Constant values to modify, if encountered
++ * @param deleteUsedEntries if true, delete map entries that are used
++ */
++ public void putPatches(final Map<String,String> utf8Map,
++ final Map<String,Object> classMap,
++ final Map<Object,Object> valueMap,
++ boolean deleteUsedEntries) throws InvalidConstantPoolFormatException {
++ final HashSet<String> usedUtf8Keys;
++ final HashSet<String> usedClassKeys;
++ final HashSet<Object> usedValueKeys;
++ if (deleteUsedEntries) {
++ usedUtf8Keys = (utf8Map == null) ? null : new HashSet<String>();
++ usedClassKeys = (classMap == null) ? null : new HashSet<String>();
++ usedValueKeys = (valueMap == null) ? null : new HashSet<Object>();
++ } else {
++ usedUtf8Keys = null;
++ usedClassKeys = null;
++ usedValueKeys = null;
++ }
++
++ outer.parse(new ConstantPoolVisitor() {
++
++ @Override
++ public void visitUTF8(int index, byte tag, String utf8) {
++ putUTF8(index, utf8Map.get(utf8));
++ if (usedUtf8Keys != null) usedUtf8Keys.add(utf8);
++ }
++
++ @Override
++ public void visitConstantValue(int index, byte tag, Object value) {
++ putConstantValue(index, tag, valueMap.get(value));
++ if (usedValueKeys != null) usedValueKeys.add(value);
++ }
++
++ @Override
++ public void visitConstantString(int index, byte tag, String name, int nameIndex) {
++ if (tag == CONSTANT_Class) {
++ putConstantValue(index, tag, classMap.get(name));
++ if (usedClassKeys != null) usedClassKeys.add(name);
++ } else {
++ assert(tag == CONSTANT_String);
++ visitConstantValue(index, tag, name);
++ }
++ }
++ });
++ if (usedUtf8Keys != null) utf8Map.keySet().removeAll(usedUtf8Keys);
++ if (usedClassKeys != null) classMap.keySet().removeAll(usedClassKeys);
++ if (usedValueKeys != null) valueMap.keySet().removeAll(usedValueKeys);
++ }
++
++ Object[] getOriginalCP(final int startIndex,
++ final int endIndex,
++ final int tagMask) throws InvalidConstantPoolFormatException {
++ final Object[] cpArray = new Object[endIndex - startIndex];
++ outer.parse(new ConstantPoolVisitor() {
++
++ void show(int index, byte tag, Object value) {
++ if (index < startIndex || index >= endIndex) return;
++ if (((1 << tag) & tagMask) == 0) return;
++ cpArray[index - startIndex] = value;
++ }
++
++ @Override
++ public void visitUTF8(int index, byte tag, String utf8) {
++ show(index, tag, utf8);
++ }
++
++ @Override
++ public void visitConstantValue(int index, byte tag, Object value) {
++ assert(tag != CONSTANT_String);
++ show(index, tag, value);
++ }
++
++ @Override
++ public void visitConstantString(int index, byte tag,
++ String value, int j) {
++ show(index, tag, value);
++ }
++
++ @Override
++ public void visitMemberRef(int index, byte tag,
++ String className, String memberName,
++ String signature,
++ int j, int k) {
++ show(index, tag, new String[]{ className, memberName, signature });
++ }
++
++ @Override
++ public void visitDescriptor(int index, byte tag,
++ String memberName, String signature,
++ int j, int k) {
++ show(index, tag, new String[]{ memberName, signature });
++ }
++ });
++ return cpArray;
++ }
++
++ /** Write the head (header plus constant pool)
++ * of the patched class file to the indicated stream.
++ */
++ void writeHead(OutputStream out) throws IOException {
++ outer.writePatchedHead(out, patchArray);
++ }
++
++ /** Write the tail (everything after the constant pool)
++ * of the patched class file to the indicated stream.
++ */
++ void writeTail(OutputStream out) throws IOException {
++ outer.writeTail(out);
++ }
++
++ private void checkConstantTag(byte tag, Object value) {
++ if (value == null)
++ throw new IllegalArgumentException(
++ "invalid null constant value");
++ if (classForTag(tag) != value.getClass())
++ throw new IllegalArgumentException(
++ "invalid constant value"
++ + (tag == CONSTANT_None ? ""
++ : " for tag "+tagName(tag))
++ + " of class "+value.getClass());
++ }
++
++ private void checkTag(int index, byte putTag) {
++ byte tag = outer.tags[index];
++ if (tag != putTag)
++ throw new IllegalArgumentException(
++ "invalid put operation"
++ + " for " + tagName(putTag)
++ + " at index " + index + " found " + tagName(tag));
++ }
++
++ private void checkTagMask(int index, int tagBitMask) {
++ byte tag = outer.tags[index];
++ int tagBit = ((tag & 0x1F) == tag) ? (1 << tag) : 0;
++ if ((tagBit & tagBitMask) == 0)
++ throw new IllegalArgumentException(
++ "invalid put operation"
++ + " at index " + index + " found " + tagName(tag));
++ }
++
++ private static void checkMemberName(String memberName) {
++ if (memberName.indexOf(';') >= 0)
++ throw new IllegalArgumentException("memberName " + memberName + " contains a ';'");
++ }
++
++ /** Set the entry of the constant pool indexed by index to
++ * a new string.
++ *
++ * @param index an index to a constant pool entry containing a
++ * {@link ConstantPoolVisitor#CONSTANT_Utf8} value.
++ * @param utf8 a string
++ *
++ * @see ConstantPoolVisitor#visitUTF8(int, byte, String)
++ */
++ public void putUTF8(int index, String utf8) {
++ if (utf8 == null) { clear(index); return; }
++ checkTag(index, CONSTANT_Utf8);
++ patchArray[index] = utf8;
++ }
++
++ /** Set the entry of the constant pool indexed by index to
++ * a new value, depending on its dynamic type.
++ *
++ * @param index an index to a constant pool entry containing a
++ * one of the following structures:
++ * {@link ConstantPoolVisitor#CONSTANT_Integer},
++ * {@link ConstantPoolVisitor#CONSTANT_Float},
++ * {@link ConstantPoolVisitor#CONSTANT_Long},
++ * {@link ConstantPoolVisitor#CONSTANT_Double},
++ * {@link ConstantPoolVisitor#CONSTANT_String}, or
++ * {@link ConstantPoolVisitor#CONSTANT_Class}
++ * @param value a boxed int, float, long or double; or a string or class object
++ * @throws IllegalArgumentException if the type of the constant does not
++ * match the constant pool entry type,
++ * as reported by {@link #getTag(int)}
++ *
++ * @see #putConstantValue(int, byte, Object)
++ * @see ConstantPoolVisitor#visitConstantValue(int, byte, Object)
++ * @see ConstantPoolVisitor#visitConstantString(int, byte, String, int)
++ */
++ public void putConstantValue(int index, Object value) {
++ if (value == null) { clear(index); return; }
++ byte tag = tagForConstant(value.getClass());
++ checkConstantTag(tag, value);
++ checkTag(index, tag);
++ patchArray[index] = value;
++ }
++
++ /** Set the entry of the constant pool indexed by index to
++ * a new value.
++ *
++ * @param index an index to a constant pool entry matching the given tag
++ * @param tag one of the following values:
++ * {@link ConstantPoolVisitor#CONSTANT_Integer},
++ * {@link ConstantPoolVisitor#CONSTANT_Float},
++ * {@link ConstantPoolVisitor#CONSTANT_Long},
++ * {@link ConstantPoolVisitor#CONSTANT_Double},
++ * {@link ConstantPoolVisitor#CONSTANT_String}, or
++ * {@link ConstantPoolVisitor#CONSTANT_Class}
++ * @param value a boxed number, string, or class object
++ * @throws IllegalArgumentException if the type of the constant does not
++ * match the constant pool entry type, or if a class name contains
++ * '/' or ';'
++ *
++ * @see #putConstantValue(int, Object)
++ * @see ConstantPoolVisitor#visitConstantValue(int, byte, Object)
++ * @see ConstantPoolVisitor#visitConstantString(int, byte, String, int)
++ */
++ public void putConstantValue(int index, byte tag, Object value) {
++ if (value == null) { clear(index); return; }
++ checkTag(index, tag);
++ if (tag == CONSTANT_Class && value instanceof String) {
++ checkClassName((String) value);
++ } else if (tag == CONSTANT_String) {
++ // the JVM accepts any object as a patch for a string
++ } else {
++ // make sure the incoming value is the right type
++ checkConstantTag(tag, value);
++ }
++ checkTag(index, tag);
++ patchArray[index] = value;
++ }
++
++ /** Set the entry of the constant pool indexed by index to
++ * a new {@link ConstantPoolVisitor#CONSTANT_NameAndType} value.
++ *
++ * @param index an index to a constant pool entry containing a
++ * {@link ConstantPoolVisitor#CONSTANT_NameAndType} value.
++ * @param memberName a memberName
++ * @param signature a signature
++ * @throws IllegalArgumentException if memberName contains the character ';'
++ *
++ * @see ConstantPoolVisitor#visitDescriptor(int, byte, String, String, int, int)
++ */
++ public void putDescriptor(int index, String memberName, String signature) {
++ checkTag(index, CONSTANT_NameAndType);
++ checkMemberName(memberName);
++ patchArray[index] = addSemis(memberName, signature);
++ }
++
++ /** Set the entry of the constant pool indexed by index to
++ * a new {@link ConstantPoolVisitor#CONSTANT_Fieldref},
++ * {@link ConstantPoolVisitor#CONSTANT_Methodref}, or
++ * {@link ConstantPoolVisitor#CONSTANT_InterfaceMethodref} value.
++ *
++ * @param index an index to a constant pool entry containing a member reference
++ * @param className a class name
++ * @param memberName a field or method name
++ * @param signature a field or method signature
++ * @throws IllegalArgumentException if memberName contains the character ';'
++ * or signature is not a correct signature
++ *
++ * @see ConstantPoolVisitor#visitMemberRef(int, byte, String, String, String, int, int)
++ */
++ public void putMemberRef(int index, byte tag,
++ String className, String memberName, String signature) {
++ checkTagMask(tag, CONSTANT_MemberRef_MASK);
++ checkTag(index, tag);
++ checkClassName(className);
++ checkMemberName(memberName);
++ if (signature.startsWith("(") == (tag == CONSTANT_Fieldref))
++ throw new IllegalArgumentException("bad signature: "+signature);
++ patchArray[index] = addSemis(className, memberName, signature);
++ }
++
++ static private final int CONSTANT_MemberRef_MASK =
++ CONSTANT_Fieldref
++ | CONSTANT_Methodref
++ | CONSTANT_InterfaceMethodref;
++
++ private static final Map<Class<?>, Byte> CONSTANT_VALUE_CLASS_TAG
++ = new IdentityHashMap<Class<?>, Byte>();
++ private static final Class[] CONSTANT_VALUE_CLASS = new Class[16];
++ static {
++ Object[][] values = {
++ {Integer.class, CONSTANT_Integer},
++ {Long.class, CONSTANT_Long},
++ {Float.class, CONSTANT_Float},
++ {Double.class, CONSTANT_Double},
++ {String.class, CONSTANT_String},
++ {Class.class, CONSTANT_Class}
++ };
++ for (Object[] value : values) {
++ Class<?> cls = (Class<?>)value[0];
++ Byte tag = (Byte) value[1];
++ CONSTANT_VALUE_CLASS_TAG.put(cls, tag);
++ CONSTANT_VALUE_CLASS[(byte)tag] = cls;
++ }
++ }
++
++ static Class<?> classForTag(byte tag) {
++ if ((tag & 0xFF) >= CONSTANT_VALUE_CLASS.length)
++ return null;
++ return CONSTANT_VALUE_CLASS[tag];
++ }
++
++ static byte tagForConstant(Class<?> cls) {
++ Byte tag = CONSTANT_VALUE_CLASS_TAG.get(cls);
++ return (tag == null) ? CONSTANT_None : (byte)tag;
++ }
++
++ private static void checkClassName(String className) {
++ if (className.indexOf('/') >= 0 || className.indexOf(';') >= 0)
++ throw new IllegalArgumentException("invalid class name " + className);
++ }
++
++ static String addSemis(String name, String... names) {
++ StringBuilder buf = new StringBuilder(name.length() * 5);
++ buf.append(name);
++ for (String name2 : names) {
++ buf.append(';').append(name2);
++ }
++ String res = buf.toString();
++ assert(stripSemis(names.length, res)[0].equals(name));
++ assert(stripSemis(names.length, res)[1].equals(names[0]));
++ assert(names.length == 1 ||
++ stripSemis(names.length, res)[2].equals(names[1]));
++ return res;
++ }
++
++ static String[] stripSemis(int count, String string) {
++ String[] res = new String[count+1];
++ int pos = 0;
++ for (int i = 0; i < count; i++) {
++ int pos2 = string.indexOf(';', pos);
++ if (pos2 < 0) pos2 = string.length(); // yuck
++ res[i] = string.substring(pos, pos2);
++ pos = pos2;
++ }
++ res[count] = string.substring(pos);
++ return res;
++ }
++
++ public String toString() {
++ StringBuilder buf = new StringBuilder(this.getClass().getName());
++ buf.append("{");
++ Object[] origCP = null;
++ for (int i = 0; i < patchArray.length; i++) {
++ if (patchArray[i] == null) continue;
++ if (origCP != null) {
++ buf.append(", ");
++ } else {
++ try {
++ origCP = getOriginalCP();
++ } catch (InvalidConstantPoolFormatException ee) {
++ origCP = new Object[0];
++ }
++ }
++ Object orig = (i < origCP.length) ? origCP[i] : "?";
++ buf.append(orig).append("=").append(patchArray[i]);
++ }
++ buf.append("}");
++ return buf.toString();
++ }
++}
+diff --git a/src/share/projects/anonk/src/java/dyn/ConstantPoolVisitor.java b/src/share/projects/anonk/src/java/dyn/ConstantPoolVisitor.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/projects/anonk/src/java/dyn/ConstantPoolVisitor.java
+@@ -0,0 +1,192 @@
++/*
++ * 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;
++
++/**
++ * A visitor called by {@link ConstantPoolParser#parse(ConstantPoolVisitor)}
++ * when a constant pool entry is parsed.
++ * <p>
++ * A visit* method is called when a constant pool entry is parsed.
++ * The first argument is always the constant pool index.
++ * The second argument is always the constant pool tag,
++ * even for methods like {@link #visitUTF8(int, byte, String)} which only apply to one tag.
++ * String arguments refer to Utf8 or NameAndType entries declared elsewhere,
++ * and are always accompanied by the indexes of those entries.
++ * <p>
++ * The order of the calls to the visit* methods is not necessarily related
++ * to the order of the entries in the constant pool.
++ * If one entry has a reference to another entry, the latter (lower-level)
++ * entry will be visited first.
++ * <p>
++ * The following table shows the relation between constant pool entry
++ * types and the corresponding visit* methods:
++ *
++ * <table border=1 cellpadding=5 summary="constant pool visitor methods">
++ * <tr><th>Tag(s)</th><th>Method</th></tr>
++ * <tr>
++ * <td>{@link #CONSTANT_Utf8}</td>
++ * <td>{@link #visitUTF8(int, byte, String)}</td>
++ * </tr><tr>
++ * <td>{@link #CONSTANT_Integer}, {@link #CONSTANT_Float},
++ * {@link #CONSTANT_Long}, {@link #CONSTANT_Double}</td>
++ * <td>{@link #visitConstantValue(int, byte, Object)}</td>
++ * </tr><tr>
++ * <td>{@link #CONSTANT_String}, {@link #CONSTANT_Class}</td>
++ * <td>{@link #visitConstantString(int, byte, String, int)}</td>
++ * </tr><tr>
++ * <td>{@link #CONSTANT_NameAndType}</td>
++ * <td>{@link #visitDescriptor(int, byte, String, String, int, int)}</td>
++ * </tr><tr>
++ * <td>{@link #CONSTANT_Fieldref},
++ * {@link #CONSTANT_Methodref},
++ * {@link #CONSTANT_InterfaceMethodref}</td>
++ * <td>{@link #visitMemberRef(int, byte, String, String, String, int, int)}</td>
++ * </tr>
++ * </table>
++ *
++ * @see ConstantPoolPatch
++ * @author Remi Forax
++ * @author jrose
++ */
++public class ConstantPoolVisitor {
++ /** Called each time an UTF8 constant pool entry is found.
++ * @param index the constant pool index
++ * @param tag always {@link #CONSTANT_Utf8}
++ * @param utf8 string encoded in modified UTF-8 format passed as a {@code String}
++ *
++ * @see ConstantPoolPatch#putUTF8(int, String)
++ */
++ public void visitUTF8(int index, byte tag, String utf8) {
++ // do nothing
++ }
++
++ /** Called for each constant pool entry that encodes an integer,
++ * a float, a long, or a double.
++ * Constant strings and classes are not managed by this method but
++ * by {@link #visitConstantString(int, byte, String, int)}.
++ *
++ * @param index the constant pool index
++ * @param tag one of {@link #CONSTANT_Integer},
++ * {@link #CONSTANT_Float},
++ * {@link #CONSTANT_Long},
++ * or {@link #CONSTANT_Double}
++ * @param value encoded value
++ *
++ * @see ConstantPoolPatch#putConstantValue(int, Object)
++ */
++ public void visitConstantValue(int index, byte tag, Object value) {
++ // do nothing
++ }
++
++ /** Called for each constant pool entry that encodes a string or a class.
++ * @param index the constant pool index
++ * @param tag one of {@link #CONSTANT_String},
++ * {@link #CONSTANT_Class},
++ * @param name string body or class name (using dot separator)
++ * @param nameIndex the index of the Utf8 string for the name
++ *
++ * @see ConstantPoolPatch#putConstantValue(int, byte, Object)
++ */
++ public void visitConstantString(int index, byte tag,
++ String name, int nameIndex) {
++ // do nothing
++ }
++
++ /** Called for each constant pool entry that encodes a name and type.
++ * @param index the constant pool index
++ * @param tag always {@link #CONSTANT_NameAndType}
++ * @param memberName a field or method name
++ * @param signature the member signature
++ * @param memberNameIndex index of the Utf8 string for the member name
++ * @param signatureIndex index of the Utf8 string for the signature
++ *
++ * @see ConstantPoolPatch#putDescriptor(int, String, String)
++ */
++ public void visitDescriptor(int index, byte tag,
++ String memberName, String signature,
++ int memberNameIndex, int signatureIndex) {
++ // do nothing
++ }
++
++ /** Called for each constant pool entry that encodes a field or method.
++ * @param index the constant pool index
++ * @param tag one of {@link #CONSTANT_Fieldref},
++ * or {@link #CONSTANT_Methodref},
++ * or {@link #CONSTANT_InterfaceMethodref}
++ * @param className the class name (using dot separator)
++ * @param memberName name of the field or method
++ * @param signature the field or method signature
++ * @param classNameIndex index of the Utf8 string for the class name
++ * @param descriptorIndex index of the NameAndType descriptor constant
++ *
++ * @see ConstantPoolPatch#putMemberRef(int, byte, String, String, String)
++ */
++ public void visitMemberRef(int index, byte tag,
++ String className, String memberName, String signature,
++ int classNameIndex, int descriptorIndex) {
++ // do nothing
++ }
++
++ public static final byte
++ CONSTANT_None = 0,
++ CONSTANT_Utf8 = 1,
++ //CONSTANT_Unicode = 2, /* unused */
++ CONSTANT_Integer = 3,
++ CONSTANT_Float = 4,
++ CONSTANT_Long = 5,
++ CONSTANT_Double = 6,
++ CONSTANT_Class = 7,
++ CONSTANT_String = 8,
++ CONSTANT_Fieldref = 9,
++ CONSTANT_Methodref = 10,
++ CONSTANT_InterfaceMethodref = 11,
++ CONSTANT_NameAndType = 12;
++
++ private static String[] TAG_NAMES = {
++ "Empty",
++ "Utf8",
++ null, //"Unicode",
++ "Integer",
++ "Float",
++ "Long",
++ "Double",
++ "Class",
++ "String",
++ "Fieldref",
++ "Methodref",
++ "InterfaceMethodref",
++ "NameAndType"
++ };
++
++ public static String tagName(byte tag) {
++ String name = null;
++ if ((tag & 0xFF) < TAG_NAMES.length)
++ name = TAG_NAMES[tag];
++ if (name == null)
++ name = "Unknown#"+(tag&0xFF);
++ return name;
++ }
++}
+diff --git a/src/share/projects/anonk/src/java/dyn/InvalidConstantPoolFormatException.java b/src/share/projects/anonk/src/java/dyn/InvalidConstantPoolFormatException.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/projects/anonk/src/java/dyn/InvalidConstantPoolFormatException.java
+@@ -0,0 +1,45 @@
++/*
++ * 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;
++
++/** Exception used when there is an error in the constant pool
++ * format.
++ */
++public class InvalidConstantPoolFormatException extends Exception {
++ private static final long serialVersionUID=-6103888330523770949L;
++
++ public InvalidConstantPoolFormatException(String message,Throwable cause) {
++ super(message,cause);
++ }
++
++ public InvalidConstantPoolFormatException(String message) {
++ super(message);
++ }
++
++ public InvalidConstantPoolFormatException(Throwable cause) {
++ super(cause);
++ }
++}
+diff --git a/src/share/projects/anonk/src/sun/misc/Unsafe.java b/src/share/projects/anonk/src/sun/misc/Unsafe.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/projects/anonk/src/sun/misc/Unsafe.java
+@@ -0,0 +1,1008 @@
++/*
++ * Copyright 2000-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 sun.misc;
++
++import java.security.*;
++import java.lang.reflect.*;
++
++
++/**
++ * A collection of methods for performing low-level, unsafe operations.
++ * Although the class and all methods are public, use of this class is
++ * limited because only trusted code can obtain instances of it.
++ *
++ * @author John R. Rose
++ * @see #getUnsafe
++ */
++
++public final class Unsafe {
++
++ private static native void registerNatives();
++ static {
++ registerNatives();
++ try {
++ Class ref = Class.forName("sun.reflect.Reflection");
++ java.lang.reflect.Method rmtf = ref.getDeclaredMethod("registerMethodsToFilter", Class.class, String.class);
++ rmtf.invoke(Unsafe.class, "getUnsafe");
++ } catch (Exception ex) {
++ }
++ }
++
++ private Unsafe() {}
++
++ private static final Unsafe theUnsafe = new Unsafe();
++
++ /**
++ * Provides the caller with the capability of performing unsafe
++ * operations.
++ *
++ * <p> The returned <code>Unsafe</code> object should be carefully guarded
++ * by the caller, since it can be used to read and write data at arbitrary
++ * memory addresses. It must never be passed to untrusted code.
++ *
++ * <p> Most methods in this class are very low-level, and correspond to a
++ * small number of hardware instructions (on typical machines). Compilers
++ * are encouraged to optimize these methods accordingly.
++ *
++ * <p> Here is a suggested idiom for using unsafe operations:
++ *
++ * <blockquote><pre>
++ * class MyTrustedClass {
++ * private static final Unsafe unsafe = Unsafe.getUnsafe();
++ * ...
++ * private long myCountAddress = ...;
++ * public int getCount() { return unsafe.getByte(myCountAddress); }
++ * }
++ * </pre></blockquote>
++ *
++ * (It may assist compilers to make the local variable be
++ * <code>final</code>.)
++ *
++ * @exception SecurityException if a security manager exists and its
++ * <code>checkPropertiesAccess</code> method doesn't allow
++ * access to the system properties.
++ */
++ public static Unsafe getUnsafe() {
++ Class cc = sun.reflect.Reflection.getCallerClass(2);
++ if (cc.getClassLoader() != null)
++ throw new SecurityException("Unsafe");
++ return theUnsafe;
++ }
++
++ /// peek and poke operations
++ /// (compilers should optimize these to memory ops)
++
++ // These work on object fields in the Java heap.
++ // They will not work on elements of packed arrays.
++
++ /**
++ * Fetches a value from a given Java variable.
++ * More specifically, fetches a field or array element within the given
++ * object <code>o</code> at the given offset, or (if <code>o</code> is
++ * null) from the memory address whose numerical value is the given
++ * offset.
++ * <p>
++ * The results are undefined unless one of the following cases is true:
++ * <ul>
++ * <li>The offset was obtained from {@link #objectFieldOffset} on
++ * the {@link java.lang.reflect.Field} of some Java field and the object
++ * referred to by <code>o</code> is of a class compatible with that
++ * field's class.
++ *
++ * <li>The offset and object reference <code>o</code> (either null or
++ * non-null) were both obtained via {@link #staticFieldOffset}
++ * and {@link #staticFieldBase} (respectively) from the
++ * reflective {@link Field} representation of some Java field.
++ *
++ * <li>The object referred to by <code>o</code> is an array, and the offset
++ * is an integer of the form <code>B+N*S</code>, where <code>N</code> is
++ * a valid index into the array, and <code>B</code> and <code>S</code> are
++ * the values obtained by {@link #arrayBaseOffset} and {@link
++ * #arrayIndexScale} (respectively) from the array's class. The value
++ * referred to is the <code>N</code><em>th</em> element of the array.
++ *
++ * </ul>
++ * <p>
++ * If one of the above cases is true, the call references a specific Java
++ * variable (field or array element). However, the results are undefined
++ * if that variable is not in fact of the type returned by this method.
++ * <p>
++ * This method refers to a variable by means of two parameters, and so
++ * it provides (in effect) a <em>double-register</em> addressing mode
++ * for Java variables. When the object reference is null, this method
++ * uses its offset as an absolute address. This is similar in operation
++ * to methods such as {@link #getInt(long)}, which provide (in effect) a
++ * <em>single-register</em> addressing mode for non-Java variables.
++ * However, because Java variables may have a different layout in memory
++ * from non-Java variables, programmers should not assume that these
++ * two addressing modes are ever equivalent. Also, programmers should
++ * remember that offsets from the double-register addressing mode cannot
++ * be portably confused with longs used in the single-register addressing
++ * mode.
++ *
++ * @param o Java heap object in which the variable resides, if any, else
++ * null
++ * @param offset indication of where the variable resides in a Java heap
++ * object, if any, else a memory address locating the variable
++ * statically
++ * @return the value fetched from the indicated Java variable
++ * @throws RuntimeException No defined exceptions are thrown, not even
++ * {@link NullPointerException}
++ */
++ public native int getInt(Object o, long offset);
++
++ /**
++ * Stores a value into a given Java variable.
++ * <p>
++ * The first two parameters are interpreted exactly as with
++ * {@link #getInt(Object, long)} to refer to a specific
++ * Java variable (field or array element). The given value
++ * is stored into that variable.
++ * <p>
++ * The variable must be of the same type as the method
++ * parameter <code>x</code>.
++ *
++ * @param o Java heap object in which the variable resides, if any, else
++ * null
++ * @param offset indication of where the variable resides in a Java heap
++ * object, if any, else a memory address locating the variable
++ * statically
++ * @param x the value to store into the indicated Java variable
++ * @throws RuntimeException No defined exceptions are thrown, not even
++ * {@link NullPointerException}
++ */
++ public native void putInt(Object o, long offset, int x);
++
++ /**
++ * Fetches a reference value from a given Java variable.
++ * @see #getInt(Object, long)
++ */
++ public native Object getObject(Object o, long offset);
++
++ /**
++ * Stores a reference value into a given Java variable.
++ * <p>
++ * Unless the reference <code>x</code> being stored is either null
++ * or matches the field type, the results are undefined.
++ * If the reference <code>o</code> is non-null, car marks or
++ * other store barriers for that object (if the VM requires them)
++ * are updated.
++ * @see #putInt(Object, int, int)
++ */
++ public native void putObject(Object o, long offset, Object x);
++
++ /** @see #getInt(Object, long) */
++ public native boolean getBoolean(Object o, long offset);
++ /** @see #putInt(Object, int, int) */
++ public native void putBoolean(Object o, long offset, boolean x);
++ /** @see #getInt(Object, long) */
++ public native byte getByte(Object o, long offset);
++ /** @see #putInt(Object, int, int) */
++ public native void putByte(Object o, long offset, byte x);
++ /** @see #getInt(Object, long) */
++ public native short getShort(Object o, long offset);
++ /** @see #putInt(Object, int, int) */
++ public native void putShort(Object o, long offset, short x);
++ /** @see #getInt(Object, long) */
++ public native char getChar(Object o, long offset);
++ /** @see #putInt(Object, int, int) */
++ public native void putChar(Object o, long offset, char x);
++ /** @see #getInt(Object, long) */
++ public native long getLong(Object o, long offset);
++ /** @see #putInt(Object, int, int) */
++ public native void putLong(Object o, long offset, long x);
++ /** @see #getInt(Object, long) */
++ public native float getFloat(Object o, long offset);
++ /** @see #putInt(Object, int, int) */
++ public native void putFloat(Object o, long offset, float x);
++ /** @see #getInt(Object, long) */
++ public native double getDouble(Object o, long offset);
++ /** @see #putInt(Object, int, int) */
++ public native void putDouble(Object o, long offset, double x);
++
++ /**
++ * This method, like all others with 32-bit offsets, was native
++ * in a previous release but is now a wrapper which simply casts
++ * the offset to a long value. It provides backward compatibility
++ * with bytecodes compiled against 1.4.
++ * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
++ * See {@link #staticFieldOffset}.
++ */
++ @Deprecated
++ public int getInt(Object o, int offset) {
++ return getInt(o, (long)offset);
++ }
++
++ /**
++ * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
++ * See {@link #staticFieldOffset}.
++ */
++ @Deprecated
++ public void putInt(Object o, int offset, int x) {
++ putInt(o, (long)offset, x);
++ }
++
++ /**
++ * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
++ * See {@link #staticFieldOffset}.
++ */
++ @Deprecated
++ public Object getObject(Object o, int offset) {
++ return getObject(o, (long)offset);
++ }
++
++ /**
++ * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
++ * See {@link #staticFieldOffset}.
++ */
++ @Deprecated
++ public void putObject(Object o, int offset, Object x) {
++ putObject(o, (long)offset, x);
++ }
++
++ /**
++ * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
++ * See {@link #staticFieldOffset}.
++ */
++ @Deprecated
++ public boolean getBoolean(Object o, int offset) {
++ return getBoolean(o, (long)offset);
++ }
++
++ /**
++ * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
++ * See {@link #staticFieldOffset}.
++ */
++ @Deprecated
++ public void putBoolean(Object o, int offset, boolean x) {
++ putBoolean(o, (long)offset, x);
++ }
++
++ /**
++ * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
++ * See {@link #staticFieldOffset}.
++ */
++ @Deprecated
++ public byte getByte(Object o, int offset) {
++ return getByte(o, (long)offset);
++ }
++
++ /**
++ * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
++ * See {@link #staticFieldOffset}.
++ */
++ @Deprecated
++ public void putByte(Object o, int offset, byte x) {
++ putByte(o, (long)offset, x);
++ }
++
++ /**
++ * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
++ * See {@link #staticFieldOffset}.
++ */
++ @Deprecated
++ public short getShort(Object o, int offset) {
++ return getShort(o, (long)offset);
++ }
++
++ /**
++ * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
++ * See {@link #staticFieldOffset}.
++ */
++ @Deprecated
++ public void putShort(Object o, int offset, short x) {
++ putShort(o, (long)offset, x);
++ }
++
++ /**
++ * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
++ * See {@link #staticFieldOffset}.
++ */
++ @Deprecated
++ public char getChar(Object o, int offset) {
++ return getChar(o, (long)offset);
++ }
++
++ /**
++ * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
++ * See {@link #staticFieldOffset}.
++ */
++ @Deprecated
++ public void putChar(Object o, int offset, char x) {
++ putChar(o, (long)offset, x);
++ }
++
++ /**
++ * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
++ * See {@link #staticFieldOffset}.
++ */
++ @Deprecated
++ public long getLong(Object o, int offset) {
++ return getLong(o, (long)offset);
++ }
++
++ /**
++ * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
++ * See {@link #staticFieldOffset}.
++ */
++ @Deprecated
++ public void putLong(Object o, int offset, long x) {
++ putLong(o, (long)offset, x);
++ }
++
++ /**
++ * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
++ * See {@link #staticFieldOffset}.
++ */
++ @Deprecated
++ public float getFloat(Object o, int offset) {
++ return getFloat(o, (long)offset);
++ }
++
++ /**
++ * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
++ * See {@link #staticFieldOffset}.
++ */
++ @Deprecated
++ public void putFloat(Object o, int offset, float x) {
++ putFloat(o, (long)offset, x);
++ }
++
++ /**
++ * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
++ * See {@link #staticFieldOffset}.
++ */
++ @Deprecated
++ public double getDouble(Object o, int offset) {
++ return getDouble(o, (long)offset);
++ }
++
++ /**
++ * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long.
++ * See {@link #staticFieldOffset}.
++ */
++ @Deprecated
++ public void putDouble(Object o, int offset, double x) {
++ putDouble(o, (long)offset, x);
++ }
++
++ // These work on values in the C heap.
++
++ /**
++ * Fetches a value from a given memory address. If the address is zero, or
++ * does not point into a block obtained from {@link #allocateMemory}, the
++ * results are undefined.
++ *
++ * @see #allocateMemory
++ */
++ public native byte getByte(long address);
++
++ /**
++ * Stores a value into a given memory address. If the address is zero, or
++ * does not point into a block obtained from {@link #allocateMemory}, the
++ * results are undefined.
++ *
++ * @see #getByte(long)
++ */
++ public native void putByte(long address, byte x);
++
++ /** @see #getByte(long) */
++ public native short getShort(long address);
++ /** @see #putByte(long, byte) */
++ public native void putShort(long address, short x);
++ /** @see #getByte(long) */
++ public native char getChar(long address);
++ /** @see #putByte(long, byte) */
++ public native void putChar(long address, char x);
++ /** @see #getByte(long) */
++ public native int getInt(long address);
++ /** @see #putByte(long, byte) */
++ public native void putInt(long address, int x);
++ /** @see #getByte(long) */
++ public native long getLong(long address);
++ /** @see #putByte(long, byte) */
++ public native void putLong(long address, long x);
++ /** @see #getByte(long) */
++ public native float getFloat(long address);
++ /** @see #putByte(long, byte) */
++ public native void putFloat(long address, float x);
++ /** @see #getByte(long) */
++ public native double getDouble(long address);
++ /** @see #putByte(long, byte) */
++ public native void putDouble(long address, double x);
++
++ /**
++ * Fetches a native pointer from a given memory address. If the address is
++ * zero, or does not point into a block obtained from {@link
++ * #allocateMemory}, the results are undefined.
++ *
++ * <p> If the native pointer is less than 64 bits wide, it is extended as
++ * an unsigned number to a Java long. The pointer may be indexed by any
++ * given byte offset, simply by adding that offset (as a simple integer) to
++ * the long representing the pointer. The number of bytes actually read
++ * from the target address maybe determined by consulting {@link
++ * #addressSize}.
++ *
++ * @see #allocateMemory
++ */
++ public native long getAddress(long address);
++
++ /**
++ * Stores a native pointer into a given memory address. If the address is
++ * zero, or does not point into a block obtained from {@link
++ * #allocateMemory}, the results are undefined.
++ *
++ * <p> The number of bytes actually written at the target address maybe
++ * determined by consulting {@link #addressSize}.
++ *
++ * @see #getAddress(long)
++ */
++ public native void putAddress(long address, long x);
++
++ /// wrappers for malloc, realloc, free:
++
++ /**
++ * Allocates a new block of native memory, of the given size in bytes. The
++ * contents of the memory are uninitialized; they will generally be
++ * garbage. The resulting native pointer will never be zero, and will be
++ * aligned for all value types. Dispose of this memory by calling {@link
++ * #freeMemory}, or resize it with {@link #reallocateMemory}.
++ *
++ * @throws IllegalArgumentException if the size is negative or too large
++ * for the native size_t type
++ *
++ * @throws OutOfMemoryError if the allocation is refused by the system
++ *
++ * @see #getByte(long)
++ * @see #putByte(long, byte)
++ */
++ public native long allocateMemory(long bytes);
++
++ /**
++ * Resizes a new block of native memory, to the given size in bytes. The
++ * contents of the new block past the size of the old block are
++ * uninitialized; they will generally be garbage. The resulting native
++ * pointer will be zero if and only if the requested size is zero. The
++ * resulting native pointer will be aligned for all value types. Dispose
++ * of this memory by calling {@link #freeMemory}, or resize it with {@link
++ * #reallocateMemory}. The address passed to this method may be null, in
++ * which case an allocation will be performed.
++ *
++ * @throws IllegalArgumentException if the size is negative or too large
++ * for the native size_t type
++ *
++ * @throws OutOfMemoryError if the allocation is refused by the system
++ *
++ * @see #allocateMemory
++ */
++ public native long reallocateMemory(long address, long bytes);
++
++ /**
++ * Sets all bytes in a given block of memory to a fixed value
++ * (usually zero).
++ *
++ * <p>This method determines a block's base address by means of two parameters,
++ * and so it provides (in effect) a <em>double-register</em> addressing mode,
++ * as discussed in {@link #getInt(Object,long)}. When the object reference is null,
++ * the offset supplies an absolute base address.
++ *
++ * <p>The stores are in coherent (atomic) units of a size determined
++ * by the address and length parameters. If the effective address and
++ * length are all even modulo 8, the stores take place in 'long' units.
++ * If the effective address and length are (resp.) even modulo 4 or 2,
++ * the stores take place in units of 'int' or 'short'.
++ *
++ * @since 1.7
++ */
++ public native void setMemory(Object o, long offset, long bytes, byte value);
++
++ /**
++ * Sets all bytes in a given block of memory to a fixed value
++ * (usually zero). This provides a <em>single-register</em> addressing mode,
++ * as discussed in {@link #getInt(Object,long)}.
++ *
++ * <p>Equivalent to <code>setMemory(null, address, bytes, value)</code>.
++ */
++ public void setMemory(long address, long bytes, byte value) {
++ setMemory(null, address, bytes, value);
++ }
++
++ /**
++ * Sets all bytes in a given block of memory to a copy of another
++ * block.
++ *
++ * <p>This method determines each block's base address by means of two parameters,
++ * and so it provides (in effect) a <em>double-register</em> addressing mode,
++ * as discussed in {@link #getInt(Object,long)}. When the object reference is null,
++ * the offset supplies an absolute base address.
++ *
++ * <p>The transfers are in coherent (atomic) units of a size determined
++ * by the address and length parameters. If the effective addresses and
++ * length are all even modulo 8, the transfer takes place in 'long' units.
++ * If the effective addresses and length are (resp.) even modulo 4 or 2,
++ * the transfer takes place in units of 'int' or 'short'.
++ *
++ * @since 1.7
++ */
++ public native void copyMemory(Object srcBase, long srcOffset,
++ Object destBase, long destOffset,
++ long bytes);
++ /**
++ * Sets all bytes in a given block of memory to a copy of another
++ * block. This provides a <em>single-register</em> addressing mode,
++ * as discussed in {@link #getInt(Object,long)}.
++ *
++ * Equivalent to <code>copyMemory(null, srcAddress, null, destAddress, bytes)</code>.
++ */
++ public void copyMemory(long srcAddress, long destAddress, long bytes) {
++ copyMemory(null, srcAddress, null, destAddress, bytes);
++ }
++
++ /**
++ * Disposes of a block of native memory, as obtained from {@link
++ * #allocateMemory} or {@link #reallocateMemory}. The address passed to
++ * this method may be null, in which case no action is taken.
++ *
++ * @see #allocateMemory
++ */
++ public native void freeMemory(long address);
++
++ /// random queries
++
++ /**
++ * This constant differs from all results that will ever be returned from
++ * {@link #staticFieldOffset}, {@link #objectFieldOffset},
++ * or {@link #arrayBaseOffset}.
++ */
++ public static final int INVALID_FIELD_OFFSET = -1;
++
++ /**
++ * Returns the offset of a field, truncated to 32 bits.
++ * This method is implemented as follows:
++ * <blockquote><pre>
++ * public int fieldOffset(Field f) {
++ * if (Modifier.isStatic(f.getModifiers()))
++ * return (int) staticFieldOffset(f);
++ * else
++ * return (int) objectFieldOffset(f);
++ * }
++ * </pre></blockquote>
++ * @deprecated As of 1.4.1, use {@link #staticFieldOffset} for static
++ * fields and {@link #objectFieldOffset} for non-static fields.
++ */
++ @Deprecated
++ public int fieldOffset(Field f) {
++ if (Modifier.isStatic(f.getModifiers()))
++ return (int) staticFieldOffset(f);
++ else
++ return (int) objectFieldOffset(f);
++ }
++
++ /**
++ * Returns the base address for accessing some static field
++ * in the given class. This method is implemented as follows:
++ * <blockquote><pre>
++ * public Object staticFieldBase(Class c) {
++ * Field[] fields = c.getDeclaredFields();
++ * for (int i = 0; i < fields.length; i++) {
++ * if (Modifier.isStatic(fields[i].getModifiers())) {
++ * return staticFieldBase(fields[i]);
++ * }
++ * }
++ * return null;
++ * }
++ * </pre></blockquote>
++ * @deprecated As of 1.4.1, use {@link #staticFieldBase(Field)}
++ * to obtain the base pertaining to a specific {@link Field}.
++ * This method works only for JVMs which store all statics
++ * for a given class in one place.
++ */
++ @Deprecated
++ public Object staticFieldBase(Class c) {
++ Field[] fields = c.getDeclaredFields();
++ for (int i = 0; i < fields.length; i++) {
++ if (Modifier.isStatic(fields[i].getModifiers())) {
++ return staticFieldBase(fields[i]);
++ }
++ }
++ return null;
++ }
++
++ /**
++ * Report the location of a given field in the storage allocation of its
++ * class. Do not expect to perform any sort of arithmetic on this offset;
++ * it is just a cookie which is passed to the unsafe heap memory accessors.
++ *
++ * <p>Any given field will always have the same offset and base, and no
++ * two distinct fields of the same class will ever have the same offset
++ * and base.
++ *
++ * <p>As of 1.4.1, offsets for fields are represented as long values,
++ * although the Sun JVM does not use the most significant 32 bits.
++ * However, JVM implementations which store static fields at absolute
++ * addresses can use long offsets and null base pointers to express
++ * the field locations in a form usable by {@link #getInt(Object,long)}.
++ * Therefore, code which will be ported to such JVMs on 64-bit platforms
++ * must preserve all bits of static field offsets.
++ * @see #getInt(Object, long)
++ */
++ public native long staticFieldOffset(Field f);
++
++ /**
++ * Report the location of a given static field, in conjunction with {@link
++ * #staticFieldBase}.
++ * <p>Do not expect to perform any sort of arithmetic on this offset;
++ * it is just a cookie which is passed to the unsafe heap memory accessors.
++ *
++ * <p>Any given field will always have the same offset, and no two distinct
++ * fields of the same class will ever have the same offset.
++ *
++ * <p>As of 1.4.1, offsets for fields are represented as long values,
++ * although the Sun JVM does not use the most significant 32 bits.
++ * It is hard to imagine a JVM technology which needs more than
++ * a few bits to encode an offset within a non-array object,
++ * However, for consistency with other methods in this class,
++ * this method reports its result as a long value.
++ * @see #getInt(Object, long)
++ */
++ public native long objectFieldOffset(Field f);
++
++ /**
++ * Report the location of a given static field, in conjunction with {@link
++ * #staticFieldOffset}.
++ * <p>Fetch the base "Object", if any, with which static fields of the
++ * given class can be accessed via methods like {@link #getInt(Object,
++ * long)}. This value may be null. This value may refer to an object
++ * which is a "cookie", not guaranteed to be a real Object, and it should
++ * not be used in any way except as argument to the get and put routines in
++ * this class.
++ */
++ public native Object staticFieldBase(Field f);
++
++ /**
++ * Ensure the given class has been initialized. This is often
++ * needed in conjunction with obtaining the static field base of a
++ * class.
++ */
++ public native void ensureClassInitialized(Class c);
++
++ /**
++ * Report the offset of the first element in the storage allocation of a
++ * given array class. If {@link #arrayIndexScale} returns a non-zero value
++ * for the same class, you may use that scale factor, together with this
++ * base offset, to form new offsets to access elements of arrays of the
++ * given class.
++ *
++ * @see #getInt(Object, long)
++ * @see #putInt(Object, long, int)
++ */
++ public native int arrayBaseOffset(Class arrayClass);
++
++ /** The value of {@code arrayBaseOffset(boolean[].class)} */
++ public static final int ARRAY_BOOLEAN_BASE_OFFSET
++ = theUnsafe.arrayBaseOffset(boolean[].class);
++
++ /** The value of {@code arrayBaseOffset(byte[].class)} */
++ public static final int ARRAY_BYTE_BASE_OFFSET
++ = theUnsafe.arrayBaseOffset(byte[].class);
++
++ /** The value of {@code arrayBaseOffset(short[].class)} */
++ public static final int ARRAY_SHORT_BASE_OFFSET
++ = theUnsafe.arrayBaseOffset(short[].class);
++
++ /** The value of {@code arrayBaseOffset(char[].class)} */
++ public static final int ARRAY_CHAR_BASE_OFFSET
++ = theUnsafe.arrayBaseOffset(char[].class);
++
++ /** The value of {@code arrayBaseOffset(int[].class)} */
++ public static final int ARRAY_INT_BASE_OFFSET
++ = theUnsafe.arrayBaseOffset(int[].class);
++
++ /** The value of {@code arrayBaseOffset(long[].class)} */
++ public static final int ARRAY_LONG_BASE_OFFSET
++ = theUnsafe.arrayBaseOffset(long[].class);
++
++ /** The value of {@code arrayBaseOffset(float[].class)} */
++ public static final int ARRAY_FLOAT_BASE_OFFSET
++ = theUnsafe.arrayBaseOffset(float[].class);
++
++ /** The value of {@code arrayBaseOffset(double[].class)} */
++ public static final int ARRAY_DOUBLE_BASE_OFFSET
++ = theUnsafe.arrayBaseOffset(double[].class);
++
++ /** The value of {@code arrayBaseOffset(Object[].class)} */
++ public static final int ARRAY_OBJECT_BASE_OFFSET
++ = theUnsafe.arrayBaseOffset(Object[].class);
++
++ /**
++ * Report the scale factor for addressing elements in the storage
++ * allocation of a given array class. However, arrays of "narrow" types
++ * will generally not work properly with accessors like {@link
++ * #getByte(Object, int)}, so the scale factor for such classes is reported
++ * as zero.
++ *
++ * @see #arrayBaseOffset
++ * @see #getInt(Object, long)
++ * @see #putInt(Object, long, int)
++ */
++ public native int arrayIndexScale(Class arrayClass);
++
++ /** The value of {@code arrayIndexScale(boolean[].class)} */
++ public static final int ARRAY_BOOLEAN_INDEX_SCALE
++ = theUnsafe.arrayIndexScale(boolean[].class);
++
++ /** The value of {@code arrayIndexScale(byte[].class)} */
++ public static final int ARRAY_BYTE_INDEX_SCALE
++ = theUnsafe.arrayIndexScale(byte[].class);
++
++ /** The value of {@code arrayIndexScale(short[].class)} */
++ public static final int ARRAY_SHORT_INDEX_SCALE
++ = theUnsafe.arrayIndexScale(short[].class);
++
++ /** The value of {@code arrayIndexScale(char[].class)} */
++ public static final int ARRAY_CHAR_INDEX_SCALE
++ = theUnsafe.arrayIndexScale(char[].class);
++
++ /** The value of {@code arrayIndexScale(int[].class)} */
++ public static final int ARRAY_INT_INDEX_SCALE
++ = theUnsafe.arrayIndexScale(int[].class);
++
++ /** The value of {@code arrayIndexScale(long[].class)} */
++ public static final int ARRAY_LONG_INDEX_SCALE
++ = theUnsafe.arrayIndexScale(long[].class);
++
++ /** The value of {@code arrayIndexScale(float[].class)} */
++ public static final int ARRAY_FLOAT_INDEX_SCALE
++ = theUnsafe.arrayIndexScale(float[].class);
++
++ /** The value of {@code arrayIndexScale(double[].class)} */
++ public static final int ARRAY_DOUBLE_INDEX_SCALE
++ = theUnsafe.arrayIndexScale(double[].class);
++
++ /** The value of {@code arrayIndexScale(Object[].class)} */
++ public static final int ARRAY_OBJECT_INDEX_SCALE
++ = theUnsafe.arrayIndexScale(Object[].class);
++
++ /**
++ * Report the size in bytes of a native pointer, as stored via {@link
++ * #putAddress}. This value will be either 4 or 8. Note that the sizes of
++ * other primitive types (as stored in native memory blocks) is determined
++ * fully by their information content.
++ */
++ public native int addressSize();
++
++ /** The value of {@code addressSize()} */
++ public static final int ADDRESS_SIZE = theUnsafe.addressSize();
++
++ /**
++ * Report the size in bytes of a native memory page (whatever that is).
++ * This value will always be a power of two.
++ */
++ public native int pageSize();
++
++
++ /// random trusted operations from JNI:
++
++ /**
++ * Tell the VM to define a class, without security checks. By default, the
++ * class loader and protection domain come from the caller's class.
++ */
++ public native Class defineClass(String name, byte[] b, int off, int len,
++ ClassLoader loader,
++ ProtectionDomain protectionDomain);
++
++ public native Class defineClass(String name, byte[] b, int off, int len);
++
++ /**
++ * Define a class but do not make it known to the class loader or system dictionary.
++ * <p>
++ * For each CP entry, the corresponding CP patch must either be null or have
++ * the a format that matches its tag:
++ * <ul>
++ * <li>Integer, Long, Float, Double: the corresponding wrapper object type from java.lang
++ * <li>Utf8: a string (must have suitable syntax if used as signature or name)
++ * <li>Class: any java.lang.Class object
++ * <li>String: any object (not just a java.lang.String)
++ * <li>InterfaceMethodRef: (NYI) a method handle to invoke in that call site's arguments
++ * </ul>
++ * @params hostClass context for linkage, access control, protection domain, and class loader
++ * @params data bytes of a class file, a raw memory address b
++ * @params length number of bytes in class file
++ * @params cpPatches where non-null entries exist, they replace corresponding CP entries in data
++ */
++ public native Class defineAnonymousClass(Class hostClass, byte[] data, Object[] cpPatches);
++
++ /** Allocate an instance but do not run any constructor.
++ Initializes the class if it has not yet been. */
++ public native Object allocateInstance(Class cls)
++ throws InstantiationException;
++
++ /** Lock the object. It must get unlocked via {@link #monitorExit}. */
++ public native void monitorEnter(Object o);
++
++ /**
++ * Unlock the object. It must have been locked via {@link
++ * #monitorEnter}.
++ */
++ public native void monitorExit(Object o);
++
++ /**
++ * Tries to lock the object. Returns true or false to indicate
++ * whether the lock succeeded. If it did, the object must be
++ * unlocked via {@link #monitorExit}.
++ */
++ public native boolean tryMonitorEnter(Object o);
++
++ /** Throw the exception without telling the verifier. */
++ public native void throwException(Throwable ee);
++
++
++ /**
++ * Atomically update Java variable to <tt>x</tt> if it is currently
++ * holding <tt>expected</tt>.
++ * @return <tt>true</tt> if successful
++ */
++ public final native boolean compareAndSwapObject(Object o, long offset,
++ Object expected,
++ Object x);
++
++ /**
++ * Atomically update Java variable to <tt>x</tt> if it is currently
++ * holding <tt>expected</tt>.
++ * @return <tt>true</tt> if successful
++ */
++ public final native boolean compareAndSwapInt(Object o, long offset,
++ int expected,
++ int x);
++
++ /**
++ * Atomically update Java variable to <tt>x</tt> if it is currently
++ * holding <tt>expected</tt>.
++ * @return <tt>true</tt> if successful
++ */
++ public final native boolean compareAndSwapLong(Object o, long offset,
++ long expected,
++ long x);
++
++ /**
++ * Fetches a reference value from a given Java variable, with volatile
++ * load semantics. Otherwise identical to {@link #getObject(Object, long)}
++ */
++ public native Object getObjectVolatile(Object o, long offset);
++
++ /**
++ * Stores a reference value into a given Java variable, with
++ * volatile store semantics. Otherwise identical to {@link #putObject(Object, long, Object)}
++ */
++ public native void putObjectVolatile(Object o, long offset, Object x);
++
++ /** Volatile version of {@link #getInt(Object, long)} */
++ public native int getIntVolatile(Object o, long offset);
++
++ /** Volatile version of {@link #putInt(Object, long, int)} */
++ public native void putIntVolatile(Object o, long offset, int x);
++
++ /** Volatile version of {@link #getBoolean(Object, long)} */
++ public native boolean getBooleanVolatile(Object o, long offset);
++
++ /** Volatile version of {@link #putBoolean(Object, long, boolean)} */
++ public native void putBooleanVolatile(Object o, long offset, boolean x);
++
++ /** Volatile version of {@link #getByte(Object, long)} */
++ public native byte getByteVolatile(Object o, long offset);
++
++ /** Volatile version of {@link #putByte(Object, long, byte)} */
++ public native void putByteVolatile(Object o, long offset, byte x);
++
++ /** Volatile version of {@link #getShort(Object, long)} */
++ public native short getShortVolatile(Object o, long offset);
++
++ /** Volatile version of {@link #putShort(Object, long, short)} */
++ public native void putShortVolatile(Object o, long offset, short x);
++
++ /** Volatile version of {@link #getChar(Object, long)} */
++ public native char getCharVolatile(Object o, long offset);
++
++ /** Volatile version of {@link #putChar(Object, long, char)} */
++ public native void putCharVolatile(Object o, long offset, char x);
++
++ /** Volatile version of {@link #getLong(Object, long)} */
++ public native long getLongVolatile(Object o, long offset);
++
++ /** Volatile version of {@link #putLong(Object, long, long)} */
++ public native void putLongVolatile(Object o, long offset, long x);
++
++ /** Volatile version of {@link #getFloat(Object, long)} */
++ public native float getFloatVolatile(Object o, long offset);
++
++ /** Volatile version of {@link #putFloat(Object, long, float)} */
++ public native void putFloatVolatile(Object o, long offset, float x);
++
++ /** Volatile version of {@link #getDouble(Object, long)} */
++ public native double getDoubleVolatile(Object o, long offset);
++
++ /** Volatile version of {@link #putDouble(Object, long, double)} */
++ public native void putDoubleVolatile(Object o, long offset, double x);
++
++ /**
++ * Version of {@link #putObjectVolatile(Object, long, Object)}
++ * that does not guarantee immediate visibility of the store to
++ * other threads. This method is generally only useful if the
++ * underlying field is a Java volatile (or if an array cell, one
++ * that is otherwise only accessed using volatile accesses).
++ */
++ public native void putOrderedObject(Object o, long offset, Object x);
++
++ /** Ordered/Lazy version of {@link #putIntVolatile(Object, long, int)} */
++ public native void putOrderedInt(Object o, long offset, int x);
++
++ /** Ordered/Lazy version of {@link #putLongVolatile(Object, long, long)} */
++ public native void putOrderedLong(Object o, long offset, long x);
++
++ /**
++ * Unblock the given thread blocked on <tt>park</tt>, or, if it is
++ * not blocked, cause the subsequent call to <tt>park</tt> not to
++ * block. Note: this operation is "unsafe" solely because the
++ * caller must somehow ensure that the thread has not been
++ * destroyed. Nothing special is usually required to ensure this
++ * when called from Java (in which there will ordinarily be a live
++ * reference to the thread) but this is not nearly-automatically
++ * so when calling from native code.
++ * @param thread the thread to unpark.
++ *
++ */
++ public native void unpark(Object thread);
++
++ /**
++ * Block current thread, returning when a balancing
++ * <tt>unpark</tt> occurs, or a balancing <tt>unpark</tt> has
++ * already occurred, or the thread is interrupted, or, if not
++ * absolute and time is not zero, the given time nanoseconds have
++ * elapsed, or if absolute, the given deadline in milliseconds
++ * since Epoch has passed, or spuriously (i.e., returning for no
++ * "reason"). Note: This operation is in the Unsafe class only
++ * because <tt>unpark</tt> is, so it would be strange to place it
++ * elsewhere.
++ */
++ public native void park(boolean isAbsolute, long time);
++
++ /**
++ * Gets the load average in the system run queue assigned
++ * to the available processors averaged over various periods of time.
++ * This method retrieves the given <tt>nelem</tt> samples and
++ * assigns to the elements of the given <tt>loadavg</tt> array.
++ * The system imposes a maximum of 3 samples, representing
++ * averages over the last 1, 5, and 15 minutes, respectively.
++ *
++ * @params loadavg an array of double of size nelems
++ * @params nelems the number of samples to be retrieved and
++ * must be 1 to 3.
++ *
++ * @return the number of samples actually retrieved; or -1
++ * if the load average is unobtainable.
++ */
++ public native int getLoadAverage(double[] loadavg, int nelems);
++}
+diff --git a/src/share/projects/anonk/src/sun/reflect/Reflection.java b/src/share/projects/anonk/src/sun/reflect/Reflection.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/projects/anonk/src/sun/reflect/Reflection.java
+@@ -0,0 +1,325 @@
++/*
++ * Copyright 2001-2006 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 sun.reflect;
++
++import java.lang.reflect.*;
++import java.util.Collections;
++import java.util.HashMap;
++import java.util.Map;
++
++/** Common utility routines used by both java.lang and
++ java.lang.reflect */
++
++public class Reflection {
++
++ /** Used to filter out fields and methods from certain classes from public
++ view, where they are sensitive or they may contain VM-internal objects.
++ These Maps are updated very rarely. Rather than synchronize on
++ each access, we use copy-on-write */
++ private static volatile Map<Class,String[]> fieldFilterMap;
++ private static volatile Map<Class,String[]> methodFilterMap;
++
++ static {
++ Map<Class,String[]> map = new HashMap<Class,String[]>();
++ map.put(Reflection.class,
++ new String[] {"fieldFilterMap", "methodFilterMap"});
++ map.put(System.class, new String[] {"security"});
++ fieldFilterMap = map;
++
++ methodFilterMap = new HashMap<Class,String[]>();
++ }
++
++ /** Returns the class of the method <code>realFramesToSkip</code>
++ frames up the stack (zero-based), ignoring frames associated
++ with java.lang.reflect.Method.invoke() and its implementation.
++ The first frame is that associated with this method, so
++ <code>getCallerClass(0)</code> returns the Class object for
++ sun.reflect.Reflection. Frames associated with
++ java.lang.reflect.Method.invoke() and its implementation are
++ completely ignored and do not count toward the number of "real"
++ frames skipped. */
++ public static native Class getCallerClass(int realFramesToSkip);
++
++ /** Retrieves the access flags written to the class file. For
++ inner classes these flags may differ from those returned by
++ Class.getModifiers(), which searches the InnerClasses
++ attribute to find the source-level access flags. This is used
++ instead of Class.getModifiers() for run-time access checks due
++ to compatibility reasons; see 4471811. Only the values of the
++ low 13 bits (i.e., a mask of 0x1FFF) are guaranteed to be
++ valid. */
++ private static native int getClassAccessFlags(Class c);
++
++ /** A quick "fast-path" check to try to avoid getCallerClass()
++ calls. */
++ public static boolean quickCheckMemberAccess(Class memberClass,
++ int modifiers)
++ {
++ return Modifier.isPublic(getClassAccessFlags(memberClass) & modifiers);
++ }
++
++ public static void ensureMemberAccess(Class currentClass,
++ Class memberClass,
++ Object target,
++ int modifiers)
++ throws IllegalAccessException
++ {
++ if (currentClass == null || memberClass == null) {
++ throw new InternalError();
++ }
++
++ if (!verifyMemberAccess(currentClass, memberClass, target, modifiers)) {
++ throw new IllegalAccessException("Class " + currentClass.getName() +
++ " can not access a member of class " +
++ memberClass.getName() +
++ " with modifiers \"" +
++ Modifier.toString(modifiers) +
++ "\"");
++ }
++ }
++
++ public static boolean verifyMemberAccess(Class currentClass,
++ // Declaring class of field
++ // or method
++ Class memberClass,
++ // May be NULL in case of statics
++ Object target,
++ int modifiers)
++ {
++ // Verify that currentClass can access a field, method, or
++ // constructor of memberClass, where that member's access bits are
++ // "modifiers".
++
++ boolean gotIsSameClassPackage = false;
++ boolean isSameClassPackage = false;
++
++ if (currentClass == memberClass) {
++ // Always succeeds
++ return true;
++ }
++
++ if (!Modifier.isPublic(getClassAccessFlags(memberClass))) {
++ isSameClassPackage = isSameClassPackage(currentClass, memberClass);
++ gotIsSameClassPackage = true;
++ if (!isSameClassPackage) {
++ return false;
++ }
++ }
++
++ // At this point we know that currentClass can access memberClass.
++
++ if (Modifier.isPublic(modifiers)) {
++ return true;
++ }
++
++ boolean successSoFar = false;
++
++ if (Modifier.isProtected(modifiers)) {
++ // See if currentClass is a subclass of memberClass
++ if (isSubclassOf(currentClass, memberClass)) {
++ successSoFar = true;
++ }
++ }
++
++ if (!successSoFar && !Modifier.isPrivate(modifiers)) {
++ if (!gotIsSameClassPackage) {
++ isSameClassPackage = isSameClassPackage(currentClass,
++ memberClass);
++ gotIsSameClassPackage = true;
++ }
++
++ if (isSameClassPackage) {
++ successSoFar = true;
++ }
++ }
++
++ if (!successSoFar) {
++ return false;
++ }
++
++ if (Modifier.isProtected(modifiers)) {
++ // Additional test for protected members: JLS 6.6.2
++ Class targetClass = (target == null ? memberClass : target.getClass());
++ if (targetClass != currentClass) {
++ if (!gotIsSameClassPackage) {
++ isSameClassPackage = isSameClassPackage(currentClass, memberClass);
++ gotIsSameClassPackage = true;
++ }
++ if (!isSameClassPackage) {
++ if (!isSubclassOf(targetClass, currentClass)) {
++ return false;
++ }
++ }
++ }
++ }
++
++ return true;
++ }
++
++ private static boolean isSameClassPackage(Class c1, Class c2) {
++ return isSameClassPackage(c1.getClassLoader(), c1.getName(),
++ c2.getClassLoader(), c2.getName());
++ }
++
++ /** Returns true if two classes are in the same package; classloader
++ and classname information is enough to determine a class's package */
++ private static boolean isSameClassPackage(ClassLoader loader1, String name1,
++ ClassLoader loader2, String name2)
++ {
++ if (loader1 != loader2) {
++ return false;
++ } else {
++ int lastDot1 = name1.lastIndexOf('.');
++ int lastDot2 = name2.lastIndexOf('.');
++ if ((lastDot1 == -1) || (lastDot2 == -1)) {
++ // One of the two doesn't have a package. Only return true
++ // if the other one also doesn't have a package.
++ return (lastDot1 == lastDot2);
++ } else {
++ int idx1 = 0;
++ int idx2 = 0;
++
++ // Skip over '['s
++ if (name1.charAt(idx1) == '[') {
++ do {
++ idx1++;
++ } while (name1.charAt(idx1) == '[');
++ if (name1.charAt(idx1) != 'L') {
++ // Something is terribly wrong. Shouldn't be here.
++ throw new InternalError("Illegal class name " + name1);
++ }
++ }
++ if (name2.charAt(idx2) == '[') {
++ do {
++ idx2++;
++ } while (name2.charAt(idx2) == '[');
++ if (name2.charAt(idx2) != 'L') {
++ // Something is terribly wrong. Shouldn't be here.
++ throw new InternalError("Illegal class name " + name2);
++ }
++ }
++
++ // Check that package part is identical
++ int length1 = lastDot1 - idx1;
++ int length2 = lastDot2 - idx2;
++
++ if (length1 != length2) {
++ return false;
++ }
++ return name1.regionMatches(false, idx1, name2, idx2, length1);
++ }
++ }
++ }
++
++ static boolean isSubclassOf(Class queryClass,
++ Class ofClass)
++ {
++ while (queryClass != null) {
++ if (queryClass == ofClass) {
++ return true;
++ }
++ queryClass = queryClass.getSuperclass();
++ }
++ return false;
++ }
++
++ // fieldNames must contain only interned Strings
++ public static synchronized void registerFieldsToFilter(Class containingClass,
++ String ... fieldNames) {
++ fieldFilterMap =
++ registerFilter(fieldFilterMap, containingClass, fieldNames);
++ }
++
++ // methodNames must contain only interned Strings
++ public static synchronized void registerMethodsToFilter(Class containingClass,
++ String ... methodNames) {
++ methodFilterMap =
++ registerFilter(methodFilterMap, containingClass, methodNames);
++ }
++
++ private static Map<Class,String[]> registerFilter(Map<Class,String[]> map,
++ Class containingClass, String ... names) {
++ if (map.get(containingClass) != null) {
++ throw new IllegalArgumentException
++ ("Filter already registered: " + containingClass);
++ }
++ map = new HashMap<Class,String[]>(map);
++ map.put(containingClass, names);
++ return map;
++ }
++
++ public static Field[] filterFields(Class containingClass,
++ Field[] fields) {
++ if (fieldFilterMap == null) {
++ // Bootstrapping
++ return fields;
++ }
++ return (Field[])filter(fields, fieldFilterMap.get(containingClass));
++ }
++
++ public static Method[] filterMethods(Class containingClass, Method[] methods) {
++ if (methodFilterMap == null) {
++ // Bootstrapping
++ return methods;
++ }
++ return (Method[])filter(methods, methodFilterMap.get(containingClass));
++ }
++
++ private static Member[] filter(Member[] members, String[] filteredNames) {
++ if ((filteredNames == null) || (members.length == 0)) {
++ return members;
++ }
++ int numNewMembers = 0;
++ for (Member member : members) {
++ boolean shouldSkip = false;
++ for (String filteredName : filteredNames) {
++ if (member.getName() == filteredName) {
++ shouldSkip = true;
++ break;
++ }
++ }
++ if (!shouldSkip) {
++ ++numNewMembers;
++ }
++ }
++ Member[] newMembers =
++ (Member[])Array.newInstance(members[0].getClass(), numNewMembers);
++ int destIdx = 0;
++ for (Member member : members) {
++ boolean shouldSkip = false;
++ for (String filteredName : filteredNames) {
++ if (member.getName() == filteredName) {
++ shouldSkip = true;
++ break;
++ }
++ }
++ if (!shouldSkip) {
++ newMembers[destIdx++] = member;
++ }
++ }
++ return newMembers;
++ }
++}
+diff --git a/src/share/projects/anonk/test/jdk/java/dyn/AnonymousTest.java b/src/share/projects/anonk/test/jdk/java/dyn/AnonymousTest.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/projects/anonk/test/jdk/java/dyn/AnonymousTest.java
@@ -0,0 +1,103 @@
+package jdk.java.dyn;
+
--- a/meth.patch Wed Dec 24 19:53:52 2008 -0800
+++ b/meth.patch Mon Jan 19 23:50:00 2009 -0800
@@ -1,11 +1,10 @@ diff --git a/src/cpu/sparc/vm/assembler_
diff --git a/src/cpu/sparc/vm/assembler_sparc.cpp b/src/cpu/sparc/vm/assembler_sparc.cpp
--- a/src/cpu/sparc/vm/assembler_sparc.cpp
+++ b/src/cpu/sparc/vm/assembler_sparc.cpp
-@@ -2614,6 +2614,100 @@
- restore();
+@@ -2615,6 +2615,100 @@
}
}
-+
+
+RegisterConstant MacroAssembler::delayed_value(intptr_t* delayed_value_addr,
+ Register tmp,
+ int offset) {
@@ -76,7 +75,7 @@ diff --git a/src/cpu/sparc/vm/assembler_
+ jmp(temp_reg, 0);
+
+ // for the various stubs which take control at this point,
-+ // see MethodHandle::generate_method_handle_stub
++ // see MethodHandles::generate_method_handle_stub
+}
+
+RegisterConstant MacroAssembler::argument_offset(RegisterConstant arg_slot,
@@ -99,9 +98,10 @@ diff --git a/src/cpu/sparc/vm/assembler_
+}
+
+
-
++
void MacroAssembler::biased_locking_enter(Register obj_reg, Register mark_reg,
Register temp_reg,
+ Label& done, Label* slow_case,
diff --git a/src/cpu/sparc/vm/assembler_sparc.hpp b/src/cpu/sparc/vm/assembler_sparc.hpp
--- a/src/cpu/sparc/vm/assembler_sparc.hpp
+++ b/src/cpu/sparc/vm/assembler_sparc.hpp
@@ -133,11 +133,10 @@ diff --git a/src/cpu/sparc/vm/assembler_
//
// Note that G5_method is only the method-self for the interpreter,
// and is logically unrelated to G5_megamorphic_method.
-@@ -258,6 +266,27 @@
-
+@@ -259,6 +267,27 @@
#endif
-+
+
+// A union type for code which has to assemble both constant and non-constant operands.
+class RegisterConstant VALUE_OBJ_CLASS_SPEC {
+ private:
@@ -158,19 +157,21 @@ diff --git a/src/cpu/sparc/vm/assembler_
+ bool is_register() const { return _r != noreg; }
+ bool is_constant() const { return _r == noreg; }
+};
-
++
// Address is an abstraction used to represent a memory location.
//
-@@ -1082,7 +1111,9 @@
+ // Note: A register location is represented via a Register, not
+@@ -1082,8 +1111,10 @@
inline void add( Register s1, Register s2, Register d );
inline void add( Register s1, int simm13a, Register d, relocInfo::relocType rtype = relocInfo::none);
inline void add( Register s1, int simm13a, Register d, RelocationHolder const& rspec);
+ inline void add( Register s1, RegisterConstant s2, Register d, int offset = 0);
inline void add( const Address& a, Register d, int offset = 0);
-+
-
+
++
void addcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
void addcc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void addc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(addc_op3 ) | rs1(s1) | rs2(s2) ); }
@@ -1298,6 +1329,11 @@
inline void ld( const Address& a, Register d, int offset = 0 );
inline void ldd( const Address& a, Register d, int offset = 0 );
@@ -183,16 +184,16 @@ diff --git a/src/cpu/sparc/vm/assembler_
// pp 177
void ldsba( Register s1, Register s2, int ia, Register d ) { emit_long( op(ldst_op) | rd(d) | op3(ldsb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
-@@ -1517,6 +1553,9 @@
- inline void stx( Register d, const Address& a, int offset = 0 );
+@@ -1518,6 +1554,9 @@
inline void st( Register d, const Address& a, int offset = 0 );
inline void std( Register d, const Address& a, int offset = 0 );
-+
+
+ inline void st( Register d, Register s1, RegisterConstant s2 );
+ inline void stx( Register d, Register s1, RegisterConstant s2 );
-
++
// pp 177
+ void stba( Register d, Register s1, Register s2, int ia ) { emit_long( op(ldst_op) | rd(d) | op3(stb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
@@ -1906,6 +1945,7 @@
inline void store_ptr_contents( Register s, Address& a, int offset = 0 );
inline void jumpl_to( Address& a, Register d, int offset = 0 );
@@ -306,36 +307,36 @@ diff --git a/src/cpu/sparc/vm/assembler_
inline void Assembler::stb( Register d, const Address& a, int offset) { relocate(a.rspec(offset)); stb( d, a.base(), a.disp() + offset); }
inline void Assembler::sth( Register d, const Address& a, int offset) { relocate(a.rspec(offset)); sth( d, a.base(), a.disp() + offset); }
inline void Assembler::stw( Register d, const Address& a, int offset) { relocate(a.rspec(offset)); stw( d, a.base(), a.disp() + offset); }
-@@ -241,6 +273,14 @@
- Assembler::ldx( s1, simm13a, d);
- #else
- Assembler::ld( s1, simm13a, d);
-+#endif
-+}
-+
+@@ -244,6 +276,14 @@
+ #endif
+ }
+
+inline void MacroAssembler::ld_ptr( Register s1, RegisterConstant s2, Register d ) {
+#ifdef _LP64
+ Assembler::ldx( s1, s2, d);
+#else
+ Assembler::ld( s1, s2, d);
++#endif
++}
++
+ inline void MacroAssembler::ld_ptr( const Address& a, Register d, int offset ) {
+ #ifdef _LP64
+ Assembler::ldx( a, d, offset );
+@@ -268,6 +308,14 @@
#endif
}
-@@ -265,6 +305,14 @@
- Assembler::stx( d, s1, simm13a);
- #else
- Assembler::st( d, s1, simm13a);
-+#endif
-+}
-+
+inline void MacroAssembler::st_ptr( Register d, Register s1, RegisterConstant s2 ) {
+#ifdef _LP64
+ Assembler::stx( d, s1, s2);
+#else
+ Assembler::st( d, s1, s2);
- #endif
- }
-
++#endif
++}
++
+ inline void MacroAssembler::st_ptr( Register d, const Address& a, int offset) {
+ #ifdef _LP64
+ Assembler::stx( d, a, offset);
@@ -570,6 +618,15 @@
}
@@ -417,9 +418,9 @@ diff --git a/src/cpu/sparc/vm/interprete
+
+
+// Method handle invoker
-+// Dispatch a method of the form java.dyn.MethodHandle::invoke(...)
++// Dispatch a method of the form java.dyn.MethodHandles::invoke(...)
+address InterpreterGenerator::generate_method_handle_entry(void) {
-+ if (!MethodHandles) {
++ if (!MethodHandleSupport) {
+ return generate_abstract_entry();
+ }
+
@@ -428,7 +429,7 @@ diff --git a/src/cpu/sparc/vm/interprete
+ Register O0_recv = O0;
+
+ Label wrong_method_type;
-+ address entry_point = MethodHandle::generate_method_handle_interpreter_entry(_masm, wrong_method_type);
++ address entry_point = MethodHandles::generate_method_handle_interpreter_entry(_masm, wrong_method_type);
+
+ __ bind(wrong_method_type);
+ __ mov(O0_recv, O1); // bad mh (actual)
@@ -518,7 +519,7 @@ new file mode 100644
+
+
+// Code generation
-+address MethodHandle::generate_method_handle_interpreter_entry(MacroAssembler* _masm,
++address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm,
+ Label& wrong_method_type) {
+ // I5_savedSP: sender SP (must preserve)
+ // G4 (Gargs): incoming argument list (must preserve)
@@ -568,7 +569,7 @@ new file mode 100644
+
+// Generate an "entry" field for a method handle.
+// This determines how the method handle will respond to calls.
-+void MethodHandle::generate_method_handle_stub(MacroAssembler* _masm, MethodHandle::EntryKind ek) {
++void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek) {
+ // Here is the register state during an interpreted call,
+ // as set up by generate_method_handle_interpreter_entry():
+ // - G5: garbage temp (was MethodHandle.invoke methodOop, unused)
@@ -945,15 +946,10 @@ diff --git a/src/cpu/sparc/vm/templateIn
diff --git a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
--- a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
+++ b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
-@@ -103,6 +103,34 @@
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::throw_ClassCastException),
- Otos_i);
-+ __ should_not_reach_here();
-+ return entry;
-+}
-+
-+
+@@ -108,6 +108,34 @@
+ }
+
+
+#ifdef ASSERT
+address last_WrongMethodType_caller;
+#endif //ASSERT
@@ -977,9 +973,14 @@ diff --git a/src/cpu/sparc/vm/templateIn
+ InterpreterRuntime::throw_WrongMethodTypeException),
+ G5_method_type, // required
+ G3_method_handle); // actual
- __ should_not_reach_here();
- return entry;
- }
++ __ should_not_reach_here();
++ return entry;
++}
++
++
+ address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(const char* name) {
+ address entry = __ pc();
+ // expression stack must be empty before entering the VM if an exception happened
@@ -448,6 +476,7 @@
const int extra_space =
@@ -1030,13 +1031,10 @@ diff --git a/src/cpu/x86/vm/assembler_x8
void MacroAssembler::mov32(AddressLiteral dst, Register src) {
if (reachable(dst)) {
movl(as_Address(dst), src);
-@@ -7088,6 +7110,241 @@
- // call indirectly to solve generation ordering problem
- movptr(rax, ExternalAddress(StubRoutines::verify_oop_subroutine_entry_address()));
- call(rax);
-+}
-+
-+
+@@ -7094,6 +7116,241 @@
+ }
+
+
+RegisterConstant MacroAssembler::delayed_value(intptr_t* delayed_value_addr, Register tmp) {
+ intptr_t value = *delayed_value_addr;
+ if (value != 0)
@@ -1246,7 +1244,7 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+ jmp(Address(temp_reg, MethodEntry::from_interpreted_entry_offset_in_bytes()));
+
+ // for the various stubs which take control at this point,
-+ // see MethodHandle::generate_method_handle_stub
++ // see MethodHandles::generate_method_handle_stub
+}
+
+
@@ -1269,8 +1267,11 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+ }
+ offset += wordSize; // return PC is on stack
+ return Address(rsp, scale_reg, scale_factor, offset);
- }
-
++}
++
++
+ void MacroAssembler::verify_oop_addr(Address addr, const char* s) {
+ if (!VerifyOops) return;
diff --git a/src/cpu/x86/vm/assembler_x86.hpp b/src/cpu/x86/vm/assembler_x86.hpp
--- a/src/cpu/x86/vm/assembler_x86.hpp
@@ -1303,11 +1304,10 @@ diff --git a/src/cpu/x86/vm/assembler_x8
// Address is an abstraction used to represent a memory location
// using any of the amd64 addressing modes with one object.
//
-@@ -153,6 +174,14 @@
- times_8 = 3,
+@@ -154,6 +175,14 @@
times_ptr = LP64_ONLY(times_8) NOT_LP64(times_4)
};
-+
+
+ static ScaleFactor times(int size) {
+ assert(size >= 1 && size <= 8 && is_power_of_2(size), "bad scale size");
+ if (size == 8) return times_8;
@@ -1315,9 +1315,10 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+ if (size == 2) return times_2;
+ return times_1;
+ }
-
++
private:
Register _base;
+ Register _index;
@@ -197,6 +226,22 @@
"inconsistent address");
}
@@ -1384,11 +1385,10 @@ diff --git a/src/cpu/x86/vm/assembler_x8
// Support for inc/dec with optimal instruction selection depending on value
void increment(Register reg, int value = 1) { LP64_ONLY(incrementq(reg, value)) NOT_LP64(incrementl(reg, value)) ; }
-@@ -1720,6 +1787,39 @@
- Label& slow_case // continuation point if fast allocation fails
+@@ -1721,6 +1788,39 @@
);
void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case);
-+
+
+ // small bootstrap problems
+ RegisterConstant delayed_value(intptr_t* delayed_value_addr, Register tmp);
+ RegisterConstant delayed_value(int(*value_fn)(), Register tmp) {
@@ -1421,9 +1421,10 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+ Register super_klass,
+ Register temp_reg,
+ Label& L_success);
-
++
//----
void set_word_if_not_zero(Register reg); // sets reg to 1 if not zero, otherwise 0
+
diff --git a/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp b/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp
--- a/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp
+++ b/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp
@@ -1454,7 +1455,7 @@ diff --git a/src/cpu/x86/vm/cppInterpret
@@ -659,8 +660,9 @@
// Always give one monitor to allow us to start interp if sync method.
// Any additional monitors need a check when moving the expression stack
- const one_monitor = frame::interpreter_frame_monitor_size() * wordSize;
+ const int one_monitor = frame::interpreter_frame_monitor_size() * wordSize;
+ const int extra_stack = methodOopDesc::extra_stack() * Interpreter::stackElementSize;
__ load_unsigned_word(rax, size_of_stack); // get size of expression stack in words
- __ lea(rax, Address(noreg, rax, Interpreter::stackElementScale(), one_monitor));
@@ -1603,16 +1604,15 @@ diff --git a/src/cpu/x86/vm/interpreter_
// throw exception
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
// the call_VM checks for exception, so we should never return here.
-@@ -213,6 +214,31 @@
-
+@@ -214,6 +215,31 @@
return entry_point;
}
-+
+
+
+// Method handle invoker
-+// Dispatch a method of the form java.dyn.MethodHandle::invoke(...)
++// Dispatch a method of the form java.dyn.MethodHandles::invoke(...)
+address InterpreterGenerator::generate_method_handle_entry(void) {
-+ if (!MethodHandles) {
++ if (!MethodHandleSupport) {
+ return generate_abstract_entry();
+ }
+
@@ -1621,7 +1621,7 @@ diff --git a/src/cpu/x86/vm/interpreter_
+ Register rcx_recv = rcx;
+
+ Label wrong_method_type;
-+ address entry_point = MethodHandle::generate_method_handle_interpreter_entry(_masm, wrong_method_type);
++ address entry_point = MethodHandles::generate_method_handle_interpreter_entry(_masm, wrong_method_type);
+
+ __ bind(wrong_method_type);
+ __ push(rax_mtype); // missed mtype (required)
@@ -1632,9 +1632,10 @@ diff --git a/src/cpu/x86/vm/interpreter_
+ return entry_point;
+}
+
-
++
// This method tells the deoptimizer how big an interpreted frame must be:
int AbstractInterpreter::size_activation(methodOop method,
+ int tempcount,
diff --git a/src/cpu/x86/vm/interpreter_x86_64.cpp b/src/cpu/x86/vm/interpreter_x86_64.cpp
--- a/src/cpu/x86/vm/interpreter_x86_64.cpp
+++ b/src/cpu/x86/vm/interpreter_x86_64.cpp
@@ -1643,9 +1644,9 @@ diff --git a/src/cpu/x86/vm/interpreter_
+// Method handle invoker
-+// Dispatch a method of the form java.dyn.MethodHandle::invoke(...)
++// Dispatch a method of the form java.dyn.MethodHandles::invoke(...)
+address InterpreterGenerator::generate_method_handle_entry(void) {
-+ if (!MethodHandles) {
++ if (!MethodHandleSupport) {
+ return generate_abstract_entry();
+ }
+
@@ -1662,7 +1663,7 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/cpu/x86/vm/methodHandles_x86.cpp
-@@ -0,0 +1,1010 @@
+@@ -0,0 +1,1132 @@
+/*
+ * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -1721,9 +1722,24 @@ new file mode 100644
+ return me;
+}
+
++#ifdef ASSERT
++static void verify_argslot(MacroAssembler* _masm, Register rax_argslot,
++ const char* error_message) {
++ // Verify that argslot lies within (rsp, rbp].
++ Label L_ok, L_bad;
++ __ cmpptr(rax_argslot, rbp);
++ __ jcc(Assembler::above, L_bad);
++ __ cmpptr(rsp, rax_argslot);
++ __ jcc(Assembler::below, L_ok);
++ __ bind(L_bad);
++ __ stop(error_message);
++ __ bind(L_ok);
++}
++#endif
++
+
+// Code generation
-+address MethodHandle::generate_method_handle_interpreter_entry(MacroAssembler* _masm,
++address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm,
+ Label& wrong_method_type) {
+ // rbx: methodOop
+ // rcx: receiver method handle (must load from sp[MethodTypeForm.vmslots])
@@ -1773,7 +1789,7 @@ new file mode 100644
+
+// Helper to insert argument slots into the stack.
+// arg_slots must be a multiple of stack_move_unit() and <= 0
-+void MethodHandle::insert_arg_slots(MacroAssembler* _masm,
++void MethodHandles::insert_arg_slots(MacroAssembler* _masm,
+ RegisterConstant arg_slots,
+ int arg_mask,
+ Register rax_argslot,
@@ -1794,17 +1810,7 @@ new file mode 100644
+ }
+
+#ifdef ASSERT
-+ {
-+ // Verify that argslot lies within (rsp, rbp].
-+ Label L_ok, L_bad;
-+ __ cmpptr(rax_argslot, rbp);
-+ __ jcc(Assembler::above, L_bad);
-+ __ cmpptr(rsp, rax_argslot);
-+ __ jcc(Assembler::below, L_ok);
-+ __ bind(L_bad);
-+ __ stop("insertion point must fall within current frame");
-+ __ bind(L_ok);
-+ }
++ verify_argslot(_masm, rax_argslot, "insertion point must fall within current frame");
+ if (arg_slots.is_register()) {
+ Label L_ok, L_bad;
+ __ cmpptr(arg_slots.as_register(), NULL_WORD);
@@ -1860,7 +1866,7 @@ new file mode 100644
+
+// Helper to remove argument slots from the stack.
+// arg_slots must be a multiple of stack_move_unit() and >= 0
-+void MethodHandle::remove_arg_slots(MacroAssembler* _masm,
++void MethodHandles::remove_arg_slots(MacroAssembler* _masm,
+ RegisterConstant arg_slots,
+ Register rax_argslot,
+ Register rbx_temp, Register rdx_temp) {
@@ -1941,7 +1947,7 @@ new file mode 100644
+
+// Generate an "entry" field for a method handle.
+// This determines how the method handle will respond to calls.
-+void MethodHandle::generate_method_handle_stub(MacroAssembler* _masm, MethodHandle::EntryKind ek) {
++void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek) {
+ // Here is the register state during an interpreted call,
+ // as set up by generate_method_handle_interpreter_entry():
+ // - rbx: garbage temp (was MethodHandle.invoke methodOop, unused)
@@ -2417,11 +2423,128 @@ new file mode 100644
+ break;
+
+ case _adapter_mh_first+_adapt_prim_to_ref:
-+ case _adapter_mh_first+_adapt_swap_args:
+ __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
+ break;
+
-+ case _adapter_mh_first+_adapt_dup_args:
++ case _adapter_mh_first+_adapt_swap_args:
++ case _adapter_mh_first+_adapt_rot_args:
++ // handled completely by optimized cases
++ __ stop("init_AdapterMethodHandle should not issue this");
++ break;
++
++ case _adapter_opt_swap_1:
++ case _adapter_opt_swap_2:
++ case _adapter_opt_rot_1_up:
++ case _adapter_opt_rot_1_down:
++ case _adapter_opt_rot_2_up:
++ case _adapter_opt_rot_2_down:
++ {
++ int rotate = 0, swap_slots = 0;
++ switch ((int)ek) {
++ case _adapter_opt_swap_1: swap_slots = 1; break;
++ case _adapter_opt_swap_2: swap_slots = 2; break;
++ case _adapter_opt_rot_1_up: swap_slots = 1; rotate++; break;
++ case _adapter_opt_rot_1_down: swap_slots = 1; rotate--; break;
++ case _adapter_opt_rot_2_up: swap_slots = 2; rotate++; break;
++ case _adapter_opt_rot_2_down: swap_slots = 2; rotate--; break;
++ default: assert(false, "");
++ }
++
++ // the real size of the move must be doubled if TaggedStackInterpreter:
++ int swap_bytes = (int)( swap_slots * Interpreter::stackElementWords() * wordSize );
++
++ // 'argslot' is the position of the first argument to swap
++ __ movl(rax_argslot, rcx_amh_vmargslot);
++ __ lea(rax_argslot, __ argument_address(rax_argslot));
++
++ // 'vminfo' is the second
++ Register rbx_destslot = rbx_temp;
++ __ movl(rbx_destslot, rcx_amh_conversion);
++ assert(_CONV_VMINFO_SHIFT == 0, "preshifted");
++ __ andl(rbx_destslot, _CONV_VMINFO_MASK);
++ __ lea(rbx_destslot, __ argument_address(rbx_destslot));
++ DEBUG_ONLY(verify_argslot(_masm, rbx_destslot, "swap point must fall within current frame"));
++
++ if (!rotate) {
++ for (int i = 0; i < swap_bytes; i += wordSize) {
++ __ movptr(rdx_temp, Address(rax_argslot , i));
++ __ push(rdx_temp);
++ __ movptr(rdx_temp, Address(rbx_destslot, i));
++ __ movptr(Address(rax_argslot, i), rdx_temp);
++ __ pop(rdx_temp);
++ __ movptr(Address(rbx_destslot, i), rdx_temp);
++ }
++ } else {
++ // push the first chunk, which is going to get overwritten
++ for (int i = swap_bytes; (i -= wordSize) >= 0; ) {
++ __ movptr(rdx_temp, Address(rax_argslot, i));
++ __ push(rdx_temp);
++ }
++
++ if (rotate > 0) {
++ // rotate upward
++ __ subptr(rax_argslot, swap_bytes);
++#ifdef ASSERT
++ {
++ // Verify that argslot > destslot, by at least swap_bytes.
++ Label L_ok;
++ __ cmpptr(rax_argslot, rbx_destslot);
++ __ jcc(Assembler::aboveEqual, L_ok);
++ __ stop("source must be above destination (upward rotation)");
++ __ bind(L_ok);
++ }
++#endif
++ // work argslot down to destslot, copying contiguous data upwards
++ // pseudo-code:
++ // rax = src_addr - swap_bytes
++ // rbx = dest_addr
++ // while (rax >= rbx) *(rax + swap_bytes) = *(rax + 0), rax--;
++ Label loop;
++ __ bind(loop);
++ __ movptr(rdx_temp, Address(rax_argslot, 0));
++ __ movptr(Address(rax_argslot, swap_bytes), rdx_temp);
++ __ addptr(rax_argslot, -wordSize);
++ __ cmpptr(rax_argslot, rbx_destslot);
++ __ jcc(Assembler::aboveEqual, loop);
++ } else {
++ __ addptr(rax_argslot, swap_bytes);
++#ifdef ASSERT
++ {
++ // Verify that argslot < destslot, by at least swap_bytes.
++ Label L_ok;
++ __ cmpptr(rax_argslot, rbx_destslot);
++ __ jcc(Assembler::belowEqual, L_ok);
++ __ stop("source must be below destination (downward rotation)");
++ __ bind(L_ok);
++ }
++#endif
++ // work argslot up to destslot, copying contiguous data downwards
++ // pseudo-code:
++ // rax = src_addr + swap_bytes
++ // rbx = dest_addr
++ // while (rax <= rbx) *(rax - swap_bytes) = *(rax + 0), rax++;
++ Label loop;
++ __ bind(loop);
++ __ movptr(rdx_temp, Address(rax_argslot, 0));
++ __ movptr(Address(rax_argslot, -swap_bytes), rdx_temp);
++ __ addptr(rax_argslot, wordSize);
++ __ cmpptr(rax_argslot, rbx_destslot);
++ __ jcc(Assembler::belowEqual, loop);
++ }
++
++ // pop the original first chunk into the destination slot, now free
++ for (int i = 0; i < swap_bytes; i += wordSize) {
++ __ pop(rdx_temp);
++ __ movptr(Address(rbx_destslot, i), rdx_temp);
++ }
++ }
++
++ __ movptr(rcx_recv, rcx_mh_vmtarget);
++ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
++ }
++ break;
++
++ case _adapter_mh_first+_adapt_dup_args:
+ {
+ // 'argslot' is the position of the first argument to duplicate
+ __ movl(rax_argslot, rcx_amh_vmargslot);
@@ -2692,12 +2815,12 @@ diff --git a/src/cpu/x86/vm/stubGenerato
generate_arraycopy_stubs();
+
+ // generic method handle stubs
-+ if (MethodHandles && SystemDictionary::MethodHandle_klass() != NULL) {
-+ for (MethodHandle::EntryKind ek = MethodHandle::_EK_FIRST;
-+ ek < MethodHandle::_EK_LIMIT;
-+ ek = MethodHandle::EntryKind(1 + (int)ek)) {
-+ StubCodeMark mark(this, "MethodHandle", MethodHandle::entry_name(ek));
-+ MethodHandle::generate_method_handle_stub(_masm, ek);
++ if (MethodHandleSupport && SystemDictionary::MethodHandle_klass() != NULL) {
++ for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST;
++ ek < MethodHandles::_EK_LIMIT;
++ ek = MethodHandles::EntryKind(1 + (int)ek)) {
++ StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek));
++ MethodHandles::generate_method_handle_stub(_masm, ek);
+ }
+ }
}
@@ -2706,11 +2829,10 @@ diff --git a/src/cpu/x86/vm/templateInte
diff --git a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
--- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
+++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
-@@ -91,6 +91,43 @@
- rax);
+@@ -92,6 +92,43 @@
return entry;
}
-+
+
+#ifdef ASSERT
+address last_WrongMethodType_caller;
+#endif //ASSERT
@@ -2747,9 +2869,10 @@ diff --git a/src/cpu/x86/vm/templateInte
+ return entry;
+}
+
-
++
address TemplateInterpreterGenerator::generate_exception_handler_common(const char* name, const char* message, bool pass_oop) {
assert(!pass_oop || message == NULL, "either oop or message but not both");
+ address entry = __ pc();
@@ -1370,6 +1407,7 @@
case Interpreter::empty : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry(); break;
case Interpreter::accessor : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry(); break;
@@ -2881,12 +3004,11 @@ diff --git a/src/cpu/x86/vm/templateTabl
}
// push return address
-@@ -3054,6 +3052,57 @@
-
+@@ -3055,6 +3053,57 @@
// profile this call
__ profile_virtual_call(rdx, rsi, rdi);
-+
-+ if (MethodHandles) { // %%% let's use this refactored code always
+
++ if (MethodHandleSupport) { // %%% let's use this refactored code always
+ Label no_such_interface, no_such_method;
+
+ __ lookup_interface_method(// inputs: rec. class, interface, itable index
@@ -2936,9 +3058,10 @@ diff --git a/src/cpu/x86/vm/templateTabl
+ }
+
+ // %%% remove this old code, in favor of the previous block:
-
++
__ mov(rdi, rdx); // Save klassOop in rdi
+ // Compute start of first itableOffsetEntry (which is at the end of the vtable)
diff --git a/src/cpu/x86/vm/templateTable_x86_64.cpp b/src/cpu/x86/vm/templateTable_x86_64.cpp
--- a/src/cpu/x86/vm/templateTable_x86_64.cpp
+++ b/src/cpu/x86/vm/templateTable_x86_64.cpp
@@ -2960,12 +3083,11 @@ diff --git a/src/cpu/x86/vm/templateTabl
}
// push return address
-@@ -3009,6 +3009,57 @@
-
+@@ -3010,6 +3010,57 @@
// profile this call
__ profile_virtual_call(rdx, r13, r14);
-+
-+ if (MethodHandles) { // %%% let's use this refactored code always
+
++ if (MethodHandleSupport) { // %%% let's use this refactored code always
+ Label no_such_interface, no_such_method;
+
+ __ lookup_interface_method(// inputs: rec. class, interface, itable index
@@ -3015,9 +3137,10 @@ diff --git a/src/cpu/x86/vm/templateTabl
+ }
+
+ // %%% remove this old code, in favor of the previous block:
-
++
__ mov(r14, rdx); // Save klassOop in r14
+ // Compute start of first itableOffsetEntry (which is at the end of
diff --git a/src/cpu/x86/vm/vtableStubs_x86_32.cpp b/src/cpu/x86/vm/vtableStubs_x86_32.cpp
--- a/src/cpu/x86/vm/vtableStubs_x86_32.cpp
+++ b/src/cpu/x86/vm/vtableStubs_x86_32.cpp
@@ -3076,7 +3199,7 @@ diff --git a/src/cpu/x86/vm/vtableStubs_
+ address npe_addr = NULL, ame_addr = NULL;
+
-+ if (MethodHandles) { // %%% let's use this refactored code always
++ if (MethodHandleSupport) { // %%% let's use this refactored code always
+ // Most registers are in use; we'll use rax, rbx, rcx, rsi
+ Register restore_rcx = rcx;
+ __ push(restore_rcx);
@@ -3167,7 +3290,7 @@ diff --git a/src/cpu/x86/vm/vtableStubs_
return (DebugVtables ? 210 : 16) + (CountCompiledCalls ? 6 : 0);
} else {
// Itable stub size
-+ if (MethodHandles) // %%% let's use this refactored code always
++ if (MethodHandleSupport) // %%% let's use this refactored code always
+ return (DebugVtables ? 159 : 79) + (CountCompiledCalls ? 6 : 0);
return (DebugVtables ? 144 : 64) + (CountCompiledCalls ? 6 : 0);
}
@@ -3312,11 +3435,11 @@ diff --git a/src/share/vm/classfile/clas
diff --git a/src/share/vm/classfile/classFileParser.cpp b/src/share/vm/classfile/classFileParser.cpp
--- a/src/share/vm/classfile/classFileParser.cpp
+++ b/src/share/vm/classfile/classFileParser.cpp
-@@ -1839,6 +1839,11 @@
+@@ -1842,6 +1842,11 @@
_has_vanilla_constructor = true;
}
-+ if (MethodHandles && m->is_method_handle_invoke()) {
++ if (MethodHandleSupport && m->is_method_handle_invoke()) {
+ THROW_MSG_(vmSymbols::java_lang_VirtualMachineError(),
+ "Method handle invokers must be defined internally to the VM", nullHandle);
+ }
@@ -3324,7 +3447,7 @@ diff --git a/src/share/vm/classfile/clas
return m;
}
-@@ -2462,6 +2467,78 @@
+@@ -2465,9 +2470,82 @@
}
@@ -3337,7 +3460,7 @@ diff --git a/src/share/vm/classfile/clas
+ // This is not particularly nice, but since there is no way to express
+ // a native wordSize field in Java, we must do it at this level.
+
-+ if (!MethodHandles) return;
++ if (!MethodHandleSupport) return;
+
+ int word_sig_index = 0;
+ const int cp_size = cp->length();
@@ -3403,22 +3526,51 @@ diff --git a/src/share/vm/classfile/clas
instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
Handle class_loader,
Handle protection_domain,
-@@ -2802,6 +2879,11 @@
- // Add fake fields for java.lang.Class instances (also see below)
- if (class_name() == vmSymbols::java_lang_Class() && class_loader.is_null()) {
++ KlassHandle host_klass,
+ GrowableArray<Handle>* cp_patches,
+ symbolHandle& parsed_name,
+ TRAPS) {
+@@ -2500,6 +2578,7 @@
+ }
+ }
+
++ _host_klass = host_klass;
+ _cp_patches = cp_patches;
+
+ instanceKlassHandle nullHandle;
+@@ -2807,6 +2886,11 @@
java_lang_Class_fix_pre(&methods, &fac, CHECK_(nullHandle));
-+ }
-+
+ }
+
+ // adjust the vmentry field declaration in java.dyn.MethodHandle
-+ if (MethodHandles && class_name() == vmSymbols::impl_java_dyn_MethodHandleImpl() && class_loader.is_null()) {
++ if (MethodHandleSupport && class_name() == vmSymbols::impl_java_dyn_MethodHandleImpl() && class_loader.is_null()) {
+ java_dyn_MethodHandle_fix_pre(cp, &fields, &fac, CHECK_(nullHandle));
- }
-
++ }
++
// Add a fake "discovered" field if it is not present
+ // for compatibility with earlier jdk's.
+ if (class_name() == vmSymbols::java_lang_ref_Reference()
+@@ -3133,7 +3217,7 @@
+ this_klass->set_method_ordering(method_ordering());
+ this_klass->set_initial_method_idnum(methods->length());
+ this_klass->set_name(cp->klass_name_at(this_class_index));
+- if (LinkWellKnownClasses) // I am well known to myself
++ if (LinkWellKnownClasses || is_anonymous()) // I am well known to myself
+ cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve
+ this_klass->set_protection_domain(protection_domain());
+ this_klass->set_fields_annotations(fields_annotations());
diff --git a/src/share/vm/classfile/classFileParser.hpp b/src/share/vm/classfile/classFileParser.hpp
--- a/src/share/vm/classfile/classFileParser.hpp
+++ b/src/share/vm/classfile/classFileParser.hpp
-@@ -145,6 +145,11 @@
+@@ -33,6 +33,7 @@
+ u2 _major_version;
+ u2 _minor_version;
+ symbolHandle _class_name;
++ KlassHandle _host_klass;
+ GrowableArray<Handle>* _cp_patches; // overrides for CP entries
+
+ bool _has_finalizer;
+@@ -145,6 +146,11 @@
// Adjust the next_nonstatic_oop_offset to place the fake fields
// before any Java fields.
void java_lang_Class_fix_post(int* next_nonstatic_oop_offset);
@@ -3430,6 +3582,32 @@ diff --git a/src/share/vm/classfile/clas
// Format checker methods
void classfile_parse_error(const char* msg, TRAPS);
+@@ -204,6 +210,10 @@
+ char* skip_over_field_name(char* name, bool slash_ok, unsigned int length);
+ char* skip_over_field_signature(char* signature, bool void_ok, unsigned int length, TRAPS);
+
++ bool is_anonymous() {
++ assert(AnonymousClasses || _host_klass.is_null(), "");
++ return _host_klass.not_null();
++ }
+ bool has_cp_patch_at(int index) {
+ assert(AnonymousClasses, "");
+ assert(index >= 0, "oob");
+@@ -249,11 +259,13 @@
+ Handle protection_domain,
+ symbolHandle& parsed_name,
+ TRAPS) {
+- return parseClassFile(name, class_loader, protection_domain, NULL, parsed_name, THREAD);
++ KlassHandle no_host_klass;
++ return parseClassFile(name, class_loader, protection_domain, no_host_klass, NULL, parsed_name, THREAD);
+ }
+ instanceKlassHandle parseClassFile(symbolHandle name,
+ Handle class_loader,
+ Handle protection_domain,
++ KlassHandle host_klass,
+ GrowableArray<Handle>* cp_patches,
+ symbolHandle& parsed_name,
+ TRAPS);
diff --git a/src/share/vm/classfile/dictionary.cpp b/src/share/vm/classfile/dictionary.cpp
--- a/src/share/vm/classfile/dictionary.cpp
+++ b/src/share/vm/classfile/dictionary.cpp
@@ -3638,7 +3816,7 @@ diff --git a/src/share/vm/classfile/java
ResourceMark rm;
tty->print_cr("Invalid layout of %s at %s", ik->external_name(), name_symbol->as_C_string());
fatal("Invalid layout of preloaded class");
-@@ -42,13 +53,15 @@
+@@ -42,14 +53,16 @@
// Same as above but for "optional" offsets that might not be present in certain JDK versions
static void
compute_optional_offset(int& dest_offset,
@@ -3652,11 +3830,100 @@ diff --git a/src/share/vm/classfile/java
dest_offset = fd.offset();
}
}
-+
-
+
++
Handle java_lang_String::basic_create(int length, bool tenured, TRAPS) {
// Create the String object first, so there's a chance that the String
-@@ -412,6 +425,8 @@
+ // and the char array it points to end up in the same cache line.
+@@ -239,21 +252,19 @@
+ typeArrayOop value = java_lang_String::value(obj);
+ int offset = java_lang_String::offset(obj);
+ int length = java_lang_String::length(obj);
++ jchar* base = value->char_at_addr(offset);
++ symbolOop sym = SymbolTable::lookup_unicode(base, length, THREAD);
++ return symbolHandle(THREAD, sym);
++}
+
+- ResourceMark rm(THREAD);
+- symbolHandle result;
++symbolOop java_lang_String::as_symbol_or_null(oop java_string) {
++ typeArrayOop value = java_lang_String::value(java_string);
++ int offset = java_lang_String::offset(java_string);
++ int length = java_lang_String::length(java_string);
++ jchar* base = value->char_at_addr(offset);
++ return SymbolTable::probe_unicode(base, length);
++}
+
+- if (length > 0) {
+- int utf8_length = UNICODE::utf8_length(value->char_at_addr(offset), length);
+- char* chars = NEW_RESOURCE_ARRAY(char, utf8_length + 1);
+- UNICODE::convert_to_utf8(value->char_at_addr(offset), length, chars);
+- // Allocate the symbol
+- result = oopFactory::new_symbol_handle(chars, utf8_length, CHECK_(symbolHandle()));
+- } else {
+- result = oopFactory::new_symbol_handle("", 0, CHECK_(symbolHandle()));
+- }
+- return result;
+-}
+
+ int java_lang_String::utf8_length(oop java_string) {
+ typeArrayOop value = java_lang_String::value(java_string);
+@@ -385,13 +396,53 @@
+ }
+
+
++void java_lang_Class::print_signature(oop java_class, outputStream* st) {
++ assert(java_lang_Class::is_instance(java_class), "must be a Class object");
++ symbolOop name = NULL;
++ bool is_instance = false;
++ if (is_primitive(java_class)) {
++ name = vmSymbols::type_signature(primitive_type(java_class));
++ } else {
++ klassOop k = as_klassOop(java_class);
++ is_instance = Klass::cast(k)->oop_is_instance();
++ name = Klass::cast(k)->name();
++ }
++ if (name == NULL) {
++ st->print("<null>");
++ return;
++ }
++ if (is_instance) st->print("L");
++ st->write((char*) name->base(), (int) name->utf8_length());
++ if (is_instance) st->print(";");
++}
++
++symbolOop java_lang_Class::as_signature(oop java_class, bool intern_if_not_found, TRAPS) {
++ assert(java_lang_Class::is_instance(java_class), "must be a Class object");
++ symbolOop name = NULL;
++ if (is_primitive(java_class)) {
++ return vmSymbols::type_signature(primitive_type(java_class));
++ } else {
++ klassOop k = as_klassOop(java_class);
++ if (!Klass::cast(k)->oop_is_instance()) {
++ return Klass::cast(k)->name();
++ } else {
++ ResourceMark rm;
++ const char* sigstr = Klass::cast(k)->signature_name();
++ int siglen = (int) strlen(sigstr);
++ if (!intern_if_not_found)
++ return SymbolTable::probe(sigstr, siglen);
++ else
++ return oopFactory::new_symbol(sigstr, siglen, THREAD);
++ }
++ }
++}
++
+ klassOop java_lang_Class::array_klass(oop java_class) {
+ klassOop k = klassOop(java_class->obj_field(array_klass_offset));
+ assert(k == NULL || k->is_klass() && Klass::cast(k)->oop_is_javaArray(), "should be array klass");
+ return k;
+ }
+
+-
+ void java_lang_Class::set_array_klass(oop java_class, klassOop klass) {
+ assert(klass->is_klass() && Klass::cast(klass)->oop_is_javaArray(), "should be array klass");
+ java_class->obj_field_put(array_klass_offset, klass);
+@@ -412,6 +463,8 @@
bool java_lang_Class::is_primitive(oop java_class) {
@@ -3665,12 +3932,10 @@ diff --git a/src/share/vm/classfile/java
klassOop k = klassOop(java_class->obj_field(klass_offset));
return k == NULL;
}
-@@ -429,6 +444,19 @@
- }
- assert(Universe::java_mirror(type) == java_class, "must be consistent");
+@@ -431,6 +484,19 @@
return type;
-+}
-+
+ }
+
+BasicType java_lang_Class::as_BasicType(oop java_class, klassOop* reference_klass) {
+ assert(java_lang_Class::is_instance(java_class), "must be a Class object");
+ if (is_primitive(java_class)) {
@@ -3682,10 +3947,12 @@ diff --git a/src/share/vm/classfile/java
+ (*reference_klass) = as_klassOop(java_class);
+ return T_OBJECT;
+ }
- }
-
-
-@@ -1970,6 +1998,21 @@
++}
++
+
+ oop java_lang_Class::primitive_mirror(BasicType t) {
+ oop mirror = Universe::java_mirror(t);
+@@ -1988,6 +2054,21 @@
}
@@ -3707,7 +3974,7 @@ diff --git a/src/share/vm/classfile/java
// Support for java_lang_ref_Reference
oop java_lang_ref_Reference::pending_list_lock() {
instanceKlass* ik = instanceKlass::cast(SystemDictionary::reference_klass());
-@@ -2019,12 +2062,220 @@
+@@ -2037,13 +2118,324 @@
}
@@ -3718,6 +3985,13 @@ diff --git a/src/share/vm/classfile/java
+int java_dyn_MethodHandle::_vmentry_offset;
+int java_dyn_MethodHandle::_vmslots_offset;
+
++int impl_java_dyn_MemberName::_clazz_offset;
++int impl_java_dyn_MemberName::_name_offset;
++int impl_java_dyn_MemberName::_type_offset;
++int impl_java_dyn_MemberName::_flags_offset;
++int impl_java_dyn_MemberName::_vmtarget_offset;
++int impl_java_dyn_MemberName::_vmindex_offset;
++
+int impl_java_dyn_DirectMethodHandle::_vmindex_offset;
+
+int impl_java_dyn_BoundMethodHandle::_argument_offset;
@@ -3727,7 +4001,7 @@ diff --git a/src/share/vm/classfile/java
+
+void java_dyn_MethodHandle::compute_offsets() {
+ klassOop k = SystemDictionary::MethodHandle_klass();
-+ if (k != NULL && MethodHandles) {
++ if (k != NULL && MethodHandleSupport) {
+ compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::java_dyn_MethodType_signature(), true);
+ compute_offset(_vmtarget_offset, k, vmSymbols::vmtarget_name(), vmSymbols::object_signature(), true);
+ compute_offset(_vmentry_offset, k, vmSymbols::vmentry_name(), vmSymbols::machine_word_signature(), true);
@@ -3738,16 +4012,28 @@ diff --git a/src/share/vm/classfile/java
+ }
+}
+
++void impl_java_dyn_MemberName::compute_offsets() {
++ klassOop k = SystemDictionary::MemberName_klass();
++ if (k != NULL && MethodHandleSupport) {
++ compute_offset(_clazz_offset, k, vmSymbols::clazz_name(), vmSymbols::class_signature());
++ compute_offset(_name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature());
++ compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::object_signature());
++ compute_offset(_flags_offset, k, vmSymbols::flags_name(), vmSymbols::int_signature());
++ compute_offset(_vmtarget_offset, k, vmSymbols::vmtarget_name(), vmSymbols::object_signature());
++ compute_offset(_vmindex_offset, k, vmSymbols::vmindex_name(), vmSymbols::int_signature());
++ }
++}
++
+void impl_java_dyn_DirectMethodHandle::compute_offsets() {
+ klassOop k = SystemDictionary::DirectMethodHandle_klass();
-+ if (k != NULL && MethodHandles) {
++ if (k != NULL && MethodHandleSupport) {
+ compute_offset(_vmindex_offset, k, vmSymbols::vmindex_name(), vmSymbols::int_signature(), true);
+ }
+}
+
+void impl_java_dyn_BoundMethodHandle::compute_offsets() {
+ klassOop k = SystemDictionary::BoundMethodHandle_klass();
-+ if (k != NULL && MethodHandles) {
++ if (k != NULL && MethodHandleSupport) {
+ compute_offset(_vmargslot_offset, k, vmSymbols::vmargslot_name(), vmSymbols::int_signature(), true);
+ compute_offset(_argument_offset, k, vmSymbols::argument_name(), vmSymbols::object_signature(), true);
+ }
@@ -3755,7 +4041,7 @@ diff --git a/src/share/vm/classfile/java
+
+void impl_java_dyn_AdapterMethodHandle::compute_offsets() {
+ klassOop k = SystemDictionary::AdapterMethodHandle_klass();
-+ if (k != NULL && MethodHandles) {
++ if (k != NULL && MethodHandleSupport) {
+ compute_offset(_conversion_offset, k, vmSymbols::conversion_name(), vmSymbols::int_signature(), true);
+ }
+}
@@ -3817,6 +4103,68 @@ diff --git a/src/share/vm/classfile/java
+ // But just in case, we use release_address_field_put.
+}
+
++/// MemberName accessors
++
++oop impl_java_dyn_MemberName::clazz(oop mname) {
++ assert(Klass::cast(mname->klass())->is_subclass_of(SystemDictionary::MemberName_klass()), "wrong type");
++ return mname->obj_field(_clazz_offset);
++}
++
++void impl_java_dyn_MemberName::set_clazz(oop mname, oop clazz) {
++ assert(Klass::cast(mname->klass())->is_subclass_of(SystemDictionary::MemberName_klass()), "wrong type");
++ mname->obj_field_put(_clazz_offset, clazz);
++}
++
++oop impl_java_dyn_MemberName::name(oop mname) {
++ assert(Klass::cast(mname->klass())->is_subclass_of(SystemDictionary::MemberName_klass()), "wrong type");
++ return mname->obj_field(_name_offset);
++}
++
++void impl_java_dyn_MemberName::set_name(oop mname, oop name) {
++ assert(Klass::cast(mname->klass())->is_subclass_of(SystemDictionary::MemberName_klass()), "wrong type");
++ mname->obj_field_put(_name_offset, name);
++}
++
++oop impl_java_dyn_MemberName::type(oop mname) {
++ assert(Klass::cast(mname->klass())->is_subclass_of(SystemDictionary::MemberName_klass()), "wrong type");
++ return mname->obj_field(_type_offset);
++}
++
++void impl_java_dyn_MemberName::set_type(oop mname, oop type) {
++ assert(Klass::cast(mname->klass())->is_subclass_of(SystemDictionary::MemberName_klass()), "wrong type");
++ mname->obj_field_put(_type_offset, type);
++}
++
++int impl_java_dyn_MemberName::flags(oop mname) {
++ assert(Klass::cast(mname->klass())->is_subclass_of(SystemDictionary::MemberName_klass()), "wrong type");
++ return mname->int_field(_flags_offset);
++}
++
++void impl_java_dyn_MemberName::set_flags(oop mname, int flags) {
++ assert(Klass::cast(mname->klass())->is_subclass_of(SystemDictionary::MemberName_klass()), "wrong type");
++ mname->int_field_put(_flags_offset, flags);
++}
++
++oop impl_java_dyn_MemberName::vmtarget(oop mname) {
++ assert(Klass::cast(mname->klass())->is_subclass_of(SystemDictionary::MemberName_klass()), "wrong type");
++ return mname->obj_field(_vmtarget_offset);
++}
++
++void impl_java_dyn_MemberName::set_vmtarget(oop mname, oop ref) {
++ assert(Klass::cast(mname->klass())->is_subclass_of(SystemDictionary::MemberName_klass()), "wrong type");
++ mname->obj_field_put(_vmtarget_offset, ref);
++}
++
++int impl_java_dyn_MemberName::vmindex(oop mname) {
++ assert(Klass::cast(mname->klass())->is_subclass_of(SystemDictionary::MemberName_klass()), "wrong type");
++ return mname->int_field(_vmindex_offset);
++}
++
++void impl_java_dyn_MemberName::set_vmindex(oop mname, int index) {
++ assert(Klass::cast(mname->klass())->is_subclass_of(SystemDictionary::MemberName_klass()), "wrong type");
++ mname->int_field_put(_vmindex_offset, index);
++}
++
+oop java_dyn_MethodHandle::vmtarget(oop mh) {
+ assert(Klass::cast(mh->klass())->is_subclass_of(SystemDictionary::MethodHandle_klass()), "wrong type");
+ return mh->obj_field(_vmtarget_offset);
@@ -3873,6 +4221,28 @@ diff --git a/src/share/vm/classfile/java
+ }
+}
+
++void java_dyn_MethodType::print_signature(oop mt, outputStream* st) {
++ st->print("(");
++ objArrayOop pts = ptypes(mt);
++ for (int i = 0, limit = pts->length(); i < limit; i++) {
++ java_lang_Class::print_signature(pts->obj_at(i), st);
++ }
++ st->print(")");
++ java_lang_Class::print_signature(rtype(mt), st);
++}
++
++symbolOop java_dyn_MethodType::as_signature(oop mt, bool intern_if_not_found, TRAPS) {
++ ResourceMark rm;
++ stringStream buffer(128);
++ print_signature(mt, &buffer);
++ const char* sigstr = buffer.base();
++ int siglen = (int) buffer.size();
++ if (!intern_if_not_found)
++ return SymbolTable::probe(sigstr, siglen);
++ else
++ return oopFactory::new_symbol(sigstr, siglen, THREAD);
++}
++
+oop java_dyn_MethodType::rtype(oop mt) {
+ assert(is_instance(mt), "must be a MethodType");
+ return mt->obj_field(_rtype_offset);
@@ -3925,16 +4295,18 @@ diff --git a/src/share/vm/classfile/java
int java_security_AccessControlContext::_context_offset = 0;
int java_security_AccessControlContext::_privilegedContext_offset = 0;
int java_security_AccessControlContext::_isPrivileged_offset = 0;
+
-
-
void java_security_AccessControlContext::compute_offsets() {
assert(_isPrivileged_offset == 0, "offsets should be initialized only once");
-@@ -2354,6 +2605,14 @@
+ fieldDescriptor fd;
+@@ -2372,6 +2764,15 @@
java_lang_System::compute_offsets();
java_lang_Thread::compute_offsets();
java_lang_ThreadGroup::compute_offsets();
-+ if (MethodHandles) {
++ if (MethodHandleSupport) {
+ java_dyn_MethodHandle::compute_offsets();
++ impl_java_dyn_MemberName::compute_offsets();
+ impl_java_dyn_DirectMethodHandle::compute_offsets();
+ impl_java_dyn_BoundMethodHandle::compute_offsets();
+ impl_java_dyn_AdapterMethodHandle::compute_offsets();
@@ -3944,7 +4316,7 @@ diff --git a/src/share/vm/classfile/java
java_security_AccessControlContext::compute_offsets();
// Initialize reflection classes. The layouts of these classes
// changed with the new reflection implementation in JDK 1.4, and
-@@ -2371,6 +2630,9 @@
+@@ -2389,6 +2790,9 @@
sun_reflect_UnsafeStaticFieldAccessorImpl::compute_offsets();
}
sun_misc_AtomicLongCSImpl::compute_offsets();
@@ -3957,15 +4329,25 @@ diff --git a/src/share/vm/classfile/java
diff --git a/src/share/vm/classfile/javaClasses.hpp b/src/share/vm/classfile/javaClasses.hpp
--- a/src/share/vm/classfile/javaClasses.hpp
+++ b/src/share/vm/classfile/javaClasses.hpp
-@@ -148,6 +148,7 @@
+@@ -107,6 +107,7 @@
+
+ // Conversion
+ static symbolHandle as_symbol(Handle java_string, TRAPS);
++ static symbolOop as_symbol_or_null(oop java_string);
+
+ // Testers
+ static bool is_instance(oop obj) {
+@@ -149,6 +150,9 @@
static oop create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS);
// Conversion
static klassOop as_klassOop(oop java_class);
+ static BasicType as_BasicType(oop java_class, klassOop* reference_klass = NULL);
++ static symbolOop as_signature(oop java_class, bool intern_if_not_found, TRAPS);
++ static void print_signature(oop java_class, outputStream *st);
// Testing
static bool is_instance(oop obj) {
return obj != NULL && obj->klass() == SystemDictionary::class_klass();
-@@ -665,6 +666,8 @@
+@@ -668,6 +672,8 @@
static BasicType basic_type(oop box);
static bool is_instance(oop box) { return basic_type(box) != T_ILLEGAL; }
static bool is_instance(oop box, BasicType type) { return basic_type(box) == type; }
@@ -3974,7 +4356,7 @@ diff --git a/src/share/vm/classfile/java
static int value_offset_in_bytes(BasicType type) {
return ( type == T_LONG || type == T_DOUBLE ) ? long_value_offset :
-@@ -769,6 +772,154 @@
+@@ -772,6 +778,255 @@
};
@@ -4023,6 +4405,78 @@ diff --git a/src/share/vm/classfile/java
+ static int vmslots_offset_in_bytes() { return _vmslots_offset; }
+};
+
++class impl_java_dyn_MemberName: AllStatic {
++ friend class JavaClasses;
++
++ private:
++ // From java.dyn.MemberName:
++ // private Class<?> clazz; // class in which the method is defined
++ // private String name; // may be null if not yet materialized
++ // private Object type; // may be null if not yet materialized
++ // private int flags; // modifier bits; see reflect.Modifier
++ // private Object vmtarget; // VM-specific target value
++ // private int vmindex; // method index within class or interface
++ static int _clazz_offset;
++ static int _name_offset;
++ static int _type_offset;
++ static int _flags_offset;
++ static int _vmtarget_offset;
++ static int _vmindex_offset;
++
++ static void compute_offsets();
++
++ public:
++ // Accessors
++ static oop clazz(oop mname);
++ static void set_clazz(oop mname, oop clazz);
++
++ static oop type(oop mname);
++ static void set_type(oop mname, oop type);
++
++ static oop name(oop mname);
++ static void set_name(oop mname, oop name);
++
++ static int flags(oop mname);
++ static void set_flags(oop mname, int flags);
++
++ static int modifiers(oop mname) { return (u2) flags(mname); }
++ static void set_modifiers(oop mname, int mods)
++ { set_flags(mname, (flags(mname) &~ (u2)-1) | (u2)mods); }
++
++ static oop vmtarget(oop mname);
++ static void set_vmtarget(oop mname, oop target);
++
++ static int vmindex(oop mname);
++ static void set_vmindex(oop mname, int index);
++
++ // Testers
++ static bool is_subclass(klassOop klass) {
++ return Klass::cast(klass)->is_subclass_of(SystemDictionary::MemberName_klass());
++ }
++ static bool is_instance(oop obj) {
++ return obj != NULL && is_subclass(obj->klass());
++ }
++
++ // Relevant integer codes (keep these in synch. with MethodHandleNatives.Constants):
++ enum {
++ MN_IS_METHOD = 0x00010000, // method (not constructor)
++ MN_IS_CONSTRUCTOR = 0x00020000, // constructor
++ MN_IS_FIELD = 0x00040000, // field
++ MN_IS_TYPE = 0x00080000, // nested type
++ MN_SEARCH_SUPERCLASSES = 0x00100000, // for MHN.getMembers
++ MN_SEARCH_INTERFACES = 0x00200000, // for MHN.getMembers
++ VM_INDEX_UNINITIALIZED = -99
++ };
++
++ // Accessors for code generation:
++ static int clazz_offset_in_bytes() { return _clazz_offset; }
++ static int type_offset_in_bytes() { return _type_offset; }
++ static int name_offset_in_bytes() { return _name_offset; }
++ static int flags_offset_in_bytes() { return _flags_offset; }
++ static int vmtarget_offset_in_bytes() { return _vmtarget_offset; }
++ static int vmindex_offset_in_bytes() { return _vmindex_offset; }
++};
++
+class impl_java_dyn_DirectMethodHandle: public java_dyn_MethodHandle {
+ friend class JavaClasses;
+
@@ -4066,9 +4520,35 @@ diff --git a/src/share/vm/classfile/java
+ static int _conversion_offset; // type of conversion to apply
+ static void compute_offsets();
+
-+public:
++ public:
+ static int conversion(oop mh);
+ static void set_conversion(oop mh, int conv);
++
++ // Relevant integer codes (keep these in synch. with MethodHandleNatives.Constants):
++ enum {
++ RETYPE_ONLY = 0x000, // no argument changes; straight retype
++ CHECK_CAST = 0x100, // ref-to-ref conversion; requires a Class argument
++ PRIM_TO_PRIM = 0x200, // converts from one primitive to another
++ REF_TO_PRIM = 0x300, // unboxes a wrapper to produce a primitive
++ PRIM_TO_REF = 0x400, // boxes a primitive into a wrapper (NYI)
++ SWAP_ARGS = 0x500, // swap arguments (vminfo is 2nd arg)
++ ROT_ARGS = 0x600, // rotate arguments (vminfo is displaced arg)
++ DUP_ARGS = 0x700, // duplicates one or more arguments (at TOS)
++ DROP_ARGS = 0x800, // remove one or more argument slots
++ COLLECT_ARGS = 0x900, // combine one or more arguments into a varargs (NYI)
++ SPREAD_ARGS = 0xA00, // expand in place a varargs array (of known size)
++ FLYBY = 0xB00, // operate first on reified argument list (NYI)
++ RICOCHET = 0xC00, // run an adapter chain on the return value (NYI)
++
++ CONV_OP_MASK = 0xF00, // byte 3 contains the conversion op field
++ CONV_VMINFO_MASK = 0x0FF, // LSB is reserved for JVM use
++ CONV_VMINFO_SHIFT = 0, // position of bits in CONV_VMINFO_MASK
++ CONV_OP_SHIFT = 8, // position of bits in CONV_OP_MASK
++ CONV_DEST_TYPE_SHIFT = 12, // byte 3 has the adapter BasicType (if needed)
++ CONV_SRC_TYPE_SHIFT = 16, // byte 2 has the source BasicType (if needed)
++ CONV_STACK_MOVE_SHIFT = 20, // high 12 bits give signed SP change
++ CONV_STACK_MOVE_MASK = (1 << (32 - CONV_STACK_MOVE_SHIFT)) - 1
++ };
+
+ static int conversion_offset_in_bytes() { return _conversion_offset; }
+};
@@ -4088,11 +4568,14 @@ diff --git a/src/share/vm/classfile/java
+
+ public:
+ // Accessors
-+ static oop rtype(oop mh);
-+ static objArrayOop ptypes(oop mh);
-+ static oop form(oop mh);
-+
-+ static oop ptype(oop mh, int index);
++ static oop rtype(oop mt);
++ static objArrayOop ptypes(oop mt);
++ static oop form(oop mt);
++
++ static oop ptype(oop mt, int index);
++
++ static symbolOop as_signature(oop mt, bool intern_if_not_found, TRAPS);
++ static void print_signature(oop mt, outputStream* st);
+
+ static bool is_instance(oop obj) {
+ return obj != NULL && obj->klass() == SystemDictionary::MethodType_klass();
@@ -4115,8 +4598,8 @@ diff --git a/src/share/vm/classfile/java
+
+ public:
+ // Accessors
-+ static int vmslots(oop mh);
-+ static oop erasedType(oop mh);
++ static int vmslots(oop mtform);
++ static oop erasedType(oop mtform);
+
+ // Accessors for code generation:
+ static int vmslots_offset_in_bytes() { return _vmslots_offset; }
@@ -4145,6 +4628,96 @@ diff --git a/src/share/vm/classfile/load
klassOop find_constrained_klass(symbolHandle name, Handle loader);
klassOop find_constrained_elem_klass(symbolHandle name, symbolHandle elem_name,
+diff --git a/src/share/vm/classfile/symbolTable.cpp b/src/share/vm/classfile/symbolTable.cpp
+--- a/src/share/vm/classfile/symbolTable.cpp
++++ b/src/share/vm/classfile/symbolTable.cpp
+@@ -109,6 +109,40 @@
+ return the_table()->lookup(index, name, len, hash);
+ }
+
++// Suggestion: Push unicode-based lookup all the way into the hashing
++// and probing logic, so there is no need for convert_to_utf8 until
++// an actual new symbolOop is created.
++symbolOop SymbolTable::lookup_unicode(const jchar* name, int utf16_length, TRAPS) {
++ int utf8_length = UNICODE::utf8_length((jchar*) name, utf16_length);
++ char stack_buf[128];
++ if (utf8_length < (int) sizeof(stack_buf)) {
++ char* chars = stack_buf;
++ UNICODE::convert_to_utf8(name, utf16_length, chars);
++ return lookup(chars, utf8_length, THREAD);
++ } else {
++ ResourceMark rm(THREAD);
++ char* chars = NEW_RESOURCE_ARRAY(char, utf8_length + 1);;
++ UNICODE::convert_to_utf8(name, utf16_length, chars);
++ return lookup(chars, utf8_length, THREAD);
++ }
++}
++
++symbolOop SymbolTable::lookup_only_unicode(const jchar* name, int utf16_length,
++ unsigned int& hash) {
++ int utf8_length = UNICODE::utf8_length((jchar*) name, utf16_length);
++ char stack_buf[128];
++ if (utf8_length < (int) sizeof(stack_buf)) {
++ char* chars = stack_buf;
++ UNICODE::convert_to_utf8(name, utf16_length, chars);
++ return lookup_only(chars, utf8_length, hash);
++ } else {
++ ResourceMark rm;
++ char* chars = NEW_RESOURCE_ARRAY(char, utf8_length + 1);;
++ UNICODE::convert_to_utf8(name, utf16_length, chars);
++ return lookup_only(chars, utf8_length, hash);
++ }
++}
++
+ void SymbolTable::add(constantPoolHandle cp, int names_count,
+ const char** names, int* lengths, int* cp_indices,
+ unsigned int* hashValues, TRAPS) {
+@@ -126,15 +160,6 @@
+ }
+ }
+
+-// Needed for preloading classes in signatures when compiling.
+-
+-symbolOop SymbolTable::probe(const char* name, int len) {
+- unsigned int hashValue = hash_symbol(name, len);
+- int index = the_table()->hash_to_index(hashValue);
+- return the_table()->lookup(index, name, len, hashValue);
+-}
+-
+-
+ symbolOop SymbolTable::basic_add(int index, u1 *name, int len,
+ unsigned int hashValue, TRAPS) {
+ assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(),
+diff --git a/src/share/vm/classfile/symbolTable.hpp b/src/share/vm/classfile/symbolTable.hpp
+--- a/src/share/vm/classfile/symbolTable.hpp
++++ b/src/share/vm/classfile/symbolTable.hpp
+@@ -91,6 +91,10 @@
+ // Only copy to C string to be added if lookup failed.
+ static symbolOop lookup(symbolHandle sym, int begin, int end, TRAPS);
+
++ // jchar (utf16) version of lookups
++ static symbolOop lookup_unicode(const jchar* name, int len, TRAPS);
++ static symbolOop lookup_only_unicode(const jchar* name, int len, unsigned int& hash);
++
+ static void add(constantPoolHandle cp, int names_count,
+ const char** names, int* lengths, int* cp_indices,
+ unsigned int* hashValues, TRAPS);
+@@ -112,7 +116,14 @@
+ // Needed for preloading classes in signatures when compiling.
+ // Returns the symbol is already present in symbol table, otherwise
+ // NULL. NO ALLOCATION IS GUARANTEED!
+- static symbolOop probe(const char* name, int len);
++ static symbolOop probe(const char* name, int len) {
++ unsigned int ignore_hash;
++ return lookup_only(name, len, ignore_hash);
++ }
++ static symbolOop probe_unicode(const jchar* name, int len) {
++ unsigned int ignore_hash;
++ return lookup_only_unicode(name, len, ignore_hash);
++ }
+
+ // Histogram
+ static void print_histogram() PRODUCT_RETURN;
diff --git a/src/share/vm/classfile/systemDictionary.cpp b/src/share/vm/classfile/systemDictionary.cpp
--- a/src/share/vm/classfile/systemDictionary.cpp
+++ b/src/share/vm/classfile/systemDictionary.cpp
@@ -4156,7 +4729,16 @@ diff --git a/src/share/vm/classfile/syst
int SystemDictionary::_number_of_modifications = 0;
-@@ -1651,6 +1652,10 @@
+@@ -960,6 +961,8 @@
+ instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name,
+ class_loader,
+ protection_domain,
++ host_klass,
++ cp_patches,
+ parsed_name,
+ THREAD);
+
+@@ -1685,6 +1688,10 @@
// represent classes we're actively loading.
placeholders_do(blk);
@@ -4167,18 +4749,18 @@ diff --git a/src/share/vm/classfile/syst
// Loader constraints. We must keep the symbolOop used in the name alive.
constraints()->always_strong_classes_do(blk);
-@@ -1685,6 +1690,10 @@
-
+@@ -1720,6 +1727,10 @@
// Adjust dictionary
dictionary()->oops_do(f);
-+
+
+ // Visit extra methods
+ if (invoke_method_table() != NULL)
+ invoke_method_table()->oops_do(f);
-
++
// Partially loaded classes
placeholders()->oops_do(f);
-@@ -1758,6 +1767,8 @@
+
+@@ -1792,6 +1803,8 @@
void SystemDictionary::methods_do(void f(methodOop)) {
dictionary()->methods_do(f);
@@ -4187,7 +4769,7 @@ diff --git a/src/share/vm/classfile/syst
}
// ----------------------------------------------------------------------------
-@@ -1790,6 +1801,7 @@
+@@ -1824,6 +1837,7 @@
_number_of_modifications = 0;
_loader_constraints = new LoaderConstraintTable(_loader_constraint_size);
_resolution_errors = new ResolutionErrorTable(_resolution_error_size);
@@ -4195,7 +4777,7 @@ diff --git a/src/share/vm/classfile/syst
// Allocate private object used as system class loader lock
_system_loader_lock_obj = oopFactory::new_system_objArray(0, CHECK);
-@@ -1851,6 +1863,9 @@
+@@ -1885,6 +1899,9 @@
wk_klass_name_limits[0] = s;
}
}
@@ -4205,39 +4787,39 @@ diff --git a/src/share/vm/classfile/syst
}
-@@ -1883,6 +1898,17 @@
- instanceKlass::cast(WK_KLASS(weak_reference_klass))->set_reference_type(REF_WEAK);
+@@ -1918,6 +1935,17 @@
instanceKlass::cast(WK_KLASS(final_reference_klass))->set_reference_type(REF_FINAL);
instanceKlass::cast(WK_KLASS(phantom_reference_klass))->set_reference_type(REF_PHANTOM);
-+
+
+ WKID meth_group_start = WK_KLASS_ENUM_NAME(MethodHandle_klass);
+ WKID meth_group_end = WK_KLASS_ENUM_NAME(WrongMethodTypeException_klass);
+ initialize_wk_klasses_until(meth_group_start, scan, CHECK);
-+ if (MethodHandles) {
++ if (MethodHandleSupport) {
+ initialize_wk_klasses_through(meth_group_start, scan, CHECK);
+ }
+ if (_well_known_klasses[meth_group_start] == NULL) {
+ // Skip the rest of the method handle classes, if MethodHandle is not loaded.
+ scan = WKID(meth_group_end+1);
+ }
-
++
initialize_wk_klasses_until(WKID_LIMIT, scan, CHECK);
-@@ -1922,6 +1948,13 @@
- return (BasicType)i;
- }
+ _box_klasses[T_BOOLEAN] = WK_KLASS(boolean_klass);
+@@ -1958,6 +1986,13 @@
return T_OBJECT;
-+}
-+
+ }
+
+KlassHandle KlassHandles::box_klass(BasicType t) {
+ if (t >= T_BOOLEAN && t <= T_VOID)
+ return KlassHandle(&SystemDictionary::_box_klasses[t], true);
+ else
+ return KlassHandle();
- }
-
++}
++
// Constraints on class loaders. The details of the algorithm can be
-@@ -2134,11 +2167,56 @@
+ // found in the OOPSLA'98 paper "Dynamic Class Loading in the Java
+ // Virtual Machine" by Sheng Liang and Gilad Bracha. The basic idea is
+@@ -2168,11 +2203,56 @@
}
@@ -4295,18 +4877,15 @@ diff --git a/src/share/vm/classfile/syst
char* SystemDictionary::check_signature_loaders(symbolHandle signature,
Handle loader1, Handle loader2,
bool is_method, TRAPS) {
-@@ -2159,6 +2237,91 @@
- sig_strm.next();
- }
- return NULL;
-+}
-+
-+
+@@ -2196,6 +2276,91 @@
+ }
+
+
+methodOop SystemDictionary::find_method_handle_invoke(symbolHandle signature,
+ Handle class_loader,
+ Handle protection_domain,
+ TRAPS) {
-+ if (!MethodHandles) return NULL;
++ if (!MethodHandleSupport) return NULL;
+ assert(class_loader.is_null() && protection_domain.is_null(),
+ "cannot load specialized versions of MethodHandle.invoke");
+ if (invoke_method_table() == NULL) {
@@ -4384,9 +4963,12 @@ diff --git a/src/share/vm/classfile/syst
+ vmSymbols::makeImpl_name(), vmSymbols::makeImpl_signature(),
+ &args, CHECK_(empty));
+ return Handle(THREAD, (oop) result.get_jobject());
- }
-
-
++}
++
++
+ // Since the identity hash code for symbols changes when the symbols are
+ // moved from the regular perm gen (hash in the mark word) to the shared
+ // spaces (hash is the address), the classes loaded into the dictionary
diff --git a/src/share/vm/classfile/systemDictionary.hpp b/src/share/vm/classfile/systemDictionary.hpp
--- a/src/share/vm/classfile/systemDictionary.hpp
+++ b/src/share/vm/classfile/systemDictionary.hpp
@@ -4398,12 +4980,13 @@ diff --git a/src/share/vm/classfile/syst
// Certain classes are preloaded, such as java.lang.Object and java.lang.String.
// They are all "well-known", in the sense that no class loader is allowed
-@@ -131,6 +132,15 @@
+@@ -131,6 +132,16 @@
template(reflect_constant_pool_klass, sun_reflect_ConstantPool, Opt_Only_JDK15) \
template(reflect_unsafe_static_field_accessor_impl_klass, sun_reflect_UnsafeStaticFieldAccessorImpl, Opt_Only_JDK15) \
\
+ /* support for dynamic typing; it's OK if these are NULL in earlier JDKs */ \
+ template(MethodHandle_klass, java_dyn_MethodHandle, Opt) \
++ template(MemberName_klass, impl_java_dyn_MemberName, Opt) \
+ template(MethodHandleImpl_klass, impl_java_dyn_MethodHandleImpl, Opt) \
+ template(AdapterMethodHandle_klass, impl_java_dyn_AdapterMethodHandle, Opt) \
+ template(BoundMethodHandle_klass, impl_java_dyn_BoundMethodHandle, Opt) \
@@ -4414,7 +4997,7 @@ diff --git a/src/share/vm/classfile/syst
template(vector_klass, java_util_Vector, Pre) \
template(hashtable_klass, java_util_Hashtable, Pre) \
template(stringBuffer_klass, java_lang_StringBuffer, Pre) \
-@@ -161,6 +171,7 @@
+@@ -161,6 +172,7 @@
class SystemDictionary : AllStatic {
friend class VMStructs;
friend class CompactingPermGenGen;
@@ -4422,12 +5005,12 @@ diff --git a/src/share/vm/classfile/syst
NOT_PRODUCT(friend class instanceKlassKlass;)
public:
-@@ -443,6 +454,17 @@
+@@ -443,6 +455,17 @@
static char* check_signature_loaders(symbolHandle signature, Handle loader1,
Handle loader2, bool is_method, TRAPS);
+ // JSR 292
-+ // find the java.dyn.MethodHandle::invoke method for a given signature
++ // find the java.dyn.MethodHandles::invoke method for a given signature
+ static methodOop find_method_handle_invoke(symbolHandle signature,
+ Handle class_loader,
+ Handle protection_domain,
@@ -4440,7 +5023,7 @@ diff --git a/src/share/vm/classfile/syst
// Utility for printing loader "name" as part of tracing constraints
static const char* loader_name(oop loader) {
return ((loader) == NULL ? "<bootloader>" :
-@@ -459,6 +481,7 @@
+@@ -459,6 +482,7 @@
enum Constants {
_loader_constraint_size = 107, // number of entries in constraint table
_resolution_error_size = 107, // number of entries in resolution error table
@@ -4448,7 +5031,7 @@ diff --git a/src/share/vm/classfile/syst
_nof_buckets = 1009 // number of buckets in hash table
};
-@@ -488,6 +511,9 @@
+@@ -488,6 +512,9 @@
// Resolution errors
static ResolutionErrorTable* _resolution_errors;
@@ -4458,7 +5041,7 @@ diff --git a/src/share/vm/classfile/syst
public:
// for VM_CounterDecay iteration support
friend class CounterDecay;
-@@ -505,6 +531,7 @@
+@@ -505,6 +532,7 @@
static PlaceholderTable* placeholders() { return _placeholders; }
static LoaderConstraintTable* constraints() { return _loader_constraints; }
static ResolutionErrorTable* resolution_errors() { return _resolution_errors; }
@@ -4466,7 +5049,7 @@ diff --git a/src/share/vm/classfile/syst
// Basic loading operations
static klassOop resolve_instance_class_or_null(symbolHandle class_name, Handle class_loader, Handle protection_domain, TRAPS);
-@@ -594,3 +621,17 @@
+@@ -595,3 +623,17 @@
static bool _has_loadClassInternal;
static bool _has_checkPackageAccess;
};
@@ -4487,7 +5070,7 @@ diff --git a/src/share/vm/classfile/vmSy
diff --git a/src/share/vm/classfile/vmSymbols.hpp b/src/share/vm/classfile/vmSymbols.hpp
--- a/src/share/vm/classfile/vmSymbols.hpp
+++ b/src/share/vm/classfile/vmSymbols.hpp
-@@ -214,7 +214,25 @@
+@@ -214,7 +214,26 @@
template(sun_reflect_UnsafeStaticFieldAccessorImpl, "sun/reflect/UnsafeStaticFieldAccessorImpl")\
template(base_name, "base") \
\
@@ -4501,6 +5084,7 @@ diff --git a/src/share/vm/classfile/vmSy
+ /* internal classes known only to the JVM: */ \
+ template(java_dyn_MethodTypeForm, "java/dyn/MethodTypeForm") \
+ template(java_dyn_MethodTypeForm_signature, "Ljava/dyn/MethodTypeForm;") \
++ template(impl_java_dyn_MemberName, "impl/java/dyn/MemberName") \
+ template(impl_java_dyn_MethodHandleImpl, "impl/java/dyn/MethodHandleImpl") \
+ template(impl_java_dyn_AdapterMethodHandle, "impl/java/dyn/AdapterMethodHandle") \
+ template(impl_java_dyn_BoundMethodHandle, "impl/java/dyn/BoundMethodHandle") \
@@ -4514,7 +5098,7 @@ diff --git a/src/share/vm/classfile/vmSy
template(object_initializer_name, "<init>") \
template(class_initializer_name, "<clinit>") \
template(println_name, "println") \
-@@ -284,6 +302,20 @@
+@@ -284,6 +303,21 @@
template(value_name, "value") \
template(frontCacheEnabled_name, "frontCacheEnabled") \
template(stringCacheEnabled_name, "stringCacheEnabled") \
@@ -4526,6 +5110,7 @@ diff --git a/src/share/vm/classfile/vmSy
+ template(vmslots_name, "vmslots") \
+ template(vmindex_name, "vmindex") \
+ template(vmargslot_name, "vmargslot") \
++ template(flags_name, "flags") \
+ template(argument_name, "argument") \
+ template(conversion_name, "conversion") \
+ template(rtype_name, "rtype") \
@@ -4535,7 +5120,7 @@ diff --git a/src/share/vm/classfile/vmSy
\
/* non-intrinsic name/signature pairs: */ \
template(register_method_name, "register") \
-@@ -347,6 +379,7 @@
+@@ -347,6 +381,7 @@
template(void_classloader_signature, "()Ljava/lang/ClassLoader;") \
template(void_object_signature, "()Ljava/lang/Object;") \
template(void_class_signature, "()Ljava/lang/Class;") \
@@ -4581,7 +5166,15 @@ diff --git a/src/share/vm/includeDB_core
interpreter_<arch_model>.cpp methodOop.hpp
interpreter_<arch_model>.cpp oop.inline.hpp
interpreter_<arch_model>.cpp sharedRuntime.hpp
-@@ -2809,6 +2812,23 @@
+@@ -2593,6 +2596,7 @@
+ linkResolver.cpp instanceKlass.hpp
+ linkResolver.cpp interpreterRuntime.hpp
+ linkResolver.cpp linkResolver.hpp
++linkResolver.cpp methodHandles.hpp
+ linkResolver.cpp nativeLookup.hpp
+ linkResolver.cpp objArrayOop.hpp
+ linkResolver.cpp reflection.hpp
+@@ -2809,6 +2813,23 @@
methodDataOop.hpp orderAccess.hpp
methodDataOop.hpp universe.hpp
@@ -4605,7 +5198,7 @@ diff --git a/src/share/vm/includeDB_core
methodKlass.cpp collectedHeap.inline.hpp
methodKlass.cpp constMethodKlass.hpp
methodKlass.cpp gcLocker.hpp
-@@ -3058,6 +3078,7 @@
+@@ -3058,6 +3079,7 @@
oop.inline.hpp arrayOop.hpp
oop.inline.hpp atomic.hpp
oop.inline.hpp barrierSet.inline.hpp
@@ -4613,7 +5206,7 @@ diff --git a/src/share/vm/includeDB_core
oop.inline.hpp cardTableModRefBS.hpp
oop.inline.hpp collectedHeap.inline.hpp
oop.inline.hpp compactingPermGenGen.hpp
-@@ -3669,6 +3690,7 @@
+@@ -3669,6 +3691,7 @@
sharedRuntime.cpp interpreter.hpp
sharedRuntime.cpp javaCalls.hpp
sharedRuntime.cpp jvmtiExport.hpp
@@ -4621,7 +5214,7 @@ diff --git a/src/share/vm/includeDB_core
sharedRuntime.cpp nativeInst_<arch>.hpp
sharedRuntime.cpp nativeLookup.hpp
sharedRuntime.cpp oop.inline.hpp
-@@ -3854,6 +3876,7 @@
+@@ -3854,6 +3877,7 @@
stubGenerator_<arch_model>.cpp handles.inline.hpp
stubGenerator_<arch_model>.cpp instanceOop.hpp
stubGenerator_<arch_model>.cpp interpreter.hpp
@@ -4632,19 +5225,19 @@ diff --git a/src/share/vm/includeDB_gc_p
diff --git a/src/share/vm/includeDB_gc_parallel b/src/share/vm/includeDB_gc_parallel
--- a/src/share/vm/includeDB_gc_parallel
+++ b/src/share/vm/includeDB_gc_parallel
-@@ -29,6 +29,12 @@
- collectorPolicy.cpp cmsGCAdaptivePolicyCounters.hpp
-
- compiledICHolderKlass.cpp oop.pcgc.inline.hpp
-+
+@@ -36,6 +36,12 @@
+ constantPoolKlass.cpp psScavenge.inline.hpp
+ constantPoolKlass.cpp parOopClosures.inline.hpp
+
+constantPoolKlass.cpp cardTableRS.hpp
+constantPoolKlass.cpp oop.pcgc.inline.hpp
+constantPoolKlass.cpp psPromotionManager.inline.hpp
+constantPoolKlass.cpp psScavenge.inline.hpp
+constantPoolKlass.cpp parOopClosures.inline.hpp
-
- constantPoolKlass.cpp cardTableRS.hpp
- constantPoolKlass.cpp oop.pcgc.inline.hpp
++
+ genCollectedHeap.cpp concurrentMarkSweepThread.hpp
+ genCollectedHeap.cpp vmCMSOperations.hpp
+
diff --git a/src/share/vm/interpreter/abstractInterpreter.hpp b/src/share/vm/interpreter/abstractInterpreter.hpp
--- a/src/share/vm/interpreter/abstractInterpreter.hpp
+++ b/src/share/vm/interpreter/abstractInterpreter.hpp
@@ -4652,19 +5245,19 @@ diff --git a/src/share/vm/interpreter/ab
empty, // empty method (code: _return)
accessor, // accessor method (code: _aload_0, _getfield, _(a|i)return)
abstract, // abstract method (throws an AbstractMethodException)
-+ method_handle, // java.dyn.MethodHandle::invoke
++ method_handle, // java.dyn.MethodHandles::invoke
java_lang_math_sin, // implementation of java.lang.Math.sin (x)
java_lang_math_cos, // implementation of java.lang.Math.cos (x)
java_lang_math_tan, // implementation of java.lang.Math.tan (x)
-@@ -90,8 +91,6 @@
- static address _slow_signature_handler; // the native method generic (slow) signature handler
+@@ -91,8 +92,6 @@
static address _rethrow_exception_entry; // rethrows an activation in previous frame
+
-
-
-
friend class AbstractInterpreterGenerator;
friend class InterpreterGenerator;
+ friend class InterpreterMacroAssembler;
diff --git a/src/share/vm/interpreter/cppInterpreter.cpp b/src/share/vm/interpreter/cppInterpreter.cpp
--- a/src/share/vm/interpreter/cppInterpreter.cpp
+++ b/src/share/vm/interpreter/cppInterpreter.cpp
@@ -4705,11 +5298,10 @@ diff --git a/src/share/vm/interpreter/in
diff --git a/src/share/vm/interpreter/interpreterRuntime.cpp b/src/share/vm/interpreter/interpreterRuntime.cpp
--- a/src/share/vm/interpreter/interpreterRuntime.cpp
+++ b/src/share/vm/interpreter/interpreterRuntime.cpp
-@@ -292,6 +292,24 @@
- // create exception
+@@ -293,6 +293,24 @@
THROW_MSG(vmSymbols::java_lang_ClassCastException(), message);
IRT_END
-+
+
+// required can be either a MethodType, or a Class (for a single argument)
+// actual (if not null) can be either a MethodHandle, or an arbitrary value (for a single argument)
+IRT_ENTRY(void, InterpreterRuntime::throw_WrongMethodTypeException(JavaThread* thread,
@@ -4727,9 +5319,10 @@ diff --git a/src/share/vm/interpreter/in
+}
+IRT_END
+
-
++
// exception_handler_for_exception(...) returns the continuation address,
+ // the exception oop (via TLS) and sets the bci/bcp for the continuation.
diff --git a/src/share/vm/interpreter/interpreterRuntime.hpp b/src/share/vm/interpreter/interpreterRuntime.hpp
--- a/src/share/vm/interpreter/interpreterRuntime.hpp
+++ b/src/share/vm/interpreter/interpreterRuntime.hpp
@@ -4744,14 +5337,12 @@ diff --git a/src/share/vm/interpreter/li
diff --git a/src/share/vm/interpreter/linkResolver.cpp b/src/share/vm/interpreter/linkResolver.cpp
--- a/src/share/vm/interpreter/linkResolver.cpp
+++ b/src/share/vm/interpreter/linkResolver.cpp
-@@ -149,6 +149,20 @@
- void LinkResolver::lookup_method_in_interfaces(methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS) {
- instanceKlass *ik = instanceKlass::cast(klass());
+@@ -151,6 +151,20 @@
result = methodHandle(THREAD, ik->lookup_method_in_all_interfaces(name(), signature()));
-+}
-+
+ }
+
+void LinkResolver::lookup_implicit_method(methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS) {
-+ if (MethodHandles &&
++ if (MethodHandleSupport && MethodHandles::enabled() &&
+ name == vmSymbolHandles::invoke_name() && klass() == SystemDictionary::MethodHandle_klass()) {
+ methodOop result_oop = SystemDictionary::find_method_handle_invoke(signature,
+ Handle(),
@@ -4762,21 +5353,23 @@ diff --git a/src/share/vm/interpreter/li
+ result = methodHandle(THREAD, result_oop);
+ }
+ }
- }
-
++}
++
void LinkResolver::check_method_accessability(KlassHandle ref_klass,
-@@ -238,6 +252,11 @@
- if (resolved_method.is_null()) { // not found in the class hierarchy
- // 3. lookup method in all the interfaces implemented by the resolved klass
+ KlassHandle resolved_klass,
+ KlassHandle sel_klass,
+@@ -240,6 +254,11 @@
lookup_method_in_interfaces(resolved_method, resolved_klass, method_name, method_signature, CHECK);
-+
-+ if (resolved_method.is_null()) {
+
+ if (resolved_method.is_null()) {
+ // JSR 292: see if this is an implicitly generated method MethodHandle.invoke(*...)
+ lookup_implicit_method(resolved_method, resolved_klass, method_name, method_signature, CHECK);
+ }
-
- if (resolved_method.is_null()) {
++
++ if (resolved_method.is_null()) {
// 4. method lookup failed
+ ResourceMark rm(THREAD);
+ THROW_MSG(vmSymbols::java_lang_NoSuchMethodError(),
diff --git a/src/share/vm/interpreter/linkResolver.hpp b/src/share/vm/interpreter/linkResolver.hpp
--- a/src/share/vm/interpreter/linkResolver.hpp
+++ b/src/share/vm/interpreter/linkResolver.hpp
@@ -4861,7 +5454,72 @@ diff --git a/src/share/vm/oops/instanceK
diff --git a/src/share/vm/oops/instanceKlass.cpp b/src/share/vm/oops/instanceKlass.cpp
--- a/src/share/vm/oops/instanceKlass.cpp
+++ b/src/share/vm/oops/instanceKlass.cpp
-@@ -1996,9 +1996,11 @@
+@@ -1813,6 +1813,8 @@
+ oop class_loader2, symbolOop class_name2) {
+ if (class_loader1 != class_loader2) {
+ return false;
++ } else if (class_name1 == class_name2) {
++ return true; // skip painful bytewise comparison
+ } else {
+ ResourceMark rm;
+
+@@ -1859,6 +1861,55 @@
+ }
+ }
+
++/* defined for now in jvm.cpp, for historical reasons *--
++klassOop instanceKlass::compute_enclosing_class_impl(instanceKlassHandle self,
++ symbolOop& simple_name_result, TRAPS) {
++ ...
++}
++*/
++
++// tell if two classes have the same enclosing class (at package level)
++bool instanceKlass::is_same_package_member_impl(instanceKlassHandle class1,
++ klassOop class2_oop, TRAPS) {
++ if (class2_oop == class1->as_klassOop()) return true;
++ if (!Klass::cast(class2_oop)->oop_is_instance()) return false;
++ instanceKlassHandle class2(THREAD, class2_oop);
++
++ // must be in same package before we try anything else
++ if (!class1->is_same_class_package(class2->class_loader(), class2->name()))
++ return false;
++
++ // As long as there is an outer1.getEnclosingClass,
++ // shift the search outward.
++ instanceKlassHandle outer1 = class1;
++ for (;;) {
++ // As we walk along, look for equalities between outer1 and class2.
++ // Eventually, the walks will terminate as outer1 stops
++ // at the top-level class around the original class.
++ symbolOop ignore_name;
++ klassOop next = outer1->compute_enclosing_class(ignore_name, CHECK_(false));
++ if (next == NULL) break;
++ if (next == class2()) return true;
++ outer1 = instanceKlassHandle(THREAD, next);
++ }
++
++ // Now do the same for class2.
++ instanceKlassHandle outer2 = class2;
++ for (;;) {
++ symbolOop ignore_name;
++ klassOop next = outer2->compute_enclosing_class(ignore_name, CHECK_(false));
++ if (next == NULL) break;
++ // Might as well check the new outer against all available values.
++ if (next == class1()) return true;
++ if (next == outer1()) return true;
++ outer2 = instanceKlassHandle(THREAD, next);
++ }
++
++ // If by this point we have not found an equality between the
++ // two classes, we know they are in separate package members.
++ return false;
++}
++
+
+ jint instanceKlass::compute_modifier_flags(TRAPS) const {
+ klassOop k = as_klassOop();
+@@ -1996,9 +2047,11 @@
// Printing
@@ -4875,7 +5533,7 @@ diff --git a/src/share/vm/oops/instanceK
fd->print_on(_st);
_st->cr();
} else {
-@@ -2019,7 +2021,7 @@
+@@ -2019,7 +2072,7 @@
value->is_typeArray() &&
offset <= (juint) value->length() &&
offset + length <= (juint) value->length()) {
@@ -4884,7 +5542,7 @@ diff --git a/src/share/vm/oops/instanceK
Handle h_obj(obj);
java_lang_String::print(h_obj, st);
st->cr();
-@@ -2027,22 +2029,22 @@
+@@ -2027,23 +2080,23 @@
}
}
@@ -4908,11 +5566,12 @@ diff --git a/src/share/vm/oops/instanceK
+ st->cr();
+ st->print(BULLET"fake entry for array: ");
array_klass->print_value_on(st);
+ st->cr();
- st->cr();
- st->cr();
}
}
-@@ -2051,6 +2053,28 @@
+
+@@ -2051,6 +2104,28 @@
st->print("a ");
name()->print_value_on(st);
obj->print_address_on(st);
@@ -4941,6 +5600,32 @@ diff --git a/src/share/vm/oops/instanceK
}
#endif // ndef PRODUCT
+diff --git a/src/share/vm/oops/instanceKlass.hpp b/src/share/vm/oops/instanceKlass.hpp
+--- a/src/share/vm/oops/instanceKlass.hpp
++++ b/src/share/vm/oops/instanceKlass.hpp
+@@ -308,6 +308,22 @@
+ bool is_same_class_package(oop classloader2, symbolOop classname2);
+ static bool is_same_class_package(oop class_loader1, symbolOop class_name1, oop class_loader2, symbolOop class_name2);
+
++ // find an enclosing class (defined where original code was, in jvm.cpp!)
++ klassOop compute_enclosing_class(symbolOop& simple_name_result, TRAPS) {
++ instanceKlassHandle self(THREAD, this->as_klassOop());
++ return compute_enclosing_class_impl(self, simple_name_result, THREAD);
++ }
++ static klassOop compute_enclosing_class_impl(instanceKlassHandle self,
++ symbolOop& simple_name_result, TRAPS);
++
++ // tell if two classes have the same enclosing class (at package level)
++ bool is_same_package_member(klassOop class2, TRAPS) {
++ instanceKlassHandle self(THREAD, this->as_klassOop());
++ return is_same_package_member_impl(self, class2, THREAD);
++ }
++ static bool is_same_package_member_impl(instanceKlassHandle self,
++ klassOop class2, TRAPS);
++
+ // initialization state
+ bool is_loaded() const { return _init_state >= loaded; }
+ bool is_linked() const { return _init_state >= linked; }
diff --git a/src/share/vm/oops/instanceKlassKlass.cpp b/src/share/vm/oops/instanceKlassKlass.cpp
--- a/src/share/vm/oops/instanceKlassKlass.cpp
+++ b/src/share/vm/oops/instanceKlassKlass.cpp
@@ -5192,11 +5877,10 @@ diff --git a/src/share/vm/oops/methodOop
set_native_function(
SharedRuntime::native_method_throw_unsatisfied_link_error_entry(),
!native_bind_event_is_interesting);
-@@ -782,6 +787,100 @@
- // caching this method should be just fine
+@@ -783,6 +788,100 @@
return false;
}
-+
+
+// Constant pool structure for invoke methods:
+enum {
+ _imcp_invoke_name = 1, // utf8: 'invoke'
@@ -5240,7 +5924,7 @@ diff --git a/src/share/vm/oops/methodOop
+
+ constantPoolHandle cp;
+ {
-+ constantPoolOop cp_oop = oopFactory::new_constantPool(_imcp_limit, CHECK_(empty));
++ constantPoolOop cp_oop = oopFactory::new_constantPool(_imcp_limit, IsSafeConc, CHECK_(empty));
+ cp = constantPoolHandle(THREAD, cp_oop);
+ }
+ cp->symbol_at_put(_imcp_invoke_name, vmSymbols::invoke_name());
@@ -5254,7 +5938,7 @@ diff --git a/src/share/vm/oops/methodOop
+ {
+ int flags_bits = (JVM_MH_INVOKE_BITS | JVM_ACC_PUBLIC | JVM_ACC_FINAL);
+ methodOop m_oop = oopFactory::new_method(0, accessFlags_from(flags_bits),
-+ 0, 0, 0, CHECK_(empty));
++ 0, 0, 0, IsSafeConc, CHECK_(empty));
+ m = methodHandle(THREAD, m_oop);
+ }
+ m->set_constants(cp());
@@ -5290,13 +5974,14 @@ diff --git a/src/share/vm/oops/methodOop
+ return m;
+}
+
-
++
methodHandle methodOopDesc:: clone_with_new_data(methodHandle m, u_char* new_code, int new_code_length,
+ u_char* new_compressed_linenumber_table, int new_compressed_linenumber_size, TRAPS) {
diff --git a/src/share/vm/oops/methodOop.hpp b/src/share/vm/oops/methodOop.hpp
--- a/src/share/vm/oops/methodOop.hpp
+++ b/src/share/vm/oops/methodOop.hpp
-@@ -519,6 +519,17 @@
+@@ -523,6 +523,17 @@
// Reflection support
bool is_overridden_in(klassOop k) const;
@@ -5310,10 +5995,42 @@ diff --git a/src/share/vm/oops/methodOop
+ oop method_handle_type() const;
+ static jint* method_type_pointer_chase();
+ // presize interpreter frames for extra stack slots, if needed
-+ static int extra_stack() { return MethodHandles ? (int)MethodHandlePushLimit : 0; }
++ static int extra_stack() { return MethodHandleSupport ? (int)MethodHandlePushLimit : 0; }
// RedefineClasses() support:
bool is_old() const { return access_flags().is_old(); }
void set_is_old() { _access_flags.set_is_old(); }
+diff --git a/src/share/vm/oops/objArrayKlass.cpp b/src/share/vm/oops/objArrayKlass.cpp
+--- a/src/share/vm/oops/objArrayKlass.cpp
++++ b/src/share/vm/oops/objArrayKlass.cpp
+@@ -502,12 +502,26 @@
+ }
+ }
+
++static int max_objArray_print_length = 4;
+
+ void objArrayKlass::oop_print_value_on(oop obj, outputStream* st) {
+ assert(obj->is_objArray(), "must be objArray");
++ st->print("a ");
+ element_klass()->print_value_on(st);
+- st->print("a [%d] ", objArrayOop(obj)->length());
+- as_klassOop()->klass()->print_value_on(st);
++ int len = objArrayOop(obj)->length();
++ st->print("[%d] ", len);
++ obj->print_address_on(st);
++ if (PrintOopAddress || PrintMiscellaneous && (WizardMode || Verbose)) {
++ st->print("{");
++ for (int i = 0; i < len; i++) {
++ if (i > max_objArray_print_length) {
++ st->print("..."); break;
++ }
++ st->print(" "INTPTR_FORMAT, (intptr_t)(void*)objArrayOop(obj)->obj_at(i));
++ }
++ st->print(" }");
++ }
++
+ }
+
+ #endif // PRODUCT
diff --git a/src/share/vm/oops/oop.cpp b/src/share/vm/oops/oop.cpp
--- a/src/share/vm/oops/oop.cpp
+++ b/src/share/vm/oops/oop.cpp
@@ -5333,7 +6050,7 @@ diff --git a/src/share/vm/oops/oop.hpp b
diff --git a/src/share/vm/oops/oop.hpp b/src/share/vm/oops/oop.hpp
--- a/src/share/vm/oops/oop.hpp
+++ b/src/share/vm/oops/oop.hpp
-@@ -256,6 +256,9 @@
+@@ -263,6 +263,9 @@
jdouble double_field_acquire(int offset) const;
void release_double_field_put(int offset, jdouble contents);
@@ -5356,11 +6073,122 @@ diff --git a/src/share/vm/oops/oop.inlin
inline int oopDesc::size_given_klass(Klass* klass) {
int lh = klass->layout_helper();
int s = lh >> LogHeapWordSize; // deliver size scaled by wordSize
+diff --git a/src/share/vm/prims/jvm.cpp b/src/share/vm/prims/jvm.cpp
+--- a/src/share/vm/prims/jvm.cpp
++++ b/src/share/vm/prims/jvm.cpp
+@@ -1242,7 +1242,7 @@
+
+ // Throws an exception if outer klass has not declared k as
+ // an inner klass
+- Reflection::check_for_inner_class(k, inner_klass, CHECK_NULL);
++ Reflection::check_for_inner_class(k, inner_klass, true, CHECK_NULL);
+
+ result->obj_at_put(members, inner_klass->java_mirror());
+ members++;
+@@ -1265,16 +1265,29 @@
+
+
+ JVM_ENTRY(jclass, JVM_GetDeclaringClass(JNIEnv *env, jclass ofClass))
+- const int inner_class_info_index = 0;
+- const int outer_class_info_index = 1;
+-
++{
+ // ofClass is a reference to a java_lang_Class object.
+ if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(ofClass)) ||
+ ! Klass::cast(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(ofClass)))->oop_is_instance()) {
+ return NULL;
+ }
+
+- instanceKlassHandle k(thread, java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(ofClass)));
++ symbolOop simple_name = NULL;
++ klassOop outer_klass
++ = instanceKlass::cast(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(ofClass))
++ )->compute_enclosing_class(simple_name, CHECK_NULL);
++ if (outer_klass == NULL) return NULL; // already a top-level class
++ if (simple_name == NULL) return NULL; // an anonymous class (inside a method)
++ return (jclass) JNIHandles::make_local(env, Klass::cast(outer_klass)->java_mirror());
++}
++JVM_END
++
++// should be in instanceKlass.cpp, but is here for historical reasons
++klassOop instanceKlass::compute_enclosing_class_impl(instanceKlassHandle k,
++ symbolOop& simple_name_result, TRAPS) {
++ Thread* thread = THREAD;
++ const int inner_class_info_index = inner_class_inner_class_info_offset;
++ const int outer_class_info_index = inner_class_outer_class_info_offset;
+
+ if (k->inner_classes()->length() == 0) {
+ // No inner class info => no declaring class
+@@ -1288,35 +1301,51 @@
+ bool found = false;
+ klassOop ok;
+ instanceKlassHandle outer_klass;
++ bool inner_is_member = false;
++ int simple_name_index = 0;
+
+ // Find inner_klass attribute
+- for(int i = 0; i < i_length && !found; i+= 4) {
++ for (int i = 0; i < i_length && !found; i += inner_class_next_offset) {
+ int ioff = i_icls->ushort_at(i + inner_class_info_index);
+ int ooff = i_icls->ushort_at(i + outer_class_info_index);
+-
+- if (ioff != 0 && ooff != 0) {
++ int noff = i_icls->ushort_at(i + inner_class_inner_name_offset);
++ if (ioff != 0) {
+ // Check to see if the name matches the class we're looking for
+ // before attempting to find the class.
+ if (i_cp->klass_name_at_matches(k, ioff)) {
+ klassOop inner_klass = i_cp->klass_at(ioff, CHECK_NULL);
+- if (k() == inner_klass) {
+- found = true;
++ found = (k() == inner_klass);
++ if (found && ooff != 0) {
+ ok = i_cp->klass_at(ooff, CHECK_NULL);
+ outer_klass = instanceKlassHandle(thread, ok);
+- }
+- }
++ simple_name_index = noff;
++ inner_is_member = true;
++ }
++ }
++ }
++ }
++
++ if (found && outer_klass.is_null()) {
++ // It may be anonymous; try for that.
++ int encl_method_class_idx = k->enclosing_method_class_index();
++ if (encl_method_class_idx != 0) {
++ ok = i_cp->klass_at(encl_method_class_idx, CHECK_NULL);
++ outer_klass = instanceKlassHandle(thread, ok);
++ inner_is_member = false;
+ }
+ }
+
+ // If no inner class attribute found for this class.
+- if (!found) return NULL;
++ if (outer_klass.is_null()) return NULL;
+
+ // Throws an exception if outer klass has not declared k as an inner klass
+- Reflection::check_for_inner_class(outer_klass, k, CHECK_NULL);
+-
+- return (jclass)JNIHandles::make_local(env, outer_klass->java_mirror());
+-JVM_END
+-
++ // We need evidence that each klass knows about the other, or else
++ // the system could allow a spoof of an inner class to gain access rights.
++ Reflection::check_for_inner_class(outer_klass, k, inner_is_member, CHECK_NULL);
++
++ simple_name_result = (inner_is_member ? i_cp->symbol_at(simple_name_index) : NULL);
++ return outer_klass();
++}
+
+ JVM_ENTRY(jstring, JVM_GetClassSignature(JNIEnv *env, jclass cls))
+ assert (cls != NULL, "illegal class");
diff --git a/src/share/vm/prims/methodHandles.cpp b/src/share/vm/prims/methodHandles.cpp
new file mode 100644
--- /dev/null
+++ b/src/share/vm/prims/methodHandles.cpp
-@@ -0,0 +1,1537 @@
+@@ -0,0 +1,2290 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -5392,8 +6220,10 @@ new file mode 100644
+#include "incls/_precompiled.incl"
+#include "incls/_methodHandles.cpp.incl"
+
-+MethodEntry* MethodHandle::_entries[MethodHandle::_EK_LIMIT] = {NULL};
-+const char* MethodHandle::_entry_names[_EK_LIMIT+1] = {
++bool MethodHandles::_enabled = false; // set true after successful native linkage
++
++MethodEntry* MethodHandles::_entries[MethodHandles::_EK_LIMIT] = {NULL};
++const char* MethodHandles::_entry_names[_EK_LIMIT+1] = {
+ "check_mtype",
+ "wrong_method_type", // what happens when there is a type mismatch
+ "invokestatic", // how a MH emulates invokestatic
@@ -5414,6 +6244,7 @@ new file mode 100644
+ "adapt_ref_to_prim",
+ "adapt_prim_to_ref",
+ "adapt_swap_args",
++ "adapt_rot_args",
+ "adapt_dup_args",
+ "adapt_drop_args",
+ "adapt_collect_args",
@@ -5422,6 +6253,12 @@ new file mode 100644
+ "adapt_ricochet",
+
+ // optimized adapter types:
++ "adapter_swap_args/1",
++ "adapter_swap_args/2",
++ "adapter_rot_args/1,up",
++ "adapter_rot_args/1,down",
++ "adapter_rot_args/2,up",
++ "adapter_rot_args/2,down",
+ "adapt_prim_to_prim/i2i",
+ "adapt_prim_to_prim/l2i",
+ "adapt_prim_to_prim/d2f",
@@ -5437,7 +6274,7 @@ new file mode 100644
+};
+
+#ifdef ASSERT
-+bool MethodHandle::spot_check_entry_names() {
++bool MethodHandles::spot_check_entry_names() {
+ assert(!strcmp(entry_name(_invokestatic_mh), "invokestatic"), "");
+ assert(!strcmp(entry_name(_bound_ref_mh), "bound_ref"), "");
+ assert(!strcmp(adapter_entry_name(_adapt_retype_only), "adapt_retype_only"), "");
@@ -5446,50 +6283,71 @@ new file mode 100644
+}
+#endif
+
-+methodOop MethodHandle::decode_DirectMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result) {
-+ oop target = java_dyn_MethodHandle::vmtarget(mh);
-+ int index = impl_java_dyn_DirectMethodHandle::vmindex(mh);
-+ if (target == NULL) return NULL;
-+ index = (short) index; // ignore high order bits
++void MethodHandles::set_enabled(bool z) {
++ if (_enabled != z) {
++ guarantee(z && MethodHandleSupport, "can only enable once, and only if -XX:+MethodHandleSupport");
++ _enabled = z;
++ }
++}
++
++methodOop MethodHandles::decode_vmtarget(oop vmtarget, int vmindex, oop mtype,
++ klassOop& receiver_limit_result, int& decode_flags_result) {
++ if (vmtarget == NULL) return NULL;
+ assert(methodOopDesc::nonvirtual_vtable_index < 0, "encoding");
-+ if (index < 0) {
-+ // an invokestatic or invokespecial DMH mentions the method directly
-+ methodOop m = (methodOop) target;
-+ int mflags = 0;
-+ decode_methodOop(m, mflags);
-+ if ((mflags & _dmf_has_receiver) != 0) {
-+ decode_flags_result |= _dmf_has_receiver;
-+ // Extract receiver type restriction from mh.type.ptypes[0].
-+ oop mtype = java_dyn_MethodHandle::type(mh);
-+ objArrayOop ptypes = (mtype == NULL) ? NULL : java_dyn_MethodType::ptypes(mtype);
++ if (vmindex < 0) {
++ // this DMH performs no dispatch; it is directly bound to a methodOop
++ // A MemberName may either be directly bound to a methodOop,
++ // or it may use the klass/index form; both forms mean the same thing.
++ methodOop m = decode_methodOop(methodOop(vmtarget), decode_flags_result);
++ if ((decode_flags_result & _dmf_has_receiver) != 0
++ && java_dyn_MethodType::is_instance(mtype)) {
++ // Extract receiver type restriction from mtype.ptypes[0].
++ objArrayOop ptypes = java_dyn_MethodType::ptypes(mtype);
+ oop ptype0 = (ptypes == NULL || ptypes->length() < 1) ? NULL : ptypes->obj_at(0);
-+ receiver_limit_result = (ptype0 == NULL) ? NULL : java_lang_Class::as_klassOop(ptype0);
++ if (java_lang_Class::is_instance(ptype0))
++ receiver_limit_result = java_lang_Class::as_klassOop(ptype0);
++ }
++ if (vmindex == methodOopDesc::nonvirtual_vtable_index) {
++ // this DMH can be an "invokespecial" version
++ decode_flags_result &= ~_dmf_does_dispatch;
++ } else {
++ assert(vmindex == methodOopDesc::invalid_vtable_index, "random vmindex?");
+ }
+ return m;
+ } else {
-+ decode_flags_result |= MethodHandle::_dmf_does_dispatch;
-+ assert(target->is_klass(), "must be class or interface");
-+ receiver_limit_result = (klassOop)target;
-+ Klass* tk = Klass::cast((klassOop)target);
++ decode_flags_result |= MethodHandles::_dmf_does_dispatch;
++ assert(vmtarget->is_klass(), "must be class or interface");
++ receiver_limit_result = (klassOop)vmtarget;
++ Klass* tk = Klass::cast((klassOop)vmtarget);
+ if (tk->is_interface()) {
-+ // an itable linkage is <interface, itable indemh>
-+ decode_flags_result |= MethodHandle::_dmf_from_interface;
-+ return klassItable::method_for_itable_index((klassOop)target, index);
++ // an itable linkage is <interface, itable index>
++ decode_flags_result |= MethodHandles::_dmf_from_interface;
++ return klassItable::method_for_itable_index((klassOop)vmtarget, vmindex);
+ } else {
+ if (!tk->oop_is_instance())
+ tk = instanceKlass::cast(SystemDictionary::object_klass());
-+ return ((instanceKlass*)tk)->method_at_vtable(index);
-+ }
-+ }
-+}
-+
-+methodOop MethodHandle::decode_BoundMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result) {
++ return ((instanceKlass*)tk)->method_at_vtable(vmindex);
++ }
++ }
++}
++
++// MemberName and DirectMethodHandle have the same linkage to the JVM internals.
++// (MemberName is the non-operational name used for queries and setup.)
++
++methodOop MethodHandles::decode_DirectMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result) {
++ oop vmtarget = impl_java_dyn_DirectMethodHandle::vmtarget(mh);
++ int vmindex = impl_java_dyn_DirectMethodHandle::vmindex(mh);
++ oop mtype = impl_java_dyn_DirectMethodHandle::type(mh);
++ return decode_vmtarget(vmtarget, vmindex, mtype, receiver_limit_result, decode_flags_result);
++}
++
++methodOop MethodHandles::decode_BoundMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result) {
+ assert(mh->klass() == SystemDictionary::BoundMethodHandle_klass(), "");
+ for (oop bmh = mh;;) {
+ // Bound MHs can be stacked to bind several arguments.
+ oop target = java_dyn_MethodHandle::vmtarget(bmh);
+ if (target == NULL) return NULL;
-+ decode_flags_result |= MethodHandle::_dmf_binds_argument;
++ decode_flags_result |= MethodHandles::_dmf_binds_argument;
+ klassOop tk = target->klass();
+ if (tk == SystemDictionary::BoundMethodHandle_klass()) {
+ bmh = target;
@@ -5505,14 +6363,14 @@ new file mode 100644
+ methodOop m = (methodOop) target;
+ DEBUG_ONLY(int argslot = impl_java_dyn_BoundMethodHandle::vmargslot(bmh));
+ assert(argslot == m->size_of_parameters() - 1, "must be initial argument (receiver)");
-+ decode_flags_result |= MethodHandle::_dmf_binds_method;
++ decode_flags_result |= MethodHandles::_dmf_binds_method;
+ return m;
+ }
+ }
+ }
+}
+
-+methodOop MethodHandle::decode_AdapterMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result) {
++methodOop MethodHandles::decode_AdapterMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result) {
+ assert(mh->klass() == SystemDictionary::AdapterMethodHandle_klass(), "");
+ for (oop amh = mh;;) {
+ // Adapter MHs can be stacked to convert several arguments.
@@ -5526,12 +6384,13 @@ new file mode 100644
+ continue;
+ } else {
+ // must be a BMH (which will bind some more arguments) or a DMH (for the final call)
-+ return MethodHandle::decode_MethodHandle(target, receiver_limit_result, decode_flags_result);
-+ }
-+ }
-+}
-+
-+methodOop MethodHandle::decode_MethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result) {
++ return MethodHandles::decode_MethodHandle(target, receiver_limit_result, decode_flags_result);
++ }
++ }
++}
++
++methodOop MethodHandles::decode_MethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result) {
++ if (mh == NULL) return NULL;
+ klassOop mhk = mh->klass();
+ assert(java_dyn_MethodHandle::is_subclass(mhk), "must be a MethodHandle");
+ if (mhk == SystemDictionary::DirectMethodHandle_klass()) {
@@ -5546,7 +6405,7 @@ new file mode 100644
+ }
+}
+
-+methodOop MethodHandle::decode_methodOop(methodOop m, int& decode_flags_result) {
++methodOop MethodHandles::decode_methodOop(methodOop m, int& decode_flags_result) {
+ assert(m->is_method(), "");
+ if (m->is_static()) {
+ // check that signature begins '(L' or '([' (not '(I', '()', etc.)
@@ -5568,14 +6427,18 @@ new file mode 100644
+ return m;
+}
+
++
+// A trusted party is handing us a cookie to determine a method.
+// Let's boil it down to the method oop they really want.
-+methodOop MethodHandle::decode_method(oop x, klassOop& receiver_limit_result, int& decode_flags_result) {
++methodOop MethodHandles::decode_method(oop x, klassOop& receiver_limit_result, int& decode_flags_result) {
+ decode_flags_result = 0;
+ receiver_limit_result = NULL;
+ klassOop xk = x->klass();
+ if (xk == Universe::methodKlassObj()) {
+ return decode_methodOop((methodOop) x, decode_flags_result);
++ } else if (xk == SystemDictionary::MemberName_klass()) {
++ // Note: This only works if the MemberName has already been resolved.
++ return decode_MemberName(x, receiver_limit_result, decode_flags_result);
+ } else if (java_dyn_MethodHandle::is_subclass(xk)) {
+ return decode_MethodHandle(x, receiver_limit_result, decode_flags_result);
+ } else if (xk == SystemDictionary::reflect_method_klass()) {
@@ -5594,13 +6457,14 @@ new file mode 100644
+ decode_flags_result);
+ } else {
+ // unrecognized object
-+ assert(!x->is_method(), "got this case first");
++ assert(!x->is_method(), "already checked");
++ assert(!impl_java_dyn_MemberName::is_instance(x), "already checked");
+ }
+ return NULL;
+}
+
+
-+int MethodHandle::decode_MethodHandle_stack_pushes(oop mh) {
++int MethodHandles::decode_MethodHandle_stack_pushes(oop mh) {
+ if (mh->klass() == SystemDictionary::DirectMethodHandle_klass())
+ return 0; // no push/pop
+ int this_vmslots = java_dyn_MethodHandle::vmslots(mh);
@@ -5609,17 +6473,15 @@ new file mode 100644
+ for (;;) {
+ oop target = java_dyn_MethodHandle::vmtarget(last_mh);
+ if (target->klass() == SystemDictionary::DirectMethodHandle_klass()) {
-+ last_vmslots = java_dyn_MethodHandle::vmslots(last_mh);
++ last_vmslots = java_dyn_MethodHandle::vmslots(target);
+ break;
+ } else if (!java_dyn_MethodHandle::is_instance(target)) {
+ // might be klass or method
+ assert(target->is_method(), "must get here with a direct ref to method");
+ last_vmslots = methodOop(target)->size_of_parameters();
+ break;
-+ } else {
-+ last_mh = target;
-+ continue;
-+ }
++ }
++ last_mh = target;
+ }
+ // If I am called with fewer VM slots than my ultimate callee,
+ // it must be that I push the additionally needed slots.
@@ -5648,23 +6510,425 @@ new file mode 100644
+ ShouldNotReachHere();
+}
+
++// MemberName support
++
++// import impl_java_dyn_MemberName.*
++enum {
++ IS_METHOD = impl_java_dyn_MemberName::MN_IS_METHOD,
++ IS_CONSTRUCTOR = impl_java_dyn_MemberName::MN_IS_CONSTRUCTOR,
++ IS_FIELD = impl_java_dyn_MemberName::MN_IS_FIELD,
++ IS_TYPE = impl_java_dyn_MemberName::MN_IS_TYPE,
++ SEARCH_SUPERCLASSES = impl_java_dyn_MemberName::MN_SEARCH_SUPERCLASSES,
++ SEARCH_INTERFACES = impl_java_dyn_MemberName::MN_SEARCH_INTERFACES,
++ ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE,
++ VM_INDEX_UNINITIALIZED = impl_java_dyn_MemberName::VM_INDEX_UNINITIALIZED
++};
++
++void MethodHandles::init_MemberName(oop mname_oop, oop target_oop) {
++ if (target_oop->klass() == SystemDictionary::reflect_field_klass()) {
++ oop clazz = java_lang_reflect_Field::clazz(target_oop); // fd.field_holder()
++ int slot = java_lang_reflect_Field::slot(target_oop); // fd.index()
++ int mods = java_lang_reflect_Field::modifiers(target_oop);
++ klassOop k = java_lang_Class::as_klassOop(clazz);
++ int offset = instanceKlass::cast(k)->offset_from_fields(slot);
++ init_MemberName(mname_oop, k, accessFlags_from(mods), offset);
++ } else {
++ int decode_flags = 0; klassOop receiver_limit = NULL;
++ methodOop m = MethodHandles::decode_method(target_oop,
++ receiver_limit, decode_flags);
++ bool do_dispatch = ((decode_flags & MethodHandles::_dmf_does_dispatch) != 0);
++ init_MemberName(mname_oop, m, do_dispatch);
++ }
++}
++
++void MethodHandles::init_MemberName(oop mname_oop, methodOop m, bool do_dispatch) {
++ int flags = ((m->is_initializer() ? IS_CONSTRUCTOR : IS_METHOD)
++ | (jushort) m->access_flags().as_short());
++ oop vmtarget = m;
++ int vmindex = methodOopDesc::invalid_vtable_index; // implies no info yet
++ if (!do_dispatch || (flags & IS_CONSTRUCTOR) || m->can_be_statically_bound())
++ vmindex = methodOopDesc::nonvirtual_vtable_index; // implies never any dispatch
++ assert(vmindex != VM_INDEX_UNINITIALIZED, "Java sentinel value");
++ impl_java_dyn_MemberName::set_vmtarget(mname_oop, vmtarget);
++ impl_java_dyn_MemberName::set_vmindex(mname_oop, vmindex);
++ impl_java_dyn_MemberName::set_flags(mname_oop, flags);
++}
++
++void MethodHandles::init_MemberName(oop mname_oop, klassOop field_holder, AccessFlags mods, int offset) {
++ int flags = (IS_FIELD | (jushort) mods.as_short());
++ oop vmtarget = field_holder;
++ int vmindex = offset; // implies no info yet
++ assert(vmindex != VM_INDEX_UNINITIALIZED, "bad alias on vmindex");
++ impl_java_dyn_MemberName::set_vmtarget(mname_oop, vmtarget);
++ impl_java_dyn_MemberName::set_vmindex(mname_oop, vmindex);
++ impl_java_dyn_MemberName::set_flags(mname_oop, flags);
++}
++
++
++methodOop MethodHandles::decode_MemberName(oop mname, klassOop& receiver_limit_result, int& decode_flags_result) {
++ int flags = impl_java_dyn_MemberName::flags(mname);
++ if ((flags & (IS_METHOD | IS_CONSTRUCTOR)) == 0) return NULL; // not invocable
++ oop vmtarget = impl_java_dyn_MemberName::vmtarget(mname);
++ int vmindex = impl_java_dyn_MemberName::vmindex(mname);
++ if (vmindex == VM_INDEX_UNINITIALIZED) return NULL; // not resolved
++ return decode_vmtarget(vmtarget, vmindex, NULL, receiver_limit_result, decode_flags_result);
++}
++
++// An unresolved member name is a mere symbolic reference.
++// Resolving it plants a vmtarget/vmindex in it,
++// which refers dirctly to JVM internals.
++void MethodHandles::resolve_MemberName(Handle mname, TRAPS) {
++ assert(impl_java_dyn_MemberName::is_instance(mname()), "");
++ assert(methodOopDesc::invalid_vtable_index - 10 > VM_INDEX_UNINITIALIZED, "Java sentinel value");
++ if (impl_java_dyn_MemberName::vmindex(mname()) != VM_INDEX_UNINITIALIZED)
++ return; // already resolved
++ oop defc_oop = impl_java_dyn_MemberName::clazz(mname());
++ oop name_str = impl_java_dyn_MemberName::name(mname());
++ oop type_str = impl_java_dyn_MemberName::type(mname());
++ int flags = impl_java_dyn_MemberName::flags(mname());
++
++ if (defc_oop == NULL || name_str == NULL || type_str == NULL)
++ { throw_IllegalArgumentException("nothing to resolve", CHECK); }
++ klassOop defc_klassOop = java_lang_Class::as_klassOop(defc_oop);
++ defc_oop = NULL; // safety
++ if (!Klass::cast(defc_klassOop)->oop_is_instance()) {
++ if (!Klass::cast(defc_klassOop)->oop_is_array()) return;
++ defc_klassOop = SystemDictionary::object_klass();
++ }
++ instanceKlassHandle defc(THREAD, defc_klassOop);
++ defc_klassOop = NULL; // safety
++ if (defc.is_null())
++ { throw_InternalError("primitive class", CHECK); }
++ defc->link_class(CHECK);
++
++ // convert the external string name to an internal symbol
++ symbolHandle name(THREAD, java_lang_String::as_symbol_or_null(name_str));
++ if (name.is_null()) return; // no such name
++ name_str = NULL; // safety
++
++ // convert the external string or reflective type to an internal signature
++ bool force_signature = (name() == vmSymbols::invoke_name());
++ symbolHandle type; {
++ symbolOop type_sym = NULL;
++ if (java_dyn_MethodType::is_instance(type_str)) {
++ type_sym = java_dyn_MethodType::as_signature(type_str, force_signature, CHECK);
++ } else if (java_lang_Class::is_instance(type_str)) {
++ type_sym = java_lang_Class::as_signature(type_str, force_signature, CHECK);
++ } else if (java_lang_String::is_instance(type_str)) {
++ if (force_signature) {
++ type = java_lang_String::as_symbol(type_str, CHECK);
++ } else {
++ type_sym = java_lang_String::as_symbol_or_null(type_str);
++ }
++ } else {
++ throw_InternalError("unrecognized type", CHECK);
++ }
++ if (type_sym != NULL)
++ type = symbolHandle(THREAD, type_sym);
++ }
++ if (type.is_null()) return; // no such signature exists in the VM
++ type_str = NULL; // safety
++
++ // Time to do the lookup.
++ switch (flags & ALL_KINDS) {
++ case IS_METHOD:
++ {
++ CallInfo result;
++ {
++ EXCEPTION_MARK;
++ if ((flags & JVM_ACC_STATIC) != 0) {
++ LinkResolver::resolve_static_call(result,
++ defc, name, type, KlassHandle(), false, false, THREAD);
++ } else if (defc->is_interface()) {
++ LinkResolver::resolve_interface_call(result, Handle(), defc,
++ defc, name, type, KlassHandle(), false, false, THREAD);
++ } else {
++ LinkResolver::resolve_virtual_call(result, Handle(), defc,
++ defc, name, type, KlassHandle(), false, false, THREAD);
++ }
++ if (HAS_PENDING_EXCEPTION) {
++ CLEAR_PENDING_EXCEPTION;
++ return;
++ }
++ }
++ methodHandle m = result.resolved_method();
++ oop vmtarget = NULL;
++ int vmindex = methodOopDesc::nonvirtual_vtable_index;
++ if (defc->is_interface()) {
++ vmindex = klassItable::compute_itable_index(m());
++ assert(vmindex >= 0, "");
++ } else if (result.has_vtable_index()) {
++ vmindex = result.vtable_index();
++ assert(vmindex >= 0, "");
++ }
++ assert(vmindex != VM_INDEX_UNINITIALIZED, "");
++ if (vmindex < 0) {
++ assert(result.is_statically_bound(), "");
++ vmtarget = m();
++ } else {
++ vmtarget = result.resolved_klass()->as_klassOop();
++ }
++ impl_java_dyn_MemberName::set_vmtarget(mname(), vmtarget);
++ impl_java_dyn_MemberName::set_vmindex(mname(), vmindex);
++ impl_java_dyn_MemberName::set_modifiers(mname(), m->access_flags().as_short());
++ DEBUG_ONLY(int junk; klassOop junk2);
++ assert(decode_MemberName(mname(), junk2, junk) == result.resolved_method()(),
++ "properly stored for later decoding");
++ return;
++ }
++ case IS_CONSTRUCTOR:
++ {
++ CallInfo result;
++ {
++ EXCEPTION_MARK;
++ if (name() == vmSymbols::object_initializer_name()) {
++ LinkResolver::resolve_special_call(result,
++ defc, name, type, KlassHandle(), false, THREAD);
++ } else {
++ break; // will throw after end of switch
++ }
++ if (HAS_PENDING_EXCEPTION) {
++ CLEAR_PENDING_EXCEPTION;
++ return;
++ }
++ }
++ assert(result.is_statically_bound(), "");
++ methodHandle m = result.resolved_method();
++ oop vmtarget = m();
++ int vmindex = methodOopDesc::nonvirtual_vtable_index;
++ impl_java_dyn_MemberName::set_vmtarget(mname(), vmtarget);
++ impl_java_dyn_MemberName::set_vmindex(mname(), vmindex);
++ impl_java_dyn_MemberName::set_modifiers(mname(), m->access_flags().as_short());
++ DEBUG_ONLY(int junk; klassOop junk2);
++ assert(decode_MemberName(mname(), junk2, junk) == result.resolved_method()(),
++ "properly stored for later decoding");
++ return;
++ }
++ case IS_FIELD:
++ {
++ // This is taken from LinkResolver::resolve_field, sans access checks.
++ fieldDescriptor fd; // find_field initializes fd if found
++ KlassHandle sel_klass(THREAD, instanceKlass::cast(defc())->find_field(name(), type(), &fd));
++ // check if field exists; i.e., if a klass containing the field def has been selected
++ if (sel_klass.is_null()) return;
++ oop vmtarget = sel_klass->as_klassOop();
++ int vmindex = fd.offset();
++ if (vmindex == VM_INDEX_UNINITIALIZED) break; // should not happen
++ impl_java_dyn_MemberName::set_vmtarget(mname(), vmtarget);
++ impl_java_dyn_MemberName::set_vmindex(mname(), vmindex);
++ impl_java_dyn_MemberName::set_modifiers(mname(), fd.access_flags().as_short());
++ return;
++ }
++ }
++ throw_InternalError("unrecognized MemberName format", THREAD);
++}
++
++// Conversely, a member name which is only initialized from JVM internals
++// may have null defc, name, and type fields.
++// Resolving it plants a vmtarget/vmindex in it,
++// which refers dirctly to JVM internals.
++void MethodHandles::expand_MemberName(Handle mname, int suppress, TRAPS) {
++ assert(impl_java_dyn_MemberName::is_instance(mname()), "");
++ oop vmtarget = impl_java_dyn_MemberName::vmtarget(mname());
++ int vmindex = impl_java_dyn_MemberName::vmindex(mname());
++ if (vmtarget == NULL || vmindex == VM_INDEX_UNINITIALIZED)
++ { throw_IllegalArgumentException("nothing to expand", CHECK); }
++
++ bool have_defc = (impl_java_dyn_MemberName::clazz(mname()) != NULL);
++ bool have_name = (impl_java_dyn_MemberName::name(mname()) != NULL);
++ bool have_type = (impl_java_dyn_MemberName::type(mname()) != NULL);
++ int flags = impl_java_dyn_MemberName::flags(mname());
++
++ if (suppress != 0) {
++ if (suppress & 1) have_defc = true;
++ if (suppress & 2) have_name = true;
++ if (suppress & 4) have_type = true;
++ }
++
++ if (have_defc && have_name && have_type) return; // nothing needed
++
++ switch (flags & ALL_KINDS) {
++ case IS_METHOD:
++ case IS_CONSTRUCTOR:
++ {
++ klassOop receiver_limit = NULL;
++ int decode_flags = 0;
++ methodHandle m(THREAD, decode_vmtarget(vmtarget, vmindex, NULL,
++ receiver_limit, decode_flags));
++ if (m.is_null()) break;
++ if (!have_defc) {
++ klassOop defc = m->method_holder();
++ if (receiver_limit != NULL && receiver_limit != defc
++ && Klass::cast(receiver_limit)->is_subtype_of(defc))
++ defc = receiver_limit;
++ impl_java_dyn_MemberName::set_clazz(mname(), Klass::cast(defc)->java_mirror());
++ }
++ if (!have_name) {
++ //Handle name = java_lang_String::create_from_symbol(m->name(), CHECK);
++ Handle name = StringTable::intern(m->name(), CHECK);
++ impl_java_dyn_MemberName::set_name(mname(), name());
++ }
++ if (!have_type) {
++ Handle type = java_lang_String::create_from_symbol(m->signature(), CHECK);
++ impl_java_dyn_MemberName::set_type(mname(), type());
++ }
++ return;
++ }
++ case IS_FIELD:
++ {
++ // This is taken from LinkResolver::resolve_field, sans access checks.
++ if (!vmtarget->is_klass()) break;
++ if (!Klass::cast((klassOop) vmtarget)->oop_is_instance()) break;
++ instanceKlassHandle defc(THREAD, (klassOop) vmtarget);
++ bool is_static = ((flags & JVM_ACC_STATIC) != 0);
++ fieldDescriptor fd; // find_field initializes fd if found
++ if (!defc->find_field_from_offset(vmindex, is_static, &fd))
++ break; // cannot expand
++ if (!have_defc) {
++ impl_java_dyn_MemberName::set_clazz(mname(), defc->java_mirror());
++ }
++ if (!have_name) {
++ //Handle name = java_lang_String::create_from_symbol(fd.name(), CHECK);
++ Handle name = StringTable::intern(fd.name(), CHECK);
++ impl_java_dyn_MemberName::set_name(mname(), name());
++ }
++ if (!have_type) {
++ Handle type = java_lang_String::create_from_symbol(fd.signature(), CHECK);
++ impl_java_dyn_MemberName::set_type(mname(), type());
++ }
++ return;
++ }
++ }
++ throw_InternalError("unrecognized MemberName format", THREAD);
++}
++
++int MethodHandles::find_MemberNames(klassOop k,
++ symbolOop name, symbolOop sig,
++ int mflags, klassOop caller,
++ int skip, objArrayOop results) {
++ DEBUG_ONLY(No_Safepoint_Verifier nsv);
++ // this code contains no safepoints!
++
++ // %%% take caller into account!
++
++ if (k == NULL || !Klass::cast(k)->oop_is_instance()) return -1;
++
++ int rfill = 0, rlimit = results->length(), rskip = skip;
++ // overflow measurement:
++ int overflow = 0, overflow_limit = MAX2(1000, rlimit);
++
++ int match_flags = mflags;
++ bool search_superc = ((match_flags & SEARCH_SUPERCLASSES) != 0);
++ bool search_intfc = ((match_flags & SEARCH_INTERFACES) != 0);
++ bool local_only = !(search_superc | search_intfc);
++ bool classes_only = false;
++
++ if (name != NULL) {
++ if (name->utf8_length() == 0) return 0; // a match is not possible
++ }
++ if (sig != NULL) {
++ if (sig->utf8_length() == 0) return 0; // a match is not possible
++ if (sig->byte_at(0) == '(')
++ match_flags &= ~(IS_FIELD | IS_TYPE);
++ else
++ match_flags &= ~(IS_CONSTRUCTOR | IS_METHOD);
++ }
++
++ if ((match_flags & IS_TYPE) != 0) {
++ // NYI, and Core Reflection works quite well for this query
++ }
++
++ if ((match_flags & IS_FIELD) != 0) {
++ for (FieldStream st(k, local_only, !search_intfc); !st.eos(); st.next()) {
++ if (name != NULL && st.name() != name)
++ continue;
++ if (sig != NULL && st.signature() != sig)
++ continue;
++ // passed the filters
++ if (rskip > 0) {
++ --rskip;
++ } else if (rfill < rlimit) {
++ oop result = results->obj_at(rfill++);
++ if (!impl_java_dyn_MemberName::is_instance(result))
++ return -99; // caller bug!
++ MethodHandles::init_MemberName(result, st.klass()->as_klassOop(), st.access_flags(), st.offset());
++ } else if (++overflow >= overflow_limit) {
++ match_flags = 0; break; // got tired of looking at overflow
++ }
++ }
++ }
++
++ if ((match_flags & (IS_METHOD | IS_CONSTRUCTOR)) != 0) {
++ // watch out for these guys:
++ symbolOop init_name = vmSymbols::object_initializer_name();
++ symbolOop clinit_name = vmSymbols::class_initializer_name();
++ if (name == clinit_name) clinit_name = NULL; // hack for exposing <clinit>
++ bool negate_name_test = false;
++ // fix name so that it captures the intention of IS_CONSTRUCTOR
++ if (!(match_flags & IS_METHOD)) {
++ // constructors only
++ if (name == NULL) {
++ name = init_name;
++ } else if (name != init_name) {
++ return 0; // no constructors of this method name
++ }
++ } else if (!(match_flags & IS_CONSTRUCTOR)) {
++ // methods only
++ if (name == NULL) {
++ name = init_name;
++ negate_name_test = true; // if we see the name, we *omit* the entry
++ } else if (name == init_name) {
++ return 0; // no methods of this constructor name
++ }
++ } else {
++ // caller will accept either sort; no need to adjust name
++ }
++ for (MethodStream st(k, local_only, !search_intfc); !st.eos(); st.next()) {
++ methodOop m = st.method();
++ symbolOop m_name = m->name();
++ if (m_name == clinit_name)
++ continue;
++ if (name != NULL && ((m_name != name) ^ negate_name_test))
++ continue;
++ if (sig != NULL && m->signature() != sig)
++ continue;
++ // passed the filters
++ if (rskip > 0) {
++ --rskip;
++ } else if (rfill < rlimit) {
++ oop result = results->obj_at(rfill++);
++ if (!impl_java_dyn_MemberName::is_instance(result))
++ return -99; // caller bug!
++ MethodHandles::init_MemberName(result, m, true);
++ } else if (++overflow >= overflow_limit) {
++ match_flags = 0; break; // got tired of looking at overflow
++ }
++ }
++ }
++
++ // return number of elements we at leasted wanted to initialize
++ return rfill + overflow;
++}
++
++
++
+
+// Decode the vmtarget field of a method handle.
+// Sanitize out methodOops, klassOops, and any other non-Java data.
+// This is for debugging and reflection.
-+oop MethodHandle::encode_target(oop mh, int format, TRAPS) {
++oop MethodHandles::encode_target(oop mh, int format, TRAPS) {
+ assert(java_dyn_MethodHandle::is_instance(mh), "must be a MH");
-+ if (format == _etf_handle_or_method_info) {
++ if (format == ETF_HANDLE_OR_METHOD_NAME) {
+ oop target = java_dyn_MethodHandle::vmtarget(target);
+ if (target == NULL) {
+ return NULL; // unformed MH
+ }
+ klassOop tklass = target->klass();
-+ if (Klass::cast(tklass)->is_subclass_of(SystemDictionary::object_klass())){
++ if (Klass::cast(tklass)->is_subclass_of(SystemDictionary::object_klass())) {
+ return target; // target is another MH (or something else?)
+ }
+ }
-+ if (format == _etf_direct_handle) {
++ if (format == ETF_DIRECT_HANDLE) {
+ oop target = mh;
+ for (;;) {
+ if (target->klass() == SystemDictionary::DirectMethodHandle_klass()) {
@@ -5685,10 +6949,7 @@ new file mode 100644
+ methodOop m = decode_MethodHandle(mh, receiver_limit, decode_flags);
+ if (m == NULL) return NULL;
+ switch (format) {
-+ case _etf_name:
-+ return StringTable::intern(m->name(), THREAD);
-+
-+ case _etf_reflect_method:
++ case ETF_REFLECT_METHOD:
+ // same as jni_ToReflectedMethod:
+ if (m->is_initializer()) {
+ return Reflection::new_constructor(m, THREAD);
@@ -5696,23 +6957,18 @@ new file mode 100644
+ return Reflection::new_method(m, UseNewReflection, false, THREAD);
+ }
+
-+ case _etf_handle_or_method_info: // method, not handle
-+ case _etf_method_info:
++ case ETF_HANDLE_OR_METHOD_NAME: // method, not handle
++ case ETF_METHOD_NAME:
+ {
-+ objArrayHandle tuple; {
-+ objArrayOop tuple_oop = oopFactory::new_objectArray(_MI_LENGTH, CHECK_NULL);
-+ tuple = objArrayHandle(THREAD, tuple_oop);
-+ }
-+ tuple->obj_at_put(_mi_declaring_class,
-+ Klass::cast(m->method_holder())->java_mirror());
-+ oop name = StringTable::intern(m->name(), CHECK_NULL);
-+ tuple->obj_at_put(_mi_name, name);
-+ oop sig = StringTable::intern(m->signature(), CHECK_NULL);
-+ tuple->obj_at_put(_mi_signature, sig);
-+ if (receiver_limit != NULL && receiver_limit != m->method_holder())
-+ tuple->obj_at_put(_mi_reference_class,
-+ Klass::cast(receiver_limit)->java_mirror());
-+ return tuple();
++ if (SystemDictionary::MemberName_klass() == NULL) break;
++ instanceKlassHandle mname_klass(THREAD, SystemDictionary::MemberName_klass());
++ mname_klass->initialize(CHECK_NULL);
++ Handle mname = mname_klass->allocate_instance_handle(CHECK_NULL);
++ impl_java_dyn_MemberName::set_vmindex(mname(), VM_INDEX_UNINITIALIZED);
++ bool do_dispatch = ((decode_flags & MethodHandles::_dmf_does_dispatch) != 0);
++ init_MemberName(mname(), m, do_dispatch);
++ expand_MemberName(mname, 0, CHECK_NULL);
++ return mname();
+ }
+ }
+
@@ -5721,7 +6977,7 @@ new file mode 100644
+ return NULL;
+}
+
-+bool MethodHandle::class_cast_needed(klassOop src, klassOop dst) {
++bool MethodHandles::class_cast_needed(klassOop src, klassOop dst) {
+ if (src == dst || dst == SystemDictionary::object_klass())
+ return false; // quickest checks
+ Klass* srck = Klass::cast(src);
@@ -5744,13 +7000,15 @@ new file mode 100644
+ return Klass::cast(SystemDictionary::object_klass())->java_mirror();
+}
+
-+bool MethodHandle::same_basic_type_for_arguments(BasicType src,
-+ BasicType dst,
-+ bool for_return) {
++bool MethodHandles::same_basic_type_for_arguments(BasicType src,
++ BasicType dst,
++ bool for_return) {
+ // return values can always be forgotten:
+ if (for_return && dst == T_VOID) return true;
+ assert(src != T_VOID && dst != T_VOID, "should not be here");
+ if (src == dst) return true;
++ if (type2size[src] != type2size[dst]) return false;
++ // allow reinterpretation casts for integral widening
+ if (is_subword_type(src)) { // subwords can fit in int or other subwords
+ if (dst == T_INT) // any subword fits in an int
+ return true;
@@ -5759,10 +7017,15 @@ new file mode 100644
+ if (src == T_BYTE && dst == T_SHORT)
+ return true; // remaining case: byte fits in short
+ }
++ // allow float/fixed reinterpretation casts
++ if (src == T_FLOAT) return dst == T_INT;
++ if (src == T_INT) return dst == T_FLOAT;
++ if (src == T_DOUBLE) return dst == T_LONG;
++ if (src == T_LONG) return dst == T_DOUBLE;
+ return false;
+}
+
-+const char* MethodHandle::check_method_receiver(methodHandle m,
++const char* MethodHandles::check_method_receiver(methodHandle m,
+ klassOop passed_recv_type) {
+ assert(!m->is_static(), "caller resp.");
+ if (passed_recv_type == NULL)
@@ -5778,7 +7041,7 @@ new file mode 100644
+// Verify that m's signature can be called type-safely by a method handle
+// of the given method type 'mtype'.
+// It takes a TRAPS argument because it must perform symbol lookups.
-+void MethodHandle::verify_method_signature(methodHandle m,
++void MethodHandles::verify_method_signature(methodHandle m,
+ Handle mtype,
+ int first_ptype_pos,
+ KlassHandle insert_ptype,
@@ -5844,7 +7107,7 @@ new file mode 100644
+
+// Main routine for verifying the MethodHandle.type of a proposed
+// direct or bound-direct method handle.
-+void MethodHandle::verify_method_type(methodHandle m,
++void MethodHandles::verify_method_type(methodHandle m,
+ oop mtype_oop,
+ bool has_bound_recv,
+ klassOop bound_recv_type_oop,
@@ -5884,22 +7147,21 @@ new file mode 100644
+ throw_InternalError(err, CHECK);
+}
+
-+void MethodHandle::verify_vmslots(Handle mh, TRAPS) {
++void MethodHandles::verify_vmslots(Handle mh, TRAPS) {
+ // Verify vmslots.
+ int check_slots = argument_slot_count(java_dyn_MethodHandle::type(mh()));
+ if (java_dyn_MethodHandle::vmslots(mh()) != check_slots)
+ { throw_InternalError("bad vmslots in BMH", CHECK); }
+}
+
-+void MethodHandle::verify_vmargslot(Handle mh, int argnum, TRAPS) {
-+ // Verify MH.vmargslot, which should point at the given argnum.
-+ int have_slot = impl_java_dyn_BoundMethodHandle::vmargslot(mh());
++void MethodHandles::verify_vmargslot(Handle mh, int argnum, int argslot, TRAPS) {
++ // Verify that argslot points at the given argnum.
+ int check_slot = argument_slot(java_dyn_MethodHandle::type(mh()), argnum);
-+ if (have_slot != check_slot) {
++ if (argslot != check_slot || argslot < 0) {
+ const char* fmt = "for argnum of %d, vmargslot is %d, should be %d";
+ int msglen = strlen(fmt) + 3*11 + 1;
+ char* msg = NEW_RESOURCE_ARRAY(char, msglen);
-+ jio_snprintf(msg, msglen, fmt, argnum, have_slot, check_slot);
++ jio_snprintf(msg, msglen, fmt, argnum, argslot, check_slot);
+ throw_InternalError(msg, CHECK);
+ }
+}
@@ -5908,7 +7170,7 @@ new file mode 100644
+// Apart from the advertised changes, caller method type X must
+// be able to invoke the callee method Y type with no violations
+// of type integrity.
-+void MethodHandle::verify_method_type_change(oop src_mtype, int src_beg, int src_end,
++void MethodHandles::verify_method_type_change(oop src_mtype, int src_beg, int src_end,
+ int insert_argnum, oop insert_type,
+ int change_argnum, oop change_type,
+ int delete_argnum,
@@ -5991,14 +7253,14 @@ new file mode 100644
+}
+
+// Handy wrapper for check_argument_type_change, to verify one src/dest pair.
-+void MethodHandle::verify_argument_type_change(oop src_type, oop dst_type,
++void MethodHandles::verify_argument_type_change(oop src_type, oop dst_type,
+ int argnum, TRAPS) {
+ const char* err = check_argument_type_change(src_type, dst_type, argnum);
+ if (err != NULL) { throw_InternalError(err, CHECK); }
+}
+
+
-+const char* MethodHandle::check_argument_type_change(BasicType src_type,
++const char* MethodHandles::check_argument_type_change(BasicType src_type,
+ klassOop src_klass,
+ BasicType dst_type,
+ klassOop dst_klass,
@@ -6059,7 +7321,8 @@ new file mode 100644
+ return msg;
+}
+
-+// Compute the depth within the stack of the given argument.
++// Compute the depth within the stack of the given argument, i.e.,
++// the combined size of arguments to the right of the given argument.
+// For the last argument (ptypes.length-1) this will be zero.
+// For the first argument (0) this will be the size of all
+// arguments but that one. For the special number -1, this
@@ -6067,19 +7330,35 @@ new file mode 100644
+// If the argument is neither -1 nor a valid argument index,
+// then return a negative number. Otherwise, the result
+// is in the range [0..vmslots] inclusive.
-+int MethodHandle::argument_slot(oop method_type, int arg) {
++int MethodHandles::argument_slot(oop method_type, int arg) {
+ objArrayOop ptypes = java_dyn_MethodType::ptypes(method_type);
-+ int result = 0;
++ int argslot = 0;
+ int len = ptypes->length();
+ if (arg < -1 || arg >= len) return -99;
-+ for (int i = arg+1; i < len; i++) {
++ for (int i = len-1; i > arg; i--) {
+ BasicType bt = java_lang_Class::as_BasicType(ptypes->obj_at(i));
-+ result += type2size[bt];
-+ }
-+ return result;
-+}
-+
-+methodOop MethodHandle::dispatch_decoded_method(methodOop m,
++ argslot += type2size[bt];
++ }
++ assert(argument_slot_to_argnum(method_type, argslot) == arg, "inverse works");
++ return argslot;
++}
++
++// Given a slot number, return the argument number.
++int MethodHandles::argument_slot_to_argnum(oop method_type, int query_argslot) {
++ objArrayOop ptypes = java_dyn_MethodType::ptypes(method_type);
++ int argslot = 0;
++ int len = ptypes->length();
++ for (int i = len-1; i >= 0; i--) {
++ if (query_argslot == argslot) return i;
++ BasicType bt = java_lang_Class::as_BasicType(ptypes->obj_at(i));
++ argslot += type2size[bt];
++ }
++ // return pseudo-arg deepest in stack:
++ if (query_argslot == argslot) return -1;
++ return -99; // oob slot, or splitting a double-slot arg
++}
++
++methodOop MethodHandles::dispatch_decoded_method(methodOop m,
+ klassOop receiver_limit,
+ int decode_flags,
+ klassOop receiver_klass,
@@ -6099,7 +7378,7 @@ new file mode 100644
+ // note that a null receiver can match any reference value, for a static method
+ return NULL;
+
-+ if (!(decode_flags & MethodHandle::_dmf_does_dispatch)) {
++ if (!(decode_flags & MethodHandles::_dmf_does_dispatch)) {
+ // pre-dispatched or static method (null receiver is OK for static)
+ return m;
+
@@ -6107,7 +7386,7 @@ new file mode 100644
+ // null receiver value; cannot dispatch
+ return NULL;
+
-+ } else if (!(decode_flags & MethodHandle::_dmf_from_interface)) {
++ } else if (!(decode_flags & MethodHandles::_dmf_from_interface)) {
+ // perform virtual dispatch
+ int vtable_index = m->vtable_index();
+ guarantee(vtable_index >= 0, "valid vtable index");
@@ -6128,7 +7407,7 @@ new file mode 100644
+ }
+}
+
-+void MethodHandle::init_DirectMethodHandle(Handle mh, methodHandle m, bool do_dispatch, TRAPS) {
++void MethodHandles::init_DirectMethodHandle(Handle mh, methodHandle m, bool do_dispatch, TRAPS) {
+ // Check arguments.
+ if (mh.is_null() || m.is_null() ||
+ (!do_dispatch && m->is_abstract()))
@@ -6157,6 +7436,8 @@ new file mode 100644
+
+ int vmindex = methodOopDesc::garbage_vtable_index;
+ oop vmtarget = NULL;
++
++ instanceKlass::cast(m->method_holder())->link_class(CHECK);
+
+ MethodEntry* me = NULL;
+ if (do_dispatch && Klass::cast(m->method_holder())->is_interface()) {
@@ -6168,7 +7449,7 @@ new file mode 100644
+ assert(vmindex >= 0, "(>=0) == do_dispatch");
+ // Set up same bits as ConstantPoolCacheEntry::set_interface_call().
+ vmtarget = m->method_holder(); // the interface
-+ me = MethodHandle::entry(MethodHandle::_invokeinterface_mh);
++ me = MethodHandles::entry(MethodHandles::_invokeinterface_mh);
+ } else if (!do_dispatch || m->can_be_statically_bound()) {
+ // We are simulating an invokestatic or invokespecial instruction.
+ // Set up the method pointer, just like ConstantPoolCacheEntry::set_method().
@@ -6176,17 +7457,24 @@ new file mode 100644
+ // this does not help dispatch, but it will make it possible to parse this MH:
+ vmindex = methodOopDesc::nonvirtual_vtable_index;
+ assert(vmindex < 0, "(>=0) == do_dispatch");
-+ if (m->is_static())
-+ me = MethodHandle::entry(MethodHandle::_invokestatic_mh);
-+ else
-+ me = MethodHandle::entry(MethodHandle::_invokespecial_mh);
++ if (!m->is_static()) {
++ me = MethodHandles::entry(MethodHandles::_invokespecial_mh);
++ } else {
++ me = MethodHandles::entry(MethodHandles::_invokestatic_mh);
++ // Part of the semantics of a static call is an initialization barrier.
++ // For a DMH, it is done now, when the handle is created.
++ Klass* k = Klass::cast(m->method_holder());
++ if (k->should_be_initialized()) {
++ k->initialize(CHECK);
++ }
++ }
+ } else {
+ // We are simulating an invokevirtual instruction.
+ // Set up the vtable index, just like ConstantPoolCacheEntry::set_method().
+ // The key logic is LinkResolver::runtime_resolve_virtual_method.
+ vmindex = m->vtable_index();
+ vmtarget = m->method_holder();
-+ me = MethodHandle::entry(MethodHandle::_invokevirtual_mh);
++ me = MethodHandles::entry(MethodHandles::_invokevirtual_mh);
+ }
+
+ if (me == NULL) { throw_InternalError(CHECK); }
@@ -6194,7 +7482,8 @@ new file mode 100644
+ impl_java_dyn_DirectMethodHandle::set_vmtarget(mh(), vmtarget);
+ impl_java_dyn_DirectMethodHandle::set_vmindex(mh(), vmindex);
+ DEBUG_ONLY(int flags; klassOop rlimit);
-+ assert(MethodHandle::decode_method(mh(), rlimit, flags) == m(), "properly stored for later decoding");
++ assert(MethodHandles::decode_method(mh(), rlimit, flags) == m(),
++ "properly stored for later decoding");
+ DEBUG_ONLY(bool actual_do_dispatch = ((flags & _dmf_does_dispatch) != 0));
+ assert(!(actual_do_dispatch && !do_dispatch),
+ "do not perform dispatch if !do_dispatch specified");
@@ -6206,7 +7495,7 @@ new file mode 100644
+}
+
+// Initialize a BMH with a receiver bound directly to a methodOop.
-+void MethodHandle::init_BoundMethodHandle_with_receiver(Handle mh,
++void MethodHandles::init_BoundMethodHandle_with_receiver(Handle mh,
+ methodOop original_m_oop,
+ klassOop receiver_limit_oop,
+ int decode_flags,
@@ -6241,7 +7530,7 @@ new file mode 100644
+ int receiver_pos = m->size_of_parameters() - 1;
+
+ // Verify MH.vmargslot, which should point at the bound receiver.
-+ verify_vmargslot(mh, -1, CHECK);
++ verify_vmargslot(mh, -1, impl_java_dyn_BoundMethodHandle::vmargslot(mh()), CHECK);
+ //verify_vmslots(mh, CHECK);
+
+ // Verify vmslots.
@@ -6252,14 +7541,14 @@ new file mode 100644
+ impl_java_dyn_BoundMethodHandle::set_vmtarget(mh(), m());
+
+ DEBUG_ONLY(int junk; klassOop junk2);
-+ assert(MethodHandle::decode_method(mh(), junk2, junk) == m(), "properly stored for later decoding");
++ assert(MethodHandles::decode_method(mh(), junk2, junk) == m(), "properly stored for later decoding");
+ assert(decode_MethodHandle_stack_pushes(mh()) == 1, "BMH pushes one stack slot");
+
+ // Done!
-+ java_dyn_MethodHandle::set_vmentry(mh(), MethodHandle::entry(MethodHandle::_bound_ref_direct_mh));
-+}
-+
-+void MethodHandle::init_BoundMethodHandle(Handle mh, Handle target, int argnum, TRAPS) {
++ java_dyn_MethodHandle::set_vmentry(mh(), MethodHandles::entry(MethodHandles::_bound_ref_direct_mh));
++}
++
++void MethodHandles::init_BoundMethodHandle(Handle mh, Handle target, int argnum, TRAPS) {
+ // Check arguments.
+ if (mh.is_null() || target.is_null() || !java_dyn_MethodHandle::is_instance(target()))
+ { throw_InternalError(CHECK); }
@@ -6268,7 +7557,7 @@ new file mode 100644
+
+ if (VerifyMethodHandles) {
+ int insert_after = argnum - 1;
-+ verify_vmargslot(mh, insert_after, CHECK);
++ verify_vmargslot(mh, insert_after, impl_java_dyn_BoundMethodHandle::vmargslot(mh()), CHECK);
+ verify_vmslots(mh, CHECK);
+ }
+
@@ -6383,14 +7672,14 @@ new file mode 100644
+
+ MethodEntry* me = NULL;
+ if (ptype == T_OBJECT) {
-+ if (direct_to_method) me = MethodHandle::entry(_bound_ref_direct_mh);
-+ else me = MethodHandle::entry(_bound_ref_mh);
++ if (direct_to_method) me = MethodHandles::entry(_bound_ref_direct_mh);
++ else me = MethodHandles::entry(_bound_ref_mh);
+ } else if (slots_pushed == 2) {
-+ if (direct_to_method) me = MethodHandle::entry(_bound_long_direct_mh);
-+ else me = MethodHandle::entry(_bound_long_mh);
++ if (direct_to_method) me = MethodHandles::entry(_bound_long_direct_mh);
++ else me = MethodHandles::entry(_bound_long_mh);
+ } else if (slots_pushed == 1) {
-+ if (direct_to_method) me = MethodHandle::entry(_bound_int_direct_mh);