diff --git a/.hgtags b/.hgtags index 32b1eca60e7..de89d4fa38d 100644 --- a/.hgtags +++ b/.hgtags @@ -31,3 +31,5 @@ d52186ee770dac57950536cd00ccbfdef360b04c jdk7-b53 15096652c4d48dfb9fc0b2cb135304db94c65ba0 jdk7-b54 c8b275d62d6b0a980c510e839b70292245863e85 jdk7-b55 a8134c4ee2cf451cf9b5e1609f39d83ecd53acc5 jdk7-b56 +b44f05654c26fcd1f995e712992f9b07ffd7c0c6 jdk7-b57 +d60a9ce3c3eabf28f5d50ae839d18be04a551bc2 jdk7-b58 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 4d5191b9635..ea493dc5890 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -31,3 +31,5 @@ c235f4a8559d196879c56af80159f67ee5d0e720 jdk7-b53 2ef382b1bbd58a68e668391c6145a4b2066c5b96 jdk7-b54 aea0ace7a1e43619800931d42bbf69c579361c2d jdk7-b55 ba12117a5e6c918578d6b2a8c693232a33289024 jdk7-b56 +ffd09e767dfa6d21466183a400f72cf62d53297f jdk7-b57 +59b497130f82ec809c245ffb5e521e3a5fabf8af jdk7-b58 diff --git a/corba/.hgtags b/corba/.hgtags index fb97578a8c2..380df11444a 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -31,3 +31,5 @@ bec82237d694f9802b820fa11bbb4f7fa9bf8e77 jdk7-b52 8130ac858d6789d5853d23044ba4a992afda574a jdk7-b54 7a869f16ba83060c34b77620406cfa89d1cd7084 jdk7-b55 553a664b807bb3a3c93f3b5a3c20ff0a90e08371 jdk7-b56 +972c6157fae57850694675da82fd58a17930db0a jdk7-b57 +2e3b8edab3ef55406494d3dd562e06882e6fc15e jdk7-b58 diff --git a/corba/make/com/sun/corba/se/sources/Makefile b/corba/make/com/sun/corba/se/sources/Makefile index 9d945a29343..fd88e589393 100644 --- a/corba/make/com/sun/corba/se/sources/Makefile +++ b/corba/make/com/sun/corba/se/sources/Makefile @@ -46,6 +46,8 @@ CORBA_JMK_DIRECTORY=$(TOPDIR)/make/com/sun/corba/minclude/ include $(CORBA_JMK_DIRECTORY)com_sun_corba_se_PortableActivationIDL.jmk include $(CORBA_JMK_DIRECTORY)com_sun_corba_se_impl_logging.jmk +FILES_java += com/sun/corba/se/org/omg/CORBA/ORB.java + # # Dirs # diff --git a/corba/src/share/classes/com/sun/corba/se/impl/presentation/rmi/IDLNameTranslatorImpl.java b/corba/src/share/classes/com/sun/corba/se/impl/presentation/rmi/IDLNameTranslatorImpl.java index 44768d1acd1..e19bc78ea7a 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/presentation/rmi/IDLNameTranslatorImpl.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/presentation/rmi/IDLNameTranslatorImpl.java @@ -202,6 +202,10 @@ public class IDLNameTranslatorImpl implements IDLNameTranslator { private IDLNameTranslatorImpl(Class[] interfaces) { + SecurityManager s = System.getSecurityManager(); + if (s != null) { + s.checkPermission(new DynamicAccessPermission("access")); + } try { IDLTypesUtil idlTypesUtil = new IDLTypesUtil(); for (int ctr=0; ctr @@ -83,7 +107,7 @@ CORBA 2.3 IDL (16) e - + (17) "{" "}" (17) e @@ -91,9 +115,9 @@ CORBA 2.3 IDL (18) "custom" "valuetype" "valuetype" - "custom" "valuetype" - "valuetype" - + "custom" "valuetype" + "valuetype" + (19) (19) e @@ -107,7 +131,7 @@ CORBA 2.3 IDL "supports" (19) e - "," + "," (20) @@ -121,7 +145,7 @@ CORBA 2.3 IDL (23) "factory" "(" ")" "factory" "(" ")" -(24) +(24) "," (25) @@ -349,7 +373,7 @@ CORBA 2.3 IDL (87) e - + (88) "oneway" @@ -386,7 +410,7 @@ CORBA 2.3 IDL -(96) "fixed" "<" "," ">" +(96) "fixed" "<" "," ">" (97) "fixed" diff --git a/corba/src/share/classes/com/sun/tools/corba/se/idl/grammar3.idl b/corba/src/share/classes/com/sun/tools/corba/se/idl/grammar3.idl index a02750881a4..28d07b44229 100644 --- a/corba/src/share/classes/com/sun/tools/corba/se/idl/grammar3.idl +++ b/corba/src/share/classes/com/sun/tools/corba/se/idl/grammar3.idl @@ -1,11 +1,35 @@ +/* + * Copyright 1999 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. + */ + /* * COMPONENT_NAME: idl.parser - * + * * ORIGINS: 27 * - * THIS PRODUCT CONTAINS RESTRICTED MATERIALS OF IBM * 5639-D57, (C) COPYRIGHT International Business Machines Corp., 1997, 1998 - * + * */ (1) // CORBA3 @@ -98,7 +122,7 @@ (16) e - + (17) "{" "}" (17) e @@ -106,9 +130,9 @@ (18) "custom" "valuetype" "valuetype" - "custom" "valuetype" - "valuetype" - + "custom" "valuetype" + "valuetype" + (19) (19) e @@ -122,7 +146,7 @@ "supports" (19) e - "," + "," (20) @@ -136,7 +160,7 @@ (23) "factory" "(" ")" "factory" "(" ")" -(24) +(24) "," (25) @@ -351,7 +375,7 @@ (85) // CORBA3 (85) "readonly" "attribute" // CORBA3 - + (85) // CORBA3 // CORBA3 @@ -389,7 +413,7 @@ (87) e - + (88) "oneway" @@ -426,7 +450,7 @@ -(96) "fixed" "<" "," ">" +(96) "fixed" "<" "," ">" (97) "fixed" @@ -450,7 +474,7 @@ (204) e "," - + (205) ":" (206) @@ -458,8 +482,8 @@ (206) e -(207) ";" - ";" +(207) ";" + ";" ";" ";" ";" diff --git a/corba/src/share/classes/com/sun/tools/corba/se/idl/idl.prp b/corba/src/share/classes/com/sun/tools/corba/se/idl/idl.prp index 386a2c735f5..2c6efdf76b4 100644 --- a/corba/src/share/classes/com/sun/tools/corba/se/idl/idl.prp +++ b/corba/src/share/classes/com/sun/tools/corba/se/idl/idl.prp @@ -1,3 +1,28 @@ +# +# Copyright 1999-2004 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. +# + # # COMPONENT_NAME: idl.parser # diff --git a/corba/src/share/classes/com/sun/tools/corba/se/idl/idl_ja.prp b/corba/src/share/classes/com/sun/tools/corba/se/idl/idl_ja.prp index 15fa230a57f..b3dd5f6c788 100644 --- a/corba/src/share/classes/com/sun/tools/corba/se/idl/idl_ja.prp +++ b/corba/src/share/classes/com/sun/tools/corba/se/idl/idl_ja.prp @@ -1,3 +1,28 @@ +# +# Copyright 1999-2005 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. +# + # # COMPONENT_NAME: idl.parser # diff --git a/corba/src/share/classes/com/sun/tools/corba/se/idl/idl_zh_CN.prp b/corba/src/share/classes/com/sun/tools/corba/se/idl/idl_zh_CN.prp index bc6e72746c5..5da7dd9a845 100644 --- a/corba/src/share/classes/com/sun/tools/corba/se/idl/idl_zh_CN.prp +++ b/corba/src/share/classes/com/sun/tools/corba/se/idl/idl_zh_CN.prp @@ -1,3 +1,28 @@ +# +# Copyright 2005 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. +# + # # COMPONENT_NAME: idl.parser # diff --git a/corba/src/share/classes/com/sun/tools/corba/se/idl/toJavaPortable/toJavaPortable.prp b/corba/src/share/classes/com/sun/tools/corba/se/idl/toJavaPortable/toJavaPortable.prp index d4d975eb7a0..c24814126da 100644 --- a/corba/src/share/classes/com/sun/tools/corba/se/idl/toJavaPortable/toJavaPortable.prp +++ b/corba/src/share/classes/com/sun/tools/corba/se/idl/toJavaPortable/toJavaPortable.prp @@ -1,3 +1,28 @@ +# +# Copyright 1999-2004 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. +# + # # COMPONENT_NAME: idl.toJava # diff --git a/corba/src/share/classes/com/sun/tools/corba/se/idl/toJavaPortable/toJavaPortable_ja.prp b/corba/src/share/classes/com/sun/tools/corba/se/idl/toJavaPortable/toJavaPortable_ja.prp index 68259c27e13..cce4ee5a7ec 100644 --- a/corba/src/share/classes/com/sun/tools/corba/se/idl/toJavaPortable/toJavaPortable_ja.prp +++ b/corba/src/share/classes/com/sun/tools/corba/se/idl/toJavaPortable/toJavaPortable_ja.prp @@ -1,3 +1,28 @@ +# +# Copyright 2001-2005 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. +# + # # COMPONENT_NAME: idl.toJava # diff --git a/corba/src/share/classes/com/sun/tools/corba/se/idl/toJavaPortable/toJavaPortable_zh_CN.prp b/corba/src/share/classes/com/sun/tools/corba/se/idl/toJavaPortable/toJavaPortable_zh_CN.prp index a8f5263fb5c..338a27a37fd 100644 --- a/corba/src/share/classes/com/sun/tools/corba/se/idl/toJavaPortable/toJavaPortable_zh_CN.prp +++ b/corba/src/share/classes/com/sun/tools/corba/se/idl/toJavaPortable/toJavaPortable_zh_CN.prp @@ -1,3 +1,28 @@ +# +# Copyright 2005 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. +# + # # COMPONENT_NAME: idl.toJava # diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 0f927fb29c5..2d7b8ac7ac7 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -31,3 +31,5 @@ dae503d9f04c1a11e182dbf7f770509c28dc0609 jdk7-b50 fafab5d5349c7c066d677538db67a1ee0fb33bd2 jdk7-b54 f8e839c086152da70d6ec5913ba6f9f509282e8d jdk7-b55 a3fd9e40ff2e854f6169eb6d09d491a28634d04f jdk7-b56 +f4cbf78110c726919f46b59a3b054c54c7e889b4 jdk7-b57 +53d9bf689e80fcc76b221bbe6c5d58e08b80cbc6 jdk7-b58 diff --git a/hotspot/agent/src/os/linux/Makefile b/hotspot/agent/src/os/linux/Makefile index e243171bc2e..c7b64107b14 100644 --- a/hotspot/agent/src/os/linux/Makefile +++ b/hotspot/agent/src/os/linux/Makefile @@ -60,6 +60,14 @@ ifndef LDNOMAP LFLAGS_LIBSA = -Xlinker --version-script=mapfile endif +# If this is a --hash-style=gnu system, use --hash-style=both +# The gnu .hash section won't work on some Linux systems like SuSE 10. +_HAS_HASH_STYLE_GNU:=$(shell $(CC) -dumpspecs | grep -- '--hash-style=gnu') +ifneq ($(_HAS_HASH_STYLE_GNU),) + LDFLAGS_HASH_STYLE = -Wl,--hash-style=both +endif +LFLAGS_LIBSA += $(LDFLAGS_HASH_STYLE) + $(LIBSA): $(OBJS) mapfile if [ ! -d $(ARCH) ] ; then mkdir $(ARCH) ; fi $(GCC) -shared $(LFLAGS_LIBSA) -o $(LIBSA) $(OBJS) $(LIBS) diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/HotSpotTypeDataBase.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/HotSpotTypeDataBase.java index 5e56a0e3f36..82f5ac44d0b 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/HotSpotTypeDataBase.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/HotSpotTypeDataBase.java @@ -306,8 +306,6 @@ public class HotSpotTypeDataBase extends BasicTypeDataBase { entryAddr = entryAddr.addOffsetTo(intConstantEntryArrayStride); } while (nameAddr != null); - String symbol = "heapOopSize"; // global int constant and value is initialized at runtime. - addIntConstant(symbol, (int)lookupInProcess(symbol).getCIntegerAt(0, 4, false)); } private void readVMLongConstants() { diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java index 44fb1a817ea..6301b560a8e 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java @@ -318,11 +318,17 @@ public class VM { logMinObjAlignmentInBytes = db.lookupIntConstant("LogMinObjAlignmentInBytes").intValue(); heapWordSize = db.lookupIntConstant("HeapWordSize").intValue(); oopSize = db.lookupIntConstant("oopSize").intValue(); - heapOopSize = db.lookupIntConstant("heapOopSize").intValue(); intxType = db.lookupType("intx"); uintxType = db.lookupType("uintx"); boolType = (CIntegerType) db.lookupType("bool"); + + if (isCompressedOopsEnabled()) { + // Size info for oops within java objects is fixed + heapOopSize = (int)getIntSize(); + } else { + heapOopSize = (int)getOopSize(); + } } /** This could be used by a reflective runtime system */ @@ -343,13 +349,12 @@ public class VM { } soleInstance = new VM(db, debugger, debugger.getMachineDescription().isBigEndian()); - debugger.putHeapConst(soleInstance.getHeapOopSize(), Universe.getNarrowOopBase(), - Universe.getNarrowOopShift()); - for (Iterator iter = vmInitializedObservers.iterator(); iter.hasNext(); ) { ((Observer) iter.next()).update(null, null); } + debugger.putHeapConst(soleInstance.getHeapOopSize(), Universe.getNarrowOopBase(), + Universe.getNarrowOopShift()); } /** This is used by the debugging system */ diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version index 03e5df8dcc9..8bffe3efc51 100644 --- a/hotspot/make/hotspot_version +++ b/hotspot/make/hotspot_version @@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2009 HS_MAJOR_VER=16 HS_MINOR_VER=0 -HS_BUILD_NUMBER=02 +HS_BUILD_NUMBER=03 JDK_MAJOR_VER=1 JDK_MINOR_VER=7 diff --git a/hotspot/make/jprt.config b/hotspot/make/jprt.config deleted file mode 100644 index bc82543b90e..00000000000 --- a/hotspot/make/jprt.config +++ /dev/null @@ -1,275 +0,0 @@ -#!echo "This is not a shell script" -# -# Copyright 2006-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. -# -# 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. -# -# - -############################################################################# -# Error -error() # message -{ - echo "ERROR: $1" - exit 6 -} -# Directory must exist -dirMustExist() # dir name -{ - if [ ! -d "$1" ] ; then - error "Directory for $2 does not exist: $1" - fi -} -# File must exist -fileMustExist() # dir name -{ - if [ ! -f "$1" ] ; then - error "File for $2 does not exist: $1" - fi -} -############################################################################# - -# Should be set by JPRT as the 3 basic inputs -bootdir="${ALT_BOOTDIR}" -slashjava="${ALT_SLASH_JAVA}" -jdk_import="${ALT_JDK_IMPORT_PATH}" - -# Check input -dirMustExist "${bootdir}" ALT_BOOTDIR -dirMustExist "${slashjava}" ALT_SLASH_JAVA -dirMustExist "${jdk_import}" ALT_JDK_IMPORT_PATH - -# Uses 'uname -s', but only expect SunOS or Linux, assume Windows otherwise. -osname=`uname -s` -if [ "${osname}" = SunOS ] ; then - - # SOLARIS: Sparc or X86 - osarch=`uname -p` - if [ "${osarch}" = sparc ] ; then - solaris_arch=sparc - else - solaris_arch=i386 - fi - - if [ "${JPRT_SOLARIS_COMPILER_NAME}" != "" ] ; then - compiler_name=${JPRT_SOLARIS_COMPILER_NAME} - else - if [ "${JPRT_JOB_PRODUCT_RELEASE}" = "jdk6" -o \ - "${JPRT_JOB_PRODUCT_RELEASE}" = "jdk6u10" -o \ - "${JPRT_JOB_PRODUCT_RELEASE}" = "jdk6u14" -o \ - "${JPRT_JOB_PRODUCT_RELEASE}" = "jdk6perf" ] ; then - # All jdk6 builds use SS11 - compiler_name=SS11 - else - compiler_name=SS12 - fi - fi - - # Get into path (make sure it matches ALT setting) - compiler_path=${slashjava}/devtools/${solaris_arch}/SUNWspro/${compiler_name}/bin - dirMustExist "${compiler_path}" COMPILER_PATH - path4sdk=${compiler_path} - - # Add basic solaris system paths - path4sdk=${path4sdk}:/usr/ccs/bin:/usr/ccs/lib:/usr/bin:/bin:/usr/sfw/bin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Find GNU make - make=/usr/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=/opt/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=${slashjava}/devtools/${solaris_arch}/bin/gnumake - fi - fi - fileMustExist "${make}" make - - # File creation mask - umask 002 - -elif [ "${osname}" = Linux ] ; then - - # LINUX: X86, AMD64 - osarch=`uname -m` - if [ "${osarch}" = i686 ] ; then - linux_arch=i586 - elif [ "${osarch}" = x86_64 ] ; then - linux_arch=amd64 - fi - - # Get the compilers into path (make sure it matches ALT setting) - compiler_path=/usr/bin - dirMustExist "${compiler_path}" COMPILER_PATH - path4sdk=${compiler_path} - - # Add basic paths - path4sdk=${path4sdk}:/usr/bin:/bin:/usr/sbin:/sbin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Find GNU make - make=/usr/bin/make - fileMustExist "${make}" make - - umask 002 - -else - - # Windows: Differs on CYGWIN vs. MKS, and the compiler available. - # Also, blanks in pathnames gives GNU make headaches, so anything placed - # in any ALT_* variable should be the short windows dosname. - - # WINDOWS: Install and use MKS or CYGWIN (should have already been done) - # Assumption here is that you are in a shell window via MKS or cygwin. - # MKS install should have defined the environment variable ROOTDIR. - # We also need to figure out which one we have: X86, AMD64 - if [ "`echo ${PROCESSOR_IDENTIFIER} | fgrep AMD64`" != "" ] ; then - windows_arch=amd64 - else - windows_arch=i586 - fi - - # We need to determine if we are running a CYGWIN shell or an MKS shell - # (if uname isn't available, then it will be unix_toolset=unknown) - unix_toolset=unknown - if [ "`uname -a | fgrep Cygwin`" = "" -a -d "${ROOTDIR}" ] ; then - # We kind of assume ROOTDIR is where MKS is and it's ok - unix_toolset=MKS - mkshome=`dosname -s "${ROOTDIR}"` - # Utility to convert to short pathnames without spaces - dosname="${mkshome}/mksnt/dosname -s" - # Most unix utilities are in the mksnt directory of ROOTDIR - unixcommand_path="${mkshome}/mksnt" - path4sdk="${unixcommand_path}" - dirMustExist "${unixcommand_path}" UNIXCOMMAND_PATH - devtools_path="${slashjava}/devtools/win32/bin" - path4sdk="${devtools_path};${path4sdk}" - dirMustExist "${devtools_path}" DEVTOOLS_PATH - # Find GNU make - make="${devtools_path}/gnumake.exe" - fileMustExist "${make}" make - elif [ "`uname -a | fgrep Cygwin`" != "" -a -f /bin/cygpath ] ; then - # For CYGWIN, uname will have "Cygwin" in it, and /bin/cygpath should exist - unix_toolset=CYGWIN - # Utility to convert to short pathnames without spaces - dosname="/usr/bin/cygpath -a -m -s" - # Most unix utilities are in the /usr/bin - unixcommand_path="/usr/bin" - path4sdk="${unixcommand_path}" - dirMustExist "${unixcommand_path}" UNIXCOMMAND_PATH - # Find GNU make - make="${unixcommand_path}/make.exe" - fileMustExist "${make}" make - else - echo "WARNING: Cannot figure out if this is MKS or CYGWIN" - fi - - # WINDOWS: Compiler setup (nasty part) - # NOTE: You can use vcvars32.bat to set PATH, LIB, and INCLUDE. - # NOTE: CYGWIN has a link.exe too, make sure the compilers are first - if [ "${windows_arch}" = i586 ] ; then - # 32bit Windows compiler settings - # VisualStudio .NET 2003 VC++ 7.1 (VS71COMNTOOLS should be defined) - vs_root=`${dosname} "${VS71COMNTOOLS}/../.."` - # Fill in PATH, LIB, and INCLUDE (unset all others to make sure) - vc7_root="${vs_root}/Vc7" - compiler_path="${vc7_root}/bin" - platform_sdk="${vc7_root}/PlatformSDK" - # LIB and INCLUDE must use ; as a separator - include4sdk="${vc7_root}/atlmfc/include" - include4sdk="${include4sdk};${vc7_root}/include" - include4sdk="${include4sdk};${platform_sdk}/include/prerelease" - include4sdk="${include4sdk};${platform_sdk}/include" - include4sdk="${include4sdk};${vs_root}/SDK/v1.1/include" - lib4sdk="${vc7_root}/atlmfc/lib" - lib4sdk="${lib4sdk};${vc7_root}/lib" - lib4sdk="${lib4sdk};${platform_sdk}/lib/prerelease" - lib4sdk="${lib4sdk};${platform_sdk}/lib" - lib4sdk="${lib4sdk};${vs_root}/SDK/v1.1/lib" - # Search path and DLL locating path - # WARNING: CYGWIN has a link.exe too, make sure compilers are first - path4sdk="${vs_root}/Common7/Tools/bin;${path4sdk}" - path4sdk="${vs_root}/SDK/v1.1/bin;${path4sdk}" - path4sdk="${vs_root}/Common7/Tools;${path4sdk}" - path4sdk="${vs_root}/Common7/Tools/bin/prerelease;${path4sdk}" - path4sdk="${vs_root}/Common7/IDE;${path4sdk}" - path4sdk="${compiler_path};${path4sdk}" - elif [ "${windows_arch}" = amd64 ] ; then - # AMD64 64bit Windows compiler settings - if [ "${MSSDK}" != "" ] ; then - platform_sdk="${MSSDK}" - else - platform_sdk=`${dosname} "C:/Program Files/Microsoft Platform SDK/"` - fi - compiler_path="${platform_sdk}/Bin/win64/x86/AMD64" - # LIB and INCLUDE must use ; as a separator - include4sdk="${platform_sdk}/Include" - include4sdk="${include4sdk};${platform_sdk}/Include/crt/sys" - include4sdk="${include4sdk};${platform_sdk}/Include/mfc" - include4sdk="${include4sdk};${platform_sdk}/Include/atl" - include4sdk="${include4sdk};${platform_sdk}/Include/crt" - lib4sdk="${platform_sdk}/Lib/AMD64" - lib4sdk="${lib4sdk};${platform_sdk}/Lib/AMD64/atlmfc" - # Search path and DLL locating path - # WARNING: CYGWIN has a link.exe too, make sure compilers are first - path4sdk="${platform_sdk}/bin;${path4sdk}" - path4sdk="${compiler_path};${path4sdk}" - fi - # Export LIB and INCLUDE - unset lib - unset Lib - LIB="${lib4sdk}" - export LIB - unset include - unset Include - INCLUDE="${include4sdk}" - export INCLUDE - # Set the ALT variable - dirMustExist "${compiler_path}" COMPILER_PATH - - # WINDOWS: Get the previous JDK to be used to bootstrap the build - path4sdk="${bootdir}/bin;${path4sdk}" - - # Turn all \\ into /, remove duplicates and trailing / - slash_path="`echo ${path4sdk} | sed -e 's@\\\\@/@g' -e 's@//@/@g' -e 's@/$@@' -e 's@/;@;@g'`" - - # For windows, it's hard to know where the system is, so we just add this - # to PATH. - path4sdk="${slash_path};${PATH}" - - # Convert path4sdk to cygwin style - if [ "${unix_toolset}" = CYGWIN ] ; then - path4sdk="`/usr/bin/cygpath -p ${path4sdk}`" - fi - -fi - -# Export PATH setting -PATH="${path4sdk}" -export PATH - -# Unset certain vars -unset LD_LIBRARY_PATH -unset LD_LIBRARY_PATH_32 -unset LD_LIBRARY_PATH_64 - diff --git a/hotspot/make/jprt.properties b/hotspot/make/jprt.properties index 2ab768f2515..c6d46e6b56b 100644 --- a/hotspot/make/jprt.properties +++ b/hotspot/make/jprt.properties @@ -70,10 +70,33 @@ jprt.my.solaris.x64.jdk6u10=solaris_x64_5.10 jprt.my.solaris.x64.jdk6u14=solaris_x64_5.10 jprt.my.solaris.x64=${jprt.my.solaris.x64.${jprt.tools.default.release}} -jprt.my.linux.i586=linux_i586 -jprt.my.linux.x64=linux_x64 -jprt.my.windows.i586=windows_i586 -jprt.my.windows.x64=windows_x64 +jprt.my.linux.i586.jdk7=linux_i586_2.6 +jprt.my.linux.i586.jdk6=linux_i586_2.4 +jprt.my.linux.i586.jdk6perf=linux_i586_2.4 +jprt.my.linux.i586.jdk6u10=linux_i586_2.4 +jprt.my.linux.i586.jdk6u14=linux_i586_2.4 +jprt.my.linux.i586=${jprt.my.linux.i586.${jprt.tools.default.release}} + +jprt.my.linux.x64.jdk7=linux_x64_2.6 +jprt.my.linux.x64.jdk6=linux_x64_2.4 +jprt.my.linux.x64.jdk6perf=linux_x64_2.4 +jprt.my.linux.x64.jdk6u10=linux_x64_2.4 +jprt.my.linux.x64.jdk6u14=linux_x64_2.4 +jprt.my.linux.x64=${jprt.my.linux.x64.${jprt.tools.default.release}} + +jprt.my.windows.i586.jdk7=windows_i586_5.0 +jprt.my.windows.i586.jdk6=windows_i586_5.0 +jprt.my.windows.i586.jdk6perf=windows_i586_5.0 +jprt.my.windows.i586.jdk6u10=windows_i586_5.0 +jprt.my.windows.i586.jdk6u14=windows_i586_5.0 +jprt.my.windows.i586=${jprt.my.windows.i586.${jprt.tools.default.release}} + +jprt.my.windows.x64.jdk7=windows_x64_5.2 +jprt.my.windows.x64.jdk6=windows_x64_5.2 +jprt.my.windows.x64.jdk6perf=windows_x64_5.2 +jprt.my.windows.x64.jdk6u10=windows_x64_5.2 +jprt.my.windows.x64.jdk6u14=windows_x64_5.2 +jprt.my.windows.x64=${jprt.my.windows.x64.${jprt.tools.default.release}} # Standard list of jprt build targets for this source tree diff --git a/hotspot/make/linux/makefiles/gcc.make b/hotspot/make/linux/makefiles/gcc.make index 002e960d36e..13e96b31d2c 100644 --- a/hotspot/make/linux/makefiles/gcc.make +++ b/hotspot/make/linux/makefiles/gcc.make @@ -113,6 +113,11 @@ endif OPT_CFLAGS/NOOPT=-O0 +# 6835796. Problem in GCC 4.3.0 with mulnode.o optimized compilation. +ifneq "$(shell expr \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) = 3 \) \))" "0" +OPT_CFLAGS/mulnode.o += -O0 +endif + #------------------------------------------------------------------------ # Linker flags diff --git a/hotspot/make/linux/makefiles/jsig.make b/hotspot/make/linux/makefiles/jsig.make index 0d254bfe8f3..9189fa5930f 100644 --- a/hotspot/make/linux/makefiles/jsig.make +++ b/hotspot/make/linux/makefiles/jsig.make @@ -39,7 +39,7 @@ LIBJSIG_MAPFILE = $(MAKEFILES_DIR)/mapfile-vers-jsig # cause problems with interposing. See CR: 6466665 # LFLAGS_JSIG += $(MAPFLAG:FILENAME=$(LIBJSIG_MAPFILE)) -LFLAGS_JSIG += -D_GNU_SOURCE -D_REENTRANT +LFLAGS_JSIG += -D_GNU_SOURCE -D_REENTRANT $(LDFLAGS_HASH_STYLE) $(LIBJSIG): $(JSIGSRCDIR)/jsig.c $(LIBJSIG_MAPFILE) @echo Making signal interposition lib... diff --git a/hotspot/make/linux/makefiles/saproc.make b/hotspot/make/linux/makefiles/saproc.make index 052adb13413..faf677863b8 100644 --- a/hotspot/make/linux/makefiles/saproc.make +++ b/hotspot/make/linux/makefiles/saproc.make @@ -51,7 +51,7 @@ checkAndBuildSA: $(MAKE) -f vm.make $(LIBSAPROC); \ fi -SA_LFLAGS = $(MAPFLAG:FILENAME=$(SAMAPFILE)) +SA_LFLAGS = $(MAPFLAG:FILENAME=$(SAMAPFILE)) $(LDFLAGS_HASH_STYLE) $(LIBSAPROC): $(SASRCFILES) $(SAMAPFILE) $(QUIETLY) if [ "$(BOOT_JAVA_HOME)" = "" ]; then \ diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index b4705e4a7f2..eb510b66701 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -2314,7 +2314,8 @@ bool os::commit_memory(char* addr, size_t size, size_t alignment_hint, void os::realign_memory(char *addr, size_t bytes, size_t alignment_hint) { } void os::free_memory(char *addr, size_t bytes) { - uncommit_memory(addr, bytes); + ::mmap(addr, bytes, PROT_READ | PROT_WRITE, + MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0); } void os::numa_make_global(char *addr, size_t bytes) { @@ -2361,6 +2362,19 @@ char *os::scan_pages(char *start, char* end, page_info* page_expected, page_info extern "C" void numa_warn(int number, char *where, ...) { } extern "C" void numa_error(char *where) { } + +// If we are running with libnuma version > 2, then we should +// be trying to use symbols with versions 1.1 +// If we are running with earlier version, which did not have symbol versions, +// we should use the base version. +void* os::Linux::libnuma_dlsym(void* handle, const char *name) { + void *f = dlvsym(handle, name, "libnuma_1.1"); + if (f == NULL) { + f = dlsym(handle, name); + } + return f; +} + bool os::Linux::libnuma_init() { // sched_getcpu() should be in libc. set_sched_getcpu(CAST_TO_FN_PTR(sched_getcpu_func_t, @@ -2370,19 +2384,19 @@ bool os::Linux::libnuma_init() { void *handle = dlopen("libnuma.so.1", RTLD_LAZY); if (handle != NULL) { set_numa_node_to_cpus(CAST_TO_FN_PTR(numa_node_to_cpus_func_t, - dlsym(handle, "numa_node_to_cpus"))); + libnuma_dlsym(handle, "numa_node_to_cpus"))); set_numa_max_node(CAST_TO_FN_PTR(numa_max_node_func_t, - dlsym(handle, "numa_max_node"))); + libnuma_dlsym(handle, "numa_max_node"))); set_numa_available(CAST_TO_FN_PTR(numa_available_func_t, - dlsym(handle, "numa_available"))); + libnuma_dlsym(handle, "numa_available"))); set_numa_tonode_memory(CAST_TO_FN_PTR(numa_tonode_memory_func_t, - dlsym(handle, "numa_tonode_memory"))); + libnuma_dlsym(handle, "numa_tonode_memory"))); set_numa_interleave_memory(CAST_TO_FN_PTR(numa_interleave_memory_func_t, - dlsym(handle, "numa_interleave_memory"))); + libnuma_dlsym(handle, "numa_interleave_memory"))); if (numa_available() != -1) { - set_numa_all_nodes((unsigned long*)dlsym(handle, "numa_all_nodes")); + set_numa_all_nodes((unsigned long*)libnuma_dlsym(handle, "numa_all_nodes")); // Create a cpu -> node mapping _cpu_to_node = new (ResourceObj::C_HEAP) GrowableArray(0, true); rebuild_cpu_to_node_map(); diff --git a/hotspot/src/os/linux/vm/os_linux.hpp b/hotspot/src/os/linux/vm/os_linux.hpp index ebd8c931b2b..a51c2feed41 100644 --- a/hotspot/src/os/linux/vm/os_linux.hpp +++ b/hotspot/src/os/linux/vm/os_linux.hpp @@ -147,7 +147,7 @@ class Linux { static void libpthread_init(); static bool libnuma_init(); - + static void* libnuma_dlsym(void* handle, const char* name); // Minimum stack size a thread can be created with (allowing // the VM to completely create the thread and enter user code) static size_t min_stack_allowed; diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp index b099908a7a7..a5e0f395779 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp @@ -53,7 +53,9 @@ void ConcurrentG1RefineThread::traversalBasedRefinement() { ResourceMark rm; HandleMark hm; - if (TraceG1Refine) gclog_or_tty->print_cr("G1-Refine starting pass"); + if (G1TraceConcurrentRefinement) { + gclog_or_tty->print_cr("G1-Refine starting pass"); + } _sts.join(); bool no_sleep = _cg1r->refine(); _sts.leave(); @@ -207,9 +209,9 @@ void ConcurrentG1RefineThread::run() { void ConcurrentG1RefineThread::yield() { - if (TraceG1Refine) gclog_or_tty->print_cr("G1-Refine-yield"); + if (G1TraceConcurrentRefinement) gclog_or_tty->print_cr("G1-Refine-yield"); _sts.yield("G1 refine"); - if (TraceG1Refine) gclog_or_tty->print_cr("G1-Refine-yield-end"); + if (G1TraceConcurrentRefinement) gclog_or_tty->print_cr("G1-Refine-yield-end"); } void ConcurrentG1RefineThread::stop() { @@ -230,7 +232,7 @@ void ConcurrentG1RefineThread::stop() { Terminator_lock->wait(); } } - if (TraceG1Refine) gclog_or_tty->print_cr("G1-Refine-stop"); + if (G1TraceConcurrentRefinement) gclog_or_tty->print_cr("G1-Refine-stop"); } void ConcurrentG1RefineThread::print() { diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index fb4f502cf94..59ff099d87a 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -448,8 +448,8 @@ ConcurrentMark::ConcurrentMark(ReservedSpace rs, gclog_or_tty->print_cr("[global] init, heap start = "PTR_FORMAT", " "heap end = "PTR_FORMAT, _heap_start, _heap_end); - _markStack.allocate(G1CMStackSize); - _regionStack.allocate(G1CMRegionStackSize); + _markStack.allocate(G1MarkStackSize); + _regionStack.allocate(G1MarkRegionStackSize); // Create & start a ConcurrentMark thread. if (G1ConcMark) { @@ -499,20 +499,21 @@ ConcurrentMark::ConcurrentMark(ReservedSpace rs, _marking_task_overhead = 1.0; } else { if (ParallelMarkingThreads > 0) { - // notice that ParallelMarkingThreads overwrites G1MarkingOverheadPerc + // notice that ParallelMarkingThreads overwrites G1MarkingOverheadPercent // if both are set _parallel_marking_threads = ParallelMarkingThreads; _sleep_factor = 0.0; _marking_task_overhead = 1.0; - } else if (G1MarkingOverheadPerc > 0) { + } else if (G1MarkingOverheadPercent > 0) { // we will calculate the number of parallel marking threads // based on a target overhead with respect to the soft real-time // goal - double marking_overhead = (double) G1MarkingOverheadPerc / 100.0; + double marking_overhead = (double) G1MarkingOverheadPercent / 100.0; double overall_cm_overhead = - (double) G1MaxPauseTimeMS * marking_overhead / (double) G1TimeSliceMS; + (double) MaxGCPauseMillis * marking_overhead / + (double) GCPauseIntervalMillis; double cpu_ratio = 1.0 / (double) os::processor_count(); double marking_thread_num = ceil(overall_cm_overhead / cpu_ratio); double marking_task_overhead = @@ -1747,7 +1748,7 @@ void ConcurrentMark::cleanup() { g1h->increment_total_collections(); #ifndef PRODUCT - if (G1VerifyConcMark) { + if (VerifyDuringGC) { G1CollectedHeap::heap()->prepare_for_verify(); G1CollectedHeap::heap()->verify(true,false); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp index 277ac636ecb..23164b6b075 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp @@ -136,9 +136,6 @@ void ConcurrentMarkThread::run() { iter++; if (!cm()->has_aborted()) { _cm->markFromRoots(); - } else { - if (TraceConcurrentMark) - gclog_or_tty->print_cr("CM-skip-mark-from-roots"); } double mark_end_time = os::elapsedVTime(); @@ -163,9 +160,6 @@ void ConcurrentMarkThread::run() { sprintf(verbose_str, "GC remark"); VM_CGC_Operation op(&final_cl, verbose_str); VMThread::execute(&op); - } else { - if (TraceConcurrentMark) - gclog_or_tty->print_cr("CM-skip-remark"); } if (cm()->restart_for_overflow() && G1TraceMarkStackOverflow) { @@ -208,8 +202,6 @@ void ConcurrentMarkThread::run() { count_end_sec - count_start_sec); } } - } else { - if (TraceConcurrentMark) gclog_or_tty->print_cr("CM-skip-end-game"); } double end_time = os::elapsedVTime(); _vtime_count_accum += (end_time - counting_start_time); @@ -230,7 +222,6 @@ void ConcurrentMarkThread::run() { VM_CGC_Operation op(&cl_cl, verbose_str); VMThread::execute(&op); } else { - if (TraceConcurrentMark) gclog_or_tty->print_cr("CM-skip-cleanup"); G1CollectedHeap::heap()->set_marking_complete(); } @@ -287,9 +278,7 @@ void ConcurrentMarkThread::run() { void ConcurrentMarkThread::yield() { - if (TraceConcurrentMark) gclog_or_tty->print_cr("CM-yield"); _sts.yield("Concurrent Mark"); - if (TraceConcurrentMark) gclog_or_tty->print_cr("CM-yield-end"); } void ConcurrentMarkThread::stop() { @@ -299,7 +288,6 @@ void ConcurrentMarkThread::stop() { while (!_has_terminated) { Terminator_lock->wait(); } - if (TraceConcurrentMark) gclog_or_tty->print_cr("CM-stop"); } void ConcurrentMarkThread::print() { @@ -314,12 +302,10 @@ void ConcurrentMarkThread::sleepBeforeNextCycle() { // below while the world is otherwise stopped. MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag); while (!started()) { - if (TraceConcurrentMark) gclog_or_tty->print_cr("CM-sleeping"); CGC_lock->wait(Mutex::_no_safepoint_check_flag); } set_in_progress(); clear_started(); - if (TraceConcurrentMark) gclog_or_tty->print_cr("CM-starting"); } // Note: this method, although exported by the ConcurrentMarkSweepThread, diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index fb4a0c79868..8f485bc540e 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -528,7 +528,7 @@ HeapRegion* G1CollectedHeap::newAllocRegion_work(size_t word_size, res->zero_fill_state() == HeapRegion::Allocated)), "Non-young alloc Regions must be zero filled (and non-H)"); - if (G1TraceRegions) { + if (G1PrintRegions) { if (res != NULL) { gclog_or_tty->print_cr("new alloc region %d:["PTR_FORMAT", "PTR_FORMAT"], " "top "PTR_FORMAT, @@ -2282,13 +2282,13 @@ void G1CollectedHeap::print_tracing_info() const { // to that. g1_policy()->print_tracing_info(); } - if (SummarizeG1RSStats) { + if (G1SummarizeRSetStats) { g1_rem_set()->print_summary_info(); } - if (SummarizeG1ConcMark) { + if (G1SummarizeConcurrentMark) { concurrent_mark()->print_summary_info(); } - if (SummarizeG1ZFStats) { + if (G1SummarizeZFStats) { ConcurrentZFThread::print_summary_info(); } g1_policy()->print_yg_surv_rate_info(); @@ -3255,7 +3255,7 @@ void G1CollectedHeap::handle_evacuation_failure_common(oop old, markOop m) { HeapRegion* r = heap_region_containing(old); if (!r->evacuation_failed()) { r->set_evacuation_failed(true); - if (G1TraceRegions) { + if (G1PrintRegions) { gclog_or_tty->print("evacuation failed in heap region "PTR_FORMAT" " "["PTR_FORMAT","PTR_FORMAT")\n", r, r->bottom(), r->end()); @@ -3466,7 +3466,7 @@ private: } static size_t gclab_word_size() { - return ParallelGCG1AllocBufferSize / HeapWordSize; + return G1ParallelGCAllocBufferSize / HeapWordSize; } static size_t bitmap_size_in_bits() { @@ -3616,7 +3616,7 @@ private: public: G1ParGCAllocBuffer() : - ParGCAllocBuffer(ParallelGCG1AllocBufferSize / HeapWordSize), + ParGCAllocBuffer(G1ParallelGCAllocBufferSize / HeapWordSize), _during_marking(G1CollectedHeap::heap()->mark_in_progress()), _bitmap(G1CollectedHeap::heap()->reserved_region().start()), _retired(false) @@ -3812,14 +3812,14 @@ public: HeapWord* obj = NULL; if (word_sz * 100 < - (size_t)(ParallelGCG1AllocBufferSize / HeapWordSize) * + (size_t)(G1ParallelGCAllocBufferSize / HeapWordSize) * ParallelGCBufferWastePct) { G1ParGCAllocBuffer* alloc_buf = alloc_buffer(purpose); add_to_alloc_buffer_waste(alloc_buf->words_remaining()); alloc_buf->retire(false, false); HeapWord* buf = - _g1h->par_allocate_during_gc(purpose, ParallelGCG1AllocBufferSize / HeapWordSize); + _g1h->par_allocate_during_gc(purpose, G1ParallelGCAllocBufferSize / HeapWordSize); if (buf == NULL) return NULL; // Let caller handle allocation failure. // Otherwise. alloc_buf->set_buf(buf); @@ -4331,7 +4331,7 @@ public: _g1h->g1_policy()->record_obj_copy_time(i, elapsed_ms-term_ms); _g1h->g1_policy()->record_termination_time(i, term_ms); } - if (G1UseSurvivorSpace) { + if (G1UseSurvivorSpaces) { _g1h->g1_policy()->record_thread_age_table(pss.age_table()); } _g1h->update_surviving_young_words(pss.surviving_young_words()+1); @@ -4435,28 +4435,6 @@ g1_process_strong_roots(bool collecting_perm_gen, // XXX What should this be doing in the parallel case? g1_policy()->record_collection_pause_end_CH_strong_roots(); - if (G1VerifyRemSet) { - // :::: FIXME :::: - // The stupid remembered set doesn't know how to filter out dead - // objects, which the smart one does, and so when it is created - // and then compared the number of entries in each differs and - // the verification code fails. - guarantee(false, "verification code is broken, see note"); - - // Let's make sure that the current rem set agrees with the stupidest - // one possible! - bool refs_enabled = ref_processor()->discovery_enabled(); - if (refs_enabled) ref_processor()->disable_discovery(); - StupidG1RemSet stupid(this); - count_closure.n = 0; - stupid.oops_into_collection_set_do(&count_closure, worker_i); - int stupid_n = count_closure.n; - count_closure.n = 0; - g1_rem_set()->oops_into_collection_set_do(&count_closure, worker_i); - guarantee(count_closure.n == stupid_n, "Old and new rem sets differ."); - gclog_or_tty->print_cr("\nFound %d pointers in heap RS.", count_closure.n); - if (refs_enabled) ref_processor()->enable_discovery(); - } if (scan_so != NULL) { scan_scan_only_set(scan_so, worker_i); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp index d022044e0b0..0da38f577cd 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp @@ -37,8 +37,9 @@ G1CollectedHeap::heap_region_containing(const void* addr) const { inline HeapRegion* G1CollectedHeap::heap_region_containing_raw(const void* addr) const { assert(_g1_reserved.contains(addr), "invariant"); - size_t index = ((intptr_t) addr - (intptr_t) _g1_reserved.start()) - >> HeapRegion::LogOfHRGrainBytes; + size_t index = pointer_delta(addr, _g1_reserved.start(), 1) + >> HeapRegion::LogOfHRGrainBytes; + HeapRegion* res = _hrs->at(index); assert(res == _hrs->addr_to_region(addr), "sanity"); return res; diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp index d259ad38ea0..c09a62ddf49 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp @@ -136,7 +136,7 @@ G1CollectorPolicy::G1CollectorPolicy() : _scanned_cards_seq(new TruncatedSeq(TruncatedSeqLength)), _rs_lengths_seq(new TruncatedSeq(TruncatedSeqLength)), - _pause_time_target_ms((double) G1MaxPauseTimeMS), + _pause_time_target_ms((double) MaxGCPauseMillis), // @@ -220,7 +220,7 @@ G1CollectorPolicy::G1CollectorPolicy() : _par_last_termination_times_ms = new double[_parallel_gc_threads]; // start conservatively - _expensive_region_limit_ms = 0.5 * (double) G1MaxPauseTimeMS; + _expensive_region_limit_ms = 0.5 * (double) MaxGCPauseMillis; // @@ -249,12 +249,12 @@ G1CollectorPolicy::G1CollectorPolicy() : // - double time_slice = (double) G1TimeSliceMS / 1000.0; - double max_gc_time = (double) G1MaxPauseTimeMS / 1000.0; + double time_slice = (double) GCPauseIntervalMillis / 1000.0; + double max_gc_time = (double) MaxGCPauseMillis / 1000.0; guarantee(max_gc_time < time_slice, "Max GC time should not be greater than the time slice"); _mmu_tracker = new G1MMUTrackerQueue(time_slice, max_gc_time); - _sigma = (double) G1ConfidencePerc / 100.0; + _sigma = (double) G1ConfidencePercent / 100.0; // start conservatively (around 50ms is about right) _concurrent_mark_init_times_ms->add(0.05); @@ -262,7 +262,7 @@ G1CollectorPolicy::G1CollectorPolicy() : _concurrent_mark_cleanup_times_ms->add(0.20); _tenuring_threshold = MaxTenuringThreshold; - if (G1UseSurvivorSpace) { + if (G1UseSurvivorSpaces) { // if G1FixedSurvivorSpaceSize is 0 which means the size is not // fixed, then _max_survivor_regions will be calculated at // calculate_young_list_target_config during initialization @@ -451,7 +451,7 @@ void G1CollectorPolicy::calculate_young_list_target_config(size_t rs_lengths) { guarantee( adaptive_young_list_length(), "pre-condition" ); double start_time_sec = os::elapsedTime(); - size_t min_reserve_perc = MAX2((size_t)2, (size_t)G1MinReservePerc); + size_t min_reserve_perc = MAX2((size_t)2, (size_t)G1MinReservePercent); min_reserve_perc = MIN2((size_t) 50, min_reserve_perc); size_t reserve_regions = (size_t) ((double) min_reserve_perc * (double) _g1->n_regions() / 100.0); @@ -1109,7 +1109,7 @@ void G1CollectorPolicy::record_collection_pause_start(double start_time_sec, _short_lived_surv_rate_group->record_scan_only_prefix(short_lived_so_length); tag_scan_only(short_lived_so_length); - if (G1UseSurvivorSpace) { + if (G1UseSurvivorSpaces) { _survivors_age_table.clear(); } @@ -1826,11 +1826,11 @@ void G1CollectorPolicy::record_collection_pause_end(bool abandoned) { _rs_lengths_seq->add((double) _max_rs_lengths); double expensive_region_limit_ms = - (double) G1MaxPauseTimeMS - predict_constant_other_time_ms(); + (double) MaxGCPauseMillis - predict_constant_other_time_ms(); if (expensive_region_limit_ms < 0.0) { // this means that the other time was predicted to be longer than // than the max pause time - expensive_region_limit_ms = (double) G1MaxPauseTimeMS; + expensive_region_limit_ms = (double) MaxGCPauseMillis; } _expensive_region_limit_ms = expensive_region_limit_ms; @@ -2093,24 +2093,24 @@ void G1CollectorPolicy::update_recent_gc_times(double end_time_sec, } double G1CollectorPolicy::recent_avg_time_for_pauses_ms() { - if (_recent_pause_times_ms->num() == 0) return (double) G1MaxPauseTimeMS; + if (_recent_pause_times_ms->num() == 0) return (double) MaxGCPauseMillis; else return _recent_pause_times_ms->avg(); } double G1CollectorPolicy::recent_avg_time_for_CH_strong_ms() { if (_recent_CH_strong_roots_times_ms->num() == 0) - return (double)G1MaxPauseTimeMS/3.0; + return (double)MaxGCPauseMillis/3.0; else return _recent_CH_strong_roots_times_ms->avg(); } double G1CollectorPolicy::recent_avg_time_for_G1_strong_ms() { if (_recent_G1_strong_roots_times_ms->num() == 0) - return (double)G1MaxPauseTimeMS/3.0; + return (double)MaxGCPauseMillis/3.0; else return _recent_G1_strong_roots_times_ms->avg(); } double G1CollectorPolicy::recent_avg_time_for_evac_ms() { - if (_recent_evac_times_ms->num() == 0) return (double)G1MaxPauseTimeMS/3.0; + if (_recent_evac_times_ms->num() == 0) return (double)MaxGCPauseMillis/3.0; else return _recent_evac_times_ms->avg(); } @@ -2197,17 +2197,18 @@ G1CollectorPolicy::conservative_avg_survival_fraction_work(double avg, } size_t G1CollectorPolicy::expansion_amount() { - if ((int)(recent_avg_pause_time_ratio() * 100.0) > G1GCPct) { - // We will double the existing space, or take G1ExpandByPctOfAvail % of - // the available expansion space, whichever is smaller, bounded below - // by a minimum expansion (unless that's all that's left.) + if ((int)(recent_avg_pause_time_ratio() * 100.0) > G1GCPercent) { + // We will double the existing space, or take + // G1ExpandByPercentOfAvailable % of the available expansion + // space, whichever is smaller, bounded below by a minimum + // expansion (unless that's all that's left.) const size_t min_expand_bytes = 1*M; size_t reserved_bytes = _g1->g1_reserved_obj_bytes(); size_t committed_bytes = _g1->capacity(); size_t uncommitted_bytes = reserved_bytes - committed_bytes; size_t expand_bytes; size_t expand_bytes_via_pct = - uncommitted_bytes * G1ExpandByPctOfAvail / 100; + uncommitted_bytes * G1ExpandByPercentOfAvailable / 100; expand_bytes = MIN2(expand_bytes_via_pct, committed_bytes); expand_bytes = MAX2(expand_bytes, min_expand_bytes); expand_bytes = MIN2(expand_bytes, uncommitted_bytes); @@ -2591,7 +2592,7 @@ size_t G1CollectorPolicy::max_regions(int purpose) { // Calculates survivor space parameters. void G1CollectorPolicy::calculate_survivors_policy() { - if (!G1UseSurvivorSpace) { + if (!G1UseSurvivorSpaces) { return; } if (G1FixedSurvivorSpaceSize == 0) { @@ -2851,7 +2852,7 @@ record_concurrent_mark_cleanup_end(size_t freed_bytes, // estimate of the number of live bytes. void G1CollectorPolicy:: add_to_collection_set(HeapRegion* hr) { - if (G1TraceRegions) { + if (G1PrintRegions) { gclog_or_tty->print_cr("added region to cset %d:["PTR_FORMAT", "PTR_FORMAT"], " "top "PTR_FORMAT", young %s", hr->hrs_index(), hr->bottom(), hr->end(), diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp index 2e4ba2f9f48..5670ebe5ac3 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp @@ -57,7 +57,7 @@ void G1MarkSweep::invoke_at_safepoint(ReferenceProcessor* rp, mark_sweep_phase1(marked_for_unloading, clear_all_softrefs); - if (G1VerifyConcMark) { + if (VerifyDuringGC) { G1CollectedHeap* g1h = G1CollectedHeap::heap(); g1h->checkConcurrentMark(); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp index f8674dd16c5..32104bc8212 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp @@ -180,6 +180,7 @@ class ScanRSClosure : public HeapRegionClosure { CardTableModRefBS *_ct_bs; int _worker_i; bool _try_claimed; + size_t _min_skip_distance, _max_skip_distance; public: ScanRSClosure(OopsInHeapRegionClosure* oc, int worker_i) : _oc(oc), @@ -191,6 +192,8 @@ public: _g1h = G1CollectedHeap::heap(); _bot_shared = _g1h->bot_shared(); _ct_bs = (CardTableModRefBS*) (_g1h->barrier_set()); + _min_skip_distance = 16; + _max_skip_distance = 2 * _g1h->n_par_threads() * _min_skip_distance; } void set_try_claimed() { _try_claimed = true; } @@ -245,9 +248,13 @@ public: HeapRegionRemSetIterator* iter = _g1h->rem_set_iterator(_worker_i); hrrs->init_iterator(iter); size_t card_index; + size_t skip_distance = 0, current_card = 0, jump_to_card = 0; while (iter->has_next(card_index)) { + if (current_card < jump_to_card) { + ++current_card; + continue; + } HeapWord* card_start = _g1h->bot_shared()->address_for_index(card_index); - #if 0 gclog_or_tty->print("Rem set iteration yielded card [" PTR_FORMAT ", " PTR_FORMAT ").\n", card_start, card_start + CardTableModRefBS::card_size_in_words); @@ -257,20 +264,28 @@ public: assert(card_region != NULL, "Yielding cards not in the heap?"); _cards++; - if (!card_region->in_collection_set()) { - // If the card is dirty, then we will scan it during updateRS. - if (!_ct_bs->is_card_claimed(card_index) && - !_ct_bs->is_card_dirty(card_index)) { - assert(_ct_bs->is_card_clean(card_index) || - _ct_bs->is_card_claimed(card_index) || - _ct_bs->is_card_deferred(card_index), - "Card is either clean, claimed or deferred"); - if (_ct_bs->claim_card(card_index)) + // If the card is dirty, then we will scan it during updateRS. + if (!card_region->in_collection_set() && !_ct_bs->is_card_dirty(card_index)) { + if (!_ct_bs->is_card_claimed(card_index) && _ct_bs->claim_card(card_index)) { scanCard(card_index, card_region); - } + } else if (_try_claimed) { + if (jump_to_card == 0 || jump_to_card != current_card) { + // We did some useful work in the previous iteration. + // Decrease the distance. + skip_distance = MAX2(skip_distance >> 1, _min_skip_distance); + } else { + // Previous iteration resulted in a claim failure. + // Increase the distance. + skip_distance = MIN2(skip_distance << 1, _max_skip_distance); + } + jump_to_card = current_card + skip_distance; + } } + ++current_card; + } + if (!_try_claimed) { + hrrs->set_iter_complete(); } - hrrs->set_iter_complete(); return false; } // Set all cards back to clean. @@ -508,7 +523,7 @@ HRInto_G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc, // and they are causing failures. When we resolve said race // conditions, we'll revert back to parallel remembered set // updating and scanning. See CRs 6677707 and 6677708. - if (G1EnableParallelRSetUpdating || (worker_i == 0)) { + if (G1ParallelRSetUpdatingEnabled || (worker_i == 0)) { updateRS(worker_i); scanNewRefsRS(oc, worker_i); } else { @@ -517,7 +532,7 @@ HRInto_G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc, _g1p->record_update_rs_time(worker_i, 0.0); _g1p->record_scan_new_refs_time(worker_i, 0.0); } - if (G1EnableParallelRSetScanning || (worker_i == 0)) { + if (G1ParallelRSetScanningEnabled || (worker_i == 0)) { scanRS(oc, worker_i); } else { _g1p->record_scan_rs_start_time(worker_i, os::elapsedTime()); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp index f6589e75c78..e8f75aa13c2 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp @@ -28,87 +28,65 @@ #define G1_FLAGS(develop, develop_pd, product, product_pd, diagnostic, experimental, notproduct, manageable, product_rw) \ \ - product(intx, ParallelGCG1AllocBufferSize, 8*K, \ + product(intx, G1ParallelGCAllocBufferSize, 8*K, \ "Size of parallel G1 allocation buffers in to-space.") \ \ - product(intx, G1TimeSliceMS, 500, \ - "Time slice for MMU specification") \ - \ - product(intx, G1MaxPauseTimeMS, 200, \ - "Max GC time per MMU time slice") \ - \ - product(intx, G1ConfidencePerc, 50, \ + product(intx, G1ConfidencePercent, 50, \ "Confidence level for MMU/pause predictions") \ \ - product(intx, G1MarkingOverheadPerc, 0, \ + develop(intx, G1MarkingOverheadPercent, 0, \ "Overhead of concurrent marking") \ \ - product(bool, G1AccountConcurrentOverhead, false, \ + develop(bool, G1AccountConcurrentOverhead, false, \ "Whether soft real-time compliance in G1 will take into account" \ "concurrent overhead") \ \ product(intx, G1YoungGenSize, 0, \ "Size of the G1 young generation, 0 is the adaptive policy") \ \ - product(bool, G1Gen, true, \ + develop(bool, G1Gen, true, \ "If true, it will enable the generational G1") \ \ - develop(intx, G1GCPct, 10, \ + develop(intx, G1GCPercent, 10, \ "The desired percent time spent on GC") \ \ - product(intx, G1PolicyVerbose, 0, \ + develop(intx, G1PolicyVerbose, 0, \ "The verbosity level on G1 policy decisions") \ \ develop(bool, G1UseHRIntoRS, true, \ "Determines whether the 'advanced' HR Into rem set is used.") \ \ - product(bool, G1VerifyRemSet, false, \ - "If true, verify the rem set functioning at each GC") \ - \ - product(bool, G1VerifyConcMark, false, \ - "If true, verify the conc marking code at full GC time") \ - \ develop(intx, G1MarkingVerboseLevel, 0, \ "Level (0-4) of verboseness of the marking code") \ \ - develop(bool, G1VerifyConcMarkPrintReachable, true, \ + develop(bool, G1VerifyConcMarkPrintReachable, false, \ "If conc mark verification fails, print reachable objects") \ \ develop(bool, G1TraceMarkStackOverflow, false, \ "If true, extra debugging code for CM restart for ovflw.") \ \ - product(bool, G1VerifyMarkingInEvac, false, \ - "If true, verify marking info during evacuation") \ - \ develop(intx, G1PausesBtwnConcMark, -1, \ "If positive, fixed number of pauses between conc markings") \ \ - product(intx, G1EfficiencyPctCausesMark, 80, \ - "The cum gc efficiency since mark fall-off that causes " \ - "new marking") \ - \ - product(bool, TraceConcurrentMark, false, \ - "Trace concurrent mark") \ - \ - product(bool, SummarizeG1ConcMark, false, \ + diagnostic(bool, G1SummarizeConcurrentMark, false, \ "Summarize concurrent mark info") \ \ - product(bool, SummarizeG1RSStats, false, \ + diagnostic(bool, G1SummarizeRSetStats, false, \ "Summarize remembered set processing info") \ \ - product(bool, SummarizeG1ZFStats, false, \ + diagnostic(bool, G1SummarizeZFStats, false, \ "Summarize zero-filling info") \ \ - product(bool, TraceG1Refine, false, \ + develop(bool, G1TraceConcurrentRefinement, false, \ "Trace G1 concurrent refinement") \ \ develop(bool, G1ConcMark, true, \ "If true, run concurrent marking for G1") \ \ - product(intx, G1CMStackSize, 2 * 1024 * 1024, \ + product(intx, G1MarkStackSize, 2 * 1024 * 1024, \ "Size of the mark stack for concurrent marking.") \ \ - product(intx, G1CMRegionStackSize, 1024 * 1024, \ + product(intx, G1MarkRegionStackSize, 1024 * 1024, \ "Size of the region stack for concurrent marking.") \ \ develop(bool, G1ConcRefine, true, \ @@ -121,7 +99,7 @@ "Number of heap regions of alloc ahead of starting collection " \ "pause to start concurrent refinement (initially)") \ \ - product(bool, G1SmoothConcRefine, true, \ + develop(bool, G1SmoothConcRefine, true, \ "Attempts to smooth out the overhead of concurrent refinement") \ \ develop(bool, G1ConcZeroFill, true, \ @@ -157,7 +135,7 @@ develop(bool, G1SATBPrintStubs, false, \ "If true, print generated stubs for the SATB barrier") \ \ - product(intx, G1ExpandByPctOfAvail, 20, \ + product(intx, G1ExpandByPercentOfAvailable, 20, \ "When expanding, % of uncommitted space to claim.") \ \ develop(bool, G1RSBarrierRegionFilter, true, \ @@ -179,18 +157,9 @@ "If true, verify that no dirty cards remain after RS log " \ "processing.") \ \ - product(intx, G1MinPausesBetweenMarks, 2, \ - "Number of inefficient pauses necessary to trigger marking.") \ - \ - product(intx, G1InefficientPausePct, 80, \ - "Threshold of an 'inefficient' pauses (as % of cum efficiency.") \ - \ develop(bool, G1RSCountHisto, false, \ "If true, print a histogram of RS occupancies after each pause") \ \ - product(bool, G1TraceFileOverwrite, false, \ - "Allow the trace file to be overwritten") \ - \ develop(intx, G1PrintRegionLivenessInfo, 0, \ "When > 0, print the occupancies of the best and worst" \ "regions.") \ @@ -198,9 +167,6 @@ develop(bool, G1PrintParCleanupStats, false, \ "When true, print extra stats about parallel cleanup.") \ \ - product(bool, G1DoAgeCohortChecks, false, \ - "When true, check well-formedness of age cohort structures.") \ - \ develop(bool, G1DisablePreBarrier, false, \ "Disable generation of pre-barrier (i.e., marking barrier) ") \ \ @@ -214,17 +180,17 @@ develop(intx, G1ConcRSLogCacheSize, 10, \ "Log base 2 of the length of conc RS hot-card cache.") \ \ - product(bool, G1ConcRSCountTraversals, false, \ + develop(bool, G1ConcRSCountTraversals, false, \ "If true, gather data about the number of times CR traverses " \ "cards ") \ \ - product(intx, G1ConcRSHotCardLimit, 4, \ + develop(intx, G1ConcRSHotCardLimit, 4, \ "The threshold that defines (>=) a hot card.") \ \ develop(bool, G1PrintOopAppls, false, \ "When true, print applications of closures to external locs.") \ \ - product(intx, G1LogRSRegionEntries, 7, \ + develop(intx, G1LogRSRegionEntries, 7, \ "Log_2 of max number of regions for which we keep bitmaps.") \ \ develop(bool, G1RecordHRRSOops, false, \ @@ -254,11 +220,11 @@ "It determines whether the system will calculate an optimum " \ "scan-only set.") \ \ - product(intx, G1MinReservePerc, 10, \ + product(intx, G1MinReservePercent, 10, \ "It determines the minimum reserve we should have in the heap " \ "to minimize the probability of promotion failure.") \ \ - product(bool, G1TraceRegions, false, \ + diagnostic(bool, G1PrintRegions, false, \ "If set G1 will print information on which regions are being " \ "allocated and which are reclaimed.") \ \ @@ -268,24 +234,24 @@ develop(bool, G1HRRSFlushLogBuffersOnVerify, false, \ "Forces flushing of log buffers before verification.") \ \ - product(bool, G1UseSurvivorSpace, true, \ + product(bool, G1UseSurvivorSpaces, true, \ "When true, use survivor space.") \ \ - product(bool, G1FixedTenuringThreshold, false, \ + develop(bool, G1FixedTenuringThreshold, false, \ "When set, G1 will not adjust the tenuring threshold") \ \ - product(bool, G1FixedEdenSize, false, \ + develop(bool, G1FixedEdenSize, false, \ "When set, G1 will not allocate unused survivor space regions") \ \ - product(uintx, G1FixedSurvivorSpaceSize, 0, \ + develop(uintx, G1FixedSurvivorSpaceSize, 0, \ "If non-0 is the size of the G1 survivor space, " \ "otherwise SurvivorRatio is used to determine the size") \ \ - experimental(bool, G1EnableParallelRSetUpdating, false, \ + experimental(bool, G1ParallelRSetUpdatingEnabled, false, \ "Enables the parallelization of remembered set updating " \ "during evacuation pauses") \ \ - experimental(bool, G1EnableParallelRSetScanning, false, \ + experimental(bool, G1ParallelRSetScanningEnabled, false, \ "Enables the parallelization of remembered set scanning " \ "during evacuation pauses") diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp index ee578bb2c4c..63ca8dc0b43 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp @@ -160,12 +160,6 @@ HeapWord* walk_mem_region_loop(ClosureType* cl, G1CollectedHeap* g1h, if (!g1h->is_obj_dead(cur_oop, hr)) { // Bottom lies entirely below top, so we can call the // non-memRegion version of oop_iterate below. -#ifndef PRODUCT - if (G1VerifyMarkingInEvac) { - VerifyLiveClosure vl_cl(g1h); - cur_oop->oop_iterate(&vl_cl); - } -#endif cur_oop->oop_iterate(cl); } cur = next_obj; @@ -197,12 +191,6 @@ void HeapRegionDCTOC::walk_mem_region_with_cl(MemRegion mr, // or it was allocated after marking finished, then we add it. Otherwise // we can safely ignore the object. if (!g1h->is_obj_dead(oop(bottom), _hr)) { -#ifndef PRODUCT - if (G1VerifyMarkingInEvac) { - VerifyLiveClosure vl_cl(g1h); - oop(bottom)->oop_iterate(&vl_cl, mr); - } -#endif oop_size = oop(bottom)->oop_iterate(cl2, mr); } else { oop_size = oop(bottom)->size(); @@ -232,12 +220,6 @@ void HeapRegionDCTOC::walk_mem_region_with_cl(MemRegion mr, // Last object. Need to do dead-obj filtering here too. if (!g1h->is_obj_dead(oop(bottom), _hr)) { -#ifndef PRODUCT - if (G1VerifyMarkingInEvac) { - VerifyLiveClosure vl_cl(g1h); - oop(bottom)->oop_iterate(&vl_cl, mr); - } -#endif oop(bottom)->oop_iterate(cl2, mr); } } @@ -713,12 +695,12 @@ void HeapRegion::verify(bool allow_dirty) const { G1CollectedHeap::heap()->print(); gclog_or_tty->print_cr(""); } - if (G1VerifyConcMark && + if (VerifyDuringGC && G1VerifyConcMarkPrintReachable && vl_cl.failures()) { g1->concurrent_mark()->print_prev_bitmap_reachable(); } - guarantee(!vl_cl.failures(), "should not have had any failures"); + guarantee(!vl_cl.failures(), "region verification failed"); guarantee(p == top(), "end of last object must match end of space"); } diff --git a/hotspot/src/share/vm/opto/connode.cpp b/hotspot/src/share/vm/opto/connode.cpp index 46f13c652b6..9e82a8e4441 100644 --- a/hotspot/src/share/vm/opto/connode.cpp +++ b/hotspot/src/share/vm/opto/connode.cpp @@ -128,6 +128,10 @@ Node *CMoveNode::is_cmove_id( PhaseTransform *phase, Node *cmp, Node *t, Node *f // Swapped Cmp is OK (phase->eqv(cmp->in(2),f) && phase->eqv(cmp->in(1),t)) ) { + // Give up this identity check for floating points because it may choose incorrect + // value around 0.0 and -0.0 + if ( cmp->Opcode()==Op_CmpF || cmp->Opcode()==Op_CmpD ) + return NULL; // Check for "(t==f)?t:f;" and replace with "f" if( b->_test._test == BoolTest::eq ) return f; diff --git a/hotspot/src/share/vm/opto/divnode.cpp b/hotspot/src/share/vm/opto/divnode.cpp index 55350e11f66..a81e3b1942f 100644 --- a/hotspot/src/share/vm/opto/divnode.cpp +++ b/hotspot/src/share/vm/opto/divnode.cpp @@ -298,8 +298,10 @@ static Node* long_by_long_mulhi(PhaseGVN* phase, Node* dividend, jlong magic_con // 6732154: Construct both w1 and w2 before transforming, so t // doesn't go dead prematurely. - w1 = phase->transform(w1); + // 6837011: We need to transform w2 before w1 because the + // transformation of w1 could return t. w2 = phase->transform(w2); + w1 = phase->transform(w1); // w1 = u0*v1 + w1; Node* u0v1 = phase->transform(new (phase->C, 3) MulLNode(u0, v1)); diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index a6021b17226..d86e7a9f16b 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -1288,10 +1288,14 @@ void Arguments::set_g1_gc_flags() { Abstract_VM_Version::parallel_worker_threads()); if (ParallelGCThreads == 0) { FLAG_SET_DEFAULT(ParallelGCThreads, - Abstract_VM_Version::parallel_worker_threads -()); + Abstract_VM_Version::parallel_worker_threads()); } no_shared_spaces(); + + // Set the maximum pause time goal to be a reasonable default. + if (FLAG_IS_DEFAULT(MaxGCPauseMillis)) { + FLAG_SET_DEFAULT(MaxGCPauseMillis, 200); + } } void Arguments::set_server_heap_size() { diff --git a/hotspot/src/share/vm/runtime/dtraceJSDT.cpp b/hotspot/src/share/vm/runtime/dtraceJSDT.cpp index 406c4e6c0be..2de788a2ffd 100644 --- a/hotspot/src/share/vm/runtime/dtraceJSDT.cpp +++ b/hotspot/src/share/vm/runtime/dtraceJSDT.cpp @@ -60,6 +60,11 @@ jlong DTraceJSDT::activate( methodHandle h_method = methodHandle(THREAD, JNIHandles::resolve_jmethod_id(probe->method)); nmethod* nm = AdapterHandlerLibrary::create_dtrace_nmethod(h_method); + if (nm == NULL) { + delete probes; + THROW_MSG_0(vmSymbols::java_lang_RuntimeException(), + "Unable to register DTrace probes (CodeCache: no room for DTrace nmethods)."); + } h_method()->set_not_compilable(CompLevel_highest_tier); h_method()->set_code(h_method, nm); probes->nmethod_at_put(count++, nm); diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 544a43fffbf..47997e17b44 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -1819,7 +1819,11 @@ class CommandLineFlags { "Decay factor to TenuredGenerationSizeIncrement") \ \ product(uintx, MaxGCPauseMillis, max_uintx, \ - "Adaptive size policy maximum GC pause time goal in msec") \ + "Adaptive size policy maximum GC pause time goal in msec, " \ + "or (G1 Only) the max. GC time per MMU time slice") \ + \ + product(intx, GCPauseIntervalMillis, 500, \ + "Time slice for MMU specification") \ \ product(uintx, MaxGCMinorPauseMillis, max_uintx, \ "Adaptive size policy maximum GC minor pause time goal in msec") \ diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.cpp b/hotspot/src/share/vm/runtime/sharedRuntime.cpp index c8b5047821e..4709b6bd748 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp @@ -1776,7 +1776,14 @@ const char* AdapterHandlerEntry::name = "I2C/C2I adapters"; GrowableArray* AdapterHandlerLibrary::_fingerprints = NULL; GrowableArray* AdapterHandlerLibrary::_handlers = NULL; const int AdapterHandlerLibrary_size = 16*K; -u_char AdapterHandlerLibrary::_buffer[AdapterHandlerLibrary_size + 32]; +BufferBlob* AdapterHandlerLibrary::_buffer = NULL; + +BufferBlob* AdapterHandlerLibrary::buffer_blob() { + // Should be called only when AdapterHandlerLibrary_lock is active. + if (_buffer == NULL) // Initialize lazily + _buffer = BufferBlob::create("adapters", AdapterHandlerLibrary_size); + return _buffer; +} void AdapterHandlerLibrary::initialize() { if (_fingerprints != NULL) return; @@ -1812,7 +1819,9 @@ int AdapterHandlerLibrary::get_create_adapter_index(methodHandle method) { assert(ic_miss != NULL, "must have handler"); int result; + NOT_PRODUCT(int code_size); BufferBlob *B = NULL; + AdapterHandlerEntry* entry = NULL; uint64_t fingerprint; { MutexLocker mu(AdapterHandlerLibrary_lock); @@ -1850,42 +1859,45 @@ int AdapterHandlerLibrary::get_create_adapter_index(methodHandle method) { // Create I2C & C2I handlers ResourceMark rm; - // Improve alignment slightly - u_char *buf = (u_char*)(((intptr_t)_buffer + CodeEntryAlignment-1) & ~(CodeEntryAlignment-1)); - CodeBuffer buffer(buf, AdapterHandlerLibrary_size); - short buffer_locs[20]; - buffer.insts()->initialize_shared_locs((relocInfo*)buffer_locs, - sizeof(buffer_locs)/sizeof(relocInfo)); - MacroAssembler _masm(&buffer); - // Fill in the signature array, for the calling-convention call. - int total_args_passed = method->size_of_parameters(); // All args on stack + BufferBlob* buf = buffer_blob(); // the temporary code buffer in CodeCache + if (buf != NULL) { + CodeBuffer buffer(buf->instructions_begin(), buf->instructions_size()); + short buffer_locs[20]; + buffer.insts()->initialize_shared_locs((relocInfo*)buffer_locs, + sizeof(buffer_locs)/sizeof(relocInfo)); + MacroAssembler _masm(&buffer); - BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType,total_args_passed); - VMRegPair * regs = NEW_RESOURCE_ARRAY(VMRegPair ,total_args_passed); - int i=0; - if( !method->is_static() ) // Pass in receiver first - sig_bt[i++] = T_OBJECT; - for( SignatureStream ss(method->signature()); !ss.at_return_type(); ss.next()) { - sig_bt[i++] = ss.type(); // Collect remaining bits of signature - if( ss.type() == T_LONG || ss.type() == T_DOUBLE ) - sig_bt[i++] = T_VOID; // Longs & doubles take 2 Java slots + // Fill in the signature array, for the calling-convention call. + int total_args_passed = method->size_of_parameters(); // All args on stack + + BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType,total_args_passed); + VMRegPair * regs = NEW_RESOURCE_ARRAY(VMRegPair ,total_args_passed); + int i=0; + if( !method->is_static() ) // Pass in receiver first + sig_bt[i++] = T_OBJECT; + for( SignatureStream ss(method->signature()); !ss.at_return_type(); ss.next()) { + sig_bt[i++] = ss.type(); // Collect remaining bits of signature + if( ss.type() == T_LONG || ss.type() == T_DOUBLE ) + sig_bt[i++] = T_VOID; // Longs & doubles take 2 Java slots + } + assert( i==total_args_passed, "" ); + + // Now get the re-packed compiled-Java layout. + int comp_args_on_stack; + + // Get a description of the compiled java calling convention and the largest used (VMReg) stack slot usage + comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed, false); + + entry = SharedRuntime::generate_i2c2i_adapters(&_masm, + total_args_passed, + comp_args_on_stack, + sig_bt, + regs); + + B = BufferBlob::create(AdapterHandlerEntry::name, &buffer); + NOT_PRODUCT(code_size = buffer.code_size()); } - assert( i==total_args_passed, "" ); - - // Now get the re-packed compiled-Java layout. - int comp_args_on_stack; - - // Get a description of the compiled java calling convention and the largest used (VMReg) stack slot usage - comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed, false); - - AdapterHandlerEntry* entry = SharedRuntime::generate_i2c2i_adapters(&_masm, - total_args_passed, - comp_args_on_stack, - sig_bt, - regs); - - B = BufferBlob::create(AdapterHandlerEntry::name, &buffer); if (B == NULL) { // CodeCache is full, disable compilation // Ought to log this but compile log is only per compile thread @@ -1912,9 +1924,9 @@ int AdapterHandlerLibrary::get_create_adapter_index(methodHandle method) { tty->cr(); tty->print_cr("i2c argument handler #%d for: %s %s (fingerprint = 0x%llx, %d bytes generated)", _handlers->length(), (method->is_static() ? "static" : "receiver"), - method->signature()->as_C_string(), fingerprint, buffer.code_size() ); + method->signature()->as_C_string(), fingerprint, code_size ); tty->print_cr("c2i argument handler starts at %p",entry->get_c2i_entry()); - Disassembler::decode(entry->get_i2c_entry(), entry->get_i2c_entry() + buffer.code_size()); + Disassembler::decode(entry->get_i2c_entry(), entry->get_i2c_entry() + code_size); } #endif @@ -1982,42 +1994,44 @@ nmethod *AdapterHandlerLibrary::create_native_wrapper(methodHandle method) { return nm; } - // Improve alignment slightly - u_char* buf = (u_char*)(((intptr_t)_buffer + CodeEntryAlignment-1) & ~(CodeEntryAlignment-1)); - CodeBuffer buffer(buf, AdapterHandlerLibrary_size); - // Need a few relocation entries - double locs_buf[20]; - buffer.insts()->initialize_shared_locs((relocInfo*)locs_buf, sizeof(locs_buf) / sizeof(relocInfo)); - MacroAssembler _masm(&buffer); + ResourceMark rm; - // Fill in the signature array, for the calling-convention call. - int total_args_passed = method->size_of_parameters(); + BufferBlob* buf = buffer_blob(); // the temporary code buffer in CodeCache + if (buf != NULL) { + CodeBuffer buffer(buf->instructions_begin(), buf->instructions_size()); + double locs_buf[20]; + buffer.insts()->initialize_shared_locs((relocInfo*)locs_buf, sizeof(locs_buf) / sizeof(relocInfo)); + MacroAssembler _masm(&buffer); - BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType,total_args_passed); - VMRegPair * regs = NEW_RESOURCE_ARRAY(VMRegPair ,total_args_passed); - int i=0; - if( !method->is_static() ) // Pass in receiver first - sig_bt[i++] = T_OBJECT; - SignatureStream ss(method->signature()); - for( ; !ss.at_return_type(); ss.next()) { - sig_bt[i++] = ss.type(); // Collect remaining bits of signature - if( ss.type() == T_LONG || ss.type() == T_DOUBLE ) - sig_bt[i++] = T_VOID; // Longs & doubles take 2 Java slots + // Fill in the signature array, for the calling-convention call. + int total_args_passed = method->size_of_parameters(); + + BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType,total_args_passed); + VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair,total_args_passed); + int i=0; + if( !method->is_static() ) // Pass in receiver first + sig_bt[i++] = T_OBJECT; + SignatureStream ss(method->signature()); + for( ; !ss.at_return_type(); ss.next()) { + sig_bt[i++] = ss.type(); // Collect remaining bits of signature + if( ss.type() == T_LONG || ss.type() == T_DOUBLE ) + sig_bt[i++] = T_VOID; // Longs & doubles take 2 Java slots + } + assert( i==total_args_passed, "" ); + BasicType ret_type = ss.type(); + + // Now get the compiled-Java layout as input arguments + int comp_args_on_stack; + comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed, false); + + // Generate the compiled-to-native wrapper code + nm = SharedRuntime::generate_native_wrapper(&_masm, + method, + total_args_passed, + comp_args_on_stack, + sig_bt,regs, + ret_type); } - assert( i==total_args_passed, "" ); - BasicType ret_type = ss.type(); - - // Now get the compiled-Java layout as input arguments - int comp_args_on_stack; - comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed, false); - - // Generate the compiled-to-native wrapper code - nm = SharedRuntime::generate_native_wrapper(&_masm, - method, - total_args_passed, - comp_args_on_stack, - sig_bt,regs, - ret_type); } // Must unlock before calling set_code @@ -2077,18 +2091,20 @@ nmethod *AdapterHandlerLibrary::create_dtrace_nmethod(methodHandle method) { return nm; } - // Improve alignment slightly - u_char* buf = (u_char*) - (((intptr_t)_buffer + CodeEntryAlignment-1) & ~(CodeEntryAlignment-1)); - CodeBuffer buffer(buf, AdapterHandlerLibrary_size); - // Need a few relocation entries - double locs_buf[20]; - buffer.insts()->initialize_shared_locs( - (relocInfo*)locs_buf, sizeof(locs_buf) / sizeof(relocInfo)); - MacroAssembler _masm(&buffer); + ResourceMark rm; - // Generate the compiled-to-native wrapper code - nm = SharedRuntime::generate_dtrace_nmethod(&_masm, method); + BufferBlob* buf = buffer_blob(); // the temporary code buffer in CodeCache + if (buf != NULL) { + CodeBuffer buffer(buf->instructions_begin(), buf->instructions_size()); + // Need a few relocation entries + double locs_buf[20]; + buffer.insts()->initialize_shared_locs( + (relocInfo*)locs_buf, sizeof(locs_buf) / sizeof(relocInfo)); + MacroAssembler _masm(&buffer); + + // Generate the compiled-to-native wrapper code + nm = SharedRuntime::generate_dtrace_nmethod(&_masm, method); + } } return nm; } diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.hpp b/hotspot/src/share/vm/runtime/sharedRuntime.hpp index 11fb6a75934..2d44165f7cd 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp @@ -557,12 +557,13 @@ class AdapterHandlerEntry : public CHeapObj { class AdapterHandlerLibrary: public AllStatic { private: - static u_char _buffer[]; // the temporary code buffer + static BufferBlob* _buffer; // the temporary code buffer in CodeCache static GrowableArray* _fingerprints; // the fingerprint collection static GrowableArray * _handlers; // the corresponding handlers enum { AbstractMethodHandler = 1 // special handler for abstract methods }; + static BufferBlob* buffer_blob(); static void initialize(); static int get_create_adapter_index(methodHandle method); static address get_i2c_entry( int index ) { diff --git a/hotspot/test/compiler/6837011/Test6837011.java b/hotspot/test/compiler/6837011/Test6837011.java new file mode 100644 index 00000000000..696e992d32c --- /dev/null +++ b/hotspot/test/compiler/6837011/Test6837011.java @@ -0,0 +1,45 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +/** + * @test + * @bug 6837011 + * @summary SIGSEGV in PhaseIdealLoop in 32bit jvm + * + * @run main/othervm -Xcomp -XX:CompileOnly=Test6837011.main Test6837011 + */ + +public class Test6837011 { + static boolean var_3 = true; + + public static void main(String[] args) { + double var_5; + char var_7 = 1; + double var_11 = 0; + + do { + var_11++; + var_5 = (var_7 /= ( var_3 ? ~1L : 3 ) ); + } while (var_11 < 1); + } +} diff --git a/jaxp/.hgtags b/jaxp/.hgtags index 40071c67c68..51d36fea7fd 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -31,3 +31,5 @@ e8837366d3fd72f7c7a47ebfdbd5106c16156f12 jdk7-b53 946a9f0c493261fa6a010dc33e61b9b535ba80c1 jdk7-b54 039945fba683ee6773a721e2bd4e449f6133769a jdk7-b55 c197c6801271c60f9c9f5d18fcc95b59e76dcd54 jdk7-b56 +e4851e9f7be26fc52a628be06ffa8aaea0919bd7 jdk7-b57 +13bf67d8c6341b841d268985cabaf747f2652bc8 jdk7-b58 diff --git a/jaxp/src/share/classes/com/sun/org/apache/xalan/internal/client/XSLTProcessorApplet.java b/jaxp/src/share/classes/com/sun/org/apache/xalan/internal/client/XSLTProcessorApplet.java deleted file mode 100644 index 519604c3355..00000000000 --- a/jaxp/src/share/classes/com/sun/org/apache/xalan/internal/client/XSLTProcessorApplet.java +++ /dev/null @@ -1,792 +0,0 @@ -/* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -/* - * Copyright 1999-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * $Id: XSLTProcessorApplet.java,v 1.2.4.1 2005/09/15 02:20:05 jeffsuttor Exp $ - */ -package com.sun.org.apache.xalan.internal.client; - -import java.applet.Applet; -import java.awt.Graphics; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringReader; -import java.io.StringWriter; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Hashtable; -import java.util.Enumeration; - -import javax.xml.transform.Templates; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; - -import com.sun.org.apache.xalan.internal.res.XSLMessages; -import com.sun.org.apache.xalan.internal.res.XSLTErrorResources; - -/** - * Provides applet host for the XSLT processor. To perform transformations on an HTML client: - *
    - *
  1. Use an <applet> tag to embed this applet in the HTML client.
  2. - *
  3. Use the DocumentURL and StyleURL PARAM tags or the {@link #setDocumentURL} and - * {@link #setStyleURL} methods to specify the XML source document and XSL stylesheet.
  4. - *
  5. Call the {@link #getHtmlText} method (or one of the transformToHtml() methods) - * to perform the transformation and return the result as a String.
  6. - *
- * - * This class extends Applet which ultimately causes this class to implement Serializable. - * This is a serious restriction on this class. All fields that are not transient and not - * static are written-out/read-in during serialization. So even private fields essentially - * become part of the API. Developers need to take care when modifying fields. - * @xsl.usage general - */ -public class XSLTProcessorApplet extends Applet -{ - - /** - * The stylesheet processor. - * This field is now transient because a - * javax.xml.transform.TransformerFactory from JAXP - * makes no claims to be serializable. - */ - transient TransformerFactory m_tfactory = null; - - /** - * @serial - */ - private String m_styleURL; - - /** - * @serial - */ - private String m_documentURL; - - // Parameter names. To change a name of a parameter, you need only make - // a single change. Simply modify the value of the parameter string below. - //-------------------------------------------------------------------------- - - /** - * @serial - */ - private final String PARAM_styleURL = "styleURL"; - - /** - * @serial - */ - private final String PARAM_documentURL = "documentURL"; - - - // We'll keep the DOM trees around, so tell which trees - // are cached. - - /** - * @serial - */ - private String m_styleURLOfCached = null; - - /** - * @serial - */ - private String m_documentURLOfCached = null; - - /** - * Save this for use on the worker thread; may not be necessary. - * @serial - */ - private URL m_codeBase = null; - - /** - * @serial - */ - private String m_treeURL = null; - - /** - * DocumentBase URL - * @serial - */ - private URL m_documentBase = null; - - /** - * Thread stuff for the trusted worker thread. - */ - transient private Thread m_callThread = null; - - /** - */ - transient private TrustedAgent m_trustedAgent = null; - - /** - * Thread for running TrustedAgent. - */ - transient private Thread m_trustedWorker = null; - - /** - * Where the worker thread puts the HTML text. - */ - transient private String m_htmlText = null; - - /** - * Where the worker thread puts the document/stylesheet text. - */ - transient private String m_sourceText = null; - - /** - * Stylesheet attribute name and value that the caller can set. - */ - transient private String m_nameOfIDAttrOfElemToModify = null; - - /** - */ - transient private String m_elemIdToModify = null; - - /** - */ - transient private String m_attrNameToSet = null; - - /** - */ - transient private String m_attrValueToSet = null; - - /** - * The XSLTProcessorApplet constructor takes no arguments. - */ - public XSLTProcessorApplet(){} - - /** - * Get basic information about the applet - * @return A String with the applet name and author. - */ - public String getAppletInfo() - { - return "Name: XSLTProcessorApplet\r\n" + "Author: Scott Boag"; - } - - /** - * Get descriptions of the applet parameters. - * @return A two-dimensional array of Strings with Name, Type, and Description - * for each parameter. - */ - public String[][] getParameterInfo() - { - - String[][] info = - { - { PARAM_styleURL, "String", "URL to an XSL stylesheet" }, - { PARAM_documentURL, "String", "URL to an XML document" }, - }; - - return info; - } - - /** - * Standard applet initialization. - */ - public void init() - { - - // PARAMETER SUPPORT - // The following code retrieves the value of each parameter - // specified with the tag and stores it in a member - // variable. - //---------------------------------------------------------------------- - String param; - - // styleURL: Parameter description - //---------------------------------------------------------------------- - param = getParameter(PARAM_styleURL); - - // stylesheet parameters - m_parameters = new Hashtable(); - - if (param != null) - setStyleURL(param); - - // documentURL: Parameter description - //---------------------------------------------------------------------- - param = getParameter(PARAM_documentURL); - - if (param != null) - setDocumentURL(param); - - m_codeBase = this.getCodeBase(); - m_documentBase = this.getDocumentBase(); - - // If you use a ResourceWizard-generated "control creator" class to - // arrange controls in your applet, you may want to call its - // CreateControls() method from within this method. Remove the following - // call to resize() before adding the call to CreateControls(); - // CreateControls() does its own resizing. - //---------------------------------------------------------------------- - resize(320, 240); - } - - /** - * Automatically called when the HTML client containing the applet loads. - * This method starts execution of the applet thread. - */ - public void start() - { - //check if user code's on the stack before invoking the worker thread - boolean passed = false; - try { - java.security.AccessController.checkPermission(new java.security.AllPermission()); - } catch (SecurityException se) { - //expected - passed = true; - } - if (!passed) { - throw new SecurityException("The XSLTProcessorApplet class must be extended and its method start() overridden."); - } - - m_trustedAgent = new TrustedAgent(); - Thread currentThread = Thread.currentThread(); - m_trustedWorker = new Thread(currentThread.getThreadGroup(), - m_trustedAgent); - m_trustedWorker.start(); - try - { - m_tfactory = TransformerFactory.newInstance(); - this.showStatus("Causing Transformer and Parser to Load and JIT..."); - - // Prime the pump so that subsequent transforms are faster. - StringReader xmlbuf = new StringReader(""); - StringReader xslbuf = new StringReader( - ""); - PrintWriter pw = new PrintWriter(new StringWriter()); - - synchronized (m_tfactory) - { - Templates templates = m_tfactory.newTemplates(new StreamSource(xslbuf)); - Transformer transformer = templates.newTransformer(); - transformer.transform(new StreamSource(xmlbuf), new StreamResult(pw)); - } - System.out.println("Primed the pump!"); - this.showStatus("Ready to go!"); - } - catch (Exception e) - { - this.showStatus("Could not prime the pump!"); - System.out.println("Could not prime the pump!"); - e.printStackTrace(); - } - } - - /** - * Do not call; this applet contains no UI or visual components. - * - */ - public void paint(Graphics g){} - - /** - * Automatically called when the HTML page containing the applet is no longer - * on the screen. Stops execution of the applet thread. - */ - public void stop() - { - if (null != m_trustedWorker) - { - m_trustedWorker.stop(); - - // m_trustedWorker.destroy(); - m_trustedWorker = null; - } - - m_styleURLOfCached = null; - m_documentURLOfCached = null; - } - - /** - * Cleanup; called when applet is terminated and unloaded. - */ - public void destroy() - { - if (null != m_trustedWorker) - { - m_trustedWorker.stop(); - - // m_trustedWorker.destroy(); - m_trustedWorker = null; - } - m_styleURLOfCached = null; - m_documentURLOfCached = null; - } - - /** - * Set the URL to the XSL stylesheet that will be used - * to transform the input XML. No processing is done yet. - * @param urlString valid URL string for XSL stylesheet. - */ - public void setStyleURL(String urlString) - { - m_styleURL = urlString; - } - - /** - * Set the URL to the XML document that will be transformed - * with the XSL stylesheet. No processing is done yet. - * @param urlString valid URL string for XML document. - */ - public void setDocumentURL(String urlString) - { - m_documentURL = urlString; - } - - /** - * The processor keeps a cache of the source and - * style trees, so call this method if they have changed - * or you want to do garbage collection. - */ - public void freeCache() - { - m_styleURLOfCached = null; - m_documentURLOfCached = null; - } - - /** - * Set an attribute in the stylesheet, which gives the ability - * to have some dynamic selection control. - * @param nameOfIDAttrOfElemToModify The name of an attribute to search for a unique id. - * @param elemId The unique ID to look for. - * @param attrName Once the element is found, the name of the attribute to set. - * @param value The value to set the attribute to. - */ - public void setStyleSheetAttribute(String nameOfIDAttrOfElemToModify, - String elemId, String attrName, - String value) - { - m_nameOfIDAttrOfElemToModify = nameOfIDAttrOfElemToModify; - m_elemIdToModify = elemId; - m_attrNameToSet = attrName; - m_attrValueToSet = value; - } - - - /** - * Stylesheet parameter key/value pair stored in a hashtable - */ - transient Hashtable m_parameters; - - /** - * Submit a stylesheet parameter. - * - * @param key stylesheet parameter key - * @param expr the parameter expression to be submitted. - * @see javax.xml.transform.Transformer#setParameter(String,Object) - */ - public void setStylesheetParam(String key, String expr) - { - m_parameters.put(key, expr); - } - - /** - * Given a String containing markup, escape the markup so it - * can be displayed in the browser. - * - * @param s String to escape - * - * The escaped string. - */ - public String escapeString(String s) - { - StringBuffer sb = new StringBuffer(); - int length = s.length(); - - for (int i = 0; i < length; i++) - { - char ch = s.charAt(i); - - if ('<' == ch) - { - sb.append("<"); - } - else if ('>' == ch) - { - sb.append(">"); - } - else if ('&' == ch) - { - sb.append("&"); - } - else if (0xd800 <= ch && ch < 0xdc00) - { - // UTF-16 surrogate - int next; - - if (i + 1 >= length) - { - throw new RuntimeException( - XSLMessages.createMessage( - XSLTErrorResources.ER_INVALID_UTF16_SURROGATE, - new Object[]{ Integer.toHexString(ch) })); //"Invalid UTF-16 surrogate detected: " - - //+Integer.toHexString(ch)+ " ?"); - } - else - { - next = s.charAt(++i); - - if (!(0xdc00 <= next && next < 0xe000)) - throw new RuntimeException( - XSLMessages.createMessage( - XSLTErrorResources.ER_INVALID_UTF16_SURROGATE, - new Object[]{ - Integer.toHexString(ch) + " " - + Integer.toHexString(next) })); //"Invalid UTF-16 surrogate detected: " - - //+Integer.toHexString(ch)+" "+Integer.toHexString(next)); - next = ((ch - 0xd800) << 10) + next - 0xdc00 + 0x00010000; - } - sb.append("&#x"); - sb.append(Integer.toHexString(next)); - sb.append(";"); - } - else - { - sb.append(ch); - } - } - return sb.toString(); - } - - /** - * Assuming the stylesheet URL and the input XML URL have been set, - * perform the transformation and return the result as a String. - * - * @return A string that contains the contents pointed to by the URL. - * - */ - public String getHtmlText() - { - m_trustedAgent.m_getData = true; - m_callThread = Thread.currentThread(); - try - { - synchronized (m_callThread) - { - m_callThread.wait(); - } - } - catch (InterruptedException ie) - { - System.out.println(ie.getMessage()); - } - return m_htmlText; - } - - /** - * Get an XML document (or stylesheet) - * - * @param treeURL valid URL string for the document. - * - * @return document - * - * @throws IOException - */ - public String getTreeAsText(String treeURL) throws IOException - { - m_treeURL = treeURL; - m_trustedAgent.m_getData = true; - m_trustedAgent.m_getSource = true; - m_callThread = Thread.currentThread(); - try - { - synchronized (m_callThread) - { - m_callThread.wait(); - } - } - catch (InterruptedException ie) - { - System.out.println(ie.getMessage()); - } - return m_sourceText; - } - - /** - * Use a Transformer to copy the source document - * to a StreamResult. - * - * @return the document as a string - */ - private String getSource() throws TransformerException - { - StringWriter osw = new StringWriter(); - PrintWriter pw = new PrintWriter(osw, false); - String text = ""; - try - { - URL docURL = new URL(m_documentBase, m_treeURL); - synchronized (m_tfactory) - { - Transformer transformer = m_tfactory.newTransformer(); - StreamSource source = new StreamSource(docURL.toString()); - StreamResult result = new StreamResult(pw); - transformer.transform(source, result); - text = osw.toString(); - } - } - catch (MalformedURLException e) - { - e.printStackTrace(); - throw new RuntimeException(e.getMessage()); - } - catch (Exception any_error) - { - any_error.printStackTrace(); - } - return text; - } - - /** - * Get the XML source Tree as a text string suitable - * for display in a browser. Note that this is for display of the - * XML itself, not for rendering of HTML by the browser. - * - * @return XML source document as a string. - * @throws Exception thrown if tree can not be converted. - */ - public String getSourceTreeAsText() throws Exception - { - return getTreeAsText(m_documentURL); - } - - /** - * Get the XSL style Tree as a text string suitable - * for display in a browser. Note that this is for display of the - * XML itself, not for rendering of HTML by the browser. - * - * @return The XSL stylesheet as a string. - * @throws Exception thrown if tree can not be converted. - */ - public String getStyleTreeAsText() throws Exception - { - return getTreeAsText(m_styleURL); - } - - /** - * Get the HTML result Tree as a text string suitable - * for display in a browser. Note that this is for display of the - * XML itself, not for rendering of HTML by the browser. - * - * @return Transformation result as unmarked text. - * @throws Exception thrown if tree can not be converted. - */ - public String getResultTreeAsText() throws Exception - { - return escapeString(getHtmlText()); - } - - /** - * Process a document and a stylesheet and return - * the transformation result. If one of these is null, the - * existing value (of a previous transformation) is not affected. - * - * @param doc URL string to XML document - * @param style URL string to XSL stylesheet - * - * @return HTML transformation result - */ - public String transformToHtml(String doc, String style) - { - - if (null != doc) - { - m_documentURL = doc; - } - - if (null != style) - { - m_styleURL = style; - } - - return getHtmlText(); - } - - /** - * Process a document and a stylesheet and return - * the transformation result. Use the xsl:stylesheet PI to find the - * document, if one exists. - * - * @param doc URL string to XML document containing an xsl:stylesheet PI. - * - * @return HTML transformation result - */ - public String transformToHtml(String doc) - { - - if (null != doc) - { - m_documentURL = doc; - } - - m_styleURL = null; - - return getHtmlText(); - } - - - /** - * Process the transformation. - * - * @return The transformation result as a string. - * - * @throws TransformerException - */ - private String processTransformation() throws TransformerException - { - String htmlData = null; - this.showStatus("Waiting for Transformer and Parser to finish loading and JITing..."); - - synchronized (m_tfactory) - { - URL documentURL = null; - URL styleURL = null; - StringWriter osw = new StringWriter(); - PrintWriter pw = new PrintWriter(osw, false); - StreamResult result = new StreamResult(pw); - - this.showStatus("Begin Transformation..."); - try - { - documentURL = new URL(m_codeBase, m_documentURL); - StreamSource xmlSource = new StreamSource(documentURL.toString()); - - styleURL = new URL(m_codeBase, m_styleURL); - StreamSource xslSource = new StreamSource(styleURL.toString()); - - Transformer transformer = m_tfactory.newTransformer(xslSource); - - - Enumeration m_keys = m_parameters.keys(); - while (m_keys.hasMoreElements()){ - Object key = m_keys.nextElement(); - Object expression = m_parameters.get(key); - transformer.setParameter((String) key, expression); - } - transformer.transform(xmlSource, result); - } - catch (TransformerConfigurationException tfe) - { - tfe.printStackTrace(); - throw new RuntimeException(tfe.getMessage()); - } - catch (MalformedURLException e) - { - e.printStackTrace(); - throw new RuntimeException(e.getMessage()); - } - - this.showStatus("Transformation Done!"); - htmlData = osw.toString(); - } - return htmlData; - } - - /** - * This class maintains a worker thread that that is - * trusted and can do things like access data. You need - * this because the thread that is called by the browser - * is not trusted and can't access data from the URLs. - */ - class TrustedAgent implements Runnable - { - - /** - * Specifies whether the worker thread should perform a transformation. - */ - public boolean m_getData = false; - - /** - * Specifies whether the worker thread should get an XML document or XSL stylesheet. - */ - public boolean m_getSource = false; - - /** - * The real work is done from here. - * - */ - public void run() - { - while (true) - { - m_trustedWorker.yield(); - - if (m_getData) // Perform a transformation or get a document. - { - try - { - m_getData = false; - m_htmlText = null; - m_sourceText = null; - if (m_getSource) // Get a document. - { - m_getSource = false; - m_sourceText = getSource(); - } - else // Perform a transformation. - m_htmlText = processTransformation(); - } - catch (Exception e) - { - e.printStackTrace(); - } - finally - { - synchronized (m_callThread) - { - m_callThread.notify(); - } - } - } - else - { - try - { - m_trustedWorker.sleep(50); - } - catch (InterruptedException ie) - { - ie.printStackTrace(); - } - } - } - } - } - - // For compatiblity with old serialized objects - // We will change non-serialized fields and change methods - // and not have this break us. - private static final long serialVersionUID=4618876841979251422L; - - // For compatibility when de-serializing old objects - private void readObject(java.io.ObjectInputStream inStream) throws IOException, ClassNotFoundException - { - inStream.defaultReadObject(); - - // Needed assignment of non-serialized fields - - // A TransformerFactory is not guaranteed to be serializable, - // so we create one here - m_tfactory = TransformerFactory.newInstance(); - } -} diff --git a/jaxp/src/share/classes/com/sun/org/apache/xalan/internal/client/package.html b/jaxp/src/share/classes/com/sun/org/apache/xalan/internal/client/package.html deleted file mode 100644 index cc48cd87a4d..00000000000 --- a/jaxp/src/share/classes/com/sun/org/apache/xalan/internal/client/package.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - Xalan Client Package. - -

Implementation of Xalan applet.

- - - - diff --git a/jaxws/.hgtags b/jaxws/.hgtags index 5e8f9c64349..f2a50939601 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -31,3 +31,5 @@ b250218eb2e534384667ec73e3713e684667fd4c jdk7-b53 50ea00dc5f143fe00025233e704903c37f8464aa jdk7-b54 e0eebd978b830c09e7862cff3f77a914c15651c9 jdk7-b55 0f7fbf85f7a1d9c027a863b9955c623352ed1292 jdk7-b56 +68257a5eb19afc11aee7eb19f7250f9b9eec7c05 jdk7-b57 +5fb4fbea81c3609916da00417fdd15dbd9e39e97 jdk7-b58 diff --git a/jaxws/src/share/classes/com/sun/codemodel/internal/JClassContainer.java b/jaxws/src/share/classes/com/sun/codemodel/internal/JClassContainer.java index 6f0e76a02d6..a4be9ba327c 100644 --- a/jaxws/src/share/classes/com/sun/codemodel/internal/JClassContainer.java +++ b/jaxws/src/share/classes/com/sun/codemodel/internal/JClassContainer.java @@ -145,6 +145,7 @@ public interface JClassContainer { * newly created Annotation Type Declaration * @exception JClassAlreadyExistsException * When the specified class/interface was already created. + */ public JDefinedClass _annotationTypeDeclaration(String name) throws JClassAlreadyExistsException; @@ -156,6 +157,7 @@ public interface JClassContainer { * newly created Enum * @exception JClassAlreadyExistsException * When the specified class/interface was already created. + */ public JDefinedClass _enum (String name) throws JClassAlreadyExistsException; diff --git a/jaxws/src/share/classes/com/sun/codemodel/internal/JDefinedClass.java b/jaxws/src/share/classes/com/sun/codemodel/internal/JDefinedClass.java index ff22fae97fc..81e1cf8d491 100644 --- a/jaxws/src/share/classes/com/sun/codemodel/internal/JDefinedClass.java +++ b/jaxws/src/share/classes/com/sun/codemodel/internal/JDefinedClass.java @@ -428,6 +428,7 @@ public class JDefinedClass * newly created Annotation Type Declaration * @exception JClassAlreadyExistsException * When the specified class/interface was already created. + */ public JDefinedClass _annotationTypeDeclaration(String name) throws JClassAlreadyExistsException { return _class (JMod.PUBLIC,name,ClassType.ANNOTATION_TYPE_DECL); diff --git a/jaxws/src/share/classes/com/sun/codemodel/internal/JForEach.java b/jaxws/src/share/classes/com/sun/codemodel/internal/JForEach.java index fd7c1bd1657..80176f36846 100644 --- a/jaxws/src/share/classes/com/sun/codemodel/internal/JForEach.java +++ b/jaxws/src/share/classes/com/sun/codemodel/internal/JForEach.java @@ -33,17 +33,17 @@ package com.sun.codemodel.internal; */ public final class JForEach implements JStatement { - private final JType type; - private final String var; - private JBlock body = null; // lazily created - private final JExpression collection; + private final JType type; + private final String var; + private JBlock body = null; // lazily created + private final JExpression collection; private final JVar loopVar; - public JForEach(JType vartype, String variable, JExpression collection) { + public JForEach(JType vartype, String variable, JExpression collection) { - this.type = vartype; - this.var = variable; - this.collection = collection; + this.type = vartype; + this.var = variable; + this.collection = collection; loopVar = new JVar(JMods.forVar(JMod.NONE), type, var, collection); } @@ -51,24 +51,24 @@ public final class JForEach implements JStatement { /** * Returns a reference to the loop variable. */ - public JVar var() { - return loopVar; - } + public JVar var() { + return loopVar; + } - public JBlock body() { - if (body == null) - body = new JBlock(); - return body; - } + public JBlock body() { + if (body == null) + body = new JBlock(); + return body; + } - public void state(JFormatter f) { - f.p("for ("); - f.g(type).id(var).p(": ").g(collection); - f.p(')'); - if (body != null) - f.g(body).nl(); - else - f.p(';').nl(); - } + public void state(JFormatter f) { + f.p("for ("); + f.g(type).id(var).p(": ").g(collection); + f.p(')'); + if (body != null) + f.g(body).nl(); + else + f.p(';').nl(); + } } diff --git a/jaxws/src/share/classes/com/sun/codemodel/internal/JMethod.java b/jaxws/src/share/classes/com/sun/codemodel/internal/JMethod.java index b3d9f6223ca..3141ebc61f1 100644 --- a/jaxws/src/share/classes/com/sun/codemodel/internal/JMethod.java +++ b/jaxws/src/share/classes/com/sun/codemodel/internal/JMethod.java @@ -38,49 +38,49 @@ import com.sun.codemodel.internal.util.ClassNameComparator; */ public class JMethod extends JGenerifiableImpl implements JDeclaration, JAnnotatable { - /** - * Modifiers for this method - */ - private JMods mods; + /** + * Modifiers for this method + */ + private JMods mods; - /** - * Return type for this method - */ - private JType type = null; + /** + * Return type for this method + */ + private JType type = null; - /** - * Name of this method - */ - private String name = null; + /** + * Name of this method + */ + private String name = null; - /** - * List of parameters for this method's declaration - */ - private final List params = new ArrayList(); + /** + * List of parameters for this method's declaration + */ + private final List params = new ArrayList(); - /** - * Set of exceptions that this method may throw. + /** + * Set of exceptions that this method may throw. * A set instance lazily created. - */ - private Set _throws; + */ + private Set _throws; - /** - * JBlock of statements that makes up the body this method - */ - private JBlock body = null; + /** + * JBlock of statements that makes up the body this method + */ + private JBlock body = null; - private JDefinedClass outer; + private JDefinedClass outer; - /** - * javadoc comments for this JMethod - */ - private JDocComment jdoc = null; + /** + * javadoc comments for this JMethod + */ + private JDocComment jdoc = null; - /** - * Variable parameter for this method's varargs declaration - * introduced in J2SE 1.5 - */ - private JVar varParam = null; + /** + * Variable parameter for this method's varargs declaration + * introduced in J2SE 1.5 + */ + private JVar varParam = null; /** * Annotations on this variable. Lazily created. @@ -88,9 +88,9 @@ public class JMethod extends JGenerifiableImpl implements JDeclaration, JAnnotat private List annotations = null; - private boolean isConstructor() { - return type == null; - } + private boolean isConstructor() { + return type == null; + } /** To set the default value for the * annotation member @@ -98,40 +98,40 @@ public class JMethod extends JGenerifiableImpl implements JDeclaration, JAnnotat private JExpression defaultValue = null; - /** - * JMethod constructor - * - * @param mods - * Modifiers for this method's declaration - * - * @param type - * Return type for the method - * - * @param name - * Name of this method - */ - JMethod(JDefinedClass outer, int mods, JType type, String name) { - this.mods = JMods.forMethod(mods); - this.type = type; - this.name = name; - this.outer = outer; - } + /** + * JMethod constructor + * + * @param mods + * Modifiers for this method's declaration + * + * @param type + * Return type for the method + * + * @param name + * Name of this method + */ + JMethod(JDefinedClass outer, int mods, JType type, String name) { + this.mods = JMods.forMethod(mods); + this.type = type; + this.name = name; + this.outer = outer; + } - /** - * Constructor constructor - * - * @param mods - * Modifiers for this constructor's declaration - * - * @param _class - * JClass containing this constructor - */ - JMethod(int mods, JDefinedClass _class) { - this.mods = JMods.forMethod(mods); - this.type = null; - this.name = _class.name(); - this.outer = _class; - } + /** + * Constructor constructor + * + * @param mods + * Modifiers for this constructor's declaration + * + * @param _class + * JClass containing this constructor + */ + JMethod(int mods, JDefinedClass _class) { + this.mods = JMods.forMethod(mods); + this.type = null; + this.name = _class.name(); + this.outer = _class; + } private Set getThrows() { if(_throws==null) @@ -139,56 +139,56 @@ public class JMethod extends JGenerifiableImpl implements JDeclaration, JAnnotat return _throws; } - /** - * Add an exception to the list of exceptions that this - * method may throw. - * - * @param exception - * Name of an exception that this method may throw - */ - public JMethod _throws(JClass exception) { + /** + * Add an exception to the list of exceptions that this + * method may throw. + * + * @param exception + * Name of an exception that this method may throw + */ + public JMethod _throws(JClass exception) { getThrows().add(exception); - return this; - } + return this; + } - public JMethod _throws(Class exception) { - return _throws(outer.owner().ref(exception)); - } + public JMethod _throws(Class exception) { + return _throws(outer.owner().ref(exception)); + } - /** - * Add the specified variable to the list of parameters - * for this method signature. - * - * @param type - * JType of the parameter being added - * - * @param name - * Name of the parameter being added - * - * @return New parameter variable - */ - public JVar param(int mods, JType type, String name) { - JVar v = new JVar(JMods.forVar(mods), type, name, null); - params.add(v); - return v; - } + /** + * Add the specified variable to the list of parameters + * for this method signature. + * + * @param type + * JType of the parameter being added + * + * @param name + * Name of the parameter being added + * + * @return New parameter variable + */ + public JVar param(int mods, JType type, String name) { + JVar v = new JVar(JMods.forVar(mods), type, name, null); + params.add(v); + return v; + } - public JVar param(JType type, String name) { - return param(JMod.NONE, type, name); - } + public JVar param(JType type, String name) { + return param(JMod.NONE, type, name); + } - public JVar param(int mods, Class type, String name) { - return param(mods, outer.owner()._ref(type), name); - } + public JVar param(int mods, Class type, String name) { + return param(mods, outer.owner()._ref(type), name); + } - public JVar param(Class type, String name) { - return param(outer.owner()._ref(type), name); - } + public JVar param(Class type, String name) { + return param(outer.owner()._ref(type), name); + } - /** - * @see #varParam(JType, String) - */ - public JVar varParam(Class type, String name) { + /** + * @see #varParam(JType, String) + */ + public JVar varParam(Class type, String name) { return varParam(outer.owner()._ref(type),name); } @@ -210,25 +210,25 @@ public class JMethod extends JGenerifiableImpl implements JDeclaration, JAnnotat * method signature. */ public JVar varParam(JType type, String name) { - if (!hasVarArgs()) { + if (!hasVarArgs()) { varParam = - new JVar( - JMods.forVar(JMod.NONE), - type.array(), - name, - null); - return varParam; - } else { - throw new IllegalStateException( - "Cannot have two varargs in a method,\n" - + "Check if varParam method of JMethod is" - + " invoked more than once"); + new JVar( + JMods.forVar(JMod.NONE), + type.array(), + name, + null); + return varParam; + } else { + throw new IllegalStateException( + "Cannot have two varargs in a method,\n" + + "Check if varParam method of JMethod is" + + " invoked more than once"); + + } } - } - /** * Adds an annotation to this variable. * @param clazz @@ -256,17 +256,17 @@ public class JMethod extends JGenerifiableImpl implements JDeclaration, JAnnotat return TypedAnnotationWriter.create(clazz,this); } - /** - * Check if there are any varargs declared - * for this method signature. - */ - public boolean hasVarArgs() { - return this.varParam!=null; - } + /** + * Check if there are any varargs declared + * for this method signature. + */ + public boolean hasVarArgs() { + return this.varParam!=null; + } - public String name() { - return name; - } + public String name() { + return name; + } /** * Changes the name of the method. @@ -276,11 +276,11 @@ public class JMethod extends JGenerifiableImpl implements JDeclaration, JAnnotat } /** - * Returns the return type. - */ - public JType type() { - return type; - } + * Returns the return type. + */ + public JType type() { + return type; + } /** * Overrides the return type. @@ -290,72 +290,72 @@ public class JMethod extends JGenerifiableImpl implements JDeclaration, JAnnotat } /** - * Returns all the parameter types in an array. - * @return - * If there's no parameter, an empty array will be returned. - */ - public JType[] listParamTypes() { - JType[] r = new JType[params.size()]; - for (int i = 0; i < r.length; i++) - r[i] = params.get(i).type(); - return r; - } + * Returns all the parameter types in an array. + * @return + * If there's no parameter, an empty array will be returned. + */ + public JType[] listParamTypes() { + JType[] r = new JType[params.size()]; + for (int i = 0; i < r.length; i++) + r[i] = params.get(i).type(); + return r; + } - /** - * Returns the varags parameter type. - * @return - * If there's no vararg parameter type, null will be returned. - */ - public JType listVarParamType() { - if (varParam != null) - return varParam.type(); - else - return null; - } + /** + * Returns the varags parameter type. + * @return + * If there's no vararg parameter type, null will be returned. + */ + public JType listVarParamType() { + if (varParam != null) + return varParam.type(); + else + return null; + } - /** - * Returns all the parameters in an array. - * @return - * If there's no parameter, an empty array will be returned. - */ - public JVar[] listParams() { - return params.toArray(new JVar[params.size()]); - } + /** + * Returns all the parameters in an array. + * @return + * If there's no parameter, an empty array will be returned. + */ + public JVar[] listParams() { + return params.toArray(new JVar[params.size()]); + } - /** - * Returns the variable parameter - * @return - * If there's no parameter, null will be returned. - */ - public JVar listVarParam() { - return varParam; - } + /** + * Returns the variable parameter + * @return + * If there's no parameter, null will be returned. + */ + public JVar listVarParam() { + return varParam; + } - /** - * Returns true if the method has the specified signature. - */ - public boolean hasSignature(JType[] argTypes) { - JVar[] p = listParams(); - if (p.length != argTypes.length) - return false; + /** + * Returns true if the method has the specified signature. + */ + public boolean hasSignature(JType[] argTypes) { + JVar[] p = listParams(); + if (p.length != argTypes.length) + return false; - for (int i = 0; i < p.length; i++) - if (!p[i].type().equals(argTypes[i])) - return false; + for (int i = 0; i < p.length; i++) + if (!p[i].type().equals(argTypes[i])) + return false; - return true; - } + return true; + } - /** - * Get the block that makes up body of this method - * - * @return Body of method - */ - public JBlock body() { - if (body == null) - body = new JBlock(); - return body; - } + /** + * Get the block that makes up body of this method + * + * @return Body of method + */ + public JBlock body() { + if (body == null) + body = new JBlock(); + return body; + } /** * Specify the default value for this annotation member @@ -367,37 +367,37 @@ public class JMethod extends JGenerifiableImpl implements JDeclaration, JAnnotat this.defaultValue = value; } - /** - * Creates, if necessary, and returns the class javadoc for this - * JDefinedClass - * - * @return JDocComment containing javadocs for this class - */ - public JDocComment javadoc() { - if (jdoc == null) - jdoc = new JDocComment(owner()); - return jdoc; - } + /** + * Creates, if necessary, and returns the class javadoc for this + * JDefinedClass + * + * @return JDocComment containing javadocs for this class + */ + public JDocComment javadoc() { + if (jdoc == null) + jdoc = new JDocComment(owner()); + return jdoc; + } - public void declare(JFormatter f) { - if (jdoc != null) - f.g(jdoc); + public void declare(JFormatter f) { + if (jdoc != null) + f.g(jdoc); if (annotations != null){ for (JAnnotationUse a : annotations) f.g(a).nl(); } - // declare the generics parameters - super.declare(f); + // declare the generics parameters + super.declare(f); - f.g(mods); - if (!isConstructor()) - f.g(type); - f.id(name).p('(').i(); + f.g(mods); + if (!isConstructor()) + f.g(type); + f.id(name).p('(').i(); // when parameters are printed in new lines, we want them to be indented. // there's a good chance no newlines happen, too, but just in case it does. - boolean first = true; + boolean first = true; for (JVar var : params) { if (!first) f.p(','); @@ -406,33 +406,33 @@ public class JMethod extends JGenerifiableImpl implements JDeclaration, JAnnotat f.b(var); first = false; } - if (hasVarArgs()) { - if (!first) - f.p(','); - f.g(varParam.type().elementType()); - f.p("... "); - f.id(varParam.name()); - } + if (hasVarArgs()) { + if (!first) + f.p(','); + f.g(varParam.type().elementType()); + f.p("... "); + f.id(varParam.name()); + } - f.o().p(')'); - if (_throws!=null && !_throws.isEmpty()) { - f.nl().i().p("throws").g(_throws).nl().o(); - } + f.o().p(')'); + if (_throws!=null && !_throws.isEmpty()) { + f.nl().i().p("throws").g(_throws).nl().o(); + } if (defaultValue != null) { f.p("default "); f.g(defaultValue); } - if (body != null) { - f.s(body); - } else if ( - !outer.isInterface() && !outer.isAnnotationTypeDeclaration() && !mods.isAbstract() && !mods.isNative()) { - // Print an empty body for non-native, non-abstract methods - f.s(new JBlock()); - } else { - f.p(';').nl(); + if (body != null) { + f.s(body); + } else if ( + !outer.isInterface() && !outer.isAnnotationTypeDeclaration() && !mods.isAbstract() && !mods.isNative()) { + // Print an empty body for non-native, non-abstract methods + f.s(new JBlock()); + } else { + f.p(';').nl(); + } } - } /** * @return @@ -447,10 +447,10 @@ public class JMethod extends JGenerifiableImpl implements JDeclaration, JAnnotat * @deprecated use {@link #mods()} */ public JMods getMods() { - return mods; - } + return mods; + } - protected JCodeModel owner() { - return outer.owner(); - } + protected JCodeModel owner() { + return outer.owner(); + } } diff --git a/jaxws/src/share/classes/com/sun/codemodel/internal/JMods.java b/jaxws/src/share/classes/com/sun/codemodel/internal/JMods.java index 60aad8fef62..f4596b18455 100644 --- a/jaxws/src/share/classes/com/sun/codemodel/internal/JMods.java +++ b/jaxws/src/share/classes/com/sun/codemodel/internal/JMods.java @@ -41,17 +41,17 @@ public class JMods implements JGenerable { = JMod.FINAL; private static int FIELD - = (JMod.PUBLIC | JMod.PRIVATE | JMod.PROTECTED - | JMod.STATIC | JMod.FINAL - | JMod.TRANSIENT | JMod.VOLATILE); + = (JMod.PUBLIC | JMod.PRIVATE | JMod.PROTECTED + | JMod.STATIC | JMod.FINAL + | JMod.TRANSIENT | JMod.VOLATILE); private static int METHOD - = (JMod.PUBLIC | JMod.PRIVATE | JMod.PROTECTED | JMod.FINAL - | JMod.ABSTRACT | JMod.STATIC | JMod.NATIVE | JMod.SYNCHRONIZED); + = (JMod.PUBLIC | JMod.PRIVATE | JMod.PROTECTED | JMod.FINAL + | JMod.ABSTRACT | JMod.STATIC | JMod.NATIVE | JMod.SYNCHRONIZED); private static int CLASS - = (JMod.PUBLIC | JMod.PRIVATE | JMod.PROTECTED - | JMod.STATIC | JMod.FINAL | JMod.ABSTRACT ); + = (JMod.PUBLIC | JMod.PRIVATE | JMod.PROTECTED + | JMod.STATIC | JMod.FINAL | JMod.ABSTRACT ); private static int INTERFACE = JMod.PUBLIC; diff --git a/jaxws/src/share/classes/com/sun/codemodel/internal/util/SingleByteEncoder.java b/jaxws/src/share/classes/com/sun/codemodel/internal/util/SingleByteEncoder.java index 3e025a7a5ed..71d4dfd82aa 100644 --- a/jaxws/src/share/classes/com/sun/codemodel/internal/util/SingleByteEncoder.java +++ b/jaxws/src/share/classes/com/sun/codemodel/internal/util/SingleByteEncoder.java @@ -24,7 +24,7 @@ */ /* - * @(#)SingleByteEncoder.java 1.14 03/01/23 + * @(#)SingleByteEncoder.java 1.14 03/01/23 */ package com.sun.codemodel.internal.util; @@ -51,109 +51,109 @@ abstract class SingleByteEncoder private final Surrogate.Parser sgp = new Surrogate.Parser(); protected SingleByteEncoder(Charset cs, - short[] index1, String index2, - int mask1, int mask2, int shift) + short[] index1, String index2, + int mask1, int mask2, int shift) { - super(cs, 1.0f, 1.0f); - this.index1 = index1; - this.index2 = index2; - this.mask1 = mask1; - this.mask2 = mask2; - this.shift = shift; + super(cs, 1.0f, 1.0f); + this.index1 = index1; + this.index2 = index2; + this.mask1 = mask1; + this.mask2 = mask2; + this.shift = shift; } public boolean canEncode(char c) { - char testEncode; - testEncode = index2.charAt(index1[(c & mask1) >> shift] - + (c & mask2)); - if (testEncode == '\u0000') - return false; - else - return true; + char testEncode; + testEncode = index2.charAt(index1[(c & mask1) >> shift] + + (c & mask2)); + if (testEncode == '\u0000') + return false; + else + return true; } private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) { - char[] sa = src.array(); - int sp = src.arrayOffset() + src.position(); - int sl = src.arrayOffset() + src.limit(); - sp = (sp <= sl ? sp : sl); - byte[] da = dst.array(); - int dp = dst.arrayOffset() + dst.position(); - int dl = dst.arrayOffset() + dst.limit(); - dp = (dp <= dl ? dp : dl); + char[] sa = src.array(); + int sp = src.arrayOffset() + src.position(); + int sl = src.arrayOffset() + src.limit(); + sp = (sp <= sl ? sp : sl); + byte[] da = dst.array(); + int dp = dst.arrayOffset() + dst.position(); + int dl = dst.arrayOffset() + dst.limit(); + dp = (dp <= dl ? dp : dl); - try { - while (sp < sl) { - char c = sa[sp]; - if (Surrogate.is(c)) { - if (sgp.parse(c, sa, sp, sl) < 0) - return sgp.error(); - return sgp.unmappableResult(); - } - if (c >= '\uFFFE') - return CoderResult.unmappableForLength(1); - if (dl - dp < 1) - return CoderResult.OVERFLOW; + try { + while (sp < sl) { + char c = sa[sp]; + if (Surrogate.is(c)) { + if (sgp.parse(c, sa, sp, sl) < 0) + return sgp.error(); + return sgp.unmappableResult(); + } + if (c >= '\uFFFE') + return CoderResult.unmappableForLength(1); + if (dl - dp < 1) + return CoderResult.OVERFLOW; - char e = index2.charAt(index1[(c & mask1) >> shift] - + (c & mask2)); + char e = index2.charAt(index1[(c & mask1) >> shift] + + (c & mask2)); - // If output byte is zero because input char is zero - // then character is mappable, o.w. fail - if (e == '\u0000' && c != '\u0000') - return CoderResult.unmappableForLength(1); + // If output byte is zero because input char is zero + // then character is mappable, o.w. fail + if (e == '\u0000' && c != '\u0000') + return CoderResult.unmappableForLength(1); - sp++; - da[dp++] = (byte)e; - } - return CoderResult.UNDERFLOW; - } finally { - src.position(sp - src.arrayOffset()); - dst.position(dp - dst.arrayOffset()); - } + sp++; + da[dp++] = (byte)e; + } + return CoderResult.UNDERFLOW; + } finally { + src.position(sp - src.arrayOffset()); + dst.position(dp - dst.arrayOffset()); + } } private CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) { - int mark = src.position(); - try { - while (src.hasRemaining()) { - char c = src.get(); - if (Surrogate.is(c)) { - if (sgp.parse(c, src) < 0) - return sgp.error(); - return sgp.unmappableResult(); - } - if (c >= '\uFFFE') - return CoderResult.unmappableForLength(1); - if (!dst.hasRemaining()) - return CoderResult.OVERFLOW; + int mark = src.position(); + try { + while (src.hasRemaining()) { + char c = src.get(); + if (Surrogate.is(c)) { + if (sgp.parse(c, src) < 0) + return sgp.error(); + return sgp.unmappableResult(); + } + if (c >= '\uFFFE') + return CoderResult.unmappableForLength(1); + if (!dst.hasRemaining()) + return CoderResult.OVERFLOW; - char e = index2.charAt(index1[(c & mask1) >> shift] - + (c & mask2)); + char e = index2.charAt(index1[(c & mask1) >> shift] + + (c & mask2)); - // If output byte is zero because input char is zero - // then character is mappable, o.w. fail - if (e == '\u0000' && c != '\u0000') - return CoderResult.unmappableForLength(1); + // If output byte is zero because input char is zero + // then character is mappable, o.w. fail + if (e == '\u0000' && c != '\u0000') + return CoderResult.unmappableForLength(1); - mark++; - dst.put((byte)e); - } - return CoderResult.UNDERFLOW; - } finally { - src.position(mark); - } + mark++; + dst.put((byte)e); + } + return CoderResult.UNDERFLOW; + } finally { + src.position(mark); + } } protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) { - if (true && src.hasArray() && dst.hasArray()) - return encodeArrayLoop(src, dst); - else - return encodeBufferLoop(src, dst); + if (true && src.hasArray() && dst.hasArray()) + return encodeArrayLoop(src, dst); + else + return encodeBufferLoop(src, dst); } public byte encode(char inputChar) { - return (byte)index2.charAt(index1[(inputChar & mask1) >> shift] + - (inputChar & mask2)); + return (byte)index2.charAt(index1[(inputChar & mask1) >> shift] + + (inputChar & mask2)); } } diff --git a/jaxws/src/share/classes/com/sun/codemodel/internal/util/Surrogate.java b/jaxws/src/share/classes/com/sun/codemodel/internal/util/Surrogate.java index 9cf6b2108f1..ca97bc1d6fa 100644 --- a/jaxws/src/share/classes/com/sun/codemodel/internal/util/Surrogate.java +++ b/jaxws/src/share/classes/com/sun/codemodel/internal/util/Surrogate.java @@ -112,7 +112,7 @@ class Surrogate { public Parser() { } - private int character; // UCS-4 + private int character; // UCS-4 private CoderResult error = CoderResult.UNDERFLOW; private boolean isPair; diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/client/p2p/HttpSOAPConnection.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/client/p2p/HttpSOAPConnection.java index 643f2d561f0..6f365dc27de 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/client/p2p/HttpSOAPConnection.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/client/p2p/HttpSOAPConnection.java @@ -55,12 +55,19 @@ import com.sun.xml.internal.messaging.saaj.util.*; */ public class HttpSOAPConnection extends SOAPConnection { - protected static Logger log = + public static final String vmVendor = System.getProperty("java.vendor.url"); + private static final String sunVmVendor = "http://java.sun.com/"; + private static final String ibmVmVendor = "http://www.ibm.com/"; + private static final boolean isSunVM = sunVmVendor.equals(vmVendor) ? true: false; + private static final boolean isIBMVM = ibmVmVendor.equals(vmVendor) ? true : false; + private static final String JAXM_URLENDPOINT="javax.xml.messaging.URLEndpoint"; + + protected static final Logger log = Logger.getLogger(LogDomainConstants.HTTP_CONN_DOMAIN, "com.sun.xml.internal.messaging.saaj.client.p2p.LocalStrings"); - public static String defaultProxyHost = null; - public static int defaultProxyPort = -1; + public static final String defaultProxyHost = null; + public static final int defaultProxyPort = -1; MessageFactory messageFactory = null; @@ -72,6 +79,9 @@ public class HttpSOAPConnection extends SOAPConnection { try { messageFactory = MessageFactory.newInstance(SOAPConstants.DYNAMIC_SOAP_PROTOCOL); + } catch (NoSuchMethodError ex) { + //fallback to default SOAP 1.1 in this case for backward compatibility + messageFactory = MessageFactory.newInstance(); } catch (Exception ex) { log.log(Level.SEVERE, "SAAJ0001.p2p.cannot.create.msg.factory", ex); throw new SOAPExceptionImpl("Unable to create message factory", ex); @@ -96,13 +106,18 @@ public class HttpSOAPConnection extends SOAPConnection { } Class urlEndpointClass = null; + ClassLoader loader = Thread.currentThread().getContextClassLoader(); try { - urlEndpointClass = Class.forName("javax.xml.messaging.URLEndpoint"); - } catch (Exception ex) { - //Do nothing. URLEndpoint is available only when JAXM is there. - log.finest("SAAJ0090.p2p.endpoint.available.only.for.JAXM"); - } + if (loader != null) { + urlEndpointClass = loader.loadClass(JAXM_URLENDPOINT); + } else { + urlEndpointClass = Class.forName(JAXM_URLENDPOINT); + } + } catch (ClassNotFoundException ex) { + //Do nothing. URLEndpoint is available only when JAXM is there. + log.finest("SAAJ0090.p2p.endpoint.available.only.for.JAXM"); + } if (urlEndpointClass != null) { if (urlEndpointClass.isInstance(endPoint)) { @@ -639,10 +654,23 @@ public class HttpSOAPConnection extends SOAPConnection { return ret; } + //private static String SSL_PKG = "com.sun.net.ssl.internal.www.protocol"; + //private static String SSL_PROVIDER = + // "com.sun.net.ssl.internal.ssl.Provider"; + private static final String SSL_PKG; + private static final String SSL_PROVIDER; - private static String SSL_PKG = "com.sun.net.ssl.internal.www.protocol"; - private static String SSL_PROVIDER = - "com.sun.net.ssl.internal.ssl.Provider"; + + static { + if (isIBMVM) { + SSL_PKG ="com.ibm.net.ssl.internal.www.protocol"; + SSL_PROVIDER ="com.ibm.net.ssl.internal.ssl.Provider"; + } else { + //if not IBM VM default to Sun. + SSL_PKG = "com.sun.net.ssl.internal.www.protocol"; + SSL_PROVIDER ="com.sun.net.ssl.internal.ssl.Provider"; + } + } private void initHttps() { //if(!setHttps) { String pkgs = System.getProperty("java.protocol.handler.pkgs"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/AttachmentPartImpl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/AttachmentPartImpl.java index 9ded9888f7d..31f472e26df 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/AttachmentPartImpl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/AttachmentPartImpl.java @@ -70,7 +70,7 @@ import javax.xml.soap.*; */ public class AttachmentPartImpl extends AttachmentPart { - protected static Logger log = + protected static final Logger log = Logger.getLogger(LogDomainConstants.SOAP_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/EnvelopeFactory.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/EnvelopeFactory.java index 81adca3ce9d..00ca9c0a9b4 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/EnvelopeFactory.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/EnvelopeFactory.java @@ -23,9 +23,9 @@ * have any questions. */ /* - * $Id: EnvelopeFactory.java,v 1.24 2006/01/27 12:49:26 vj135062 Exp $ - * $Revision: 1.24 $ - * $Date: 2006/01/27 12:49:26 $ + * + * + * */ @@ -55,7 +55,7 @@ import com.sun.xml.internal.messaging.saaj.util.transform.EfficientStreamingTran */ public class EnvelopeFactory { - protected static Logger + protected static final Logger log = Logger.getLogger(LogDomainConstants.SOAP_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ImageDataContentHandler.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ImageDataContentHandler.java index a8eed2e4f81..85968511df0 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ImageDataContentHandler.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ImageDataContentHandler.java @@ -49,7 +49,7 @@ import com.sun.xml.internal.messaging.saaj.util.LogDomainConstants; public class ImageDataContentHandler extends Component implements DataContentHandler { - protected static Logger log = + protected static final Logger log = Logger.getLogger(LogDomainConstants.SOAP_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/MessageFactoryImpl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/MessageFactoryImpl.java index 97cff5ad6aa..945139fc69a 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/MessageFactoryImpl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/MessageFactoryImpl.java @@ -23,9 +23,9 @@ * have any questions. */ /* - * $Id: MessageFactoryImpl.java,v 1.23 2006/01/27 12:49:27 vj135062 Exp $ - * $Revision: 1.23 $ - * $Date: 2006/01/27 12:49:27 $ + * + * + * */ @@ -54,15 +54,15 @@ import com.sun.xml.internal.messaging.saaj.util.TeeInputStream; */ public class MessageFactoryImpl extends MessageFactory { - protected static Logger log = + protected static final Logger log = Logger.getLogger(LogDomainConstants.SOAP_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.LocalStrings"); - protected static OutputStream listener; + protected OutputStream listener; protected boolean lazyAttachments = false; - public static OutputStream listen(OutputStream newListener) { + public OutputStream listen(OutputStream newListener) { OutputStream oldListener = listener; listener = newListener; return oldListener; diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/MessageImpl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/MessageImpl.java index 02be27a92f1..51b47bbe1fd 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/MessageImpl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/MessageImpl.java @@ -23,9 +23,9 @@ * have any questions. */ /* - * $Id: MessageImpl.java,v 1.5 2006/12/12 10:16:33 kumarjayanti Exp $ - * $Revision: 1.5 $ - * $Date: 2006/12/12 10:16:33 $ + * + * + * */ @@ -69,7 +69,7 @@ public abstract class MessageImpl public static final String CONTENT_ID = "Content-ID"; public static final String CONTENT_LOCATION = "Content-Location"; - protected static Logger log = + protected static final Logger log = Logger.getLogger(LogDomainConstants.SOAP_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/SAAJMetaFactoryImpl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/SAAJMetaFactoryImpl.java index f06b596c4a1..990f19fa150 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/SAAJMetaFactoryImpl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/SAAJMetaFactoryImpl.java @@ -37,7 +37,7 @@ import com.sun.xml.internal.messaging.saaj.util.LogDomainConstants; public class SAAJMetaFactoryImpl extends SAAJMetaFactory { - protected static Logger log = + protected static final Logger log = Logger.getLogger(LogDomainConstants.SOAP_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/SOAPDocumentImpl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/SOAPDocumentImpl.java index a2e7ae761c7..260d1c84276 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/SOAPDocumentImpl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/SOAPDocumentImpl.java @@ -23,7 +23,7 @@ * have any questions. */ /* - * $Id: SOAPDocumentImpl.java,v 1.15 2006/01/27 12:49:29 vj135062 Exp $ + * */ @@ -45,7 +45,7 @@ import com.sun.xml.internal.messaging.saaj.util.LogDomainConstants; public class SOAPDocumentImpl extends DocumentImpl implements SOAPDocument { - protected static Logger log = + protected static final Logger log = Logger.getLogger(LogDomainConstants.SOAP_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/SOAPFactoryImpl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/SOAPFactoryImpl.java index 2c1f71314cb..3bbc6cb9103 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/SOAPFactoryImpl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/SOAPFactoryImpl.java @@ -23,9 +23,9 @@ * have any questions. */ /* - * $Id: SOAPFactoryImpl.java,v 1.21 2006/01/27 12:49:29 vj135062 Exp $ - * $Revision: 1.21 $ - * $Date: 2006/01/27 12:49:29 $ + * + * + * */ @@ -50,7 +50,7 @@ import org.w3c.dom.Attr; public abstract class SOAPFactoryImpl extends SOAPFactory { - protected static Logger + protected static final Logger log = Logger.getLogger(LogDomainConstants.SOAP_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/SOAPPartImpl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/SOAPPartImpl.java index 1125bdc3d83..a0b1039306b 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/SOAPPartImpl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/SOAPPartImpl.java @@ -23,9 +23,9 @@ * have any questions. */ /* - * $Id: SOAPPartImpl.java,v 1.1.1.1 2006/01/27 13:10:55 kumarjayanti Exp $ - * $Revision: 1.1.1.1 $ - * $Date: 2006/01/27 13:10:55 $ + * + * + * */ @@ -59,7 +59,7 @@ import javax.xml.transform.sax.SAXSource; * @author Anil Vijendran (anil@sun.com) */ public abstract class SOAPPartImpl extends SOAPPart implements SOAPDocument { - protected static Logger log = + protected static final Logger log = Logger.getLogger(LogDomainConstants.SOAP_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/impl/CDATAImpl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/impl/CDATAImpl.java index 64110619d38..c44cd4b5444 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/impl/CDATAImpl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/impl/CDATAImpl.java @@ -23,9 +23,9 @@ * have any questions. */ /* - * $Id: CDATAImpl.java,v 1.19 2006/01/27 12:49:34 vj135062 Exp $ - * $Revision: 1.19 $ - * $Date: 2006/01/27 12:49:34 $ + * + * + * */ @@ -43,7 +43,7 @@ public class CDATAImpl extends com.sun.org.apache.xerces.internal.dom.CDATASectionImpl implements javax.xml.soap.Text { - protected static Logger log = + protected static final Logger log = Logger.getLogger(LogDomainConstants.SOAP_IMPL_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.impl.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/impl/CommentImpl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/impl/CommentImpl.java index 6931d53a370..32266d3e349 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/impl/CommentImpl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/impl/CommentImpl.java @@ -23,9 +23,9 @@ * have any questions. */ /* - * $Id: CommentImpl.java,v 1.17 2006/01/27 12:49:34 vj135062 Exp $ - * $Revision: 1.17 $ - * $Date: 2006/01/27 12:49:34 $ + * + * + * */ @@ -47,7 +47,7 @@ public class CommentImpl extends com.sun.org.apache.xerces.internal.dom.CommentImpl implements javax.xml.soap.Text, org.w3c.dom.Comment { - protected static Logger log = + protected static final Logger log = Logger.getLogger(LogDomainConstants.SOAP_IMPL_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.impl.LocalStrings"); protected static ResourceBundle rb = diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/impl/ElementImpl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/impl/ElementImpl.java index 2afcf90b997..80c98922f27 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/impl/ElementImpl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/impl/ElementImpl.java @@ -23,9 +23,9 @@ * have any questions. */ /* - * $Id: ElementImpl.java,v 1.6 2006/11/16 16:01:14 kumarjayanti Exp $ - * $Revision: 1.6 $ - * $Date: 2006/11/16 16:01:14 $ + * + * + * */ @@ -60,7 +60,7 @@ public class ElementImpl protected QName elementQName; - protected static Logger log = + protected static final Logger log = Logger.getLogger(LogDomainConstants.SOAP_IMPL_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.impl.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/impl/TextImpl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/impl/TextImpl.java index 9b6dc60b996..064b6c6e181 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/impl/TextImpl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/impl/TextImpl.java @@ -23,9 +23,9 @@ * have any questions. */ /* - * $Id: TextImpl.java,v 1.19 2006/01/27 12:49:36 vj135062 Exp $ - * $Revision: 1.19 $ - * $Date: 2006/01/27 12:49:36 $ + * + * + * */ @@ -43,7 +43,7 @@ public class TextImpl extends com.sun.org.apache.xerces.internal.dom.TextImpl implements javax.xml.soap.Text, org.w3c.dom.Text { - protected static Logger log = + protected static final Logger log = Logger.getLogger(LogDomainConstants.SOAP_IMPL_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.impl.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/name/NameImpl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/name/NameImpl.java index 2b682ca7e63..43c2602b99a 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/name/NameImpl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/name/NameImpl.java @@ -23,9 +23,9 @@ * have any questions. */ /* - * $Id: NameImpl.java,v 1.48 2006/01/27 12:49:38 vj135062 Exp $ - * $Revision: 1.48 $ - * $Date: 2006/01/27 12:49:38 $ + * + * + * */ @@ -63,7 +63,7 @@ public class NameImpl implements Name { protected String prefix = ""; private String qualifiedName = null; - protected static Logger log = + protected static final Logger log = Logger.getLogger(LogDomainConstants.NAMING_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.name.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/Fault1_1Impl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/Fault1_1Impl.java index 0eb5fe3a159..5f34dc31507 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/Fault1_1Impl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/Fault1_1Impl.java @@ -23,7 +23,7 @@ * have any questions. */ /* - * $Id: Fault1_1Impl.java,v 1.1.1.1 2006/01/27 13:10:57 kumarjayanti Exp $ + * */ @@ -57,7 +57,7 @@ import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl; public class Fault1_1Impl extends FaultImpl { - protected static Logger log = + protected static final Logger log = Logger.getLogger( LogDomainConstants.SOAP_VER1_1_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.ver1_1.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/Header1_1Impl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/Header1_1Impl.java index 99eedfa9afa..7ef3e0cd349 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/Header1_1Impl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/Header1_1Impl.java @@ -23,7 +23,7 @@ * have any questions. */ /* - * $Id: Header1_1Impl.java,v 1.29 2006/01/27 12:49:41 vj135062 Exp $ + * */ @@ -50,7 +50,7 @@ import com.sun.xml.internal.messaging.saaj.util.LogDomainConstants; public class Header1_1Impl extends HeaderImpl { - protected static Logger log = + protected static final Logger log = Logger.getLogger(LogDomainConstants.SOAP_VER1_1_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.ver1_1.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/HeaderElement1_1Impl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/HeaderElement1_1Impl.java index fbc54bd771a..0a875a9c3f9 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/HeaderElement1_1Impl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/HeaderElement1_1Impl.java @@ -23,7 +23,7 @@ * have any questions. */ /* - * $Id: HeaderElement1_1Impl.java,v 1.29 2006/01/27 12:49:41 vj135062 Exp $ + * */ @@ -49,7 +49,7 @@ import com.sun.xml.internal.messaging.saaj.util.LogDomainConstants; public class HeaderElement1_1Impl extends HeaderElementImpl { - protected static Logger log = + protected static final Logger log = Logger.getLogger(LogDomainConstants.SOAP_VER1_1_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.ver1_1.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/Message1_1Impl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/Message1_1Impl.java index c1d60c0c277..7d2f71b6184 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/Message1_1Impl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/Message1_1Impl.java @@ -23,7 +23,7 @@ * have any questions. */ /* - * $Id: Message1_1Impl.java,v 1.24 2006/01/27 12:49:41 vj135062 Exp $ + * */ @@ -48,7 +48,7 @@ import com.sun.xml.internal.messaging.saaj.util.LogDomainConstants; public class Message1_1Impl extends MessageImpl implements SOAPConstants { - protected static Logger log = + protected static final Logger log = Logger.getLogger(LogDomainConstants.SOAP_VER1_1_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.ver1_1.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/SOAPPart1_1Impl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/SOAPPart1_1Impl.java index 805b20c526e..5a03285be91 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/SOAPPart1_1Impl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/SOAPPart1_1Impl.java @@ -23,7 +23,7 @@ * have any questions. */ /* - * $Id: SOAPPart1_1Impl.java,v 1.1.1.1 2006/01/27 13:10:57 kumarjayanti Exp $ + * */ @@ -48,7 +48,7 @@ import com.sun.xml.internal.messaging.saaj.util.XMLDeclarationParser; public class SOAPPart1_1Impl extends SOAPPartImpl implements SOAPConstants { - protected static Logger log = + protected static final Logger log = Logger.getLogger(LogDomainConstants.SOAP_VER1_1_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.ver1_1.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Body1_2Impl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Body1_2Impl.java index b5dd821b9e3..328ecb7a546 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Body1_2Impl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Body1_2Impl.java @@ -23,7 +23,7 @@ * have any questions. */ /* - * $Id: Body1_2Impl.java,v 1.32 2006/01/27 12:49:44 vj135062 Exp $ + * */ @@ -50,7 +50,7 @@ import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl; public class Body1_2Impl extends BodyImpl { - protected static Logger log = + protected static final Logger log = Logger.getLogger(Body1_2Impl.class.getName(), "com.sun.xml.internal.messaging.saaj.soap.ver1_2.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Detail1_2Impl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Detail1_2Impl.java index bf7cbcb4e7d..ec880e50e34 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Detail1_2Impl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Detail1_2Impl.java @@ -23,7 +23,7 @@ * have any questions. */ /* - * $Id: Detail1_2Impl.java,v 1.24 2006/01/27 12:49:45 vj135062 Exp $ + * */ @@ -47,7 +47,7 @@ import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl; public class Detail1_2Impl extends DetailImpl { - protected static Logger log = + protected static final Logger log = Logger.getLogger(Detail1_2Impl.class.getName(), "com.sun.xml.internal.messaging.saaj.soap.ver1_2.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Envelope1_2Impl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Envelope1_2Impl.java index 468ee62cddc..11d4dc2ff9d 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Envelope1_2Impl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Envelope1_2Impl.java @@ -23,7 +23,7 @@ * have any questions. */ /* - * $Id: Envelope1_2Impl.java,v 1.26 2006/01/27 12:49:47 vj135062 Exp $ + * */ @@ -47,7 +47,7 @@ import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl; public class Envelope1_2Impl extends EnvelopeImpl { - protected static Logger log = + protected static final Logger log = Logger.getLogger(Envelope1_2Impl.class.getName(), "com.sun.xml.internal.messaging.saaj.soap.ver1_2.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Fault1_2Impl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Fault1_2Impl.java index 431c94b1d02..0e789f8df94 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Fault1_2Impl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Fault1_2Impl.java @@ -23,7 +23,7 @@ * have any questions. */ /* - * $Id: Fault1_2Impl.java,v 1.1.1.1 2006/01/27 13:10:57 kumarjayanti Exp $ + * */ @@ -51,7 +51,7 @@ import com.sun.xml.internal.messaging.saaj.util.LogDomainConstants; public class Fault1_2Impl extends FaultImpl { - protected static Logger log = + protected static final Logger log = Logger.getLogger( LogDomainConstants.SOAP_VER1_2_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.ver1_2.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Header1_2Impl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Header1_2Impl.java index 20d64a33c9b..2ea0f0d9191 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Header1_2Impl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Header1_2Impl.java @@ -23,7 +23,7 @@ * have any questions. */ /* - * $Id: Header1_2Impl.java,v 1.36 2006/01/27 12:49:48 vj135062 Exp $ + * */ @@ -53,7 +53,7 @@ import com.sun.xml.internal.messaging.saaj.util.LogDomainConstants; public class Header1_2Impl extends HeaderImpl { - protected static Logger log = + protected static final Logger log = Logger.getLogger( LogDomainConstants.SOAP_VER1_2_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.ver1_2.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/HeaderElement1_2Impl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/HeaderElement1_2Impl.java index afdf5c8eb18..14ebdadc12d 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/HeaderElement1_2Impl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/HeaderElement1_2Impl.java @@ -23,7 +23,7 @@ * have any questions. */ /* - * $Id: HeaderElement1_2Impl.java,v 1.29 2006/01/27 12:49:48 vj135062 Exp $ + * */ @@ -47,7 +47,7 @@ import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl; public class HeaderElement1_2Impl extends HeaderElementImpl { - private static Logger log = + private static final Logger log = Logger.getLogger(HeaderElement1_2Impl.class.getName(), "com.sun.xml.internal.messaging.saaj.soap.ver1_2.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/SOAPPart1_2Impl.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/SOAPPart1_2Impl.java index 25afd910f10..a21da41b63e 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/SOAPPart1_2Impl.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/SOAPPart1_2Impl.java @@ -23,7 +23,7 @@ * have any questions. */ /* - * $Id: SOAPPart1_2Impl.java,v 1.1.1.1 2006/01/27 13:10:57 kumarjayanti Exp $ + * */ @@ -47,7 +47,7 @@ import com.sun.xml.internal.messaging.saaj.util.XMLDeclarationParser; public class SOAPPart1_2Impl extends SOAPPartImpl implements SOAPConstants{ - protected static Logger log = + protected static final Logger log = Logger.getLogger(SOAPPart1_2Impl.class.getName(), "com.sun.xml.internal.messaging.saaj.soap.ver1_2.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/util/RejectDoctypeSaxFilter.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/util/RejectDoctypeSaxFilter.java index 9a83344cd6d..c977ae6968f 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/util/RejectDoctypeSaxFilter.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/util/RejectDoctypeSaxFilter.java @@ -45,12 +45,12 @@ import org.xml.sax.helpers.AttributesImpl; * because they are not legal in SOAP. If the user of this class sets a * LexicalHandler, then it forwards events to that handler. * - * $Id: RejectDoctypeSaxFilter.java,v 1.13 2006/01/27 12:49:52 vj135062 Exp $ + * * @author Edwin Goei */ public class RejectDoctypeSaxFilter extends XMLFilterImpl implements XMLReader, LexicalHandler{ - protected static Logger log = + protected static final Logger log = Logger.getLogger(LogDomainConstants.UTIL_DOMAIN, "com.sun.xml.internal.messaging.saaj.util.LocalStrings"); diff --git a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/util/transform/EfficientStreamingTransformer.java b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/util/transform/EfficientStreamingTransformer.java index 620f9c526f9..903b618f7b0 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/util/transform/EfficientStreamingTransformer.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/messaging/saaj/util/transform/EfficientStreamingTransformer.java @@ -62,20 +62,22 @@ import com.sun.xml.internal.messaging.saaj.util.FastInfosetReflection; public class EfficientStreamingTransformer extends javax.xml.transform.Transformer { - static final String version; - static final String vendor; + //static final String version; + //static final String vendor; - protected static TransformerFactory transformerFactory = TransformerFactory.newInstance(); + protected static final TransformerFactory transformerFactory = TransformerFactory.newInstance(); - static { - version = System.getProperty("java.vm.version"); - vendor = System.getProperty("java.vm.vendor"); - if (vendor.startsWith("Sun") && - (version.startsWith("1.4") || version.startsWith("1.3"))) { - transformerFactory = - new com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl(); - } - } + //removing support for Java 1.4 and 1.3 : CR6658158 + /*static { + version = System.getProperty("java.vm.version"); + vendor = System.getProperty("java.vm.vendor"); + if (vendor.startsWith("Sun") && + (version.startsWith("1.4") || version.startsWith("1.3"))) { + transformerFactory = + new com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl(); + } +} +*/ /** * TransformerFactory instance. diff --git a/jaxws/src/share/classes/com/sun/xml/internal/txw2/DatatypeWriter.java b/jaxws/src/share/classes/com/sun/xml/internal/txw2/DatatypeWriter.java index c9e4b17d02d..23c30eb08da 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/txw2/DatatypeWriter.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/txw2/DatatypeWriter.java @@ -25,6 +25,9 @@ package com.sun.xml.internal.txw2; +import java.util.AbstractList; +import java.util.Collections; +import java.util.List; import javax.xml.namespace.QName; /** @@ -53,50 +56,60 @@ public interface DatatypeWriter

{ */ void print(DT dt, NamespaceResolver resolver, StringBuilder buf); + static final List> BUILTIN = Collections.unmodifiableList(new AbstractList() { - static final DatatypeWriter[] BUILDIN = new DatatypeWriter[] { - new DatatypeWriter() { - public Class getType() { - return String.class; - } - public void print(String s, NamespaceResolver resolver, StringBuilder buf) { - buf.append(s); - } - }, - new DatatypeWriter() { - public Class getType() { - return Integer.class; - } - public void print(Integer i, NamespaceResolver resolver, StringBuilder buf) { - buf.append(i); - } - }, - new DatatypeWriter() { - public Class getType() { - return Float.class; - } - public void print(Float f, NamespaceResolver resolver, StringBuilder buf) { - buf.append(f); - } - }, - new DatatypeWriter() { - public Class getType() { - return Double.class; - } - public void print(Double d, NamespaceResolver resolver, StringBuilder buf) { - buf.append(d); - } - }, - new DatatypeWriter() { - public Class getType() { - return QName.class; - } - public void print(QName qn, NamespaceResolver resolver, StringBuilder buf) { - String p = resolver.getPrefix(qn.getNamespaceURI()); - if(p.length()!=0) - buf.append(p).append(':'); - buf.append(qn.getLocalPart()); + private DatatypeWriter[] BUILTIN_ARRAY = new DatatypeWriter[] { + new DatatypeWriter() { + public Class getType() { + return String.class; + } + public void print(String s, NamespaceResolver resolver, StringBuilder buf) { + buf.append(s); + } + }, + new DatatypeWriter() { + public Class getType() { + return Integer.class; + } + public void print(Integer i, NamespaceResolver resolver, StringBuilder buf) { + buf.append(i); + } + }, + new DatatypeWriter() { + public Class getType() { + return Float.class; + } + public void print(Float f, NamespaceResolver resolver, StringBuilder buf) { + buf.append(f); + } + }, + new DatatypeWriter() { + public Class getType() { + return Double.class; + } + public void print(Double d, NamespaceResolver resolver, StringBuilder buf) { + buf.append(d); + } + }, + new DatatypeWriter() { + public Class getType() { + return QName.class; + } + public void print(QName qn, NamespaceResolver resolver, StringBuilder buf) { + String p = resolver.getPrefix(qn.getNamespaceURI()); + if(p.length()!=0) + buf.append(p).append(':'); + buf.append(qn.getLocalPart()); + } } + }; + + public DatatypeWriter get(int n) { + return BUILTIN_ARRAY[n]; } - }; + + public int size() { + return BUILTIN_ARRAY.length; + } + }); } diff --git a/jaxws/src/share/classes/com/sun/xml/internal/txw2/Document.java b/jaxws/src/share/classes/com/sun/xml/internal/txw2/Document.java index a69a3d8979f..1c05e4bc75f 100644 --- a/jaxws/src/share/classes/com/sun/xml/internal/txw2/Document.java +++ b/jaxws/src/share/classes/com/sun/xml/internal/txw2/Document.java @@ -76,7 +76,7 @@ public final class Document { Document(XmlSerializer out) { this.out = out; - for( DatatypeWriter dw : DatatypeWriter.BUILDIN ) + for( DatatypeWriter dw : DatatypeWriter.BUILTIN ) datatypeWriters.put(dw.getType(),dw); } diff --git a/jdk/.hgtags b/jdk/.hgtags index 2aa2d05dcb6..5ab0b72ea45 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -32,3 +32,4 @@ d1c43d1f5676a24ba86221ac7cad5694f3a9afda jdk7-b54 522bb5aa17e0c0cff00b1ed7d1b51bc4db2cfef9 jdk7-b55 7fd3bc37afe36f8f6165ba679db1229716db822a jdk7-b56 d5a1223e961891564de25c39fba6f2442d0fb045 jdk7-b57 +9ba256e2e5c161b89e638390f998baa175ec9abe jdk7-b58 diff --git a/jdk/make/common/Release.gmk b/jdk/make/common/Release.gmk index 4bee467967d..da7f4690932 100644 --- a/jdk/make/common/Release.gmk +++ b/jdk/make/common/Release.gmk @@ -52,6 +52,9 @@ EXCLUDE_PROPWARN_PKGS = com.sun.java.swing.plaf \ com.sun.java.swing.plaf.motif \ com.sun.java.swing.plaf.gtk +# This is a stopgap until 6839872 is fixed. +EXCLUDE_PROPWARN_PKGS += sun.dyn + # 64-bit solaris has a few special cases. We define the variable # SOLARIS64 for use in this Makefile to easily test those cases ifeq ($(PLATFORM), solaris) diff --git a/jdk/make/docs/CORE_PKGS.gmk b/jdk/make/docs/CORE_PKGS.gmk index 9ea6f0c09ba..43a380ef836 100644 --- a/jdk/make/docs/CORE_PKGS.gmk +++ b/jdk/make/docs/CORE_PKGS.gmk @@ -1,5 +1,5 @@ # -# Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2001-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 @@ -55,6 +55,7 @@ EXCLUDE_PKGS = \ # This is a list of regular expressions. So foo.* matches "foo" and "foo.bar". # ACTIVE_JSR_PKGS= \ + java.dyn \ java.sql \ javax.activation \ javax.annotation.* \ @@ -96,6 +97,7 @@ CORE_PKGS = \ java.awt.print \ java.beans \ java.beans.beancontext \ + java.dyn \ java.io \ java.lang \ java.lang.annotation \ diff --git a/jdk/make/java/Makefile b/jdk/make/java/Makefile index 44d05a532a6..ca48cc9bef5 100644 --- a/jdk/make/java/Makefile +++ b/jdk/make/java/Makefile @@ -1,5 +1,5 @@ # -# Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 1995-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,7 @@ SUBDIRS += hpi version jvm redist verify fdlibm java sun_nio jli main zip # Others # Note: java_crw_demo java_hprof_demo are demos but must be delivered built in sdk SUBDIRS += security npt java_crw_demo java_hprof_demo \ - math awt util text applet net nio \ + math awt util text applet net nio dyn \ sql rmi jar beans logging management instrument diff --git a/jdk/make/java/dyn/Makefile b/jdk/make/java/dyn/Makefile new file mode 100644 index 00000000000..00cc225f4d0 --- /dev/null +++ b/jdk/make/java/dyn/Makefile @@ -0,0 +1,44 @@ +# +# Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Sun designates this +# particular file as subject to the "Classpath" exception as provided +# by Sun in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +BUILDDIR = ../.. + +PACKAGE = java.dyn +PRODUCT = java +include $(BUILDDIR)/common/Defs.gmk + +AUTO_FILES_JAVA_DIRS = java/dyn sun/dyn + +# The sources built here use new language syntax to generate +# method handle calls. Let's be sure we are using that format. +#LANGUAGE_VERSION = -source 7 +#CLASS_VERSION = -target 7 + +# Actually, it will be less disruptive to compile with the same +# -target option as the rest of the system, and just turn on +# the specific compiler option we need here: +OTHER_JAVACFLAGS = -XDinvokedynamic + +include $(BUILDDIR)/common/Classes.gmk diff --git a/jdk/src/share/classes/java/awt/GraphicsDevice.java b/jdk/src/share/classes/java/awt/GraphicsDevice.java index c7d9b13fba6..2080225ab43 100644 --- a/jdk/src/share/classes/java/awt/GraphicsDevice.java +++ b/jdk/src/share/classes/java/awt/GraphicsDevice.java @@ -282,7 +282,7 @@ public abstract class GraphicsDevice { w.setOpacity(1.0f); } Color bgColor = w.getBackground(); - if (bgColor.getAlpha() < 255) { + if ((bgColor != null) && (bgColor.getAlpha() < 255)) { bgColor = new Color(bgColor.getRed(), bgColor.getGreen(), bgColor.getBlue(), 255); w.setBackground(bgColor); diff --git a/jdk/src/share/classes/java/dyn/CallSite.java b/jdk/src/share/classes/java/dyn/CallSite.java new file mode 100644 index 00000000000..34624a5a170 --- /dev/null +++ b/jdk/src/share/classes/java/dyn/CallSite.java @@ -0,0 +1,224 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.dyn; + +import sun.dyn.util.BytecodeName; + +/** + * An {@code invokedynamic} call site, as reified by the + * containing class's bootstrap method. + * Every call site object corresponds to a distinct instance + * of the invokedynamic instruction, and vice versa. + * Every call site has one state variable, called the {@code target}. + * It is typed as a {@link MethodHandle}. This state is never null, and + * it is the responsibility of the bootstrap method to produce call sites + * which have been pre-linked to an initial target method. + *

+ * (Note: The bootstrap method may elect to produce call sites of a + * language-specific subclass of {@code CallSite}. In such a case, + * the subclass may claim responsibility for initializing its target to + * a non-null value, by overriding {@link #initialTarget}.) + *

+ * An {@code invokedynamic} instruction which has not yet been executed + * is said to be unlinked. When an unlinked call site is executed, + * the containing class's bootstrap method is called to manufacture a call site, + * for the instruction. If the bootstrap method does not assign a non-null + * value to the new call site's target variable, the method {@link #initialTarget} + * is called to produce the new call site's first target method. + *

+ * @see Linkage#registerBootstrapMethod(java.lang.Class, java.dyn.MethodHandle) + * @author John Rose, JSR 292 EG + */ +public class CallSite { + // Fields used only by the JVM. Do not use or change. + private Object vmmethod; + int callerMID, callerBCI; // supplied by the JVM + + MethodHandle target; + final Object caller; // usually a class + final String name; + final MethodType type; + + /** + * Make a call site given the parameters from a call to the bootstrap method. + * The resulting call site is in an unlinked state, which means that before + * it is returned from a bootstrap method call it must be provided with + * a target method via a call to {@link CallSite#setTarget}. + * @param caller the class in which the relevant {@code invokedynamic} instruction occurs + * @param name the name specified by the {@code invokedynamic} instruction + * @param type the method handle type derived from descriptor of the {@code invokedynamic} instruction + */ + public CallSite(Object caller, String name, MethodType type) { + this.caller = caller; + this.name = name; + this.type = type; + } + + private static void privateInitializeCallSite(CallSite site, int callerMID, int callerBCI) { + site.callerMID = callerMID; + site.callerBCI = callerBCI; + if (site.target == null) + site.setTarget(site.initialTarget()); + } + + /** + * Just after a call site is created by a bootstrap method handle, + * if the target has not been initialized by the factory method itself, + * the method {@code initialTarget} is called to produce an initial + * non-null target. (Live call sites must never have null targets.) + *

+ * If the bootstrap method itself does not initialize the call site, + * this method must be overridden, because it just raises an + * {@code InvokeDynamicBootstrapError}, which in turn causes the + * linkage of the {@code invokedynamic} instruction to terminate + * abnormally. + */ + protected MethodHandle initialTarget() { + throw new InvokeDynamicBootstrapError("target must be initialized before call site is linked: "+this); + } + + /** + * Report the current linkage state of the call site. (This is mutable.) + * The value maybe null only if the call site is currently unlinked. + * When a linked call site is invoked, the target method is used directly. + * When an unlinked call site is invoked, its bootstrap method receives + * the call, as if via {@link Linkage#bootstrapInvokeDynamic}. + *

+ * The interactions of {@code getTarget} with memory are the same + * as of a read from an ordinary variable, such as an array element or a + * non-volatile, non-final field. + *

+ * In particular, the current thread may choose to reuse the result + * of a previous read of the target from memory, and may fail to see + * a recent update to the target by another thread. + * @return the current linkage state of the call site + * @see #setTarget + */ + public MethodHandle getTarget() { + return target; + } + + /** + * Link or relink the call site, by setting its target method. + *

+ * The interactions of {@code setTarget} with memory are the same + * as of a write to an ordinary variable, such as an array element or a + * non-volatile, non-final field. + *

+ * In particular, unrelated threads may fail to see the updated target + * until they perform a read from memory. + * Stronger guarantees can be created by putting appropriate operations + * into the bootstrap method and/or the target methods used + * at any given call site. + * @param target the new target, or null if it is to be unlinked + * @throws NullPointerException if the proposed new target is null + * @throws WrongMethodTypeException if the proposed new target + * has a method type that differs from the call site's {@link #type()} + */ + public void setTarget(MethodHandle target) { + checkTarget(target); + this.target = target; + } + + protected void checkTarget(MethodHandle target) { + target.type(); // provoke NPE + if (!canSetTarget(target)) + throw new WrongMethodTypeException(String.valueOf(target)); + } + + protected boolean canSetTarget(MethodHandle target) { + return (target != null && target.type() == type()); + } + + /** + * Report the class containing the call site. + * This is an immutable property of the call site, set from the first argument to the constructor. + * @return class containing the call site + */ + public Class callerClass() { + return (Class) caller; + } + + /** + * Report the method name specified in the {@code invokedynamic} instruction. + * This is an immutable property of the call site, set from the second argument to the constructor. + *

+ * Note that the name is a JVM bytecode name, and as such can be any + * non-empty string, as long as it does not contain certain "dangerous" + * characters such as slash {@code '/'} and dot {@code '.'}. + * See the Java Virtual Machine specification for more details. + *

+ * Application such as a language runtimes may need to encode + * arbitrary program element names and other configuration information + * into the name. A standard convention for doing this is + * specified here. + * @return method name specified by the call site + */ + public String name() { + return name; + } + + /** + * Report the method name specified in the {@code invokedynamic} instruction, + * as a series of components, individually demangled according to + * the standard convention + * specified here. + *

+ * Non-empty runs of characters between dangerous characters are demangled. + * Each component is either a completely arbitrary demangled string, + * or else a character constant for a punctuation character, typically ':'. + * (In principle, the character can be any dangerous character that the + * JVM lets through in a method name, such as '$' or ']'. + * Runtime implementors are encouraged to use colon ':' for building + * structured names.) + *

+ * In the common case where the name contains no dangerous characters, + * the result is an array whose only element array is the demangled + * name at the call site. Such a demangled name can be any sequence + * of any number of any unicode characters. + * @return method name components specified by the call site + */ + public Object[] nameComponents() { + return BytecodeName.parseBytecodeName(name); + } + + /** + * Report the resolved result and parameter types of this call site, + * which are derived from its bytecode-level invocation descriptor. + * The types are packaged into a {@link MethodType}. + * Any linked target of this call site must be exactly this method type. + * This is an immutable property of the call site, set from the third argument to the constructor. + * @return method type specified by the call site + */ + public MethodType type() { + return type; + } + + @Override + public String toString() { + return "CallSite#"+hashCode()+"["+name+type+" => "+target+"]"; + } +} diff --git a/jdk/src/share/classes/java/dyn/InvokeDynamic.java b/jdk/src/share/classes/java/dyn/InvokeDynamic.java new file mode 100644 index 00000000000..2bec7b7dfe6 --- /dev/null +++ b/jdk/src/share/classes/java/dyn/InvokeDynamic.java @@ -0,0 +1,54 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.dyn; + +/** + * Syntactic marker to request javac to emit an {@code invokedynamic} instruction. + * An {@code invokedynamic} instruction is a 5-byte bytecoded instruction + * which begins with an opcode byte of value 186 ({@code 0xBA}), + * and is followed by a two-byte index of a {@code NameAndType} constant + * pool entry, then by two zero bytes. The constant pool reference gives + * the method name and argument and return types of the call site; there + * is no other information provided at the call site. + *

+ * The {@code invokedynamic} instruction is incomplete without a target method. + * The target method is a property of the reified call site object + * (of type {@link CallSite}) which is in a one-to-one association with each + * corresponding {@code invokedynamic} instruction. The call site object + * is initially produced by a bootstrap method associated with + * the call site, via the various overloadings of {@link Linkage#registerBootstrapMethod}. + *

+ * The type {@code InvokeDynamic} has no particular meaning as a + * class or interface supertype, or an object type; it can never be instantiated. + * Logically, it denotes a source of all dynamically typed methods. + * It may be viewed as a pure syntactic marker (an importable one) of static calls. + * @author John Rose, JSR 292 EG + */ +public final class InvokeDynamic { + private InvokeDynamic() { throw new InternalError(); } // do not instantiate + + // no statically defined static methods +} diff --git a/jdk/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java b/jdk/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java new file mode 100644 index 00000000000..975ba7d3a2d --- /dev/null +++ b/jdk/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java @@ -0,0 +1,55 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.dyn; + +/** + * Thrown to indicate that an {@code invokedynamic} instruction has + * failed to find its bootstrap method, or the bootstrap method has + * failed to provide a call site with a non-null target. + *

+ * The boostrap method must have been declared during a class's initialization + * by a call to {@link Linkage#registerBootstrapMethod}. + * + * @author John Rose, JSR 292 EG + */ +public class InvokeDynamicBootstrapError extends LinkageError { + /** + * Constructs a {@code InvokeDynamicBootstrapError} with no detail message. + */ + public InvokeDynamicBootstrapError() { + super(); + } + + /** + * Constructs a {@code InvokeDynamicBootstrapError} with the specified + * detail message. + * + * @param s the detail message. + */ + public InvokeDynamicBootstrapError(String s) { + super(s); + } +} diff --git a/jdk/src/share/classes/java/dyn/JavaMethodHandle.java b/jdk/src/share/classes/java/dyn/JavaMethodHandle.java new file mode 100644 index 00000000000..b7432a77521 --- /dev/null +++ b/jdk/src/share/classes/java/dyn/JavaMethodHandle.java @@ -0,0 +1,83 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.dyn; + +/** + * A Java method handle extends the basic method handle type with additional + * programmer defined methods and fields. + * Its behavior as a method handle is determined at instance creation time, + * by providing the new instance with an "entry point" method handle + * to handle calls. This entry point must accept a leading argument + * whose type is the Java method handle itself or a supertype, and the + * entry point is always called with the Java method handle itself as + * the first argument. This is similar to ordinary virtual methods, which also + * accept the receiver object {@code this} as an implicit leading argument. + * The {@code MethodType} of the Java method handle is the same as that + * of the entry point method handle, with the leading parameter type + * omitted. + *

+ * Here is an example of usage: + *

+ *     class Greeter extends JavaMethodHandle {
+ *         public void run() { System.out.println("hello, "+greetee); }
+ *         private final String greetee;
+ *         Greeter(String greetee) {
+ *             super(RUN);
+ *             this.greetee = greetee;
+ *         }
+ *         // the entry point function is computed once:
+ *         private static final MethodHandle RUN
+ *             = MethodHandles.findVirtual(MyMethodHandle.class, "run",
+ *                   MethodType.make(void.class));
+ *     }
+ *     Greeter greeter = new Greeter("world");
+ *     greeter.run();  // prints "hello, world"
+ *     MethodHandle mh = greeter;
+ *     mh.invoke();  // also prints "hello, world"
+ * 
+ *

+ * In this example, the method {@code run} provides the entry point. + * The entry point need not be a constant value; it may be independently + * computed in each call to the constructor. The entry point does not + * even need to be a method on the Java method handle class, though + * that is the typical case. + * @see MethodHandle + * @author John Rose, JSR 292 EG + */ +public abstract class JavaMethodHandle + // Note: This is an implementation inheritance hack, and will be removed + // with a JVM change which moves the required hidden behavior onto this class. + extends sun.dyn.BoundMethodHandle +{ + /** + * When creating a, pass in {@code entryPoint}, any method handle which + * can take the current object + * @param entryPoint + */ + protected JavaMethodHandle(MethodHandle entryPoint) { + super(entryPoint, 0); + } +} diff --git a/jdk/src/share/classes/java/dyn/Linkage.java b/jdk/src/share/classes/java/dyn/Linkage.java new file mode 100644 index 00000000000..cbeeb3351de --- /dev/null +++ b/jdk/src/share/classes/java/dyn/Linkage.java @@ -0,0 +1,209 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.dyn; + +import java.util.WeakHashMap; +import sun.reflect.Reflection; +import static sun.dyn.util.VerifyAccess.checkBootstrapPrivilege; + +/** + * Static methods which control the linkage of invokedynamic call sites. + * @author John Rose, JSR 292 EG + */ +public class Linkage { + private Linkage() {} // do not instantiate + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Register a bootstrap method to use when linking a given caller class. + * It must be a method handle of a type equivalent to {@link CallSite#CallSite}. + * In other words, it must act as a factory method which accepts the arguments + * to {@code CallSite}'s constructor (a class, a string, and a method type), + * and returns a {@code CallSite} object (possibly of a subclass of {@code CallSite}). + *

+ * The registration will fail with an {@code IllegalStateException} if any of the following conditions hold: + *

    + *
  • The caller of this method is in a different package than the {@code callerClass}, + * and there is a security manager, and its {@code checkPermission} call throws + * when passed {@link LinkagePermission}("registerBootstrapMethod",callerClass). + *
  • The given class already has a bootstrap method from a previous + * call to this method. + *
  • The given class is already fully initialized. + *
  • The given class is in the process of initialization, in another thread. + *
+ * Because of these rules, a class may install its own bootstrap method in + * a static initializer. + */ + public static + void registerBootstrapMethod(Class callerClass, MethodHandle mh) { + Class callc = Reflection.getCallerClass(2); + checkBootstrapPrivilege(callc, callerClass, "registerBootstrapMethod"); + checkBSM(mh); + synchronized (bootstrapMethods) { + if (bootstrapMethods.containsKey(callerClass)) + throw new IllegalStateException("bootstrap method already declared in "+callerClass); + bootstrapMethods.put(callerClass, mh); + } + } + + static void checkBSM(MethodHandle mh) { + if (mh == null) throw new IllegalArgumentException("null bootstrap method"); + if (mh.type() == OLD_BOOTSTRAP_METHOD_TYPE) // FIXME: delete at EDR/PFD + throw new WrongMethodTypeException("bootstrap method must be a CallSite factory"); + if (mh.type() != BOOTSTRAP_METHOD_TYPE) + throw new WrongMethodTypeException(mh.toString()); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Simplified version of registerBootstrapMethod for self-registration, + * to be called from a static initializer. + * Finds a static method of the required type in the + * given class, and installs it on the caller. + * @throws IllegalArgumentException if there is no such method + */ + public static + void registerBootstrapMethod(Class runtime, String name) { + Class callc = Reflection.getCallerClass(2); + MethodHandle bootstrapMethod = + MethodHandles.findStaticFrom(callc, runtime, name, BOOTSTRAP_METHOD_TYPE); + // FIXME: exception processing wrong here + checkBSM(bootstrapMethod); + Linkage.registerBootstrapMethod(callc, bootstrapMethod); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Simplified version of registerBootstrapMethod for self-registration, + * to be called from a static initializer. + * Finds a static method of the required type in the + * caller's class, and installs it on the caller. + * @throws IllegalArgumentException if there is no such method + */ + public static + void registerBootstrapMethod(String name) { + Class callc = Reflection.getCallerClass(2); + MethodHandle bootstrapMethod = + MethodHandles.findStaticFrom(callc, callc, name, BOOTSTRAP_METHOD_TYPE); + // FIXME: exception processing wrong here + checkBSM(bootstrapMethod); + Linkage.registerBootstrapMethod(callc, bootstrapMethod); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Report the bootstrap method registered for a given class. + * Returns null if the class has never yet registered a bootstrap method, + * or if the class has explicitly registered a null bootstrap method. + * Only callers privileged to set the bootstrap method may inquire + * about it, because a bootstrap method is potentially a back-door entry + * point into its class. + */ + public static + MethodHandle getBootstrapMethod(Class callerClass) { + Class callc = Reflection.getCallerClass(2); + checkBootstrapPrivilege(callc, callerClass, "registerBootstrapMethod"); + synchronized (bootstrapMethods) { + return bootstrapMethods.get(callerClass); + } + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * The type of any bootstrap method is a three-argument method + * {@code (Class, String, MethodType)} returning a {@code CallSite}. + */ + public static final MethodType BOOTSTRAP_METHOD_TYPE + = MethodType.make(CallSite.class, + Class.class, String.class, MethodType.class); + + private static final MethodType OLD_BOOTSTRAP_METHOD_TYPE + = MethodType.make(Object.class, + CallSite.class, Object[].class); + + private static final WeakHashMap bootstrapMethods = + new WeakHashMap(); + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Invalidate all invokedynamic call sites everywhere. + *

+ * When this method returns, every invokedynamic instruction + * will invoke its bootstrap method on next call. + *

+ * It is unspecified whether call sites already known to the Java + * code will continue to be associated with invokedynamic + * instructions. If any call site is still so associated, its + * {@link CallSite#getTarget()} method is guaranteed to return null + * the invalidation operation completes. + *

+ * Invalidation operations are likely to be slow. Use them sparingly. + */ + public static + Object invalidateAll() { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkPermission(new LinkagePermission("invalidateAll")); + } + throw new UnsupportedOperationException("NYI"); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Invalidate all invokedynamic call sites associated + * with the given class. + * (These are exactly those sites which report the given class + * via the {@link CallSite#callerClass()} method.) + *

+ * When this method returns, every matching invokedynamic + * instruction will invoke its bootstrap method on next call. + *

+ * For additional semantics of call site invalidation, + * see {@link #invalidateAll()}. + */ + public static + Object invalidateCallerClass(Class callerClass) { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkPermission(new LinkagePermission("invalidateAll", callerClass)); + } + throw new UnsupportedOperationException("NYI"); + } + + private static Object doNotBootstrap(CallSite site, Object... arguments) { + throw new UnsupportedOperationException("call site must not have null target: "+site); + } + + private static final MethodHandle DO_NOT_BOOTSTRAP = + MethodHandles.Lookup.IMPL_LOOKUP.findStatic(Linkage.class, "doNotBootstrap", + OLD_BOOTSTRAP_METHOD_TYPE); + + // Up-call from the JVM. Obsolete. FIXME: Delete from VM then from here. + static + MethodHandle findBootstrapMethod(Class callerClass, Class searchBootstrapClass) { + return DO_NOT_BOOTSTRAP; + } +} diff --git a/jdk/src/share/classes/java/dyn/LinkagePermission.java b/jdk/src/share/classes/java/dyn/LinkagePermission.java new file mode 100644 index 00000000000..6ea86f8b555 --- /dev/null +++ b/jdk/src/share/classes/java/dyn/LinkagePermission.java @@ -0,0 +1,111 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.dyn; + +import java.security.*; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.StringTokenizer; + +/** + * This class is for runtime permissions. A RuntimePermission + * contains a name (also referred to as a "target name") but + * no actions list; you either have the named permission + * or you don't. + * + *

+ * The target name is the name of the runtime permission (see below). The + * naming convention follows the hierarchical property naming convention. + * Also, an asterisk + * may appear at the end of the name, following a ".", or by itself, to + * signify a wildcard match. For example: "loadLibrary.*" or "*" is valid, + * "*loadLibrary" or "a*b" is not valid. + *

+ * The following table lists all the possible RuntimePermission target names, + * and for each provides a description of what the permission allows + * and a discussion of the risks of granting code the permission. + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Permission Target NameWhat the Permission AllowsRisks of Allowing this Permission
registerBootstrapMethod.{class name}Specifying a bootstrap method for invokedynamic, within a class of the given nameAn attacker could attempt to attach a bootstrap method to a class which + * has just been loaded, thus gaining control of its invokedynamic calls.
invalidateAllForce the relinking of invokedynamic call sites everywhere.This could allow an attacker to slow down the system, or perhaps surface timing bugs in a dynamic language implementations, by forcing redundant relinking operations.
invalidateCallerClass.{class name}Force the relinking of invokedynamic call sites in the given class.See {@code invalidateAll}.
+ * + * @see java.security.BasicPermission + * @see java.lang.SecurityManager + * + * @author John Rose, JSR 292 EG + */ + +public final class LinkagePermission extends BasicPermission { + /** + * Create a new LinkagePermission with the given name. + * The name is the symbolic name of the LinkagePermission, such as + * "registerBootstrapMethod", "invalidateClass.*", etc. An asterisk + * may appear at the end of the name, following a ".", or by itself, to + * signify a wildcard match. + * + * @param name the name of the LinkagePermission + */ + public LinkagePermission(String name) { + super(name); + } + + /** + * Create a new LinkagePermission with the given name on the given class. + * Equivalent to {@code LinkagePermission(name+"."+clazz.getName())}. + * + * @param name the name of the LinkagePermission + * @param clazz the class affected by the permission + */ + public LinkagePermission(String name, Class clazz) { + super(name + "." + clazz.getName()); + } +} diff --git a/jdk/src/share/classes/java/dyn/MethodHandle.java b/jdk/src/share/classes/java/dyn/MethodHandle.java new file mode 100644 index 00000000000..688a9d3fd70 --- /dev/null +++ b/jdk/src/share/classes/java/dyn/MethodHandle.java @@ -0,0 +1,135 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.dyn; + +//import sun.dyn.*; + +import sun.dyn.Access; +import sun.dyn.MethodHandleImpl; + +/** + * A method handle is a typed reference to the entry point of a method. + *

+ * Method handles are strongly typed according to signature. + * They are not distinguished by method name or enclosing class. + * A method handle must be invoked under a signature which exactly matches + * the method handle's own type. + *

+ * Every method handle confesses its type via the type accessor. + * The structure of this type is a series of classes, one of which is + * the return type of the method (or void.class if none). + *

+ * Every method handle appears as an object containing a method named + * invoke, whose signature exactly matches + * the method handle's type. + * A normal Java method call (using the invokevirtual instruction) + * can invoke this method from Java source code (if language support is present). + *

+ * Every call to a method handle specifies an intended method type, + * which must exactly match the type of the method handle. + * (The type is specified in the invokevirtual instruction, + * via a {@code CONSTANT_NameAndType} constant pool entry.) + * The call looks within the receiver object for a method + * named invoke of the intended method type. + * The call fails with a {@link WrongMethodTypeException} + * if the method does not exist, even if there is an invoke + * method of a closely similar signature. + *

+ * A method handle is an unrestricted capability to call a method. + * A method handle can be formed on a non-public method by a class + * that has access to that method; the resulting handle can be used + * in any place by any caller who receives a reference to it. Thus, access + * checking is performed when the method handle is created, not + * (as in reflection) every time it is called. Handles to non-public + * methods, or in non-public classes, should generally be kept secret. + * They should not be passed to untrusted code. + *

+ * Bytecode in an extended JVM can directly call a method handle's + * invoke from an invokevirtual instruction. + * The receiver class type must be MethodHandle and the method name + * must be invoke. The signature of the invocation + * (after resolving symbolic type names) must exactly match the method type + * of the target method. + *

+ * Bytecode in an extended JVM can directly obtain a method handle + * for any accessible method from a ldc instruction + * which refers to a CONSTANT_Methodref or + * CONSTANT_InterfaceMethodref constant pool entry. + *

+ * All JVMs can also use a reflective API called MethodHandles + * for creating and calling method handles. + *

+ * A method reference may refer either to a static or non-static method. + * In the non-static case, the method handle type includes an explicit + * receiver argument, prepended before any other arguments. + * In the method handle's type, the initial receiver argument is typed + * according to the class under which the method was initially requested. + * (E.g., if a non-static method handle is obtained via ldc, + * the type of the receiver is the class named in the constant pool entry.) + *

+ * When a method handle to a virtual method is invoked, the method is + * always looked up in the receiver (that is, the first argument). + *

+ * A non-virtual method handles to a specific virtual method implementation + * can also be created. These do not perform virtual lookup based on + * receiver type. Such a method handle simulates the effect of + * an invokespecial instruction to the same method. + * + * @see MethodType + * @see MethodHandles + * @author John Rose, JSR 292 EG + */ +public abstract class MethodHandle + // Note: This is an implementation inheritance hack, and will be removed + // with a JVM change which moves the required hidden state onto this class. + extends MethodHandleImpl +{ + // interface MethodHandle> + // { T type(); public R invoke(A...); } + + final private MethodType type; + + /** + * Report the type of this method handle. + * Every invocation of this method handle must exactly match this type. + * @return the method handle type + */ + public MethodType type() { + return type; + } + + /** + * The constructor for MethodHandle may only be called by privileged code. + * Subclasses may be in other packages, but must possess + * a token which they obtained from MH with a security check. + * @param token non-null object which proves access permission + * @param type type (permanently assigned) of the new method handle + */ + protected MethodHandle(Access token, MethodType type) { + super(token); + this.type = type; + } +} diff --git a/jdk/src/share/classes/java/dyn/MethodHandles.java b/jdk/src/share/classes/java/dyn/MethodHandles.java new file mode 100644 index 00000000000..3a9f7ed3e97 --- /dev/null +++ b/jdk/src/share/classes/java/dyn/MethodHandles.java @@ -0,0 +1,1104 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.dyn; + +import java.lang.reflect.Constructor; +import sun.dyn.Access; +import sun.dyn.MemberName; +import sun.dyn.MethodHandleImpl; +import sun.dyn.util.VerifyAccess; +import sun.dyn.util.Wrapper; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import sun.dyn.Invokers; +import sun.dyn.MethodTypeImpl; +import sun.reflect.Reflection; +import static sun.dyn.MemberName.newIllegalArgumentException; +import static sun.dyn.MemberName.newNoAccessException; + +/** + * Fundamental operations and utilities for MethodHandle. + *

+ * API Note: The matching of method types in this API cannot + * be completely checked by Java's generic type system for three reasons: + *

    + *
  1. Method types range over all possible arities, + * from no arguments to an arbitrary number of arguments. + * Generics are not variadic, and so cannot represent this.
  2. + *
  3. Method types can specify arguments of primitive types, + * which Java generic types cannot range over.
  4. + *
  5. Method types can optionally specify varargs (ellipsis).
  6. + *
+ * @author John Rose, JSR 292 EG + */ +public class MethodHandles { + + private MethodHandles() { } // do not instantiate + + private static final Access IMPL_TOKEN = Access.getToken(); + private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(IMPL_TOKEN); + static { MethodHandleImpl.initStatics(); } + // See IMPL_LOOKUP below. + + //// Method handle creation from ordinary methods. + + public static Lookup lookup() { + return new Lookup(); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * A factory object for creating method handles, when the creation + * requires access checking. Method handles do not perform + * access checks when they are called; this is a major difference + * from reflective {@link Method}, which performs access checking + * against every caller, on every call. Method handle access + * restrictions are enforced when a method handle is created. + * The caller class against which those restrictions are enforced + * is known as the "lookup class". {@link Lookup} embodies an + * authenticated lookup class, and can be used to create any number + * of access-checked method handles, all checked against a single + * lookup class. + *

+ * A class which needs to create method handles will call + * {@code MethodHandles.lookup()} to create a factory for itself. + * It may then use this factory to create method handles on + * all of its methods, including private ones. + * It may also delegate the lookup (e.g., to a metaobject protocol) + * by passing the {@code Lookup} object to other code. + * If this other code creates method handles, they will be access + * checked against the original lookup class, and not with any higher + * privileges. + *

+ * Note that access checks only apply to named and reflected methods. + * Other method handle creation methods, such as {@link #convertArguments}, + * do not require any access checks, and can be done independently + * of any lookup class. + *

+ * A note about error conditions: A lookup can fail, because + * the containing class is not accessible to the lookup class, or + * because the desired class member is missing, or because the + * desired class member is not accessible to the lookup class. + * It can also fail if a security manager is installed and refuses + * access. In any of these cases, an exception will be + * thrown from the attempted lookup. + * In general, the conditions under which a method handle may be + * created for a method {@code M} are exactly as restrictive as the conditions + * under which the lookup class could have compiled a call to {@code M}. + * At least some of these error conditions are likely to be + * represented by checked exceptions in the final version of this API. + */ + public static final + class Lookup { + private final Class lookupClass; + + /** Which class is performing the lookup? It is this class against + * which checks are performed for visibility and access permissions. + *

+ * This value is null if and only if this lookup is {@link #PUBLIC_LOOKUP}. + */ + public Class lookupClass() { + return lookupClass; + } + + /** Embody the current class (the lookupClass) as a lookup class + * for method handle creation. + * Must be called by from a method in this package, + * which in turn is called by a method not in this package. + * Also, don't make it private, lest javac interpose + * an access$N method. + */ + Lookup() { + Class caller = getCallerClassAtEntryPoint(); + // make sure we haven't accidentally picked up this class: + checkUnprivilegedlookupClass(caller); + this.lookupClass = caller; + } + + private Lookup(Class lookupClass) { + this.lookupClass = lookupClass; + } + + private static final Class PUBLIC_ONLY = sun.dyn.empty.Empty.class; + + /** Version of lookup which is trusted minimally. + * It can only be used to create method handles to + * publicly accessible members. + */ + public static final Lookup PUBLIC_LOOKUP = new Lookup(PUBLIC_ONLY); + + /** Package-private version of lookup which is trusted. */ + static final Lookup IMPL_LOOKUP = new Lookup(null); + static { MethodHandleImpl.initLookup(IMPL_TOKEN, IMPL_LOOKUP); } + + private static void checkUnprivilegedlookupClass(Class lookupClass) { + String name = lookupClass.getName(); + if (name.startsWith("java.dyn.") || name.startsWith("sun.dyn.")) + throw newIllegalArgumentException("illegal lookupClass: "+lookupClass); + } + + @Override + public String toString() { + if (lookupClass == PUBLIC_ONLY) + return "public"; + if (lookupClass == null) + return "privileged"; + return lookupClass.getName(); + } + + // call this from an entry point method in Lookup with extraFrames=0. + private static Class getCallerClassAtEntryPoint() { + final int CALLER_DEPTH = 4; + // 0: Reflection.getCC, 1: getCallerClassAtEntryPoint, + // 2: Lookup., 3: MethodHandles.*, 4: caller + // Note: This should be the only use of getCallerClass in this file. + return Reflection.getCallerClass(CALLER_DEPTH); + } + + /** + * Produce a method handle for a static method. + * The type of the method handle will be that of the method. + * The method and all its argument types must be accessible to the lookup class. + * If the method's class has not yet been initialized, that is done + * immediately, before the method handle is returned. + * @param defc the class from which the method is accessed + * @param name the name of the method + * @param type the type of the method + * @return the desired method handle + * @exception SecurityException TBD + * @exception NoAccessException if the method does not exist or access checking fails + */ + public + MethodHandle findStatic(Class defc, String name, MethodType type) throws NoAccessException { + MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type, Modifier.STATIC), true, lookupClass); + checkStatic(true, method, lookupClass); + //throw NoSuchMethodException + return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClass); + } + + /** + * Produce a method handle for a virtual method. + * The type of the method handle will be that of the method, + * with the receiver type ({@code defc}) prepended. + * The method and all its argument types must be accessible to the lookup class. + *

+ * (BUG NOTE: The type {@code Object} may be prepended instead + * of the receiver type, if the receiver type is not on the boot class path. + * This is due to a temporary JVM limitation, in which MethodHandle + * claims to be unable to access such classes. To work around this + * bug, use {@code convertArguments} to normalize the type of the leading + * argument to a type on the boot class path, such as {@code Object}.) + *

+ * When called, the handle will treat the first argument as a receiver + * and dispatch on the receiver's type to determine which method + * implementation to enter. + * (The dispatching action is identical with that performed by an + * {@code invokevirtual} or {@code invokeinterface} instruction.) + * @param defc the class or interface from which the method is accessed + * @param name the name of the method + * @param type the type of the method, with the receiver argument omitted + * @return the desired method handle + * @exception SecurityException TBD + * @exception NoAccessException if the method does not exist or access checking fails + */ + public MethodHandle findVirtual(Class defc, String name, MethodType type) throws NoAccessException { + MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type), true, lookupClass); + checkStatic(false, method, lookupClass); + return MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClass); + } + + /** + * Produce an early-bound method handle for a virtual method, + * as if called from an {@code invokespecial} + * instruction from {@code caller}. + * The type of the method handle will be that of the method, + * with a suitably restricted receiver type (such as {@code caller}) prepended. + * The method and all its argument types must be accessible + * to the caller. + *

+ * When called, the handle will treat the first argument as a receiver, + * but will not dispatch on the receiver's type. + * (This direct invocation action is identical with that performed by an + * {@code invokespecial} instruction.) + *

+ * If the explicitly specified caller class is not identical with the + * lookup class, a security check TBD is performed. + * @param defc the class or interface from which the method is accessed + * @param name the name of the method, or "" for a constructor + * @param type the type of the method, with the receiver argument omitted + * @param specialCaller the proposed calling class to perform the {@code invokespecial} + * @return the desired method handle + * @exception SecurityException TBD + * @exception NoAccessException if the method does not exist or access checking fails + */ + public MethodHandle findSpecial(Class defc, String name, MethodType type, + Class specialCaller) throws NoAccessException { + checkSpecialCaller(specialCaller, lookupClass); + MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type), false, specialCaller); + checkStatic(false, method, lookupClass); + if (name.equals("")) { + throw newNoAccessException("cannot directly invoke a constructor", method, null); + } else if (defc.isInterface() || !defc.isAssignableFrom(specialCaller)) { + throw newNoAccessException("method must be in a superclass of lookup class", method, lookupClass); + } + return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, specialCaller); + } + + /** + * Produce an early-bound method handle for a non-static method. + * The receiver must have a supertype {@code defc} in which a method + * of the given name and type is accessible to the lookup class. + * The method and all its argument types must be accessible to the lookup class. + * The type of the method handle will be that of the method. + * The given receiver will be bound into the method handle. + *

+ * Equivalent to the following expression: + * + * {@link #insertArgument}({@link #findVirtual}(defc, name, type), receiver) + * + * @param receiver the object from which the method is accessed + * @param name the name of the method + * @param type the type of the method, with the receiver argument omitted + * @return the desired method handle + * @exception SecurityException TBD + * @exception NoAccessException if the method does not exist or access checking fails + */ + public MethodHandle bind(Object receiver, String name, MethodType type) throws NoAccessException { + Class rcvc = receiver.getClass(); // may get NPE + MemberName reference = new MemberName(rcvc, name, type); + MemberName method = IMPL_NAMES.resolveOrFail(reference, true, lookupClass); + checkStatic(false, method, lookupClass); + MethodHandle dmh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClass); + MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, dmh, receiver); + if (bmh == null) + throw newNoAccessException(method, lookupClass); + return bmh; + } + + /** + * Make a direct method handle to m, if the lookup class has permission. + * If m is non-static, the receiver argument is treated as an initial argument. + * If m is virtual, overriding is respected on every call. + * Unlike the Core Reflection API, exceptions are not wrapped. + * The type of the method handle will be that of the method, + * with the receiver type prepended (but only if it is non-static). + * If the method's {@code accessible} flag is not set, + * access checking is performed immediately on behalf of the lookup class. + * If m is not public, do not share the resulting handle with untrusted parties. + * @param m the reflected method + * @return a method handle which can invoke the reflected method + * @exception NoAccessException if access checking fails + */ + public MethodHandle unreflect(Method m) throws NoAccessException { + return unreflectImpl(new MemberName(m), m.isAccessible(), true, lookupClass); + } + + /** + * Produce a method handle for a reflected method. + * It will bypass checks for overriding methods on the receiver, + * as if by the {@code invokespecial} instruction. + * The type of the method handle will be that of the method, + * with the receiver type prepended. + * If the method's {@code accessible} flag is not set, + * access checking is performed immediately on behalf of the lookup class, + * as if {@code invokespecial} instruction were being linked. + * @param m the reflected method + * @return a method handle which can invoke the reflected method + * @exception NoAccessException if access checking fails + */ + public MethodHandle unreflectSpecial(Method m, Class specialCaller) throws NoAccessException { + checkSpecialCaller(specialCaller, lookupClass); + MemberName mname = new MemberName(m); + checkStatic(false, mname, lookupClass); + return unreflectImpl(mname, m.isAccessible(), false, specialCaller); + } + + /** + * Produce a method handle for a reflected constructor. + * The type of the method handle will be that of the constructor. + * The method handle will perform a {@code newInstance} operation, + * creating a new instance of the constructor's class on the + * arguments passed to the method handle. + *

+ * If the constructor's {@code accessible} flag is not set, + * access checking is performed immediately on behalf of the lookup class, + * as if {@code invokespecial} instruction were being linked. + * @param ctor the reflected constructor + * @return a method handle which can invoke the reflected constructor + * @exception NoAccessException if access checking fails + */ + public MethodHandle unreflectConstructor(Constructor ctor) throws NoAccessException { + MemberName m = new MemberName(ctor); + return unreflectImpl(m, ctor.isAccessible(), false, lookupClass); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Produce a method handle giving read access to a reflected field. + * The type of the method handle will have a return type of the field's + * value type. Its sole argument will be the field's containing class + * (but only if it is non-static). + * If the method's {@code accessible} flag is not set, + * access checking is performed immediately on behalf of the lookup class. + * @param f the reflected field + * @return a method handle which can load values from the reflected field + * @exception NoAccessException if access checking fails + */ + public MethodHandle unreflectGetter(Field f) throws NoAccessException { + return MethodHandleImpl.accessField(IMPL_TOKEN, new MemberName(f), false, lookupClass); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Produce a method handle giving write access to a reflected field. + * The type of the method handle will have a void return type. + * Its last argument will be the field's value type. + * Its other argument will be the field's containing class + * (but only if it is non-static). + * If the method's {@code accessible} flag is not set, + * access checking is performed immediately on behalf of the lookup class. + * @param f the reflected field + * @return a method handle which can store values into the reflected field + * @exception NoAccessException if access checking fails + */ + public MethodHandle unreflectSetter(Field f) throws NoAccessException { + return MethodHandleImpl.accessField(IMPL_TOKEN, new MemberName(f), true, lookupClass); + } + + } + + static /*must not be public*/ + MethodHandle findStaticFrom(Class lookupClass, + Class defc, String name, MethodType type) throws NoAccessException { + MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type, Modifier.STATIC), true, lookupClass); + checkStatic(true, method, lookupClass); + return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClass); + } + + static void checkStatic(boolean wantStatic, MemberName m, Class lookupClass) { + if (wantStatic != m.isStatic()) { + String message = wantStatic ? "expected a static method" : "expected a non-static method"; + throw newNoAccessException(message, m, lookupClass); + } + } + + static void checkSpecialCaller(Class specialCaller, Class lookupClass) { + if (lookupClass == Lookup.IMPL_LOOKUP.lookupClass()) + return; // privileged action + if (lookupClass == null || // public-only access + !VerifyAccess.isSamePackageMember(specialCaller, lookupClass)) + throw newNoAccessException("no private access", new MemberName(specialCaller), lookupClass); + } + + // Helper for creating handles on reflected methods and constructors. + static MethodHandle unreflectImpl(MemberName m, boolean isAccessible, + boolean doDispatch, Class lookupClass) { + MethodType mtype = m.getInvocationType(); + Class defc = m.getDeclaringClass(); + int mods = m.getModifiers(); + if (m.isStatic()) { + if (!isAccessible && + VerifyAccess.isAccessible(defc, mods, false, lookupClass) == null) + throw newNoAccessException(m, lookupClass); + } else { + Class constraint; + if (isAccessible) { + // abbreviated access check for "unlocked" method + constraint = doDispatch ? defc : lookupClass; + } else { + constraint = VerifyAccess.isAccessible(defc, mods, doDispatch, lookupClass); + } + if (constraint != defc && !constraint.isAssignableFrom(defc)) { + if (!defc.isAssignableFrom(constraint)) + throw newNoAccessException("receiver must be in caller class", m, lookupClass); + mtype = mtype.changeParameterType(0, constraint); + } + } + return MethodHandleImpl.findMethod(IMPL_TOKEN, m, doDispatch, lookupClass); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Produce a method handle giving read access to elements of an array. + * The type of the method handle will have a return type of the array's + * element type. Its first argument will be the array type, + * and the second will be {@code int}. + * @param arrayClass an array type + * @return a method handle which can load values from the given array type + * @throws IllegalArgumentException if arrayClass is not an array type + */ + public static + MethodHandle arrayElementGetter(Class arrayClass) throws IllegalArgumentException { + return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, false); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Produce a method handle giving write access to elements of an array. + * The type of the method handle will have a void return type. + * Its last argument will be the array's element type. + * The first and second arguments will be the array type and int. + * @return a method handle which can store values into the array type + * @throws IllegalArgumentException if arrayClass is not an array type + */ + public static + MethodHandle arrayElementSetter(Class arrayClass) throws IllegalArgumentException { + return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, true); + } + + + /// method handle invocation (reflective style) + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Call the {@code invoke} method of a given method handle, + * with arguments that exactly match the parameter types of the method handle. + * The length of the arguments array must equal the parameter count + * of the target's type. + * The arguments array is spread into separate arguments, and + * basic reference and unboxing conversions are applied. + *

+ * In order to match the type of the target, the following argument + * conversions are applied as necessary: + *

    + *
  • reference casting + *
  • unboxing + *
+ * The following conversions are not applied: + *
    + *
  • primitive conversions (e.g., {@code byte} to {@code int} + *
  • varargs conversions other than the initial spread + *
  • any application-specific conversions (e.g., string to number) + *
+ * The result returned by the call is boxed if it is a primitive, + * or forced to null if the return type is void. + *

+ * This call is a convenience method for the following code: + *

+     *   MethodHandle invoker = MethodHandles.genericInvoker(target.type(), 0, true);
+     *   Object result = invoker.invoke(arguments);
+     * 
+ * @param target the method handle to invoke + * @param arguments the arguments to pass to the target + * @return the result returned by the target + */ + public static + Object invoke(MethodHandle target, Object... arguments) { + int argc = arguments == null ? 0 : arguments.length; + MethodType type = target.type(); + if (argc <= 4) { + MethodHandle invoker = invokers(type).genericInvoker(); + switch (argc) { + case 0: return invoker.invoke(target); + case 1: return invoker.invoke(target, + arguments[0]); + case 2: return invoker.invoke(target, + arguments[0], arguments[1]); + case 3: return invoker.invoke(target, + arguments[0], arguments[1], arguments[2]); + case 4: return invoker.invoke(target, + arguments[0], arguments[1], arguments[2], arguments[3]); + } + } + MethodHandle invoker = invokers(type).varargsInvoker(); + return invoker.invoke(target, arguments); + } + + public static + Object invoke_0(MethodHandle target) { + MethodHandle invoker = invokers(target.type()).genericInvoker(); + return invoker.invoke(target); + } + public static + Object invoke_1(MethodHandle target, Object a0) { + MethodHandle invoker = invokers(target.type()).genericInvoker(); + return invoker.invoke(target, a0); + } + public static + Object invoke_2(MethodHandle target, Object a0, Object a1) { + MethodHandle invoker = invokers(target.type()).genericInvoker(); + return invoker.invoke(target, a0, a1); + } + public static + Object invoke_3(MethodHandle target, Object a0, Object a1, Object a2) { + MethodHandle invoker = invokers(target.type()).genericInvoker(); + return invoker.invoke(target, a0, a1, a2); + } + public static + Object invoke_4(MethodHandle target, Object a0, Object a1, Object a2, Object a3) { + MethodHandle invoker = invokers(target.type()).genericInvoker(); + return invoker.invoke(target, a0, a1, a2, a3); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Give a method handle which will invoke any method handle of the + * given type on a standard set of {@code Object} type arguments. + * The the resulting invoker will be a method handle with the following + * arguments: + *
    + *
  • a single {@code MethodHandle} target + *
  • zero or more {@code Object} values + *
  • an optional {@code Object[]} array containing more arguments + *
+ * The invoker will spread the varargs array (if present), apply + * reference casts as necessary, and unbox primitive arguments. + * The return value of the invoker will be an {@code Object} reference, + * boxing a primitive value if the original type returns a primitive, + * and always null if the original type returns void. + *

+ * This is a convenience method equivalent to the following code: + *

+     * MethodHandle invoker = exactInvoker(type);
+     * MethodType genericType = MethodType.makeGeneric(objectArgCount, varargs);
+     * genericType = genericType.insertParameterType(0, MethodHandle.class);
+     * if (!varargs)
+     *     return convertArguments(invoker, genericType);
+     * else
+     *     return spreadArguments(invoker, genericType);
+     * 
+ * @param type the desired target type + * @param objectArgCount number of fixed (non-varargs) {@code Object} arguments + * @param varargs if true, the invoker will accept a final {@code Object[]} argument + * @return a method handle suitable for invoking any method handle of the given type + */ + static public + MethodHandle genericInvoker(MethodType type, int objectArgCount, boolean varargs) { + return invokers(type).genericInvoker(); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Give a method handle which will take a invoke any method handle of the + * given type. The resulting invoker will have a type which is + * exactly equal to the desired type, except that it will accept + * an additional leading argument of type {@code MethodHandle}. + *

+ * This is a convenience method equivalent to the following code: + *

+     *     MethodHandles.lookup().findVirtual(MethodHandle.class, "invoke", type);
+     * 
+ * @param type the desired target type + * @return a method handle suitable for invoking any method handle of the given type + */ + static public + MethodHandle exactInvoker(MethodType type) { + return invokers(type).exactInvoker(); + } + + static private Invokers invokers(MethodType type) { + return MethodTypeImpl.invokers(IMPL_TOKEN, type); + } + + /** + * WORK IN PROGRESS: + * Perform value checking, exactly as if for an adapted method handle. + * It is assumed that the given value is either null, of type T0, + * or (if T0 is primitive) of the wrapper type corresponding to T0. + * The following checks and conversions are made: + *
    + *
  • If T0 and T1 are references, then a cast to T1 is applied. + * (The types do not need to be related in any particular way.) + *
  • If T0 and T1 are primitives, then a widening or narrowing + * conversion is applied, if one exists. + *
  • If T0 is a primitive and T1 a reference, and + * T0 has a wrapper type TW, a boxing conversion to TW is applied, + * possibly followed by a reference conversion. + * T1 must be TW or a supertype. + *
  • If T0 is a reference and T1 a primitive, and + * T1 has a wrapper type TW, an unboxing conversion is applied, + * possibly preceded by a reference conversion. + * T0 must be TW or a supertype. + *
  • If T1 is void, the return value is discarded + *
  • If T0 is void and T1 a reference, a null value is introduced. + *
  • If T0 is void and T1 a primitive, a zero value is introduced. + *
+ * If the value is discarded, null will be returned. + * @param valueType + * @param value + * @return the value, converted if necessary + * @throws java.lang.ClassCastException if a cast fails + */ + static + T1 checkValue(Class t0, Class t1, Object value) + throws ClassCastException + { + if (t0 == t1) { + // no conversion needed; just reassert the same type + if (t0.isPrimitive()) + return Wrapper.asPrimitiveType(t1).cast(value); + else + return Wrapper.OBJECT.cast(value, t1); + } + boolean prim0 = t0.isPrimitive(), prim1 = t1.isPrimitive(); + if (!prim0) { + // check contract with caller + Wrapper.OBJECT.cast(value, t0); + if (!prim1) { + return Wrapper.OBJECT.cast(value, t1); + } + // convert reference to primitive by unboxing + Wrapper w1 = Wrapper.forPrimitiveType(t1); + return w1.cast(value, t1); + } + // check contract with caller: + Wrapper.asWrapperType(t0).cast(value); + Wrapper w1 = Wrapper.forPrimitiveType(t1); + return w1.cast(value, t1); + } + + static + Object checkValue(Class T1, Object value) + throws ClassCastException + { + Class T0; + if (value == null) + T0 = Object.class; + else + T0 = value.getClass(); + return checkValue(T0, T1, value); + } + + /// method handle modification (creation from other method handles) + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Produce a method handle which adapts the type of the + * given method handle to a new type, by pairwise argument conversion, + * and/or varargs conversion. + * The original type and new type must have the same number of + * arguments, or else one or both them the must be varargs types. + * The resulting method handle is guaranteed to confess a type + * which is equal to the desired new type, with any varargs property erased. + *

+ * If the original type and new type are equal, returns target. + *

+ * The following conversions are applied as needed both to + * arguments and return types. Let T0 and T1 be the differing + * new and old parameter types (or old and new return types) + * for corresponding values passed by the new and old method types. + *

+ * If an ordinary (non-varargs) parameter of the new type is + * to be boxed in a varargs parameter of the old type of type T1[], + * then T1 is the element type of the varargs array. + * Otherwise, if a varargs parameter of the new type of type T0[] + * is to be spread into one or more outgoing old type parameters, + * then T0 is the element type of the + * If the new type is varargs and the old type is not, the varargs + * argument will be checked and must be a non-null array of exactly + * the right length. If there are no parameters in the old type + * corresponding to the new varargs parameter, the varargs argument + * is also allowed to be null. + *

+ * Given those types T0, T1, one of the following conversions is applied + * if possible: + *

    + *
  • If T0 and T1 are references, then a cast to T2 is applied, + * where T2 is Object if T1 is an interface, else T1. + * (The types do not need to be related in any particular way. + * The treatment of interfaces follows the usage of the bytecode verifier.) + *
  • If T0 and T1 are primitives, then a Java casting + * conversion (JLS 5.5) is applied, if one exists. + *
  • If T0 and T1 are primitives and one is boolean, + * the boolean is treated as a one-bit unsigned integer. + * (This treatment follows the usage of the bytecode verifier.) + * A conversion from another primitive type behaves as if + * it first converts to byte, and then masks all but the low bit. + *
  • If T0 is a primitive and T1 a reference, a boxing + * conversion is applied if one exists, possibly followed by + * an reference conversion to a superclass. + * T1 must be a wrapper class or a supertype of one. + * If T1 is a wrapper class, T0 is converted if necessary + * to T1's primitive type by one of the preceding conversions. + * Otherwise, T0 is boxed, and its wrapper converted to T1. + *
  • If T0 is a reference and T1 a primitive, an unboxing + * conversion is applied if one exists, possibly preceded by + * a reference conversion to a wrapper class. + * T0 must be a wrapper class or a supertype of one. + * If T0 is a wrapper class, its primitive value is converted + * if necessary to T1 by one of the preceding conversions. + * Otherwise, T0 is converted directly to the wrapper type for T1, + * which is then unboxed. + *
  • If T1 is void, any returned value is discarded + *
  • If T0 is void and T1 a reference, a null value is introduced. + *
  • If T0 is void and T1 a primitive, a zero value is introduced. + *
+ * @param target the method handle to invoke after arguments are retyped + * @param newType the expected type of the new method handle + * @return a method handle which delegates to {@code target} after performing + * any necessary argument conversions, and arranges for any + * necessary return value conversions + * @throws WrongMethodTypeException if the conversion cannot be made + */ + public static + MethodHandle convertArguments(MethodHandle target, MethodType newType) { + MethodType oldType = target.type(); + if (oldType.equals(newType)) + return target; + MethodHandle res = MethodHandleImpl.convertArguments(IMPL_TOKEN, target, + newType, oldType, null); + if (res == null) + throw newIllegalArgumentException("cannot convert to "+newType+": "+target); + return res; + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Produce a method handle which adapts the calling sequence of the + * given method handle to a new type, by reordering the arguments. + * The resulting method handle is guaranteed to confess a type + * which is equal to the desired new type. + *

+ * The given array controls the reordering. + * Call {@code #I} the number of incoming parameters (the value + * {@code newType.parameterCount()}, and call {@code #O} the number + * of outgoing parameters (the value {@code target.type().parameterCount()}). + * Then the length of the reordering array must be {@code #O}, + * and each element must be a non-negative number less than {@code #I}. + * For every {@code N} less than {@code #O}, the {@code N}-th + * outgoing argument will be taken from the {@code I}-th incoming + * argument, where {@code I} is {@code reorder[N]}. + *

+ * The reordering array need not specify an actual permutation. + * An incoming argument will be duplicated if its index appears + * more than once in the array, and an incoming argument will be dropped + * if its index does not appear in the array. + *

+ * Pairwise conversions are applied as needed to arguments and return + * values, as with {@link #convertArguments}. + * @param target the method handle to invoke after arguments are reordered + * @param newType the expected type of the new method handle + * @param reorder a string which controls the reordering + * @return a method handle which delegates to {@code target} after performing + * any necessary argument motion and conversions, and arranges for any + * necessary return value conversions + */ + public static + MethodHandle permuteArguments(MethodHandle target, MethodType newType, int[] reorder) { + MethodType oldType = target.type(); + checkReorder(reorder, newType, oldType); + return MethodHandleImpl.convertArguments(IMPL_TOKEN, target, + newType, oldType, + reorder); + } + + private static void checkReorder(int[] reorder, MethodType newType, MethodType oldType) { + if (reorder.length == oldType.parameterCount()) { + int limit = newType.parameterCount(); + boolean bad = false; + for (int i : reorder) { + if (i < 0 || i >= limit) { + bad = true; break; + } + } + if (!bad) return; + } + throw newIllegalArgumentException("bad reorder array"); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Produce a method handle which adapts the type of the + * given method handle to a new type, by spreading the final argument. + * The resulting method handle is guaranteed to confess a type + * which is equal to the desired new type. + *

+ * The final parameter type of the new type must be an array type T[]. + * This is the type of what is called the spread argument. + * All other arguments of the new type are called ordinary arguments. + *

+ * The ordinary arguments of the new type are pairwise converted + * to the initial parameter types of the old type, according to the + * rules in {@link #convertArguments}. + * Any additional arguments in the old type + * are converted from the array element type T, + * again according to the rules in {@link #convertArguments}. + * The return value is converted according likewise. + *

+ * The call verifies that the spread argument is in fact an array + * of exactly the type length, i.e., the excess number of + * arguments in the old type over the ordinary arguments in the new type. + * If there are no excess arguments, the spread argument is also + * allowed to be null. + * @param target the method handle to invoke after the argument is prepended + * @param newType the expected type of the new method handle + * @return a new method handle which spreads its final argument, + * before calling the original method handle + */ + public static + MethodHandle spreadArguments(MethodHandle target, MethodType newType) { + MethodType oldType = target.type(); + int inargs = newType.parameterCount(); + int outargs = oldType.parameterCount(); + int spreadPos = inargs - 1; + int numSpread = (outargs - spreadPos); + MethodHandle res = null; + if (spreadPos >= 0 && numSpread >= 0) { + res = MethodHandleImpl.spreadArguments(IMPL_TOKEN, target, newType, spreadPos); + } + if (res == null) { + throw newIllegalArgumentException("cannot spread "+newType+" to " +oldType); + } + return res; + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Produce a method handle which adapts the type of the + * given method handle to a new type, by collecting a series of + * trailing arguments into an array. + * The resulting method handle is guaranteed to confess a type + * which is equal to the desired new type. + *

+ * This method is inverse to {@link #spreadArguments}. + * The final parameter type of the old type must be an array type T[], + * which is the type of what is called the spread argument. + * The trailing arguments of the new type which correspond to + * the spread argument are all converted to type T and collected + * into an array before the original method is called. + *

+ * ISSUE: Unify this with combineArguments. CollectArguments + * is combineArguments with (a) new Object[]{...} as a combiner, + * and (b) the combined arguments dropped, in favor of the combined result. + * @param target the method handle to invoke after the argument is prepended + * @param newType the expected type of the new method handle + * @return a new method handle which collects some trailings argument + * into an array, before calling the original method handle + */ + public static + MethodHandle collectArguments(MethodHandle target, MethodType newType) { + MethodType oldType = target.type(); + int inargs = newType.parameterCount(); + int outargs = oldType.parameterCount(); + int collectPos = outargs - 1; + int numCollect = (inargs - collectPos); + if (collectPos < 0 || numCollect < 0) + throw newIllegalArgumentException("wrong number of arguments"); + return MethodHandleImpl.collectArguments(IMPL_TOKEN, target, newType, collectPos); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Produce a method handle which calls the original method handle, + * after inserting the given argument at the given position. + * The type of the new method handle will drop the corresponding argument + * type from the original handle's type. + *

+ * The given argument object must match the dropped argument type. + * If the dropped argument type is a primitive, the argument object + * must be a wrapper, and is unboxed to produce the primitive. + *

+ * The pos may range between zero and N (inclusively), + * where N is the number of argument types in target, + * meaning to insert the new argument as the first or last (respectively), + * or somewhere in between. + * @param target the method handle to invoke after the argument is inserted + * @param pos where to insert the argument (zero for the first) + * @param value the argument to insert + * @return a new method handle which inserts an additional argument, + * before calling the original method handle + */ + public static + MethodHandle insertArgument(MethodHandle target, int pos, Object value) { + MethodType oldType = target.type(); + ArrayList> ptypes = + new ArrayList>(oldType.parameterList()); + int outargs = oldType.parameterCount(); + int inargs = outargs - 1; + if (pos < 0 || pos >= outargs) + throw newIllegalArgumentException("no argument type to append"); + Class valueType = ptypes.remove(pos); + value = checkValue(valueType, value); + if (pos == 0 && !valueType.isPrimitive()) { + // At least for now, make bound method handles a special case. + // This lets us get by with minimal JVM support, at the expense + // of generating signature-specific adapters as Java bytecodes. + MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, target, value); + if (bmh != null) return bmh; + // else fall through to general adapter machinery + } + return MethodHandleImpl.bindArgument(IMPL_TOKEN, target, pos, value); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Produce a method handle which calls the original method handle, + * after dropping the given argument(s) at the given position. + * The type of the new method handle will insert the given argument + * type(s), at that position, into the original handle's type. + *

+ * The pos may range between zero and N-1, + * where N is the number of argument types in target, + * meaning to drop the first or last argument (respectively), + * or an argument somewhere in between. + * @param target the method handle to invoke after the argument is dropped + * @param valueTypes the type(s) of the argument to drop + * @param pos which argument to drop (zero for the first) + * @return a new method handle which drops an argument of the given type, + * before calling the original method handle + */ + public static + MethodHandle dropArguments(MethodHandle target, int pos, Class... valueTypes) { + if (valueTypes.length == 0) return target; + MethodType oldType = target.type(); + int outargs = oldType.parameterCount(); + int inargs = outargs + valueTypes.length; + if (pos < 0 || pos >= inargs) + throw newIllegalArgumentException("no argument type to remove"); + ArrayList> ptypes = + new ArrayList>(oldType.parameterList()); + ptypes.addAll(pos, Arrays.asList(valueTypes)); + MethodType newType = MethodType.make(oldType.returnType(), ptypes); + return MethodHandleImpl.dropArguments(IMPL_TOKEN, target, newType, pos); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Make a method handle which adapts a target method handle, + * by guarding it with a test, a boolean-valued method handle. + * If the guard fails, a fallback handle is called instead. + * All three method handles must have the same corresponding + * argument and return types, except that the return type + * of the test must be boolean. + *

Here is pseudocode for the resulting adapter: + *

+     * signature T(A...);
+     * boolean test(A...);
+     * T target(A...);
+     * T fallback(A...);
+     * T adapter(A... a) {
+     *   if (test(a...))
+     *     return target(a...);
+     *   else
+     *     return fallback(a...);
+     * }
+     * 
+ * @param test method handle used for test, must return boolean + * @param target method handle to call if test passes + * @param fallback method handle to call if test fails + * @return method handle which incorporates the specified if/then/else logic + * @throws IllegalArgumentException if {@code test} does not return boolean, + * or if all three method types do not match (with the return + * type of {@code test} changed to match that of {@code target}). + */ + public static + MethodHandle guardWithTest(MethodHandle test, + MethodHandle target, + MethodHandle fallback) { + if (target.type() != fallback.type()) + throw newIllegalArgumentException("target and fallback types do not match"); + if (target.type().changeReturnType(boolean.class) != test.type()) + throw newIllegalArgumentException("target and test types do not match"); + /* { + MethodHandle invoke = findVirtual(MethodHandle.class, "invoke", target.type()); + static MethodHandle choose(boolean z, MethodHandle t, MethodHandle f) { + return z ? t : f; + } + static MethodHandle compose(MethodHandle f, MethodHandle g) { + Class initargs = g.type().parameterArray(); + f = dropArguments(f, 1, initargs); // ignore 2nd copy of args + return combineArguments(f, g); + } + // choose = \z.(z ? target : fallback) + MethodHandle choose = findVirtual(MethodHandles.class, "choose", + MethodType.make(boolean.class, MethodHandle.class, MethodHandle.class)); + choose = appendArgument(choose, target); + choose = appendArgument(choose, fallback); + MethodHandle dispatch = compose(choose, test); + // dispatch = \(a...).(test(a...) ? target : fallback) + return combineArguments(invoke, dispatch, 0); + // return \(a...).((test(a...) ? target : fallback).invoke(a...)) + } */ + return MethodHandleImpl.makeGuardWithTest(IMPL_TOKEN, test, target, fallback); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Adapt a target method handle {@code target} by first processing + * its arguments, and then calling the target. + * The initial processing is performed by a second method handle, the {@code combiner}. + * After this, control passes to the {@code target}, with the same arguments. + *

+ * The return value of the {@code combiner} is inserted into the argument list + * for the {@code target} at the indicated position {@code pos}, if it is non-negative. + * Except for this inserted argument (if any), the argument types of + * the target {@code target} and the {@code combiner} must be identical. + *

+ * (Note that {@link #dropArguments} can be used to remove any arguments + * that either the {@code combiner} or {@code target} does not wish to receive.) + *

+ * The combiner handle must have the same argument types as the + * target handle, but must return {@link MethodHandle} instead of + * the ultimate return type. The returned method handle, in turn, + * is required to have exactly the given final method type. + *

Here is pseudocode for the resulting adapter: + *

+     * signature V(A[pos]..., B...);
+     * signature T(A[pos]..., V, B...);
+     * T target(A... a, V v, B... b);
+     * V combiner(A..., B...);
+     * T adapter(A... a, B... b) {
+     *   V v = combiner(a..., b...);
+     *   return target(a..., v, b...);
+     * }
+     * 
+ * @param target the method handle to invoke after arguments are combined + * @param pos where the return value of {@code combiner} is to + * be inserted as an argument to {@code target} + * @param combiner method handle to call initially on the incoming arguments + * @return method handle which incorporates the specified dispatch logic + * @throws IllegalArgumentException if {@code combiner} does not itself + * return either void or the {@code pos}-th argument of {@code target}, + * or does not have the same argument types as {@code target} + * (minus the inserted argument) + */ + public static + MethodHandle combineArguments(MethodHandle target, int pos, MethodHandle combiner) { + MethodType mhType = target.type(); + Class combineType = combiner.type().returnType(); + MethodType incomingArgs; + if (pos < 0) { + // No inserted argument; target & combiner must have same argument types. + incomingArgs = mhType; + if (!incomingArgs.changeReturnType(combineType).equals(combiner.type())) + throw newIllegalArgumentException("target and combiner types do not match"); + } else { + // Inserted argument. + if (pos >= mhType.parameterCount() + || mhType.parameterType(pos) != combineType) + throw newIllegalArgumentException("inserted combiner argument does not match target"); + incomingArgs = mhType.dropParameterType(pos); + } + if (!incomingArgs.changeReturnType(combineType).equals(combiner.type())) { + throw newIllegalArgumentException("target and combiner types do not match"); + } + return MethodHandleImpl.combineArguments(IMPL_TOKEN, target, combiner, pos); + } + +} diff --git a/jdk/src/share/classes/java/dyn/MethodType.java b/jdk/src/share/classes/java/dyn/MethodType.java new file mode 100644 index 00000000000..8e340de18f0 --- /dev/null +++ b/jdk/src/share/classes/java/dyn/MethodType.java @@ -0,0 +1,575 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.dyn; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import sun.dyn.Access; +import sun.dyn.Invokers; +import sun.dyn.MethodTypeImpl; +import sun.dyn.util.BytecodeSignature; +import static sun.dyn.MemberName.newIllegalArgumentException; + +/** + * Run-time token used to match call sites with method handles. + * The structure is a return type accompanied by any number of parameter types. + * The types (primitive, void, and reference) are represented by Class objects. + * All instances of MethodType are immutable. + * Two instances are completely interchangeable if they compare equal. + * Equality depends exactly on the return and parameter types. + *

+ * This type can be created only by factory methods, which manage interning. + * + * @author John Rose, JSR 292 EG + */ +public final +class MethodType { + private final Class rtype; + private final Class[] ptypes; + private MethodTypeForm form; // erased form, plus cached data about primitives + private MethodType wrapAlt; // alternative wrapped/unwrapped version + private Invokers invokers; // cache of handy higher-order adapters + + private static final Access IMPL_TOKEN = Access.getToken(); + + // share a cache with a friend in this package + Invokers getInvokers() { return invokers; } + void setInvokers(Invokers inv) { invokers = inv; } + + static { + // This hack allows the implementation package special access to + // the internals of MethodType. In particular, the Form has all sorts + // of cached information useful to the implementation code. + MethodTypeImpl.setMethodTypeFriend(IMPL_TOKEN, new MethodTypeImpl.MethodTypeFriend() { + public Class[] ptypes(MethodType mt) { return mt.ptypes; } + public MethodTypeImpl form(MethodType mt) { return mt.form; } + public void setForm(MethodType mt, MethodTypeImpl form) { + assert(mt.form == null); + mt.form = (MethodTypeForm) form; + } + public MethodType makeImpl(Class rtype, Class[] ptypes, boolean trusted) { + return MethodType.makeImpl(rtype, ptypes, trusted); + } + public MethodTypeImpl newMethodTypeForm(MethodType mt) { + return new MethodTypeForm(mt); + } + public Invokers getInvokers(MethodType mt) { return mt.invokers; } + public void setInvokers(MethodType mt, Invokers inv) { mt.invokers = inv; } + }); + } + + private MethodType(Class rtype, Class[] ptypes) { + checkRtype(rtype); + checkPtypes(ptypes); + this.rtype = rtype; + this.ptypes = ptypes; + } + + private void checkRtype(Class rtype) { + rtype.equals(rtype); // null check + } + private void checkPtypes(Class[] ptypes) { + for (Class ptype : ptypes) { + ptype.equals(ptype); // null check + if (ptype == void.class) + throw newIllegalArgumentException("void parameter: "+this); + } + } + + static final HashMap internTable + = new HashMap(); + + static final Class[] NO_PTYPES = {}; + + /** Find or create an instance of the given method type. + * @param rtype the return type + * @param ptypes the parameter types + * @return the interned method type with the given parts + * @throws NullPointerException if rtype or any ptype is null + * @throws IllegalArgumentException if any of the ptypes is void + */ + public static + MethodType make(Class rtype, Class[] ptypes) { + return makeImpl(rtype, ptypes, false); + } + + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. */ + public static + MethodType make(Class rtype, List> ptypes) { + return makeImpl(rtype, ptypes.toArray(NO_PTYPES), true); + } + + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. + * The leading parameter type is prepended to the remaining array. + */ + public static + MethodType make(Class rtype, Class ptype0, Class... ptypes) { + Class[] ptypes1 = new Class[1+ptypes.length]; + ptypes1[0] = ptype0; + System.arraycopy(ptypes, 0, ptypes1, 1, ptypes.length); + return makeImpl(rtype, ptypes1, true); + } + + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. + * The resulting method has no parameter types. + */ + public static + MethodType make(Class rtype) { + return makeImpl(rtype, NO_PTYPES, true); + } + + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. + * The resulting method has the single given parameter type. + */ + public static + MethodType make(Class rtype, Class ptype0) { + return makeImpl(rtype, new Class[]{ ptype0 }, true); + } + + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. + * The resulting method has the same parameter types as {@code ptypes}, + * and the specified return type. + */ + public static + MethodType make(Class rtype, MethodType ptypes) { + return makeImpl(rtype, ptypes.ptypes, true); + } + + /** + * Sole factory method to find or create an interned method type. + * @param rtype desired return type + * @param ptypes desired parameter types + * @param trusted whether the ptypes can be used without cloning + * @return the unique method type of the desired structure + */ + private static + MethodType makeImpl(Class rtype, Class[] ptypes, boolean trusted) { + if (ptypes == null || ptypes.length == 0) { + ptypes = NO_PTYPES; trusted = true; + } + MethodType mt1 = new MethodType(rtype, ptypes); + MethodType mt0; + synchronized (internTable) { + mt0 = internTable.get(mt1); + if (mt0 != null) + return mt0; + } + if (!trusted) + // defensively copy the array passed in by the user + mt1 = new MethodType(rtype, ptypes.clone()); + // promote the object to the Real Thing, and reprobe + MethodTypeImpl.initForm(IMPL_TOKEN, mt1); + synchronized (internTable) { + mt0 = internTable.get(mt1); + if (mt0 != null) + return mt0; + internTable.put(mt1, mt1); + } + return mt1; + } + + // Entry point from JVM. TODO: Change the name & signature. + private static MethodType makeImpl(Class rtype, Class[] ptypes, + boolean ignore1, boolean ignore2) { + return makeImpl(rtype, ptypes, true); + } + + private static final MethodType[] objectOnlyTypes = new MethodType[20]; + + /** + * Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}. + * All parameters and the return type will be Object, except the final varargs parameter if any. + * @param objectArgCount number of parameters (excluding the varargs parameter if any) + * @param varargs whether there will be a varargs parameter, of type Object[] + * @return a totally generic method type, given only its count of parameters and varargs + * @see #makeGeneric(int) + */ + public static + MethodType makeGeneric(int objectArgCount, boolean varargs) { + MethodType mt; + int ivarargs = (!varargs ? 0 : 1); + int ootIndex = objectArgCount*2 + ivarargs; + if (ootIndex < objectOnlyTypes.length) { + mt = objectOnlyTypes[ootIndex]; + if (mt != null) return mt; + } + Class[] ptypes = new Class[objectArgCount + ivarargs]; + Arrays.fill(ptypes, Object.class); + if (ivarargs != 0) ptypes[objectArgCount] = Object[].class; + mt = makeImpl(Object.class, ptypes, true); + if (ootIndex < objectOnlyTypes.length) { + objectOnlyTypes[ootIndex] = mt; // cache it here also! + } + return mt; + } + + /** + * All parameters and the return type will be Object. + * @param objectArgCount number of parameters + * @return a totally generic method type, given only its count of parameters + * @see #makeGeneric(int, boolean) + */ + public static + MethodType makeGeneric(int objectArgCount) { + return makeGeneric(objectArgCount, false); + } + + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}. + * @param num the index (zero-based) of the parameter type to change + * @param nptype a new parameter type to replace the old one with + * @return the same type, except with the selected parameter changed + */ + public MethodType changeParameterType(int num, Class nptype) { + if (parameterType(num) == nptype) return this; + Class[] nptypes = ptypes.clone(); + nptypes[num] = nptype; + return makeImpl(rtype, nptypes, true); + } + + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}. + * @param num the position (zero-based) of the inserted parameter type + * @param nptype a new parameter type to insert into the parameter list + * @return the same type, except with the selected parameter inserted + */ + public MethodType insertParameterType(int num, Class nptype) { + int len = ptypes.length; + Class[] nptypes = Arrays.copyOfRange(ptypes, 0, len+1); + System.arraycopy(nptypes, num, nptypes, num+1, len-num); + nptypes[num] = nptype; + return makeImpl(rtype, nptypes, true); + } + + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}. + * @param num the index (zero-based) of the parameter type to remove + * @return the same type, except with the selected parameter removed + */ + public MethodType dropParameterType(int num) { + int len = ptypes.length; + Class[] nptypes; + if (num == 0) { + nptypes = Arrays.copyOfRange(ptypes, 1, len); + } else { + nptypes = Arrays.copyOfRange(ptypes, 0, len-1); + System.arraycopy(ptypes, num+1, nptypes, num, (len-1)-num); + } + return makeImpl(rtype, nptypes, true); + } + + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}. + * @param nrtype a return parameter type to replace the old one with + * @return the same type, except with the return type change + */ + public MethodType changeReturnType(Class nrtype) { + if (returnType() == nrtype) return this; + return makeImpl(nrtype, ptypes, true); + } + + /** Convenience method. + * Report if this type contains a primitive argument or return value. + * @return true if any of the types are primitives + */ + public boolean hasPrimitives() { + return form.hasPrimitives(); + } + + /** Convenience method. + * Report if this type contains a wrapper argument or return value. + * Wrappers are types which box primitive values, such as {@link Integer}. + * @return true if any of the types are wrappers + */ + public boolean hasWrappers() { + return unwrap() != this; + } + + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. + * Erase all reference types to Object. + * @return a version of the original type with all reference types replaced + */ + public MethodType erase() { + return form.erasedType(); + } + + /** Convenience method for {@link #makeGeneric(int)}. + * Convert all types, both reference and primitive, to Object. + * @return a version of the original type with all types replaced + */ + public MethodType generic() { + return makeGeneric(parameterCount()); + } + + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. + * Convert all primitive types to their corresponding wrapper types. + * A {@code void} return type is changed to the type {@code java.lang.Void}. + * @return a version of the original type with all primitive types replaced + */ + public MethodType wrap() { + return hasPrimitives() ? wrapWithPrims(this) : this; + } + + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. + * Convert all wrapper types to their corresponding primitive types. + * A return type of {@code java.lang.Void} is changed to {@code void}. + * @return a version of the original type with all wrapper types replaced + */ + public MethodType unwrap() { + MethodType noprims = !hasPrimitives() ? this : wrapWithPrims(this); + return unwrapWithNoPrims(noprims); + } + + private static MethodType wrapWithPrims(MethodType pt) { + assert(pt.hasPrimitives()); + MethodType wt = pt.wrapAlt; + if (wt == null) { + // fill in lazily + wt = MethodTypeImpl.canonicalize(pt, MethodTypeImpl.WRAP, MethodTypeImpl.WRAP); + assert(wt != null); + pt.wrapAlt = wt; + } + return wt; + } + + private static MethodType unwrapWithNoPrims(MethodType wt) { + assert(!wt.hasPrimitives()); + MethodType uwt = wt.wrapAlt; + if (uwt == null) { + // fill in lazily + uwt = MethodTypeImpl.canonicalize(wt, MethodTypeImpl.UNWRAP, MethodTypeImpl.UNWRAP); + if (uwt == null) + uwt = wt; // type has no wrappers or prims at all + wt.wrapAlt = uwt; + } + return uwt; + } + + /** @param num the index (zero-based) of the desired parameter type + * @return the selected parameter type + */ + public Class parameterType(int num) { + return ptypes[num]; + } + /** @return the number of parameter types */ + public int parameterCount() { + return ptypes.length; + } + /** @return the return type */ + public Class returnType() { + return rtype; + } + + /** + * Convenience method to present the arguments as a list. + * @return the parameter types (as an immutable list) + */ + public List> parameterList() { + return Collections.unmodifiableList(Arrays.asList(ptypes)); + } + + /** + * Convenience method to present the arguments as an array. + * @return the parameter types (as a fresh copy if necessary) + */ + public Class[] parameterArray() { + return ptypes.clone(); + } + + /** + * Compares the specified object with this type for equality. + * That is, it returns true if and only if the specified object + * is also a method type with exactly the same parameters and return type. + * @param x object to compare + * @see Object#equals(Object) + */ + @Override + public boolean equals(Object x) { + return this == x || x instanceof MethodType && equals((MethodType)x); + } + + private boolean equals(MethodType that) { + return this.rtype == that.rtype + && Arrays.equals(this.ptypes, that.ptypes); + } + + /** + * Returns the hash code value for this method type. + * It is defined to be the same as the hashcode of a List + * whose elements are the return type followed by the + * parameter types. + * @return the hash code value for this method type + * @see Object#hashCode() + * @see #equals(Object) + * @see List#hashCode() + */ + @Override + public int hashCode() { + int hashCode = 31 + rtype.hashCode(); + for (Class ptype : ptypes) + hashCode = 31*hashCode + ptype.hashCode(); + return hashCode; + } + + /** + * The string representation of a method type is a + * parenthesis enclosed, comma separated list of type names, + * followed immediately by the return type. + *

+ * If a type name is array, it the base type followed + * by [], rather than the Class.getName of the array type. + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("("); + for (int i = 0; i < ptypes.length; i++) { + if (i > 0) sb.append(","); + putName(sb, ptypes[i]); + } + sb.append(")"); + putName(sb, rtype); + return sb.toString(); + } + + static void putName(StringBuilder sb, Class cls) { + int brackets = 0; + while (cls.isArray()) { + cls = cls.getComponentType(); + brackets++; + } + String n = cls.getName(); + /* + if (n.startsWith("java.lang.")) { + String nb = n.substring("java.lang.".length()); + if (nb.indexOf('.') < 0) n = nb; + } else if (n.indexOf('.') < 0) { + n = "."+n; // anonymous package + } + */ + sb.append(n); + while (brackets > 0) { + sb.append("[]"); + brackets--; + } + } + + /// Queries which have to do with the bytecode architecture + + /** The number of JVM stack slots required to invoke a method + * of this type. Note that (for historic reasons) the JVM requires + * a second stack slot to pass long and double arguments. + * So this method returns {@link #parameterCount()} plus the + * number of long and double parameters (if any). + *

+ * This method is included for the benfit of applications that must + * generate bytecodes that process method handles and invokedynamic. + * @return the number of JVM stack slots for this type's parameters + */ + public int parameterSlotCount() { + return form.parameterSlotCount(); + } + + /** Number of JVM stack slots which carry all parameters after + * the given position, which must be in the range of 0 to + * {@code parameterCount} inclusive. Successive parameters are + * more shallowly stacked, and parameters are indexed in the bytecodes + * according to their trailing edge. Thus, to obtain the depth + * in the outgoing call stack of parameter {@code N}, obtain + * the {@code parameterSlotDepth} of its trailing edge + * at position {@code N+1}. + *

+ * Parameters of type {@code long} and {@code double} occupy + * two stack slots (for historical reasons) and all others occupy one. + * Therefore, the number returned is the number of arguments + * including and after the given parameter, + * plus the number of long or double arguments + * at or after after the argument for the given parameter. + *

+ * This method is included for the benfit of applications that must + * generate bytecodes that process method handles and invokedynamic. + * @param num an index (zero-based, inclusive) within the parameter types + * @return the index of the (shallowest) JVM stack slot transmitting the + * given parameter + */ + public int parameterSlotDepth(int num) { + if (num < 0 || num > ptypes.length) + parameterType(num); // force a range check + return form.parameterToArgSlot(num-1); + } + + /** The number of JVM stack slots required to receive a return value + * from a method of this type. + * If the {@link #returnType() return type} is void, it will be zero, + * else if the return type is long or double, it will be two, else one. + *

+ * This method is included for the benfit of applications that must + * generate bytecodes that process method handles and invokedynamic. + * @return the number of JVM stack slots (0, 1, or 2) for this type's return value + */ + public int returnSlotCount() { + return form.returnSlotCount(); + } + + /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. + * Find or create an instance (interned) of the given method type. + * Any class or interface name embedded in the signature string + * will be resolved by calling {@link ClassLoader#loadClass(java.lang.String)} + * on the given loader (or if it is null, on the system class loader). + *

+ * Note that it is possible to build method types which cannot be + * constructed by this method, because their component types are + * not all reachable from a common class loader. + *

+ * This method is included for the benfit of applications that must + * generate bytecodes that process method handles and invokedynamic. + * @param bytecodeSignature a bytecode-level signature string "(T...)T" + * @param loader the class loader in which to look up the types + * @return a method type matching the bytecode-level signature + * @throws IllegalArgumentException if the string is not well-formed + * @throws TypeNotPresentException if a named type cannot be found + */ + public static MethodType fromBytecodeString(String bytecodeSignature, ClassLoader loader) + throws IllegalArgumentException, TypeNotPresentException + { + List> types = BytecodeSignature.parseMethod(bytecodeSignature, loader); + Class rtype = types.remove(types.size() - 1); + Class[] ptypes = types.toArray(NO_PTYPES); + return makeImpl(rtype, ptypes, true); + } + + /** + * Create a bytecode signature representation of the type. + * Note that this is not a strict inverse of + *

+ * This method is included for the benfit of applications that must + * generate bytecodes that process method handles and invokedynamic. + * {@link #fromBytecodeString(java.lang.String, java.lang.ClassLoader)}, + * because the latter requires a suitable class loader argument. + * @return the bytecode signature representation + */ + public String toBytecodeString() { + return BytecodeSignature.unparse(this); + } +} diff --git a/jdk/src/share/classes/java/dyn/MethodTypeForm.java b/jdk/src/share/classes/java/dyn/MethodTypeForm.java new file mode 100644 index 00000000000..d37ba91f7a8 --- /dev/null +++ b/jdk/src/share/classes/java/dyn/MethodTypeForm.java @@ -0,0 +1,39 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.dyn; + +/** + * TO DO: Temporary shim; remove after refactoring effects are complete in JVM. + * @author John Rose + */ +import sun.dyn.MethodTypeImpl; + +class MethodTypeForm extends MethodTypeImpl { + + MethodTypeForm(MethodType erasedType) { + super(erasedType); + } +} diff --git a/jdk/src/share/classes/java/dyn/NoAccessException.java b/jdk/src/share/classes/java/dyn/NoAccessException.java new file mode 100644 index 00000000000..bb83b401cce --- /dev/null +++ b/jdk/src/share/classes/java/dyn/NoAccessException.java @@ -0,0 +1,75 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.dyn; + +/** + * Thrown to indicate that a caller has attempted to create a method handle + * which calls a method to which the caller does not have access. + * This unchecked exception is analogous to {@link IllegalAccessException}, + * which is a checked exception thrown when reflective invocation fails + * because of an access check. With method handles, this same access + * checking is performed on behalf of the method handle creator, + * at the time of creation. + * @author John Rose, JSR 292 EG + */ +public class NoAccessException extends RuntimeException { + /** + * Constructs a {@code NoAccessException} with no detail message. + */ + public NoAccessException() { + super(); + } + + /** + * Constructs a {@code NoAccessException} with the specified + * detail message. + * + * @param s the detail message + */ + public NoAccessException(String s) { + super(s); + } + + /** + * Constructs a {@code NoAccessException} with the specified cause. + * + * @param cause the underlying cause of the exception + */ + public NoAccessException(Throwable cause) { + super(cause); + } + + /** + * Constructs a {@code NoAccessException} with the specified + * detail message and cause. + * + * @param s the detail message + * @param cause the underlying cause of the exception + */ + public NoAccessException(String s, Throwable cause) { + super(s, cause); + } +} diff --git a/jdk/src/share/classes/java/dyn/WrongMethodTypeException.java b/jdk/src/share/classes/java/dyn/WrongMethodTypeException.java new file mode 100644 index 00000000000..08745f6711c --- /dev/null +++ b/jdk/src/share/classes/java/dyn/WrongMethodTypeException.java @@ -0,0 +1,59 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.dyn; + +/** + * Thrown to indicate that code has attempted to call a method handle + * via the wrong method type. As with the bytecode representation of + * normal Java method calls, method handle calls are strongly typed + * to a specific signature associated with a call site. + *

+ * This exception may also be thrown when two method handles are + * composed, and the system detects that their types cannot be + * matched up correctly. This amounts to an early evaluation + * of the type mismatch, at method handle construction time, + * instead of when the mismatched method handle is called. + * + * @author John Rose, JSR 292 EG + */ +public class WrongMethodTypeException extends RuntimeException { + /** + * Constructs a {@code WrongMethodTypeException} with no detail message. + */ + public WrongMethodTypeException() { + super(); + } + + /** + * Constructs a {@code WrongMethodTypeException} with the specified + * detail message. + * + * @param s the detail message. + */ + public WrongMethodTypeException(String s) { + super(s); + } +} diff --git a/jdk/src/share/classes/java/dyn/package-info.java b/jdk/src/share/classes/java/dyn/package-info.java new file mode 100644 index 00000000000..858d0e9bcbf --- /dev/null +++ b/jdk/src/share/classes/java/dyn/package-info.java @@ -0,0 +1,32 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * This package contains dynamic language support provided directly by + * the Java core class libraries and virtual machine. + * @author John Rose, JSR 292 EG + */ + +package java.dyn; diff --git a/jdk/src/share/classes/java/io/Console.java b/jdk/src/share/classes/java/io/Console.java index 201b66f71b5..abd0e0c04c2 100644 --- a/jdk/src/share/classes/java/io/Console.java +++ b/jdk/src/share/classes/java/io/Console.java @@ -503,20 +503,25 @@ public final class Console implements Flushable // Set up JavaIOAccess in SharedSecrets static { - - // Add a shutdown hook to restore console's echo state should - // it be necessary. - sun.misc.SharedSecrets.getJavaLangAccess() - .registerShutdownHook(0 /* shutdown hook invocation order */, - new Runnable() { - public void run() { - try { - if (echoOff) { - echo(true); - } - } catch (IOException x) { } - } - }); + try { + // Add a shutdown hook to restore console's echo state should + // it be necessary. + sun.misc.SharedSecrets.getJavaLangAccess() + .registerShutdownHook(0 /* shutdown hook invocation order */, + false /* only register if shutdown is not in progress */, + new Runnable() { + public void run() { + try { + if (echoOff) { + echo(true); + } + } catch (IOException x) { } + } + }); + } catch (IllegalStateException e) { + // shutdown is already in progress and console is first used + // by a shutdown hook + } sun.misc.SharedSecrets.setJavaIOAccess(new sun.misc.JavaIOAccess() { public Console console() { diff --git a/jdk/src/share/classes/java/io/DeleteOnExitHook.java b/jdk/src/share/classes/java/io/DeleteOnExitHook.java index 1dc5c9d85bc..44d604c4d99 100644 --- a/jdk/src/share/classes/java/io/DeleteOnExitHook.java +++ b/jdk/src/share/classes/java/io/DeleteOnExitHook.java @@ -34,23 +34,31 @@ import java.io.File; */ class DeleteOnExitHook { - static { - sun.misc.SharedSecrets.getJavaLangAccess() - .registerShutdownHook(2 /* Shutdown hook invocation order */, - new Runnable() { - public void run() { - runHooks(); - } - }); - } - private static LinkedHashSet files = new LinkedHashSet(); + static { + // DeleteOnExitHook must be the last shutdown hook to be invoked. + // Application shutdown hooks may add the first file to the + // delete on exit list and cause the DeleteOnExitHook to be + // registered during shutdown in progress. So set the + // registerShutdownInProgress parameter to true. + sun.misc.SharedSecrets.getJavaLangAccess() + .registerShutdownHook(2 /* Shutdown hook invocation order */, + true /* register even if shutdown in progress */, + new Runnable() { + public void run() { + runHooks(); + } + } + ); + } private DeleteOnExitHook() {} static synchronized void add(String file) { - if(files == null) + if(files == null) { + // DeleteOnExitHook is running. Too late to add a file throw new IllegalStateException("Shutdown in progress"); + } files.add(file); } diff --git a/jdk/src/share/classes/java/lang/ApplicationShutdownHooks.java b/jdk/src/share/classes/java/lang/ApplicationShutdownHooks.java index b3341de15a4..1afe8fad2b3 100644 --- a/jdk/src/share/classes/java/lang/ApplicationShutdownHooks.java +++ b/jdk/src/share/classes/java/lang/ApplicationShutdownHooks.java @@ -35,17 +35,26 @@ import java.util.*; */ class ApplicationShutdownHooks { + /* The set of registered hooks */ + private static IdentityHashMap hooks; static { - Shutdown.add(1 /* shutdown hook invocation order */, - new Runnable() { - public void run() { - runHooks(); + try { + Shutdown.add(1 /* shutdown hook invocation order */, + false /* not registered if shutdown in progress */, + new Runnable() { + public void run() { + runHooks(); + } } - }); + ); + hooks = new IdentityHashMap(); + } catch (IllegalStateException e) { + // application shutdown hooks cannot be added if + // shutdown is in progress. + hooks = null; + } } - /* The set of registered hooks */ - private static IdentityHashMap hooks = new IdentityHashMap(); private ApplicationShutdownHooks() {} diff --git a/jdk/src/share/classes/java/lang/Shutdown.java b/jdk/src/share/classes/java/lang/Shutdown.java index b77b45056a7..2d0b0dd03e2 100644 --- a/jdk/src/share/classes/java/lang/Shutdown.java +++ b/jdk/src/share/classes/java/lang/Shutdown.java @@ -53,6 +53,9 @@ class Shutdown { private static final int MAX_SYSTEM_HOOKS = 10; private static final Runnable[] hooks = new Runnable[MAX_SYSTEM_HOOKS]; + // the index of the currently running shutdown hook to the hooks array + private static int currentRunningHook = 0; + /* The preceding static fields are protected by this lock */ private static class Lock { }; private static Object lock = new Lock(); @@ -68,17 +71,39 @@ class Shutdown { } - /* Add a new shutdown hook. Checks the shutdown state and the hook itself, + /** + * Add a new shutdown hook. Checks the shutdown state and the hook itself, * but does not do any security checks. + * + * The registerShutdownInProgress parameter should be false except + * registering the DeleteOnExitHook since the first file may + * be added to the delete on exit list by the application shutdown + * hooks. + * + * @params slot the slot in the shutdown hook array, whose element + * will be invoked in order during shutdown + * @params registerShutdownInProgress true to allow the hook + * to be registered even if the shutdown is in progress. + * @params hook the hook to be registered + * + * @throw IllegalStateException + * if registerShutdownInProgress is false and shutdown is in progress; or + * if registerShutdownInProgress is true and the shutdown process + * already passes the given slot */ - static void add(int slot, Runnable hook) { + static void add(int slot, boolean registerShutdownInProgress, Runnable hook) { synchronized (lock) { - if (state > RUNNING) - throw new IllegalStateException("Shutdown in progress"); - if (hooks[slot] != null) throw new InternalError("Shutdown hook at slot " + slot + " already registered"); + if (!registerShutdownInProgress) { + if (state > RUNNING) + throw new IllegalStateException("Shutdown in progress"); + } else { + if (state > HOOKS || (state == HOOKS && slot <= currentRunningHook)) + throw new IllegalStateException("Shutdown in progress"); + } + hooks[slot] = hook; } } @@ -86,11 +111,15 @@ class Shutdown { /* Run all registered shutdown hooks */ private static void runHooks() { - /* We needn't bother acquiring the lock just to read the hooks field, - * since the hooks can't be modified once shutdown is in progress - */ - for (Runnable hook : hooks) { + for (int i=0; i < MAX_SYSTEM_HOOKS; i++) { try { + Runnable hook; + synchronized (lock) { + // acquire the lock to make sure the hook registered during + // shutdown is visible here. + currentRunningHook = i; + hook = hooks[i]; + } if (hook != null) hook.run(); } catch(Throwable t) { if (t instanceof ThreadDeath) { diff --git a/jdk/src/share/classes/java/lang/System.java b/jdk/src/share/classes/java/lang/System.java index 6c539b28e1c..902591332de 100644 --- a/jdk/src/share/classes/java/lang/System.java +++ b/jdk/src/share/classes/java/lang/System.java @@ -1171,8 +1171,8 @@ public final class System { public void blockedOn(Thread t, Interruptible b) { t.blockedOn(b); } - public void registerShutdownHook(int slot, Runnable r) { - Shutdown.add(slot, r); + public void registerShutdownHook(int slot, boolean registerShutdownInProgress, Runnable hook) { + Shutdown.add(slot, registerShutdownInProgress, hook); } }); } diff --git a/jdk/src/share/classes/java/util/zip/ZipFile.java b/jdk/src/share/classes/java/util/zip/ZipFile.java index 8ee0bc2eb57..f37121c5256 100644 --- a/jdk/src/share/classes/java/util/zip/ZipFile.java +++ b/jdk/src/share/classes/java/util/zip/ZipFile.java @@ -154,7 +154,7 @@ class ZipFile implements ZipConstants { * @param file the ZIP file to be opened for reading * @param mode the mode in which the file is to be opened * @param charset - * the {@link java.nio.charset.Charset {@code charset}} to + * the {@linkplain java.nio.charset.Charset charset} to * be used to decode the ZIP entry name and comment that are not * encoded by using UTF-8 encoding (indicated by entry's general * purpose flag). @@ -206,7 +206,7 @@ class ZipFile implements ZipConstants { * * @param name the name of the zip file * @param charset - * the {@link java.nio.charset.Charset {@code charset}} to + * the {@linkplain java.nio.charset.Charset charset} to * be used to decode the ZIP entry name and comment that are not * encoded by using UTF-8 encoding (indicated by entry's general * purpose flag). @@ -230,7 +230,7 @@ class ZipFile implements ZipConstants { * Opens a ZIP file for reading given the specified File object. * @param file the ZIP file to be opened for reading * @param charset - * The {@link java.nio.charset.Charset {@code charset}} to be + * The {@linkplain java.nio.charset.Charset charset} to be * used to decode the ZIP entry name and comment (ignored if * the language * encoding bit of the ZIP entry's general purpose bit diff --git a/jdk/src/share/classes/java/util/zip/ZipInputStream.java b/jdk/src/share/classes/java/util/zip/ZipInputStream.java index 83f9ad4b753..ed6f331e8f6 100644 --- a/jdk/src/share/classes/java/util/zip/ZipInputStream.java +++ b/jdk/src/share/classes/java/util/zip/ZipInputStream.java @@ -84,7 +84,7 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants { * @param in the actual input stream * * @param charset - * The {@link java.nio.charset.Charset {@code charset}} to be + * The {@linkplain java.nio.charset.Charset charset} to be * used to decode the ZIP entry name (ignored if the * language * encoding bit of the ZIP entry's general purpose bit diff --git a/jdk/src/share/classes/java/util/zip/ZipOutputStream.java b/jdk/src/share/classes/java/util/zip/ZipOutputStream.java index da35ed97f14..d33a922ebbb 100644 --- a/jdk/src/share/classes/java/util/zip/ZipOutputStream.java +++ b/jdk/src/share/classes/java/util/zip/ZipOutputStream.java @@ -108,7 +108,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { * * @param out the actual output stream * - * @param charset the {@link java.nio.charset.Charset charset} + * @param charset the {@linkplain java.nio.charset.Charset charset} * to be used to encode the entry names and comments * * @since 1.7 diff --git a/jdk/src/share/classes/sun/dyn/Access.java b/jdk/src/share/classes/sun/dyn/Access.java new file mode 100644 index 00000000000..bf137c32d10 --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/Access.java @@ -0,0 +1,109 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn; + +import sun.reflect.Reflection; + +/** + * Access control to this package. + * Classes in other packages can attempt to acquire the access token, + * but will fail if they are not recognized as friends. + * Certain methods in this package, although public, require a non-null + * access token in order to proceed; they act like package-private methods. + * @author jrose + */ + +public class Access { + + private Access() { } + + /** + * The heart of this pattern: The list of classes which are + * permitted to acquire the access token, and become honorary + * members of this package. + */ + private static final String[] FRIENDS = { + "java.dyn.", "sun.dyn." + }; + + /** + * The following object is NOT public. That's the point of the pattern. + * It is package-private, so that any member of this package + * can acquire the access token, and give it away to trusted friends. + */ + static final Access TOKEN = new Access(); + + /** + * @return Access.TOKEN, if the caller is a friend of this package + */ + public static Access getToken() { + Class callc = Reflection.getCallerClass(2); + if (isFriend(callc)) + return TOKEN; + else + throw new IllegalAccessError("bad caller: " + callc); + } + + /** Is the given name the name of a class which could be our friend? */ + public static boolean isFriendName(String name) { + for (String friend : FRIENDS) { + if (name.startsWith(friend)) + return true; + } + return false; + } + + /** Is the given class a friend? True if {@link #isFriendName}, + * and the given class also shares a class loader with us. + */ + public static boolean isFriend(Class c) { + return isFriendName(c.getName()) && c.getClassLoader() == CLASS_LOADER; + } + + private static final ClassLoader CLASS_LOADER = Access.class.getClassLoader(); + + /** + * Throw an IllegalAccessError if the caller does not possess + * the Access.TOKEN. + * @param must be Access.TOKEN + */ + public static void check(Access token) { + if (token == null) + fail(); + // else it must be the unique Access.TOKEN + assert(token == Access.TOKEN); + } + private static void fail() { + final int CALLER_DEPTH = 3; + // 0: Reflection.getCC, 1: this.fail, 2: Access.*, 3: caller + Class callc = Reflection.getCallerClass(CALLER_DEPTH); + throw new IllegalAccessError("bad caller: " + callc); + } + + static { + //sun.reflect.Reflection.registerMethodsToFilter(MH.class, "getToken"); + } +} diff --git a/jdk/src/share/classes/sun/dyn/AdapterMethodHandle.java b/jdk/src/share/classes/sun/dyn/AdapterMethodHandle.java new file mode 100644 index 00000000000..334e0a563a7 --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/AdapterMethodHandle.java @@ -0,0 +1,728 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn; + +import sun.dyn.util.VerifyType; +import sun.dyn.util.Wrapper; +import java.dyn.*; +import java.util.Arrays; +import static sun.dyn.MethodHandleNatives.Constants.*; +import static sun.dyn.MethodHandleImpl.newIllegalArgumentException; + +/** + * This method handle performs simple conversion or checking of a single argument. + * @author jrose + */ +public class AdapterMethodHandle extends BoundMethodHandle { + + //MethodHandle vmtarget; // next AMH or BMH in chain or final DMH + //Object argument; // parameter to the conversion if needed + //int vmargslot; // which argument slot is affected + private final int conversion; // the type of conversion: RETYPE_ONLY, etc. + + // Constructors in this class *must* be package scoped or private. + private AdapterMethodHandle(MethodHandle target, MethodType newType, + long conv, Object convArg) { + super(newType, convArg, newType.parameterSlotDepth(1+convArgPos(conv))); + this.conversion = convCode(conv); + if (MethodHandleNatives.JVM_SUPPORT) { + // JVM might update VM-specific bits of conversion (ignore) + MethodHandleNatives.init(this, target, convArgPos(conv)); + } + } + private AdapterMethodHandle(MethodHandle target, MethodType newType, + long conv) { + this(target, newType, conv, null); + } + + private static final Access IMPL_TOKEN = Access.getToken(); + + // TO DO: When adapting another MH with a null conversion, clone + // the target and change its type, instead of adding another layer. + + /** Can a JVM-level adapter directly implement the proposed + * argument conversions, as if by MethodHandles.convertArguments? + */ + public static boolean canPairwiseConvert(MethodType newType, MethodType oldType) { + // same number of args, of course + int len = newType.parameterCount(); + if (len != oldType.parameterCount()) + return false; + + // Check return type. (Not much can be done with it.) + Class exp = newType.returnType(); + Class ret = oldType.returnType(); + if (!VerifyType.isNullConversion(ret, exp)) + return false; + + // Check args pairwise. + for (int i = 0; i < len; i++) { + Class src = newType.parameterType(i); // source type + Class dst = oldType.parameterType(i); // destination type + if (!canConvertArgument(src, dst)) + return false; + } + + return true; + } + + /** Can a JVM-level adapter directly implement the proposed + * argument conversion, as if by MethodHandles.convertArguments? + */ + public static boolean canConvertArgument(Class src, Class dst) { + // ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes, + // so we don't need to repeat so much decision making. + if (VerifyType.isNullConversion(src, dst)) { + return true; + } else if (src.isPrimitive()) { + if (dst.isPrimitive()) + return canPrimCast(src, dst); + else + return canBoxArgument(src, dst); + } else { + if (dst.isPrimitive()) + return canUnboxArgument(src, dst); + else + return true; // any two refs can be interconverted + } + } + + /** + * Create a JVM-level adapter method handle to conform the given method + * handle to the similar newType, using only pairwise argument conversions. + * For each argument, convert incoming argument to the exact type needed. + * Only null conversions are allowed on the return value (until + * the JVM supports ricochet adapters). + * The argument conversions allowed are casting, unboxing, + * integral widening or narrowing, and floating point widening or narrowing. + * @param token access check + * @param newType required call type + * @param target original method handle + * @return an adapter to the original handle with the desired new type, + * or the original target if the types are already identical + * or null if the adaptation cannot be made + */ + public static MethodHandle makePairwiseConvert(Access token, + MethodType newType, MethodHandle target) { + Access.check(token); + MethodType oldType = target.type(); + if (newType == oldType) return target; + + if (!canPairwiseConvert(newType, oldType)) + return null; + // (after this point, it is an assertion error to fail to convert) + + // Find last non-trivial conversion (if any). + int lastConv = newType.parameterCount()-1; + while (lastConv >= 0) { + Class src = newType.parameterType(lastConv); // source type + Class dst = oldType.parameterType(lastConv); // destination type + if (VerifyType.isNullConversion(src, dst)) { + --lastConv; + } else { + break; + } + } + // Now build a chain of one or more adapters. + MethodHandle adapter = target; + MethodType midType = oldType.changeReturnType(newType.returnType()); + for (int i = 0; i <= lastConv; i++) { + Class src = newType.parameterType(i); // source type + Class dst = midType.parameterType(i); // destination type + if (VerifyType.isNullConversion(src, dst)) { + // do nothing: difference is trivial + continue; + } + // Work the current type backward toward the desired caller type: + if (i != lastConv) { + midType = midType.changeParameterType(i, src); + } else { + // When doing the last (or only) real conversion, + // force all remaining null conversions to happen also. + assert(VerifyType.isNullConversion(newType, midType.changeParameterType(i, src))); + midType = newType; + } + + // Tricky case analysis follows. + // It parallels canConvertArgument() above. + if (src.isPrimitive()) { + if (dst.isPrimitive()) { + adapter = makePrimCast(token, midType, adapter, i, dst); + } else { + adapter = makeBoxArgument(token, midType, adapter, i, dst); + } + } else { + if (dst.isPrimitive()) { + // Caller has boxed a primitive. Unbox it for the target. + // The box type must correspond exactly to the primitive type. + // This is simpler than the powerful set of widening + // conversions supported by reflect.Method.invoke. + // Those conversions require a big nest of if/then/else logic, + // which we prefer to make a user responsibility. + adapter = makeUnboxArgument(token, midType, adapter, i, dst); + } else { + // Simple reference conversion. + // Note: Do not check for a class hierarchy relation + // between src and dst. In all cases a 'null' argument + // will pass the cast conversion. + adapter = makeCheckCast(token, midType, adapter, i, dst); + } + } + assert(adapter != null); + assert(adapter.type() == midType); + } + if (adapter.type() != newType) { + // Only trivial conversions remain. + adapter = makeRetypeOnly(IMPL_TOKEN, newType, adapter); + assert(adapter != null); + // Actually, that's because there were no non-trivial ones: + assert(lastConv == -1); + } + assert(adapter.type() == newType); + return adapter; + } + + /** + * Create a JVM-level adapter method handle to permute the arguments + * of the given method. + * @param token access check + * @param newType required call type + * @param target original method handle + * @param argumentMap for each target argument, position of its source in newType + * @return an adapter to the original handle with the desired new type, + * or the original target if the types are already identical + * and the permutation is null + * @throws IllegalArgumentException if the adaptation cannot be made + * directly by a JVM-level adapter, without help from Java code + */ + public static MethodHandle makePermutation(Access token, + MethodType newType, MethodHandle target, + int[] argumentMap) { + MethodType oldType = target.type(); + boolean nullPermutation = true; + for (int i = 0; i < argumentMap.length; i++) { + int pos = argumentMap[i]; + if (pos != i) + nullPermutation = false; + if (pos < 0 || pos >= newType.parameterCount()) { + argumentMap = new int[0]; break; + } + } + if (argumentMap.length != oldType.parameterCount()) + throw newIllegalArgumentException("bad permutation: "+Arrays.toString(argumentMap)); + if (nullPermutation) { + MethodHandle res = makePairwiseConvert(token, newType, target); + // well, that was easy + if (res == null) + throw newIllegalArgumentException("cannot convert pairwise: "+newType); + return res; + } + + // Check return type. (Not much can be done with it.) + Class exp = newType.returnType(); + Class ret = oldType.returnType(); + if (!VerifyType.isNullConversion(ret, exp)) + throw newIllegalArgumentException("bad return conversion for "+newType); + + // See if the argument types match up. + for (int i = 0; i < argumentMap.length; i++) { + int j = argumentMap[i]; + Class src = newType.parameterType(j); + Class dst = oldType.parameterType(i); + if (!VerifyType.isNullConversion(src, dst)) + throw newIllegalArgumentException("bad argument #"+j+" conversion for "+newType); + } + + // Now figure out a nice mix of SWAP, ROT, DUP, and DROP adapters. + // A workable greedy algorithm is as follows: + // Drop unused outgoing arguments (right to left: shallowest first). + // Duplicate doubly-used outgoing arguments (left to right: deepest first). + // Then the remaining problem is a true argument permutation. + // Marshal the outgoing arguments as required from left to right. + // That is, find the deepest outgoing stack position that does not yet + // have the correct argument value, and correct at least that position + // by swapping or rotating in the misplaced value (from a shallower place). + // If the misplaced value is followed by one or more consecutive values + // (also misplaced) issue a rotation which brings as many as possible + // into position. Otherwise make progress with either a swap or a + // rotation. Prefer the swap as cheaper, but do not use it if it + // breaks a slot pair. Prefer the rotation over the swap if it would + // preserve more consecutive values shallower than the target position. + // When more than one rotation will work (because the required value + // is already adjacent to the target position), then use a rotation + // which moves the old value in the target position adjacent to + // one of its consecutive values. Also, prefer shorter rotation + // spans, since they use fewer memory cycles for shuffling. + + throw new UnsupportedOperationException("NYI"); + } + + private static byte basicType(Class type) { + if (type == null) return T_VOID; + switch (Wrapper.forBasicType(type)) { + case BOOLEAN: return T_BOOLEAN; + case CHAR: return T_CHAR; + case FLOAT: return T_FLOAT; + case DOUBLE: return T_DOUBLE; + case BYTE: return T_BYTE; + case SHORT: return T_SHORT; + case INT: return T_INT; + case LONG: return T_LONG; + case OBJECT: return T_OBJECT; + case VOID: return T_VOID; + } + return 99; // T_ILLEGAL or some such + } + + /** Number of stack slots for the given type. + * Two for T_DOUBLE and T_FLOAT, one for the rest. + */ + private static int type2size(int type) { + assert(type >= T_BOOLEAN && type <= T_OBJECT); + return (type == T_FLOAT || type == T_DOUBLE) ? 2 : 1; + } + + /** Construct an adapter conversion descriptor for a single-argument conversion. */ + private static long makeConv(int convOp, int argnum, int src, int dest) { + assert(src == (src & 0xF)); + assert(dest == (dest & 0xF)); + assert(convOp >= OP_CHECK_CAST && convOp <= OP_PRIM_TO_REF); + long stackMove = type2size(dest) - type2size(src); + return ((long) argnum << 32 | + (long) convOp << CONV_OP_SHIFT | + (int) src << CONV_SRC_TYPE_SHIFT | + (int) dest << CONV_DEST_TYPE_SHIFT | + stackMove << CONV_STACK_MOVE_SHIFT + ); + } + private static long makeConv(int convOp, int argnum, int stackMove) { + assert(convOp >= OP_SWAP_ARGS && convOp <= OP_SPREAD_ARGS); + byte src = 0, dest = 0; + if (convOp >= OP_COLLECT_ARGS && convOp <= OP_SPREAD_ARGS) + src = dest = T_OBJECT; + return ((long) argnum << 32 | + (long) convOp << CONV_OP_SHIFT | + (int) src << CONV_SRC_TYPE_SHIFT | + (int) dest << CONV_DEST_TYPE_SHIFT | + stackMove << CONV_STACK_MOVE_SHIFT + ); + } + private static long makeConv(int convOp) { + assert(convOp == OP_RETYPE_ONLY); + return (long) convOp << CONV_OP_SHIFT; // stackMove, src, dst, argnum all zero + } + private static int convCode(long conv) { + return (int)conv; + } + private static int convArgPos(long conv) { + return (int)(conv >>> 32); + } + private static boolean convOpSupported(int convOp) { + assert(convOp >= 0 && convOp <= CONV_OP_LIMIT); + return ((1<> CONV_OP_SHIFT; } + + @Override + public String toString() { + return addTypeString(this, "Adapted[" + basicToString(nonAdapter((MethodHandle)vmtarget)) + "]"); + } + + private static MethodHandle nonAdapter(MethodHandle mh) { + return (MethodHandle) + MethodHandleNatives.getTarget(mh, ETF_DIRECT_HANDLE); + } + + /* Return one plus the position of the first non-trivial difference + * between the given types. This is not a symmetric operation; + * we are considering adapting the targetType to adapterType. + * Trivial differences are those which could be ignored by the JVM + * without subverting the verifier. Otherwise, adaptable differences + * are ones for which we could create an adapter to make the type change. + * Return zero if there are no differences (other than trivial ones). + * Return 1+N if N is the only adaptable argument difference. + * Return the -2-N where N is the first of several adaptable + * argument differences. + * Return -1 if there there are differences which are not adaptable. + */ + private static int diffTypes(MethodType adapterType, + MethodType targetType, + boolean raw) { + int diff; + diff = diffReturnTypes(adapterType, targetType, raw); + if (diff != 0) return diff; + int nargs = adapterType.parameterCount(); + if (nargs != targetType.parameterCount()) + return -1; + diff = diffParamTypes(adapterType, 0, targetType, 0, nargs, raw); + //System.out.println("diff "+adapterType); + //System.out.println(" "+diff+" "+targetType); + return diff; + } + private static int diffReturnTypes(MethodType adapterType, + MethodType targetType, + boolean raw) { + Class src = targetType.returnType(); + Class dst = adapterType.returnType(); + if ((!raw + ? VerifyType.canPassUnchecked(src, dst) + : VerifyType.canPassRaw(src, dst) + ) > 0) + return 0; // no significant difference + if (raw && !src.isPrimitive() && !dst.isPrimitive()) + return 0; // can force a reference return (very carefully!) + //if (false) return 1; // never adaptable! + return -1; // some significant difference + } + private static int diffParamTypes(MethodType adapterType, int tstart, + MethodType targetType, int astart, + int nargs, boolean raw) { + assert(nargs >= 0); + int res = 0; + for (int i = 0; i < nargs; i++) { + Class src = adapterType.parameterType(tstart+i); + Class dest = targetType.parameterType(astart+i); + if ((!raw + ? VerifyType.canPassUnchecked(src, dest) + : VerifyType.canPassRaw(src, dest) + ) <= 0) { + // found a difference; is it the only one so far? + if (res != 0) + return -1-res; // return -2-i for prev. i + res = 1+i; + } + } + return res; + } + + /** Can a retyping adapter (alone) validly convert the target to newType? */ + public static boolean canRetypeOnly(MethodType newType, MethodType targetType) { + return canRetypeOnly(newType, targetType, false); + } + /** Can a retyping adapter (alone) convert the target to newType? + * It is allowed to widen subword types and void to int, to make bitwise + * conversions between float/int and double/long, and to perform unchecked + * reference conversions on return. This last feature requires that the + * caller be trusted, and perform explicit cast conversions on return values. + */ + static boolean canRawRetypeOnly(MethodType newType, MethodType targetType) { + return canRetypeOnly(newType, targetType, true); + } + static boolean canRetypeOnly(MethodType newType, MethodType targetType, boolean raw) { + if (!convOpSupported(OP_RETYPE_ONLY)) return false; + int diff = diffTypes(newType, targetType, raw); + // %%% This assert is too strong. Factor diff into VerifyType and reconcile. + assert((diff == 0) == VerifyType.isNullConversion(newType, targetType)); + return diff == 0; + } + + /** Factory method: Performs no conversions; simply retypes the adapter. + * Allows unchecked argument conversions pairwise, if they are safe. + * Returns null if not possible. + */ + public static MethodHandle makeRetypeOnly(Access token, + MethodType newType, MethodHandle target) { + return makeRetypeOnly(token, newType, target, false); + } + public static MethodHandle makeRawRetypeOnly(Access token, + MethodType newType, MethodHandle target) { + return makeRetypeOnly(token, newType, target, true); + } + static MethodHandle makeRetypeOnly(Access token, + MethodType newType, MethodHandle target, boolean raw) { + Access.check(token); + if (!canRetypeOnly(newType, target.type(), raw)) + return null; + // TO DO: clone the target guy, whatever he is, with new type. + return new AdapterMethodHandle(target, newType, makeConv(OP_RETYPE_ONLY)); + } + + /** Can a checkcast adapter validly convert the target to newType? + * The JVM supports all kind of reference casts, even silly ones. + */ + public static boolean canCheckCast(MethodType newType, MethodType targetType, + int arg, Class castType) { + if (!convOpSupported(OP_CHECK_CAST)) return false; + Class src = newType.parameterType(arg); + Class dst = targetType.parameterType(arg); + if (!canCheckCast(src, castType) + || !VerifyType.isNullConversion(castType, dst)) + return false; + int diff = diffTypes(newType, targetType, false); + return (diff == arg+1); // arg is sole non-trivial diff + } + /** Can an primitive conversion adapter validly convert src to dst? */ + public static boolean canCheckCast(Class src, Class dst) { + return (!src.isPrimitive() && !dst.isPrimitive()); + } + + /** Factory method: Forces a cast at the given argument. + * The castType is the target of the cast, and can be any type + * with a null conversion to the corresponding target parameter. + * Return null if this cannot be done. + */ + public static MethodHandle makeCheckCast(Access token, + MethodType newType, MethodHandle target, + int arg, Class castType) { + Access.check(token); + if (!canCheckCast(newType, target.type(), arg, castType)) + return null; + long conv = makeConv(OP_CHECK_CAST, arg, 0); + return new AdapterMethodHandle(target, newType, conv, castType); + } + + /** Can an primitive conversion adapter validly convert the target to newType? + * The JVM currently supports all conversions except those between + * floating and integral types. + */ + public static boolean canPrimCast(MethodType newType, MethodType targetType, + int arg, Class convType) { + if (!convOpSupported(OP_PRIM_TO_PRIM)) return false; + Class src = newType.parameterType(arg); + Class dst = targetType.parameterType(arg); + if (!canPrimCast(src, convType) + || !VerifyType.isNullConversion(convType, dst)) + return false; + int diff = diffTypes(newType, targetType, false); + return (diff == arg+1); // arg is sole non-trivial diff + } + /** Can an primitive conversion adapter validly convert src to dst? */ + public static boolean canPrimCast(Class src, Class dst) { + if (src == dst || !src.isPrimitive() || !dst.isPrimitive()) { + return false; + } else if (Wrapper.forPrimitiveType(dst).isFloating()) { + // both must be floating types + return Wrapper.forPrimitiveType(src).isFloating(); + } else { + // both are integral, and all combinations work fine + assert(Wrapper.forPrimitiveType(src).isIntegral() && + Wrapper.forPrimitiveType(dst).isIntegral()); + return true; + } + } + + /** Factory method: Truncate the given argument with zero or sign extension, + * and/or convert between single and doubleword versions of integer or float. + * The convType is the target of the conversion, and can be any type + * with a null conversion to the corresponding target parameter. + * Return null if this cannot be done. + */ + public static MethodHandle makePrimCast(Access token, + MethodType newType, MethodHandle target, + int arg, Class convType) { + Access.check(token); + MethodType oldType = target.type(); + Class src = newType.parameterType(arg); + Class dst = oldType.parameterType(arg); + if (!canPrimCast(newType, oldType, arg, convType)) + return null; + long conv = makeConv(OP_PRIM_TO_PRIM, arg, basicType(src), basicType(convType)); + return new AdapterMethodHandle(target, newType, conv); + } + + /** Can an unboxing conversion validly convert src to dst? + * The JVM currently supports all kinds of casting and unboxing. + * The convType is the unboxed type; it can be either a primitive or wrapper. + */ + public static boolean canUnboxArgument(MethodType newType, MethodType targetType, + int arg, Class convType) { + if (!convOpSupported(OP_REF_TO_PRIM)) return false; + Class src = newType.parameterType(arg); + Class dst = targetType.parameterType(arg); + Class boxType = Wrapper.asWrapperType(convType); + convType = Wrapper.asPrimitiveType(convType); + if (!canCheckCast(src, boxType) + || boxType == convType + || !VerifyType.isNullConversion(convType, dst)) + return false; + int diff = diffTypes(newType, targetType, false); + return (diff == arg+1); // arg is sole non-trivial diff + } + /** Can an primitive unboxing adapter validly convert src to dst? */ + public static boolean canUnboxArgument(Class src, Class dst) { + return (!src.isPrimitive() && Wrapper.asPrimitiveType(dst).isPrimitive()); + } + + /** Factory method: Unbox the given argument. + * Return null if this cannot be done. + */ + public static MethodHandle makeUnboxArgument(Access token, + MethodType newType, MethodHandle target, + int arg, Class convType) { + MethodType oldType = target.type(); + Class src = newType.parameterType(arg); + Class dst = oldType.parameterType(arg); + Class boxType = Wrapper.asWrapperType(convType); + Class primType = Wrapper.asPrimitiveType(convType); + if (!canUnboxArgument(newType, oldType, arg, convType)) + return null; + MethodType castDone = newType; + if (!VerifyType.isNullConversion(src, boxType)) + castDone = newType.changeParameterType(arg, boxType); + long conv = makeConv(OP_REF_TO_PRIM, arg, T_OBJECT, basicType(primType)); + MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType); + if (castDone == newType) + return adapter; + return makeCheckCast(token, newType, adapter, arg, boxType); + } + + /** Can an primitive boxing adapter validly convert src to dst? */ + public static boolean canBoxArgument(Class src, Class dst) { + if (!convOpSupported(OP_PRIM_TO_REF)) return false; + throw new UnsupportedOperationException("NYI"); + } + + /** Factory method: Unbox the given argument. + * Return null if this cannot be done. + */ + public static MethodHandle makeBoxArgument(Access token, + MethodType newType, MethodHandle target, + int arg, Class convType) { + // this is difficult to do in the JVM because it must GC + return null; + } + + // TO DO: makeSwapArguments, makeRotateArguments, makeDuplicateArguments + + /** Can an adapter simply drop arguments to convert the target to newType? */ + public static boolean canDropArguments(MethodType newType, MethodType targetType, + int dropArgPos, int dropArgCount) { + if (dropArgCount == 0) + return canRetypeOnly(newType, targetType); + if (!convOpSupported(OP_DROP_ARGS)) return false; + if (diffReturnTypes(newType, targetType, false) != 0) + return false; + int nptypes = newType.parameterCount(); + // parameter types must be the same up to the drop point + if (dropArgPos != 0 && diffParamTypes(newType, 0, targetType, 0, dropArgPos, false) != 0) + return false; + int afterPos = dropArgPos + dropArgCount; + int afterCount = nptypes - afterPos; + if (dropArgPos < 0 || dropArgPos >= nptypes || + dropArgCount < 1 || afterPos > nptypes || + targetType.parameterCount() != nptypes - dropArgCount) + return false; + // parameter types after the drop point must also be the same + if (afterCount != 0 && diffParamTypes(newType, afterPos, targetType, dropArgPos, afterCount, false) != 0) + return false; + return true; + } + + /** Factory method: Drop selected arguments. + * Allow unchecked retyping of remaining arguments, pairwise. + * Return null if this is not possible. + */ + public static MethodHandle makeDropArguments(Access token, + MethodType newType, MethodHandle target, + int dropArgPos, int dropArgCount) { + Access.check(token); + if (dropArgCount == 0) + return makeRetypeOnly(IMPL_TOKEN, newType, target); + MethodType mt = target.type(); + int argCount = mt.parameterCount(); + if (!canDropArguments(newType, mt, dropArgPos, dropArgCount)) + return null; + int dropSlotCount, dropSlotPos; + if (dropArgCount >= argCount) { + assert(dropArgPos == argCount-1); + dropSlotPos = 0; + dropSlotCount = mt.parameterSlotCount(); + } else { + // arglist: [0: keep... | dpos: drop... | dpos+dcount: keep... ] + int lastDroppedArg = dropArgPos + dropArgCount - 1; + int lastKeptArg = dropArgPos - 1; // might be -1, which is OK + dropSlotPos = mt.parameterSlotDepth(1+lastDroppedArg); + int lastKeptSlot = mt.parameterSlotDepth(1+lastKeptArg); + dropSlotCount = lastKeptSlot - dropSlotPos; + assert(dropSlotCount >= dropArgCount); + } + long conv = makeConv(OP_DROP_ARGS, dropArgPos, +dropSlotCount); + return new AdapterMethodHandle(target, newType, dropSlotCount, conv); + } + + /** Can an adapter spread an argument to convert the target to newType? */ + public static boolean canSpreadArguments(MethodType newType, MethodType targetType, + Class spreadArgType, int spreadArgPos, int spreadArgCount) { + if (!convOpSupported(OP_SPREAD_ARGS)) return false; + if (diffReturnTypes(newType, targetType, false) != 0) + return false; + int nptypes = newType.parameterCount(); + // parameter types must be the same up to the spread point + if (spreadArgPos != 0 && diffParamTypes(newType, 0, targetType, 0, spreadArgPos, false) != 0) + return false; + int afterPos = spreadArgPos + spreadArgCount; + int afterCount = nptypes - afterPos; + if (spreadArgPos < 0 || spreadArgPos >= nptypes || + spreadArgCount < 0 || + targetType.parameterCount() != nptypes - 1 + spreadArgCount) + return false; + // parameter types after the spread point must also be the same + if (afterCount != 0 && diffParamTypes(newType, spreadArgPos+1, targetType, afterPos, afterCount, false) != 0) + return false; + // match the array element type to the spread arg types + Class rawSpreadArgType = newType.parameterType(spreadArgPos); + if (rawSpreadArgType != spreadArgType && !canCheckCast(rawSpreadArgType, spreadArgType)) + return false; + for (int i = 0; i < spreadArgCount; i++) { + Class src = VerifyType.spreadArgElementType(spreadArgType, i); + Class dst = targetType.parameterType(spreadArgPos + i); + if (src == null || !VerifyType.isNullConversion(src, dst)) + return false; + } + return true; + } + + /** Factory method: Spread selected argument. */ + public static MethodHandle makeSpreadArguments(Access token, + MethodType newType, MethodHandle target, + Class spreadArgType, int spreadArgPos, int spreadArgCount) { + Access.check(token); + MethodType mt = target.type(); + int argCount = mt.parameterCount(); + if (!canSpreadArguments(newType, mt, spreadArgType, spreadArgPos, spreadArgCount)) + return null; + int spreadSlotCount, spreadSlotPos; + if (spreadArgCount >= argCount) { + assert(spreadArgPos == argCount-1); + spreadSlotPos = 0; + spreadSlotCount = mt.parameterSlotCount(); + } else { + // arglist: [0: keep... | dpos: spread... | dpos+dcount: keep... ] + int lastSpreadArg = spreadArgPos + spreadArgCount - 1; + int lastKeptArg = spreadArgPos - 1; // might be -1, which is OK + spreadSlotPos = mt.parameterSlotDepth(1+lastSpreadArg); + int lastKeptSlot = mt.parameterSlotDepth(1+lastKeptArg); + spreadSlotCount = lastKeptSlot - spreadSlotPos; + assert(spreadSlotCount >= spreadArgCount); + } + long conv = makeConv(OP_SPREAD_ARGS, spreadArgPos, spreadSlotCount); + return new AdapterMethodHandle(target, newType, conv, spreadArgType); + } + + // TO DO: makeCollectArguments, makeFlyby, makeRicochet +} diff --git a/jdk/src/share/classes/sun/dyn/BoundMethodHandle.java b/jdk/src/share/classes/sun/dyn/BoundMethodHandle.java new file mode 100644 index 00000000000..b0c511c2171 --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/BoundMethodHandle.java @@ -0,0 +1,180 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn; + +import sun.dyn.util.VerifyType; +import sun.dyn.util.Wrapper; +import java.dyn.*; + +/** + * The flavor of method handle which emulates an invoke instruction + * on a predetermined argument. The JVM dispatches to the correct method + * when the handle is created, not when it is invoked. + * @author jrose + */ +public class BoundMethodHandle extends MethodHandle { + //MethodHandle vmtarget; // next BMH or final DMH or methodOop + private final Object argument; // argument to insert + private final int vmargslot; // position at which it is inserted + + // Constructors in this class *must* be package scoped or private. + + /** Bind a direct MH to its receiver (or first ref. argument). + * The JVM will pre-dispatch the MH if it is not already static. + */ + BoundMethodHandle(DirectMethodHandle mh, Object argument) { + super(Access.TOKEN, mh.type().dropParameterType(0)); + // check the type now, once for all: + this.argument = checkReferenceArgument(argument, mh, 0); + this.vmargslot = this.type().parameterSlotCount(); + if (MethodHandleNatives.JVM_SUPPORT) { + this.vmtarget = null; // maybe updated by JVM + MethodHandleNatives.init(this, mh, 0); + } else { + this.vmtarget = mh; + } + } + + private static final int REF_ARG = 0, PRIM_ARG = 1, SELF_ARG = 2; + + /** Insert an argument into an arbitrary method handle. + * If argnum is zero, inserts the first argument, etc. + * The argument type must be a reference. + */ + BoundMethodHandle(MethodHandle mh, Object argument, int argnum) { + this(mh, argument, argnum, mh.type().parameterType(argnum).isPrimitive() ? PRIM_ARG : REF_ARG); + } + + /** Insert an argument into an arbitrary method handle. + * If argnum is zero, inserts the first argument, etc. + */ + BoundMethodHandle(MethodHandle mh, Object argument, int argnum, int whichArg) { + super(Access.TOKEN, mh.type().dropParameterType(argnum)); + if (whichArg == PRIM_ARG) + this.argument = bindPrimitiveArgument(argument, mh, argnum); + else { + if (whichArg == SELF_ARG) argument = this; + this.argument = checkReferenceArgument(argument, mh, argnum); + } + this.vmargslot = this.type().parameterSlotDepth(argnum); + if (MethodHandleNatives.JVM_SUPPORT) { + this.vmtarget = null; // maybe updated by JVM + MethodHandleNatives.init(this, mh, argnum); + } else { + this.vmtarget = mh; + } + } + + /** For the AdapterMethodHandle subclass. + */ + BoundMethodHandle(MethodType type, Object argument, int vmargslot) { + super(Access.TOKEN, type); + this.argument = argument; + this.vmargslot = vmargslot; + assert(this.getClass() == AdapterMethodHandle.class); + } + + /** Initialize the current object as a method handle, binding it + * as the {@code argnum}th argument of the method handle {@code entryPoint}. + * The invocation type of the resulting method handle will be the + * same as {@code entryPoint}, except that the {@code argnum}th argument + * type will be dropped. + */ + public BoundMethodHandle(MethodHandle entryPoint, int argnum) { + this(entryPoint, null, argnum, SELF_ARG); + + // Note: If the conversion fails, perhaps because of a bad entryPoint, + // the MethodHandle.type field will not be filled in, and therefore + // no MH.invoke call will ever succeed. The caller may retain a pointer + // to the broken method handle, but no harm can be done with it. + } + + /** Initialize the current object as a method handle, binding it + * as the first argument of the method handle {@code entryPoint}. + * The invocation type of the resulting method handle will be the + * same as {@code entryPoint}, except that the first argument + * type will be dropped. + */ + public BoundMethodHandle(MethodHandle entryPoint) { + this(entryPoint, null, 0, SELF_ARG); + } + + /** Make sure the given {@code argument} can be used as {@code argnum}-th + * parameter of the given method handle {@code mh}, which must be a reference. + *

+ * If this fails, throw a suitable {@code WrongMethodTypeException}, + * which will prevent the creation of an illegally typed bound + * method handle. + */ + final static Object checkReferenceArgument(Object argument, MethodHandle mh, int argnum) { + Class ptype = mh.type().parameterType(argnum); + if (ptype.isPrimitive()) { + // fail + } else if (argument == null) { + return null; + } else if (VerifyType.isNullReferenceConversion(argument.getClass(), ptype)) { + return argument; + } + throw badBoundArgumentException(argument, mh, argnum); + } + + /** Make sure the given {@code argument} can be used as {@code argnum}-th + * parameter of the given method handle {@code mh}, which must be a primitive. + *

+ * If this fails, throw a suitable {@code WrongMethodTypeException}, + * which will prevent the creation of an illegally typed bound + * method handle. + */ + final static Object bindPrimitiveArgument(Object argument, MethodHandle mh, int argnum) { + Class ptype = mh.type().parameterType(argnum); + Wrapper wrap = Wrapper.forPrimitiveType(ptype); + Object zero = wrap.zero(); + if (zero == null) { + // fail + } else if (argument == null) { + if (ptype != int.class && wrap.isSubwordOrInt()) + return Integer.valueOf(0); + else + return zero; + } else if (VerifyType.isNullReferenceConversion(argument.getClass(), zero.getClass())) { + if (ptype != int.class && wrap.isSubwordOrInt()) + return Wrapper.INT.wrap(argument); + else + return argument; + } + throw badBoundArgumentException(argument, mh, argnum); + } + + final static RuntimeException badBoundArgumentException(Object argument, MethodHandle mh, int argnum) { + String atype = (argument == null) ? "null" : argument.getClass().toString(); + return new WrongMethodTypeException("cannot bind "+atype+" argument to parameter #"+argnum+" of "+mh.type()); + } + + @Override + public String toString() { + return "Bound[" + super.toString() + "]"; + } +} diff --git a/jdk/src/share/classes/sun/dyn/CallSiteImpl.java b/jdk/src/share/classes/sun/dyn/CallSiteImpl.java new file mode 100644 index 00000000000..c5ac600eacd --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/CallSiteImpl.java @@ -0,0 +1,70 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn; + +import java.dyn.*; + +/** + * The CallSite privately created by the JVM at every invokedynamic instruction. + * @author jrose + */ +class CallSiteImpl extends CallSite { + // Fields used only by the JVM. Do not use or change. + private Object vmmethod; + + // Values supplied by the JVM: + int callerMID, callerBCI; + + private CallSiteImpl(Class caller, String name, MethodType type) { + super(caller, name, type); + } + + @Override + public void setTarget(MethodHandle mh) { + checkTarget(mh); + if (MethodHandleNatives.JVM_SUPPORT) + MethodHandleNatives.linkCallSite(this, (MethodHandle) mh); + else + super.setTarget(mh); + } + + private static final MethodHandle PRIVATE_INITIALIZE_CALL_SITE = + MethodHandleImpl.IMPL_LOOKUP.findStatic(CallSite.class, "privateInitializeCallSite", + MethodType.make(void.class, CallSite.class, int.class, int.class)); + + // this is the up-call from the JVM: + static CallSite makeSite(Class caller, String name, MethodType type, + int callerMID, int callerBCI) { + MethodHandle bsm = Linkage.getBootstrapMethod(caller); + if (bsm == null) + throw new InvokeDynamicBootstrapError("class has no bootstrap method: "+caller); + CallSite site = bsm.invoke(caller, name, type); + if (site == null) + throw new InvokeDynamicBootstrapError("class bootstrap method failed to create a call site: "+caller); + PRIVATE_INITIALIZE_CALL_SITE.invoke(site, callerMID, callerBCI); + return site; + } +} diff --git a/jdk/src/share/classes/sun/dyn/DirectMethodHandle.java b/jdk/src/share/classes/sun/dyn/DirectMethodHandle.java new file mode 100644 index 00000000000..58f21fc0020 --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/DirectMethodHandle.java @@ -0,0 +1,54 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn; + +import java.dyn.*; +import static sun.dyn.MethodHandleNatives.Constants.*; + +/** + * The flavor of method handle which emulates invokespecial or invokestatic. + * @author jrose + */ +class DirectMethodHandle extends MethodHandle { + //inherited oop vmtarget; // methodOop or virtual class/interface oop + private final int vmindex; // method index within class or interface + { vmindex = VM_INDEX_UNINITIALIZED; } // JVM may change this + + // Constructors in this class *must* be package scoped or private. + DirectMethodHandle(MethodType mtype, MemberName m, boolean doDispatch, Class lookupClass) { + super(Access.TOKEN, mtype); + + assert(m.isMethod() || !doDispatch && m.isConstructor()); + if (!m.isResolved()) + throw new InternalError(); + + MethodHandleNatives.init(this, (Object) m, doDispatch, lookupClass); + } + + boolean isValid() { + return (vmindex != VM_INDEX_UNINITIALIZED); + } +} diff --git a/jdk/src/share/classes/sun/dyn/FilterGeneric.java b/jdk/src/share/classes/sun/dyn/FilterGeneric.java new file mode 100644 index 00000000000..a99eb26c9ee --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/FilterGeneric.java @@ -0,0 +1,338 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Sf, tifth 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.dyn; + +import java.dyn.JavaMethodHandle; +import java.dyn.MethodHandle; +import java.dyn.MethodType; +import java.dyn.NoAccessException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +/** + * "Flyby adapters" which apply arbitrary conversions to arguments + * on the way to a ultimate target. + * For simplicity, these are all generically typed. + * @author jrose + */ +class FilterGeneric { + // type for the outgoing call (will be generic) + private final MethodType targetType; + // position of (first) argument to participate in filtering + private final short argumentPosition; + // number of arguments to participate in filtering + private final short argumentCount; + // how the result interacts with the filtered arguments: Prepend, Append, Replace, Discard + private final char replaceMode; + // prototype adapter (clone and customize for each new target & conversion!) + private final Adapter adapter; + // entry point for adapter (Adapter mh, a...) => ... + private final MethodHandle entryPoint; + // more of them (loosely cached) + private FilterGeneric variations; + + /** Compute and cache information common to all unboxing adapters + * that can call out to targets of the erasure-family of the given erased type. + */ + // TO DO: Make this private. + FilterGeneric(MethodType targetType, short argumentPosition, short argumentCount, char replaceMode) { + if (argumentCount == 0) { + if (replaceMode == 'P' || replaceMode == 'A') replaceMode = 'R'; + if (replaceMode == 'I') argumentPosition = 0; + } + this.targetType = targetType; + this.argumentPosition = argumentPosition; + this.argumentCount = argumentCount; + this.replaceMode = replaceMode; + validate(targetType, argumentPosition, argumentCount, replaceMode); + Adapter ad = findAdapter(targetType, argumentPosition, argumentCount, replaceMode, filterType()); + if (ad == null) + ad = buildAdapterFromBytecodes(targetType, argumentPosition, argumentCount, replaceMode, filterType()); + this.adapter = ad; + this.entryPoint = ad.prototypeEntryPoint(); + } + + Adapter makeInstance(MethodHandle filter, MethodHandle target) { + return adapter.makeInstance(entryPoint, filter, target); + } + + /** Build an adapter of the given generic type, which invokes typedTarget + * on the incoming arguments, after unboxing as necessary. + * The return value is boxed if necessary. + * @param genericType the required type of the result + * @param typedTarget the target + * @return an adapter method handle + */ + public static MethodHandle make(MethodHandle target, int pos, MethodHandle filter) { + return FilterGeneric.of(target.type(), (short)pos, (short)1, 'R').makeInstance(filter, target); + } + + /** Return the adapter information for this type's erasure. */ + static FilterGeneric of(MethodType type, short ap, short ac, char mode) { + if (type.generic() != type) + throw new IllegalArgumentException("must be generic: "+type); + validate(type, ap, ac, mode); + MethodTypeImpl form = MethodTypeImpl.of(type); + FilterGeneric filterGen = form.filterGeneric; + if (filterGen == null) + form.filterGeneric = filterGen = new FilterGeneric(type, (short)0, (short)1, 'R'); + return find(filterGen, ap, ac, mode); + } + + static FilterGeneric find(FilterGeneric gen, short ap, short ac, char mode) { + for (;;) { + if (gen.argumentPosition == ap && + gen.argumentCount == ac && + gen.replaceMode == mode) { + return gen; + } + FilterGeneric gen2 = gen.variations; + if (gen2 == null) break; + gen = gen2; + } + FilterGeneric gen2 = new FilterGeneric(gen.targetType, ap, ac, mode); + gen.variations = gen2; // OK if this smashes another cached chain + return gen2; + } + + private static void validate(MethodType type, short ap, short ac, char mode) { + int endpos = ap + ac; + switch (mode) { + case 'P': case 'A': case 'R': case 'D': + if (ap >= 0 && ac >= 0 && + endpos >= 0 && endpos <= type.parameterCount()) + return; + default: + throw new InternalError("configuration "+patternName(ap, ac, mode)); + } + } + + public String toString() { + return "FilterGeneric/"+patternName()+targetType; + } + + String patternName() { + return patternName(argumentPosition, argumentCount, replaceMode); + } + + static String patternName(short ap, short ac, char mode) { + return ""+mode+ap+(ac>1?"_"+ac:""); + } + + Class filterType() { + return Object.class; // result of filter operation; an uninteresting type + } + + static MethodType targetType(MethodType entryType, short ap, short ac, char mode, + Class arg) { + MethodType type = entryType; + int pos = ap; + switch (mode) { + case 'A': + pos += ac; + case 'P': + type = type.insertParameterType(pos, arg); + break; + case 'I': + for (int i = 1; i < ac; i++) + type = type.dropParameterType(pos); + assert(type.parameterType(pos) == arg); + break; + case 'D': + break; + } + return type; + } + + static MethodType entryType(MethodType targetType, short ap, short ac, char mode, + Class arg) { + MethodType type = targetType; + int pos = ap; + switch (mode) { + case 'A': + pos += ac; + case 'P': + type = type.dropParameterType(pos); + break; + case 'I': + for (int i = 1; i < ac; i++) + type = type.insertParameterType(pos, arg); + assert(type.parameterType(pos) == arg); + break; + case 'D': + break; + } + return type; + } + + /* Create an adapter that handles spreading calls for the given type. */ + static Adapter findAdapter(MethodType targetType, short ap, short ac, char mode, Class arg) { + MethodType entryType = entryType(targetType, ap, ac, mode, arg); + int argc = targetType.parameterCount(); + String pname = patternName(ap, ac, mode); + String cname0 = "F"+argc; + String cname1 = "F"+argc+mode; + String cname2 = "F"+argc+pname; + String[] cnames = { cname0, cname1, cname1+"X", cname2 }; + String iname = "invoke_"+pname; + // e.g., F5R; invoke_R3 + for (String cname : cnames) { + Class acls = Adapter.findSubClass(cname); + if (acls == null) continue; + // see if it has the required invoke method + MethodHandle entryPoint = null; + try { + entryPoint = MethodHandleImpl.IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls); + } catch (NoAccessException ex) { + } + if (entryPoint == null) continue; + Constructor ctor = null; + try { + ctor = acls.getDeclaredConstructor(MethodHandle.class); + } catch (NoSuchMethodException ex) { + } catch (SecurityException ex) { + } + if (ctor == null) continue; + try { + // Produce an instance configured as a prototype. + return ctor.newInstance(entryPoint); + } catch (IllegalArgumentException ex) { + } catch (InvocationTargetException ex) { + } catch (InstantiationException ex) { + } catch (IllegalAccessException ex) { + } + } + return null; + } + + static Adapter buildAdapterFromBytecodes(MethodType targetType, short ap, short ac, char mode, Class arg) { + throw new UnsupportedOperationException("NYI"); + } + + /** + * This adapter takes some untyped arguments, and returns an untyped result. + * Internally, it applies the invoker to the target, which causes the + * objects to be unboxed; the result is a raw type in L/I/J/F/D. + * This result is passed to convert, which is responsible for + * converting the raw result into a boxed object. + * The invoker is kept separate from the target because it can be + * generated once per type erasure family, and reused across adapters. + */ + static abstract class Adapter extends JavaMethodHandle { + protected final MethodHandle filter; + protected final MethodHandle target; + + protected boolean isPrototype() { return target == null; } + protected Adapter(MethodHandle entryPoint) { + this(entryPoint, entryPoint, null); + assert(isPrototype()); + } + protected MethodHandle prototypeEntryPoint() { + if (!isPrototype()) throw new InternalError(); + return filter; + } + + protected Adapter(MethodHandle entryPoint, + MethodHandle filter, MethodHandle target) { + super(entryPoint); + this.filter = filter; + this.target = target; + } + + /** Make a copy of self, with new fields. */ + protected abstract Adapter makeInstance(MethodHandle entryPoint, + MethodHandle filter, MethodHandle target); + // { return new ThisType(entryPoint, filter, target); } + + static private final String CLASS_PREFIX; // "sun.dyn.FilterGeneric$" + static { + String aname = Adapter.class.getName(); + String sname = Adapter.class.getSimpleName(); + if (!aname.endsWith(sname)) throw new InternalError(); + CLASS_PREFIX = aname.substring(0, aname.length() - sname.length()); + } + /** Find a sibing class of Adapter. */ + static Class findSubClass(String name) { + String cname = Adapter.CLASS_PREFIX + name; + try { + return Class.forName(cname).asSubclass(Adapter.class); + } catch (ClassNotFoundException ex) { + return null; + } catch (ClassCastException ex) { + return null; + } + } + } + + //* generated classes follow this pattern: + static class F1RX extends Adapter { + protected F1RX(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F1RX(MethodHandle e, MethodHandle f, MethodHandle t) + { super(e, f, t); } + protected F1RX makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) + { return new F1RX(e, f, t); } + protected Object filter(Object a0) { return filter.invoke(a0); } + protected Object target(Object a0) { return target.invoke(a0); } + protected Object invoke_R0(Object a0) { return target(filter(a0)); } + } + static class F2RX extends Adapter { + protected F2RX(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F2RX(MethodHandle e, MethodHandle f, MethodHandle t) + { super(e, f, t); } + protected F2RX makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) + { return new F2RX(e, f, t); } + protected Object filter(Object a0) { return filter.invoke(a0); } + protected Object target(Object a0, Object a1) { return target.invoke(a0, a1); } + protected Object invoke_R0(Object a0, Object a1) { return target(filter(a0), a1); } + protected Object invoke_R1(Object a0, Object a1) { return target(a0, filter(a1)); } + } + static class F3RX extends Adapter { + protected F3RX(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F3RX(MethodHandle e, MethodHandle f, MethodHandle t) + { super(e, f, t); } + protected F3RX makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) + { return new F3RX(e, f, t); } + protected Object filter(Object a0) { return filter.invoke(a0); } + protected Object target(Object a0, Object a1, Object a2) { return target.invoke(a0, a1, a2); } + protected Object invoke_R0(Object a0, Object a1, Object a2) { return target(filter(a0), a1, a2); } + protected Object invoke_R1(Object a0, Object a1, Object a2) { return target(a0, filter(a1), a2); } + protected Object invoke_R2(Object a0, Object a1, Object a2) { return target(a0, a1, filter(a2)); } + } + static class F4RX extends Adapter { + protected F4RX(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F4RX(MethodHandle e, MethodHandle f, MethodHandle t) + { super(e, f, t); } + protected F4RX makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) + { return new F4RX(e, f, t); } + protected Object filter(Object a0) { return filter.invoke(a0); } + protected Object target(Object a0, Object a1, Object a2, Object a3) { return target.invoke(a0, a1, a2, a3); } + protected Object invoke_R0(Object a0, Object a1, Object a2, Object a3) { return target(filter(a0), a1, a2, a3); } + protected Object invoke_R1(Object a0, Object a1, Object a2, Object a3) { return target(a0, filter(a1), a2, a3); } + protected Object invoke_R2(Object a0, Object a1, Object a2, Object a3) { return target(a0, a1, filter(a2), a3); } + protected Object invoke_R3(Object a0, Object a1, Object a2, Object a3) { return target(a0, a1, a2, filter(a3)); } + } + // */ +} diff --git a/jdk/src/share/classes/sun/dyn/FilterOneArgument.java b/jdk/src/share/classes/sun/dyn/FilterOneArgument.java new file mode 100644 index 00000000000..c2fd98e0c09 --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/FilterOneArgument.java @@ -0,0 +1,73 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn; + +import java.dyn.JavaMethodHandle; +import java.dyn.MethodHandle; +import java.dyn.MethodHandles; +import java.dyn.MethodType; + +/** + * Unary function composition, useful for many small plumbing jobs. + * The invoke method takes a single reference argument, and returns a reference + * Internally, it first calls the {@code filter} method on the argument, + * Making up the difference between the raw method type and the + * final method type is the responsibility of a JVM-level adapter. + * @author jrose + */ +public class FilterOneArgument extends JavaMethodHandle { + protected final MethodHandle filter; // Object -> Object + protected final MethodHandle target; // Object -> Object + + protected Object entryPoint(Object argument) { + Object filteredArgument = filter.invoke(argument); + return target.invoke(filteredArgument); + } + + private static final MethodHandle entryPoint = + MethodHandleImpl.IMPL_LOOKUP.findVirtual(FilterOneArgument.class, "entryPoint", MethodType.makeGeneric(1)); + + protected FilterOneArgument(MethodHandle filter, MethodHandle target) { + super(entryPoint); + this.filter = filter; + this.target = target; + } + + public static MethodHandle make(MethodHandle filter, MethodHandle target) { + if (filter == null) return target; + if (target == null) return filter; + return new FilterOneArgument(filter, target); + } + + public String toString() { + return filter + "|>" + target; + } + +// MethodHandle make(MethodHandle filter1, MethodHandle filter2, MethodHandle target) { +// MethodHandle filter = make(filter1, filter2); +// return make(filter, target); +// } +} diff --git a/jdk/src/share/classes/sun/dyn/FromGeneric.java b/jdk/src/share/classes/sun/dyn/FromGeneric.java new file mode 100644 index 00000000000..85f35d65577 --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/FromGeneric.java @@ -0,0 +1,627 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn; + +import java.dyn.JavaMethodHandle; +import java.dyn.MethodHandle; +import java.dyn.MethodHandles; +import java.dyn.MethodType; +import java.dyn.NoAccessException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import sun.dyn.util.ValueConversions; +import sun.dyn.util.Wrapper; + +/** + * Adapters which mediate between incoming calls which are not generic + * and outgoing calls which are. Any call can be represented generically + * boxing up its arguments, and (on return) unboxing the return value. + *

+ * A call is "generic" (in MethodHandle terms) if its MethodType features + * only Object arguments. A non-generic call therefore features + * primitives and/or reference types other than Object. + * An adapter has types for its incoming and outgoing calls. + * The incoming call type is simply determined by the adapter's type + * (the MethodType it presents to callers). The outgoing call type + * is determined by the adapter's target (a MethodHandle that the adapter + * either binds internally or else takes as a leading argument). + * (To stretch the term, adapter-like method handles may have multiple + * targets or be polymorphic across multiple call types.) + *

+ * This adapter can sometimes be more directly implemented + * by the JVM's built-in OP_SPREAD_ARGS adapter. + * @author jrose + */ +class FromGeneric { + // type for the outgoing call (may have primitives, etc.) + private final MethodType targetType; + // type of the outgoing call internal to the adapter + private final MethodType internalType; + // prototype adapter (clone and customize for each new target!) + private final Adapter adapter; + // entry point for adapter (Adapter mh, a...) => ... + private final MethodHandle entryPoint; + // unboxing invoker of type (MH, Object**N) => raw return value + // it makes up the difference of internalType => targetType + private final MethodHandle unboxingInvoker; + // conversion which boxes a the target's raw return value + private final MethodHandle returnConversion; + + /** Compute and cache information common to all unboxing adapters + * that can call out to targets of the erasure-family of the given erased type. + */ + private FromGeneric(MethodType targetType) { + this.targetType = targetType; + MethodType internalType0; + // the target invoker will generally need casts on reference arguments + Adapter ad = findAdapter(internalType0 = targetType.erase()); + if (ad != null) { + // Immediate hit to exactly the adapter we want, + // with no monkeying around with primitive types. + this.internalType = internalType0; + this.adapter = ad; + this.entryPoint = ad.prototypeEntryPoint(); + this.returnConversion = computeReturnConversion(targetType, internalType0); + this.unboxingInvoker = computeUnboxingInvoker(targetType, internalType0); + return; + } + + // outgoing primitive arguments will be wrapped; unwrap them + MethodType primsAsObj = MethodTypeImpl.of(targetType).primArgsAsBoxes(); + MethodType objArgsRawRet = MethodTypeImpl.of(primsAsObj).primsAsInts(); + if (objArgsRawRet != targetType) + ad = findAdapter(internalType0 = objArgsRawRet); + if (ad == null) { + ad = buildAdapterFromBytecodes(internalType0 = targetType); + } + this.internalType = internalType0; + this.adapter = ad; + MethodType tepType = targetType.insertParameterType(0, adapter.getClass()); + this.entryPoint = ad.prototypeEntryPoint(); + this.returnConversion = computeReturnConversion(targetType, internalType0); + this.unboxingInvoker = computeUnboxingInvoker(targetType, internalType0); + } + + /** + * The typed target will be called according to targetType. + * The adapter code will in fact see the raw result from internalType, + * and must box it into an object. Produce a converter for this. + */ + private static MethodHandle computeReturnConversion( + MethodType targetType, MethodType internalType) { + Class tret = targetType.returnType(); + Class iret = internalType.returnType(); + Wrapper wrap = Wrapper.forBasicType(tret); + if (!iret.isPrimitive()) { + assert(iret == Object.class); + return ValueConversions.identity(); + } else if (wrap.primitiveType() == iret) { + return ValueConversions.box(wrap, false); + } else { + assert(tret == double.class ? iret == long.class : iret == int.class); + return ValueConversions.boxRaw(wrap, false); + } + } + + /** + * The typed target will need an exact invocation point; provide it here. + * The adapter will possibly need to make a slightly different call, + * so adapt the invoker. This way, the logic for making up the + * difference between what the adapter can call and what the target + * needs can be cached once per type. + */ + private static MethodHandle computeUnboxingInvoker( + MethodType targetType, MethodType internalType) { + // All the adapters we have here have reference-untyped internal calls. + assert(internalType == internalType.erase()); + MethodHandle invoker = MethodHandles.exactInvoker(targetType); + // cast all narrow reference types, unbox all primitive arguments: + MethodType fixArgsType = internalType.changeReturnType(targetType.returnType()); + MethodHandle fixArgs = AdapterMethodHandle.convertArguments(Access.TOKEN, + invoker, Invokers.invokerType(fixArgsType), + invoker.type(), null); + if (fixArgs == null) + throw new InternalError("bad fixArgs"); + // reinterpret the calling sequence as raw: + MethodHandle retyper = AdapterMethodHandle.makeRawRetypeOnly(Access.TOKEN, + Invokers.invokerType(internalType), fixArgs); + if (retyper == null) + throw new InternalError("bad retyper"); + return retyper; + } + + Adapter makeInstance(MethodHandle typedTarget) { + MethodType type = typedTarget.type(); + if (type == targetType) { + return adapter.makeInstance(entryPoint, unboxingInvoker, returnConversion, typedTarget); + } + // my erased-type is not exactly the same as the desired type + assert(type.erase() == targetType); // else we are busted + MethodHandle invoker = computeUnboxingInvoker(type, internalType); + return adapter.makeInstance(entryPoint, invoker, returnConversion, typedTarget); + } + + /** Build an adapter of the given generic type, which invokes typedTarget + * on the incoming arguments, after unboxing as necessary. + * The return value is boxed if necessary. + * @param genericType the required type of the result + * @param typedTarget the target + * @return an adapter method handle + */ + public static MethodHandle make(MethodHandle typedTarget) { + MethodType type = typedTarget.type(); + if (type == type.generic()) return typedTarget; + return FromGeneric.of(type).makeInstance(typedTarget); + } + + /** Return the adapter information for this type's erasure. */ + static FromGeneric of(MethodType type) { + MethodTypeImpl form = MethodTypeImpl.of(type); + FromGeneric fromGen = form.fromGeneric; + if (fromGen == null) + form.fromGeneric = fromGen = new FromGeneric(form.erasedType()); + return fromGen; + } + + public String toString() { + return "FromGeneric"+targetType; + } + + /* Create an adapter that handles spreading calls for the given type. */ + static Adapter findAdapter(MethodType internalType) { + MethodType entryType = internalType.generic(); + MethodTypeImpl form = MethodTypeImpl.of(internalType); + Class rtype = internalType.returnType(); + int argc = form.parameterCount(); + int lac = form.longPrimitiveParameterCount(); + int iac = form.primitiveParameterCount() - lac; + String intsAndLongs = (iac > 0 ? "I"+iac : "")+(lac > 0 ? "J"+lac : ""); + String rawReturn = String.valueOf(Wrapper.forPrimitiveType(rtype).basicTypeChar()); + String cname0 = rawReturn + argc; + String cname1 = "A" + argc; + String[] cnames = { cname0+intsAndLongs, cname0, cname1+intsAndLongs, cname1 }; + String iname = "invoke_"+cname0+intsAndLongs; + // e.g., D5I2, D5, L5I2, L5; invoke_D5 + for (String cname : cnames) { + Class acls = Adapter.findSubClass(cname); + if (acls == null) continue; + // see if it has the required invoke method + MethodHandle entryPoint = null; + try { + entryPoint = MethodHandleImpl.IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls); + } catch (NoAccessException ex) { + } + if (entryPoint == null) continue; + Constructor ctor = null; + try { + ctor = acls.getDeclaredConstructor(MethodHandle.class); + } catch (NoSuchMethodException ex) { + } catch (SecurityException ex) { + } + if (ctor == null) continue; + try { + // Produce an instance configured as a prototype. + return ctor.newInstance(entryPoint); + } catch (IllegalArgumentException ex) { + } catch (InvocationTargetException ex) { + } catch (InstantiationException ex) { + } catch (IllegalAccessException ex) { + } + } + return null; + } + + static Adapter buildAdapterFromBytecodes(MethodType internalType) { + throw new UnsupportedOperationException("NYI"); + } + + /** + * This adapter takes some untyped arguments, and returns an untyped result. + * Internally, it applies the invoker to the target, which causes the + * objects to be unboxed; the result is a raw type in L/I/J/F/D. + * This result is passed to convert, which is responsible for + * converting the raw result into a boxed object. + * The invoker is kept separate from the target because it can be + * generated once per type erasure family, and reused across adapters. + */ + static abstract class Adapter extends JavaMethodHandle { + /* + * class X<> extends Adapter { + * (MH, Object**N)=>raw(R) invoker; + * (any**N)=>R target; + * raw(R)=>Object convert; + * Object invoke(Object**N a) = convert(invoker(target, a...)) + * } + */ + protected final MethodHandle invoker; // (MH, Object**N) => raw(R) + protected final MethodHandle convert; // raw(R) => Object + protected final MethodHandle target; // (any**N) => R + + protected boolean isPrototype() { return target == null; } + protected Adapter(MethodHandle entryPoint) { + this(entryPoint, null, entryPoint, null); + assert(isPrototype()); + } + protected MethodHandle prototypeEntryPoint() { + if (!isPrototype()) throw new InternalError(); + return convert; + } + + protected Adapter(MethodHandle entryPoint, + MethodHandle invoker, MethodHandle convert, MethodHandle target) { + super(entryPoint); + this.invoker = invoker; + this.convert = convert; + this.target = target; + } + + /** Make a copy of self, with new fields. */ + protected abstract Adapter makeInstance(MethodHandle entryPoint, + MethodHandle invoker, MethodHandle convert, MethodHandle target); + // { return new ThisType(entryPoint, convert, target); } + + /// Conversions on the value returned from the target. + protected Object convert_L(Object result) { return convert.invoke(result); } + protected Object convert_I(int result) { return convert.invoke(result); } + protected Object convert_J(long result) { return convert.invoke(result); } + protected Object convert_F(float result) { return convert.invoke(result); } + protected Object convert_D(double result) { return convert.invoke(result); } + + static private final String CLASS_PREFIX; // "sun.dyn.FromGeneric$" + static { + String aname = Adapter.class.getName(); + String sname = Adapter.class.getSimpleName(); + if (!aname.endsWith(sname)) throw new InternalError(); + CLASS_PREFIX = aname.substring(0, aname.length() - sname.length()); + } + /** Find a sibing class of Adapter. */ + static Class findSubClass(String name) { + String cname = Adapter.CLASS_PREFIX + name; + try { + return Class.forName(cname).asSubclass(Adapter.class); + } catch (ClassNotFoundException ex) { + return null; + } catch (ClassCastException ex) { + return null; + } + } + } + + /* generated classes follow this pattern: + static class xA2 extends Adapter { + protected xA2(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected xA2(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { super(e, i, c, t); } + protected xA2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { return new xA2(e, i, c, t); } + protected Object invoke_L2(Object a0, Object a1) { return convert_L(invoker.invoke(target, a0, a1)); } + protected Object invoke_I2(Object a0, Object a1) { return convert_I(invoker.invoke(target, a0, a1)); } + protected Object invoke_J2(Object a0, Object a1) { return convert_J(invoker.invoke(target, a0, a1)); } + protected Object invoke_F2(Object a0, Object a1) { return convert_F(invoker.invoke(target, a0, a1)); } + protected Object invoke_D2(Object a0, Object a1) { return convert_D(invoker.invoke(target, a0, a1)); } + } + // */ + +/* +: SHELL; n=FromGeneric; cp -p $n.java $n.java-; sed < $n.java- > $n.java+ -e '/{{*{{/,/}}*}}/w /tmp/genclasses.java' -e '/}}*}}/q'; (cd /tmp; javac -d . genclasses.java; java -cp . genclasses) >> $n.java+; echo '}' >> $n.java+; mv $n.java+ $n.java; mv $n.java- $n.java~ +//{{{ +import java.util.*; +class genclasses { + static String[] TYPES = { "Object", "int ", "long ", "float ", "double" }; + static String[] TCHARS = { "L", "I", "J", "F", "D", "A" }; + static String[][] TEMPLATES = { { + "@for@ arity=0..10 rcat<=4 nrefs<=99 nints=0 nlongs=0", + " //@each-cat@", + " static class @cat@ extends Adapter {", + " protected @cat@(MethodHandle entryPoint) { super(entryPoint); } // to build prototype", + " protected @cat@(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)", + " { super(e, i, c, t); }", + " protected @cat@ makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)", + " { return new @cat@(e, i, c, t); }", + " //@each-R@", + " protected Object invoke_@catN@(@Tvav@) { return convert_@Rc@(invoker.<@R@>invoke(target@av@)); }", + " //@end-R@", + " }", + } }; + static final String NEWLINE_INDENT = "\n "; + enum VAR { + cat, catN, R, Rc, av, Tvav, Ovav; + public final String pattern = "@"+toString().replace('_','.')+"@"; + public String binding; + static void makeBindings(boolean topLevel, int rcat, int nrefs, int nints, int nlongs) { + int nargs = nrefs + nints + nlongs; + if (topLevel) + VAR.cat.binding = catstr(ALL_RETURN_TYPES ? TYPES.length : rcat, nrefs, nints, nlongs); + VAR.catN.binding = catstr(rcat, nrefs, nints, nlongs); + VAR.R.binding = TYPES[rcat]; + VAR.Rc.binding = TCHARS[rcat]; + String[] Tv = new String[nargs]; + String[] av = new String[nargs]; + String[] Tvav = new String[nargs]; + String[] Ovav = new String[nargs]; + for (int i = 0; i < nargs; i++) { + int tcat = (i < nrefs) ? 0 : (i < nrefs + nints) ? 1 : 2; + Tv[i] = TYPES[tcat]; + av[i] = arg(i); + Tvav[i] = param(Tv[i], av[i]); + Ovav[i] = param("Object", av[i]); + } + VAR.av.binding = comma(", ", av); + VAR.Tvav.binding = comma(Tvav); + VAR.Ovav.binding = comma(Ovav); + } + static String arg(int i) { return "a"+i; } + static String param(String t, String a) { return t+" "+a; } + static String comma(String[] v) { return comma("", v); } + static String comma(String sep, String[] v) { + if (v.length == 0) return ""; + String res = sep+v[0]; + for (int i = 1; i < v.length; i++) res += ", "+v[i]; + return res; + } + static String transform(String string) { + for (VAR var : values()) + string = string.replaceAll(var.pattern, var.binding); + return string; + } + } + static String[] stringsIn(String[] strings, int beg, int end) { + return Arrays.copyOfRange(strings, beg, Math.min(end, strings.length)); + } + static String[] stringsBefore(String[] strings, int pos) { + return stringsIn(strings, 0, pos); + } + static String[] stringsAfter(String[] strings, int pos) { + return stringsIn(strings, pos, strings.length); + } + static int indexAfter(String[] strings, int pos, String tag) { + return Math.min(indexBefore(strings, pos, tag) + 1, strings.length); + } + static int indexBefore(String[] strings, int pos, String tag) { + for (int i = pos, end = strings.length; ; i++) { + if (i == end || strings[i].endsWith(tag)) return i; + } + } + static int MIN_ARITY, MAX_ARITY, MAX_RCAT, MAX_REFS, MAX_INTS, MAX_LONGS; + static boolean ALL_ARG_TYPES, ALL_RETURN_TYPES; + static HashSet done = new HashSet(); + public static void main(String... av) { + for (String[] template : TEMPLATES) { + int forLinesLimit = indexBefore(template, 0, "@each-cat@"); + String[] forLines = stringsBefore(template, forLinesLimit); + template = stringsAfter(template, forLinesLimit); + for (String forLine : forLines) + expandTemplate(forLine, template); + } + } + static void expandTemplate(String forLine, String[] template) { + String[] params = forLine.split("[^0-9]+"); + if (params[0].length() == 0) params = stringsAfter(params, 1); + System.out.println("//params="+Arrays.asList(params)); + int pcur = 0; + MIN_ARITY = Integer.valueOf(params[pcur++]); + MAX_ARITY = Integer.valueOf(params[pcur++]); + MAX_RCAT = Integer.valueOf(params[pcur++]); + MAX_REFS = Integer.valueOf(params[pcur++]); + MAX_INTS = Integer.valueOf(params[pcur++]); + MAX_LONGS = Integer.valueOf(params[pcur++]); + if (pcur != params.length) throw new RuntimeException("bad extra param: "+forLine); + if (MAX_RCAT >= TYPES.length) MAX_RCAT = TYPES.length - 1; + ALL_ARG_TYPES = (indexBefore(template, 0, "@each-Tv@") < template.length); + ALL_RETURN_TYPES = (indexBefore(template, 0, "@each-R@") < template.length); + for (int nargs = MIN_ARITY; nargs <= MAX_ARITY; nargs++) { + for (int rcat = 0; rcat <= MAX_RCAT; rcat++) { + expandTemplate(template, true, rcat, nargs, 0, 0); + if (ALL_ARG_TYPES) break; + expandTemplateForPrims(template, true, rcat, nargs, 1, 1); + if (ALL_RETURN_TYPES) break; + } + } + } + static String catstr(int rcat, int nrefs, int nints, int nlongs) { + int nargs = nrefs + nints + nlongs; + String cat = TCHARS[rcat] + nargs; + if (!ALL_ARG_TYPES) cat += (nints==0?"":"I"+nints)+(nlongs==0?"":"J"+nlongs); + return cat; + } + static void expandTemplateForPrims(String[] template, boolean topLevel, int rcat, int nargs, int minints, int minlongs) { + for (int isLong = 0; isLong <= 1; isLong++) { + for (int nprims = 1; nprims <= nargs; nprims++) { + int nrefs = nargs - nprims; + int nints = ((1-isLong) * nprims); + int nlongs = (isLong * nprims); + expandTemplate(template, topLevel, rcat, nrefs, nints, nlongs); + } + } + } + static void expandTemplate(String[] template, boolean topLevel, + int rcat, int nrefs, int nints, int nlongs) { + int nargs = nrefs + nints + nlongs; + if (nrefs > MAX_REFS || nints > MAX_INTS || nlongs > MAX_LONGS) return; + VAR.makeBindings(topLevel, rcat, nrefs, nints, nlongs); + if (topLevel && !done.add(VAR.cat.binding)) { + System.out.println(" //repeat "+VAR.cat.binding); + return; + } + for (int i = 0; i < template.length; i++) { + String line = template[i]; + if (line.endsWith("@each-cat@")) { + // ignore + } else if (line.endsWith("@each-R@")) { + int blockEnd = indexAfter(template, i, "@end-R@"); + String[] block = stringsIn(template, i+1, blockEnd-1); + for (int rcat1 = rcat; rcat1 <= MAX_RCAT; rcat1++) + expandTemplate(block, false, rcat1, nrefs, nints, nlongs); + VAR.makeBindings(topLevel, rcat, nrefs, nints, nlongs); + i = blockEnd-1; continue; + } else if (line.endsWith("@each-Tv@")) { + int blockEnd = indexAfter(template, i, "@end-Tv@"); + String[] block = stringsIn(template, i+1, blockEnd-1); + expandTemplate(block, false, rcat, nrefs, nints, nlongs); + expandTemplateForPrims(block, false, rcat, nargs, nints+1, nlongs+1); + VAR.makeBindings(topLevel, rcat, nrefs, nints, nlongs); + i = blockEnd-1; continue; + } else { + System.out.println(VAR.transform(line)); + } + } + } +} +//}}} */ +//params=[0, 10, 4, 99, 0, 0] + static class A0 extends Adapter { + protected A0(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A0(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { super(e, i, c, t); } + protected A0 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { return new A0(e, i, c, t); } + protected Object invoke_L0() { return convert_L(invoker.invoke(target)); } + protected Object invoke_I0() { return convert_I(invoker.invoke(target)); } + protected Object invoke_J0() { return convert_J(invoker.invoke(target)); } + protected Object invoke_F0() { return convert_F(invoker.invoke(target)); } + protected Object invoke_D0() { return convert_D(invoker.invoke(target)); } + } + static class A1 extends Adapter { + protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A1(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { super(e, i, c, t); } + protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { return new A1(e, i, c, t); } + protected Object invoke_L1(Object a0) { return convert_L(invoker.invoke(target, a0)); } + protected Object invoke_I1(Object a0) { return convert_I(invoker.invoke(target, a0)); } + protected Object invoke_J1(Object a0) { return convert_J(invoker.invoke(target, a0)); } + protected Object invoke_F1(Object a0) { return convert_F(invoker.invoke(target, a0)); } + protected Object invoke_D1(Object a0) { return convert_D(invoker.invoke(target, a0)); } + } + static class A2 extends Adapter { + protected A2(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A2(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { super(e, i, c, t); } + protected A2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { return new A2(e, i, c, t); } + protected Object invoke_L2(Object a0, Object a1) { return convert_L(invoker.invoke(target, a0, a1)); } + protected Object invoke_I2(Object a0, Object a1) { return convert_I(invoker.invoke(target, a0, a1)); } + protected Object invoke_J2(Object a0, Object a1) { return convert_J(invoker.invoke(target, a0, a1)); } + protected Object invoke_F2(Object a0, Object a1) { return convert_F(invoker.invoke(target, a0, a1)); } + protected Object invoke_D2(Object a0, Object a1) { return convert_D(invoker.invoke(target, a0, a1)); } + } + static class A3 extends Adapter { + protected A3(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A3(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { super(e, i, c, t); } + protected A3 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { return new A3(e, i, c, t); } + protected Object invoke_L3(Object a0, Object a1, Object a2) { return convert_L(invoker.invoke(target, a0, a1, a2)); } + protected Object invoke_I3(Object a0, Object a1, Object a2) { return convert_I(invoker.invoke(target, a0, a1, a2)); } + protected Object invoke_J3(Object a0, Object a1, Object a2) { return convert_J(invoker.invoke(target, a0, a1, a2)); } + protected Object invoke_F3(Object a0, Object a1, Object a2) { return convert_F(invoker.invoke(target, a0, a1, a2)); } + protected Object invoke_D3(Object a0, Object a1, Object a2) { return convert_D(invoker.invoke(target, a0, a1, a2)); } + } + static class A4 extends Adapter { + protected A4(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A4(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { super(e, i, c, t); } + protected A4 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { return new A4(e, i, c, t); } + protected Object invoke_L4(Object a0, Object a1, Object a2, Object a3) { return convert_L(invoker.invoke(target, a0, a1, a2, a3)); } + protected Object invoke_I4(Object a0, Object a1, Object a2, Object a3) { return convert_I(invoker.invoke(target, a0, a1, a2, a3)); } + protected Object invoke_J4(Object a0, Object a1, Object a2, Object a3) { return convert_J(invoker.invoke(target, a0, a1, a2, a3)); } + protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3) { return convert_F(invoker.invoke(target, a0, a1, a2, a3)); } + protected Object invoke_D4(Object a0, Object a1, Object a2, Object a3) { return convert_D(invoker.invoke(target, a0, a1, a2, a3)); } + } + static class A5 extends Adapter { + protected A5(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A5(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { super(e, i, c, t); } + protected A5 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { return new A5(e, i, c, t); } + protected Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_L(invoker.invoke(target, a0, a1, a2, a3, a4)); } + protected Object invoke_I5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_I(invoker.invoke(target, a0, a1, a2, a3, a4)); } + protected Object invoke_J5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_J(invoker.invoke(target, a0, a1, a2, a3, a4)); } + protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_F(invoker.invoke(target, a0, a1, a2, a3, a4)); } + protected Object invoke_D5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_D(invoker.invoke(target, a0, a1, a2, a3, a4)); } + } + static class A6 extends Adapter { + protected A6(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A6(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { super(e, i, c, t); } + protected A6 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { return new A6(e, i, c, t); } + protected Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_L(invoker.invoke(target, a0, a1, a2, a3, a4, a5)); } + protected Object invoke_I6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_I(invoker.invoke(target, a0, a1, a2, a3, a4, a5)); } + protected Object invoke_J6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_J(invoker.invoke(target, a0, a1, a2, a3, a4, a5)); } + protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_F(invoker.invoke(target, a0, a1, a2, a3, a4, a5)); } + protected Object invoke_D6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_D(invoker.invoke(target, a0, a1, a2, a3, a4, a5)); } + } + static class A7 extends Adapter { + protected A7(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A7(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { super(e, i, c, t); } + protected A7 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { return new A7(e, i, c, t); } + protected Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_L(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_I7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_I(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_J7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_J(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_F(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_D7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_D(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6)); } + } + static class A8 extends Adapter { + protected A8(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A8(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { super(e, i, c, t); } + protected A8 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { return new A8(e, i, c, t); } + protected Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_L(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_I8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_I(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_J8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_J(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_F(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_D8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_D(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); } + } + static class A9 extends Adapter { + protected A9(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A9(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { super(e, i, c, t); } + protected A9 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { return new A9(e, i, c, t); } + protected Object invoke_L9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_L(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_I9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_I(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_J9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_J(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_F(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_D9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_D(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + } + static class A10 extends Adapter { + protected A10(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A10(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { super(e, i, c, t); } + protected A10 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) + { return new A10(e, i, c, t); } + protected Object invoke_L10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_L(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_I10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_I(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_J10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_J(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_F10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_F(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_D10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_D(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + } +} diff --git a/jdk/src/share/classes/sun/dyn/Invokers.java b/jdk/src/share/classes/sun/dyn/Invokers.java new file mode 100644 index 00000000000..eddd437a5d5 --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/Invokers.java @@ -0,0 +1,86 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn; + +import java.dyn.MethodHandle; +import java.dyn.MethodHandles; +import java.dyn.MethodType; + + +/** + * Construction and caching of often-used invokers. + * @author jrose + */ +public class Invokers { + // exact type (sans leading taget MH) for the outgoing call + private final MethodType targetType; + + // exact invoker for the outgoing call + private /*lazy*/ MethodHandle exactInvoker; + + // generic (untyped) invoker for the outgoing call + private /*lazy*/ MethodHandle genericInvoker; + + /** Compute and cache information common to all collecting adapters + * that implement members of the erasure-family of the given erased type. + */ + public Invokers(Access token, MethodType targetType) { + Access.check(token); + this.targetType = targetType; + } + + public static MethodType invokerType(MethodType targetType) { + return targetType.insertParameterType(0, MethodHandle.class); + } + + public MethodHandle exactInvoker() { + MethodHandle invoker = exactInvoker; + if (invoker != null) return invoker; + invoker = MethodHandleImpl.IMPL_LOOKUP.findVirtual(MethodHandle.class, "invoke", targetType); + if (invoker == null) throw new InternalError("JVM cannot find invoker for "+targetType); + assert(invokerType(targetType) == invoker.type()); + exactInvoker = invoker; + return invoker; + } + + public MethodHandle genericInvoker() { + MethodHandle invoker1 = exactInvoker(); + MethodHandle invoker = genericInvoker; + if (invoker != null) return invoker; + MethodType genericType = targetType.generic(); + invoker = MethodHandles.convertArguments(invoker1, invokerType(genericType)); + genericInvoker = invoker; + return invoker; + } + + public MethodHandle varargsInvoker() { + throw new UnsupportedOperationException("NYI"); + } + + public String toString() { + return "Invokers"+targetType; + } +} diff --git a/jdk/src/share/classes/sun/dyn/MemberName.java b/jdk/src/share/classes/sun/dyn/MemberName.java new file mode 100644 index 00000000000..26919efa8c5 --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/MemberName.java @@ -0,0 +1,551 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn; + +import sun.dyn.util.BytecodeSignature; +import java.dyn.*; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Member; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import static sun.dyn.MethodHandleNatives.Constants.*; + +/** + * Compact information which fully characterizes a method or field reference. + * When resolved, it includes a direct pointer to JVM metadata. + * This representation is stateless and only decriptive. + * It provides no private information and no capability to use the member. + *

+ * By contrast, a java.lang.reflect.Method contains fuller information + * about the internals of a method (except its bytecodes) and also + * allows invocation. A MemberName is much lighter than a reflect.Method, + * since it contains about 7 fields to Method's 16 (plus its sub-arrays), + * and those seven fields omit much of the information in Method. + * @author jrose + */ +public final class MemberName implements Member, Cloneable { + private Class clazz; // class in which the method is defined + private String name; // may be null if not yet materialized + private Object type; // may be null if not yet materialized + private int flags; // modifier bits; see reflect.Modifier + + private Object vmtarget; // VM-specific target value + private int vmindex; // method index within class or interface + + { vmindex = VM_INDEX_UNINITIALIZED; } + + public Class getDeclaringClass() { + if (clazz == null && isResolved()) { + expandFromVM(); + } + return clazz; + } + + public ClassLoader getClassLoader() { + return clazz.getClassLoader(); + } + + public String getName() { + if (name == null) { + expandFromVM(); + if (name == null) return null; + } + return name; + } + + public MethodType getMethodType() { + if (type == null) { + expandFromVM(); + if (type == null) return null; + } + if (!isInvocable()) + throw newIllegalArgumentException("not invocable, no method type"); + if (type instanceof MethodType) { + return (MethodType) type; + } + if (type instanceof String) { + String sig = (String) type; + MethodType res = MethodType.fromBytecodeString(sig, getClassLoader()); + this.type = res; + return res; + } + if (type instanceof Object[]) { + Object[] typeInfo = (Object[]) type; + Class[] ptypes = (Class[]) typeInfo[1]; + Class rtype = (Class) typeInfo[0]; + MethodType res = MethodType.make(rtype, ptypes); + this.type = res; + return res; + } + throw new InternalError("bad method type "+type); + } + + public MethodType getInvocationType() { + MethodType itype = getMethodType(); + if (!isStatic()) + itype = itype.insertParameterType(0, clazz); + return itype; + } + + public Class[] getParameterTypes() { + return getMethodType().parameterArray(); + } + + public Class getReturnType() { + return getMethodType().returnType(); + } + + public Class getFieldType() { + if (type == null) { + expandFromVM(); + if (type == null) return null; + } + if (isInvocable()) + throw newIllegalArgumentException("not a field or nested class, no simple type"); + if (type instanceof Class) { + return (Class) type; + } + if (type instanceof String) { + String sig = (String) type; + MethodType mtype = MethodType.fromBytecodeString("()"+sig, getClassLoader()); + Class res = mtype.returnType(); + this.type = res; + return res; + } + throw new InternalError("bad field type "+type); + } + + public Object getType() { + return (isInvocable() ? getMethodType() : getFieldType()); + } + + public String getSignature() { + if (type == null) { + expandFromVM(); + if (type == null) return null; + } + if (type instanceof String) + return (String) type; + if (isInvocable()) + return BytecodeSignature.unparse(getMethodType()); + else + return BytecodeSignature.unparse(getFieldType()); + } + + public int getModifiers() { + return (flags & RECOGNIZED_MODIFIERS); + } + + private void setFlags(int flags) { + this.flags = flags; + assert(testAnyFlags(ALL_KINDS)); + } + + private boolean testFlags(int mask, int value) { + return (flags & mask) == value; + } + private boolean testAllFlags(int mask) { + return testFlags(mask, mask); + } + private boolean testAnyFlags(int mask) { + return !testFlags(mask, 0); + } + + public boolean isStatic() { + return Modifier.isStatic(flags); + } + public boolean isPublic() { + return Modifier.isPublic(flags); + } + public boolean isPrivate() { + return Modifier.isPrivate(flags); + } + public boolean isProtected() { + return Modifier.isProtected(flags); + } + public boolean isFinal() { + return Modifier.isFinal(flags); + } + public boolean isAbstract() { + return Modifier.isAbstract(flags); + } + // let the rest (native, volatile, transient, etc.) be tested via Modifier.isFoo + + // unofficial modifier flags, used by HotSpot: + static final int BRIDGE = 0x00000040; + static final int VARARGS = 0x00000080; + static final int SYNTHETIC = 0x00001000; + static final int ANNOTATION= 0x00002000; + static final int ENUM = 0x00004000; + public boolean isBridge() { + return testAllFlags(IS_METHOD | BRIDGE); + } + public boolean isVarargs() { + return testAllFlags(VARARGS) && isInvocable(); + } + public boolean isSynthetic() { + return testAllFlags(SYNTHETIC); + } + + static final String CONSTRUCTOR_NAME = ""; // the ever-popular + + // modifiers exported by the JVM: + static final int RECOGNIZED_MODIFIERS = 0xFFFF; + + // private flags, not part of RECOGNIZED_MODIFIERS: + static final int + IS_METHOD = MN_IS_METHOD, // method (not constructor) + IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor + IS_FIELD = MN_IS_FIELD, // field + IS_TYPE = MN_IS_TYPE; // nested type + static final int // for MethodHandleNatives.getMembers + SEARCH_SUPERCLASSES = MN_SEARCH_SUPERCLASSES, + SEARCH_INTERFACES = MN_SEARCH_INTERFACES; + + static final int ALL_ACCESS = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED; + static final int ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE; + static final int IS_INVOCABLE = IS_METHOD | IS_CONSTRUCTOR; + static final int IS_FIELD_OR_METHOD = IS_METHOD | IS_FIELD; + static final int SEARCH_ALL_SUPERS = SEARCH_SUPERCLASSES | SEARCH_INTERFACES; + + public boolean isInvocable() { + return testAnyFlags(IS_INVOCABLE); + } + public boolean isFieldOrMethod() { + return testAnyFlags(IS_FIELD_OR_METHOD); + } + public boolean isMethod() { + return testAllFlags(IS_METHOD); + } + public boolean isConstructor() { + return testAllFlags(IS_CONSTRUCTOR); + } + public boolean isField() { + return testAllFlags(IS_FIELD); + } + public boolean isType() { + return testAllFlags(IS_TYPE); + } + public boolean isPackage() { + return !testAnyFlags(ALL_ACCESS); + } + + /** Initialize a query. It is not resolved. */ + private void init(Class defClass, String name, Object type, int flags) { + // defining class is allowed to be null (for a naked name/type pair) + name.toString(); // null check + type.equals(type); // null check + // fill in fields: + this.clazz = defClass; + this.name = name; + this.type = type; + setFlags(flags); + assert(!isResolved()); + } + + private void expandFromVM() { + if (!isResolved()) return; + if (type instanceof Object[]) + type = null; // don't saddle JVM w/ typeInfo + MethodHandleNatives.expand(this); + } + + // Capturing information from the Core Reflection API: + private static int flagsMods(int flags, int mods) { + assert((flags & RECOGNIZED_MODIFIERS) == 0); + assert((mods & ~RECOGNIZED_MODIFIERS) == 0); + return flags | mods; + } + public MemberName(Method m) { + Object[] typeInfo = { m.getReturnType(), m.getParameterTypes() }; + init(m.getDeclaringClass(), m.getName(), typeInfo, flagsMods(IS_METHOD, m.getModifiers())); + // fill in vmtarget, vmindex while we have m in hand: + MethodHandleNatives.init(this, m); + assert(isResolved()); + } + public MemberName(Constructor ctor) { + Object[] typeInfo = { void.class, ctor.getParameterTypes() }; + init(ctor.getDeclaringClass(), CONSTRUCTOR_NAME, typeInfo, flagsMods(IS_CONSTRUCTOR, ctor.getModifiers())); + // fill in vmtarget, vmindex while we have ctor in hand: + MethodHandleNatives.init(this, ctor); + assert(isResolved()); + } + public MemberName(Field fld) { + init(fld.getDeclaringClass(), fld.getName(), fld.getType(), flagsMods(IS_FIELD, fld.getModifiers())); + // fill in vmtarget, vmindex while we have fld in hand: + MethodHandleNatives.init(this, fld); + assert(isResolved()); + } + public MemberName(Class type) { + init(type.getDeclaringClass(), type.getSimpleName(), type, flagsMods(IS_TYPE, type.getModifiers())); + vmindex = 0; // isResolved + assert(isResolved()); + } + + // bare-bones constructor; the JVM will fill it in + MemberName() { } + + // locally useful cloner + @Override protected MemberName clone() { + try { + return (MemberName) super.clone(); + } catch (CloneNotSupportedException ex) { + throw new InternalError(); + } + } + + // %%% define equals/hashcode? + + // Construction from symbolic parts, for queries: + public MemberName(Class defClass, String name, Class type, int modifiers) { + init(defClass, name, type, IS_FIELD | (modifiers & RECOGNIZED_MODIFIERS)); + } + public MemberName(Class defClass, String name, Class type) { + this(defClass, name, type, 0); + } + public MemberName(Class defClass, String name, MethodType type, int modifiers) { + int flagBit = (name.equals(CONSTRUCTOR_NAME) ? IS_CONSTRUCTOR : IS_METHOD); + init(defClass, name, type, flagBit | (modifiers & RECOGNIZED_MODIFIERS)); + } + public MemberName(Class defClass, String name, MethodType type) { + this(defClass, name, type, 0); + } + + boolean isResolved() { + return (vmindex != VM_INDEX_UNINITIALIZED); + } + + public boolean hasReceiverTypeDispatch() { + return (isMethod() && getVMIndex(Access.TOKEN) >= 0); + } + + @Override + public String toString() { + if (isType()) + return type.toString(); // class java.lang.String + // else it is a field, method, or constructor + StringBuilder buf = new StringBuilder(); + if (getDeclaringClass() != null) { + buf.append(getName(clazz)); + buf.append('.'); + } + buf.append(getName()); + if (!isInvocable()) buf.append('/'); + buf.append(getName(getType())); + /* + buf.append('/'); + // key: Public, private, pRotected, sTatic, Final, sYnchronized, + // transient/Varargs, native, (interface), abstract, sTrict, sYnthetic, + // (annotation), Enum, (unused) + final String FIELD_MOD_CHARS = "PprTF?vt????Y?E?"; + final String METHOD_MOD_CHARS = "PprTFybVn?atY???"; + String modChars = (isInvocable() ? METHOD_MOD_CHARS : FIELD_MOD_CHARS); + for (int i = 0; i < modChars.length(); i++) { + if ((flags & (1 << i)) != 0) { + char mc = modChars.charAt(i); + if (mc != '.') + buf.append(mc); + } + } + */ + return buf.toString(); + } + private static String getName(Object obj) { + if (obj instanceof Class) + return ((Class)obj).getName(); + return obj.toString(); + } + + // Queries to the JVM: + public int getVMIndex(Access token) { + Access.check(token); + if (!isResolved()) + throw newIllegalStateException("not resolved"); + return vmindex; + } +// public Object getVMTarget(Access token) { +// Access.check(token); +// if (!isResolved()) +// throw newIllegalStateException("not resolved"); +// return vmtarget; +// } + private RuntimeException newIllegalStateException(String message) { + return new IllegalStateException(message+": "+this); + } + + // handy shared exception makers (they simplify the common case code) + public static RuntimeException newIllegalArgumentException(String message) { + return new IllegalArgumentException(message); + } + public static NoAccessException newNoAccessException(MemberName name, Class lookupClass) { + return newNoAccessException("cannot access", name, lookupClass); + } + public static NoAccessException newNoAccessException(String message, + MemberName name, Class lookupClass) { + message += ": " + name; + if (lookupClass != null) message += ", from " + lookupClass.getName(); + return new NoAccessException(message); + } + + /** Actually making a query requires an access check. */ + public static Factory getFactory(Access token) { + Access.check(token); + return Factory.INSTANCE; + } + public static Factory getFactory() { + return getFactory(Access.getToken()); + } + public static class Factory { + private Factory() { } // singleton pattern + static Factory INSTANCE = new Factory(); + + private static int ALLOWED_FLAGS = SEARCH_ALL_SUPERS | ALL_KINDS; + + /// Queries + List getMembers(Class defc, + String matchName, Object matchType, + int matchFlags, Class lookupClass) { + matchFlags &= ALLOWED_FLAGS; + String matchSig = null; + if (matchType != null) { + matchSig = BytecodeSignature.unparse(matchType); + if (matchSig.startsWith("(")) + matchFlags &= ~(ALL_KINDS & ~IS_INVOCABLE); + else + matchFlags &= ~(ALL_KINDS & ~IS_FIELD); + } + final int BUF_MAX = 0x2000; + int len1 = matchName == null ? 10 : matchType == null ? 4 : 1; + MemberName[] buf = newMemberBuffer(len1); + int totalCount = 0; + ArrayList bufs = null; + for (;;) { + int bufCount = MethodHandleNatives.getMembers(defc, + matchName, matchSig, matchFlags, + lookupClass, + totalCount, buf); + if (bufCount <= buf.length) { + if (bufCount >= 0) + totalCount += bufCount; + break; + } + // JVM returned tp us with an intentional overflow! + totalCount += buf.length; + int excess = bufCount - buf.length; + if (bufs == null) bufs = new ArrayList(1); + bufs.add(buf); + int len2 = buf.length; + len2 = Math.max(len2, excess); + len2 = Math.max(len2, totalCount / 4); + buf = newMemberBuffer(Math.min(BUF_MAX, len2)); + } + ArrayList result = new ArrayList(totalCount); + if (bufs != null) { + for (MemberName[] buf0 : bufs) { + Collections.addAll(result, buf0); + } + } + Collections.addAll(result, buf); + // Signature matching is not the same as type matching, since + // one signature might correspond to several types. + // So if matchType is a Class or MethodType, refilter the results. + if (matchType != null && matchType != matchSig) { + for (Iterator it = result.iterator(); it.hasNext();) { + MemberName m = it.next(); + if (!matchType.equals(m.getType())) + it.remove(); + } + } + return result; + } + boolean resolveInPlace(MemberName m, boolean searchSupers, Class lookupClass) { + MethodHandleNatives.resolve(m, lookupClass); + if (m.isResolved()) return true; + int matchFlags = m.flags | (searchSupers ? SEARCH_ALL_SUPERS : 0); + String matchSig = m.getSignature(); + MemberName[] buf = { m }; + int n = MethodHandleNatives.getMembers(m.getDeclaringClass(), + m.getName(), matchSig, matchFlags, lookupClass, 0, buf); + if (n != 1) return false; + return m.isResolved(); + } + public MemberName resolveOrNull(MemberName m, boolean searchSupers, Class lookupClass) { + MemberName result = m.clone(); + if (resolveInPlace(result, searchSupers, lookupClass)) + return result; + return null; + } + public MemberName resolveOrFail(MemberName m, boolean searchSupers, Class lookupClass) { + MemberName result = resolveOrNull(m, searchSupers, lookupClass); + if (result != null) + return result; + throw newNoAccessException(m, lookupClass); + } + public List getMethods(Class defc, boolean searchSupers, + Class lookupClass) { + return getMethods(defc, searchSupers, null, null, lookupClass); + } + public List getMethods(Class defc, boolean searchSupers, + String name, MethodType type, Class lookupClass) { + int matchFlags = IS_METHOD | (searchSupers ? SEARCH_ALL_SUPERS : 0); + return getMembers(defc, name, type, matchFlags, lookupClass); + } + public List getConstructors(Class defc, Class lookupClass) { + return getMembers(defc, null, null, IS_CONSTRUCTOR, lookupClass); + } + public List getFields(Class defc, boolean searchSupers, + Class lookupClass) { + return getFields(defc, searchSupers, null, null, lookupClass); + } + public List getFields(Class defc, boolean searchSupers, + String name, Class type, Class lookupClass) { + int matchFlags = IS_FIELD | (searchSupers ? SEARCH_ALL_SUPERS : 0); + return getMembers(defc, name, type, matchFlags, lookupClass); + } + public List getNestedTypes(Class defc, boolean searchSupers, + Class lookupClass) { + int matchFlags = IS_TYPE | (searchSupers ? SEARCH_ALL_SUPERS : 0); + return getMembers(defc, null, null, matchFlags, lookupClass); + } + private static MemberName[] newMemberBuffer(int length) { + MemberName[] buf = new MemberName[length]; + // fill the buffer with dummy structs for the JVM to fill in + for (int i = 0; i < length; i++) + buf[i] = new MemberName(); + return buf; + } + } + +// static { +// System.out.println("Hello world! My methods are:"); +// System.out.println(Factory.INSTANCE.getMethods(MemberName.class, true, null)); +// } +} diff --git a/jdk/src/share/classes/sun/dyn/MethodHandleImpl.java b/jdk/src/share/classes/sun/dyn/MethodHandleImpl.java new file mode 100644 index 00000000000..2dd59deeff0 --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/MethodHandleImpl.java @@ -0,0 +1,373 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn; + +import java.dyn.MethodHandle; +import java.dyn.MethodHandles; +import java.dyn.MethodHandles.Lookup; +import java.dyn.MethodType; +import sun.dyn.util.VerifyType; +import java.dyn.NoAccessException; +import static sun.dyn.MemberName.newIllegalArgumentException; +import static sun.dyn.MemberName.newNoAccessException; + +/** + * Base class for method handles, containing JVM-specific fields and logic. + * TO DO: It should not be a base class. + * @author jrose + */ +public abstract class MethodHandleImpl { + + // Fields which really belong in MethodHandle: + private byte vmentry; // adapter stub or method entry point + //private int vmslots; // optionally, hoist type.form.vmslots + protected Object vmtarget; // VM-specific, class-specific target value + //MethodType type; // defined in MethodHandle + + // TO DO: vmtarget should be invisible to Java, since the JVM puts internal + // managed pointers into it. Making it visible exposes it to debuggers, + // which can cause errors when they treat the pointer as an Object. + + // These two dummy fields are present to force 'I' and 'J' signatures + // into this class's constant pool, so they can be transferred + // to vmentry when this class is loaded. + static final int INT_FIELD = 0; + static final long LONG_FIELD = 0; + + // type is defined in java.dyn.MethodHandle, which is platform-independent + + // vmentry (a void* field) is used *only* by by the JVM. + // The JVM adjusts its type to int or long depending on system wordsize. + // Since it is statically typed as neither int nor long, it is impossible + // to use this field from Java bytecode. (Please don't try to, either.) + + // The vmentry is an assembly-language stub which is jumped to + // immediately after the method type is verified. + // For a direct MH, this stub loads the vmtarget's entry point + // and jumps to it. + + /** + * VM-based method handles must have a security token. + * This security token can only be obtained by trusted code. + * Do not create method handles directly; use factory methods. + */ + public MethodHandleImpl(Access token) { + Access.check(token); + } + + /** Initialize the method type form to participate in JVM calls. + * This is done once for each erased type. + */ + public static void init(Access token, MethodType self) { + Access.check(token); + if (MethodHandleNatives.JVM_SUPPORT) + MethodHandleNatives.init(self); + } + + /// Factory methods to create method handles: + + private static final MemberName.Factory LOOKUP = MemberName.Factory.INSTANCE; + + static private Lookup IMPL_LOOKUP_INIT; + + public static void initLookup(Access token, Lookup lookup) { + Access.check(token); + if (IMPL_LOOKUP_INIT != null || lookup.lookupClass() != null) + throw new InternalError(); + IMPL_LOOKUP_INIT = lookup; + } + + public static Lookup getLookup(Access token) { + Access.check(token); + return IMPL_LOOKUP; + } + + static { + // Force initialization: + Lookup.PUBLIC_LOOKUP.lookupClass(); + if (IMPL_LOOKUP_INIT == null) + throw new InternalError(); + } + + public static void initStatics() { + // Trigger preceding sequence. + } + + /** Shared secret with MethodHandles.Lookup, a copy of Lookup.IMPL_LOOKUP. */ + static final Lookup IMPL_LOOKUP = IMPL_LOOKUP_INIT; + + + /** Look up a given method. + * Callable only from java.dyn and related packages. + *

+ * The resulting method handle type will be of the given type, + * with a receiver type {@code rcvc} prepended if the member is not static. + *

+ * Access checks are made as of the given lookup class. + * In particular, if the method is protected and {@code defc} is in a + * different package from the lookup class, then {@code rcvc} must be + * the lookup class or a subclass. + * @param token Proof that the lookup class has access to this package. + * @param member Resolved method or constructor to call. + * @param name Name of the desired method. + * @param rcvc Receiver type of desired non-static method (else null) + * @param doDispatch whether the method handle will test the receiver type + * @param lookupClass access-check relative to this class + * @return a direct handle to the matching method + * @throws NoAccessException if the given method cannot be accessed by the lookup class + */ + public static + MethodHandle findMethod(Access token, MemberName method, + boolean doDispatch, Class lookupClass) { + Access.check(token); // only trusted calls + MethodType mtype = method.getMethodType(); + MethodType rtype = mtype; + if (method.isStatic()) { + doDispatch = false; + } else { + // adjust the advertised receiver type to be exactly the one requested + // (in the case of invokespecial, this will be the calling class) + Class recvType = method.getDeclaringClass(); + mtype = mtype.insertParameterType(0, recvType); + if (method.isConstructor()) + doDispatch = true; + // FIXME: JVM has trouble building MH.invoke sites for + // classes off the boot class path + rtype = mtype; + if (recvType.getClassLoader() != null) + rtype = rtype.changeParameterType(0, Object.class); + } + DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, lookupClass); + if (!mh.isValid()) + throw newNoAccessException(method, lookupClass); + MethodHandle rmh = AdapterMethodHandle.makePairwiseConvert(token, rtype, mh); + if (rmh == null) throw new InternalError(); + return rmh; + } + + public static + MethodHandle accessField(Access token, + MemberName member, boolean isSetter, + Class lookupClass) { + Access.check(token); + // FIXME: Use sun.misc.Unsafe to dig up the dirt on the field. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public static + MethodHandle accessArrayElement(Access token, + Class arrayClass, boolean isSetter) { + Access.check(token); + if (!arrayClass.isArray()) + throw newIllegalArgumentException("not an array: "+arrayClass); + // FIXME: Use sun.misc.Unsafe to dig up the dirt on the array. + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** Bind a predetermined first argument to the given direct method handle. + * Callable only from MethodHandles. + * @param token Proof that the caller has access to this package. + * @param target Any direct method handle. + * @param receiver Receiver (or first static method argument) to pre-bind. + * @return a BoundMethodHandle for the given DirectMethodHandle, or null if it does not exist + */ + public static + MethodHandle bindReceiver(Access token, + MethodHandle target, Object receiver) { + Access.check(token); + if (target instanceof AdapterMethodHandle) { + Object info = MethodHandleNatives.getTargetInfo(target); + if (info instanceof DirectMethodHandle) { + DirectMethodHandle dmh = (DirectMethodHandle) info; + if (receiver == null || + dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) + target = dmh; + } + } + if (target instanceof DirectMethodHandle) + return new BoundMethodHandle((DirectMethodHandle)target, receiver, 0); + return null; // let caller try something else + } + + /** Bind a predetermined argument to the given arbitrary method handle. + * Callable only from MethodHandles. + * @param token Proof that the caller has access to this package. + * @param target Any method handle. + * @param receiver Argument (which can be a boxed primitive) to pre-bind. + * @return a suitable BoundMethodHandle + */ + public static + MethodHandle bindArgument(Access token, + MethodHandle target, int argnum, Object receiver) { + Access.check(token); + throw new UnsupportedOperationException("NYI"); + } + + public static MethodHandle convertArguments(Access token, + MethodHandle target, + MethodType newType, + MethodType oldType, + int[] permutationOrNull) { + Access.check(token); + MethodHandle res = AdapterMethodHandle.makePairwiseConvert(token, newType, target); + if (res != null) + return res; + int argc = oldType.parameterCount(); + // The JVM can't do it directly, so fill in the gap with a Java adapter. + // TO DO: figure out what to put here from case-by-case experience + // Use a heavier method: Convert all the arguments to Object, + // then back to the desired types. We might have to use Java-based + // method handles to do this. + MethodType objType = MethodType.makeGeneric(argc); + MethodHandle objTarget = AdapterMethodHandle.makePairwiseConvert(token, objType, target); + if (objTarget == null) + objTarget = FromGeneric.make(target); + res = AdapterMethodHandle.makePairwiseConvert(token, newType, objTarget); + if (res != null) + return res; + return ToGeneric.make(newType, objTarget); + } + + public static MethodHandle spreadArguments(Access token, + MethodHandle target, + MethodType newType, + int spreadArg) { + Access.check(token); + // TO DO: maybe allow the restarg to be Object and implicitly cast to Object[] + MethodType oldType = target.type(); + // spread the last argument of newType to oldType + int spreadCount = oldType.parameterCount() - spreadArg; + Class spreadArgType = Object[].class; + MethodHandle res = AdapterMethodHandle.makeSpreadArguments(token, newType, target, spreadArgType, spreadArg, spreadCount); + if (res != null) + return res; + // try an intermediate adapter + Class spreadType = null; + if (spreadArg < 0 || spreadArg >= newType.parameterCount() + || !VerifyType.isSpreadArgType(spreadType = newType.parameterType(spreadArg))) + throw newIllegalArgumentException("no restarg in "+newType); + Class[] ptypes = oldType.parameterArray(); + for (int i = 0; i < spreadCount; i++) + ptypes[spreadArg + i] = VerifyType.spreadArgElementType(spreadType, i); + MethodType midType = MethodType.make(newType.returnType(), ptypes); + // after spreading, some arguments may need further conversion + target = convertArguments(token, target, midType, oldType, null); + if (target == null) + throw new UnsupportedOperationException("NYI: convert "+midType+" =calls=> "+oldType); + res = AdapterMethodHandle.makeSpreadArguments(token, newType, target, spreadArgType, spreadArg, spreadCount); + return res; + } + + public static MethodHandle collectArguments(Access token, + MethodHandle target, + MethodType newType, + int collectArg) { + if (collectArg > 0) + throw new UnsupportedOperationException("NYI"); + throw new UnsupportedOperationException("NYI"); + } + public static + MethodHandle dropArguments(Access token, MethodHandle target, + MethodType newType, int argnum) { + Access.check(token); + throw new UnsupportedOperationException("NYI"); + } + + public static + MethodHandle makeGuardWithTest(Access token, + final MethodHandle test, + final MethodHandle target, + final MethodHandle fallback) { + Access.check(token); + // %%% This is just a sketch. It needs to be de-boxed. + // Adjust the handles to accept varargs lists. + MethodType type = target.type(); + Class rtype = type.returnType(); + if (type.parameterCount() != 1 || type.parameterType(0).isPrimitive()) { + MethodType vatestType = MethodType.make(boolean.class, Object[].class); + MethodType vatargetType = MethodType.make(rtype, Object[].class); + MethodHandle vaguard = makeGuardWithTest(token, + MethodHandles.spreadArguments(test, vatestType), + MethodHandles.spreadArguments(target, vatargetType), + MethodHandles.spreadArguments(fallback, vatargetType)); + return MethodHandles.collectArguments(vaguard, type); + } + if (rtype.isPrimitive()) { + MethodType boxtype = type.changeReturnType(Object.class); + MethodHandle boxguard = makeGuardWithTest(token, + test, + MethodHandles.convertArguments(target, boxtype), + MethodHandles.convertArguments(fallback, boxtype)); + return MethodHandles.convertArguments(boxguard, type); + } + // Got here? Reduced calling sequence to Object(Object). + class Guarder { + Object invoke(Object x) { + // If javac supports MethodHandle.invoke directly: + //z = vatest.invoke(arguments); + // If javac does not support direct MH.invoke calls: + boolean z = (Boolean) MethodHandles.invoke_1(test, x); + MethodHandle mh = (z ? target : fallback); + return MethodHandles.invoke_1(mh, x); + } + MethodHandle handle() { + MethodType invokeType = MethodType.makeGeneric(0, true); + MethodHandle vh = IMPL_LOOKUP.bind(this, "invoke", invokeType); + return MethodHandles.collectArguments(vh, target.type()); + } + } + return new Guarder().handle(); + } + + public static + MethodHandle combineArguments(Access token, MethodHandle target, MethodHandle checker, int pos) { + Access.check(token); + throw new UnsupportedOperationException("Not yet implemented"); + } + + protected static String basicToString(MethodHandle target) { + MemberName name = null; + if (target != null) + name = MethodHandleNatives.getMethodName(target); + if (name == null) + return ""; + return name.getName(); + } + + protected static String addTypeString(MethodHandle target, String name) { + if (target == null) return name; + return name+target.type(); + } + static RuntimeException newIllegalArgumentException(String string) { + return new IllegalArgumentException(string); + } + + @Override + public String toString() { + MethodHandle self = (MethodHandle) this; + return addTypeString(self, basicToString(self)); + } +} diff --git a/jdk/src/share/classes/sun/dyn/MethodHandleNatives.java b/jdk/src/share/classes/sun/dyn/MethodHandleNatives.java new file mode 100644 index 00000000000..fc2d82aa8ff --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/MethodHandleNatives.java @@ -0,0 +1,263 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn; + +import java.dyn.MethodHandle; +import java.dyn.MethodType; +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import static sun.dyn.MethodHandleNatives.Constants.*; + +/** + * The JVM interface for the method handles package is all here. + * @author jrose + */ +class MethodHandleNatives { + + private MethodHandleNatives() { } // static only + + /// MethodName support + + static native void init(MemberName self, Object ref); + static native void expand(MemberName self); + static native void resolve(MemberName self, Class caller); + static native int getMembers(Class defc, String matchName, String matchSig, + int matchFlags, Class caller, int skip, MemberName[] results); + + /// MethodHandle support + + /** Initialize the method handle to adapt the call. */ + static native void init(AdapterMethodHandle self, MethodHandle target, int argnum); + /** Initialize the method handle to call the correct method, directly. */ + static native void init(BoundMethodHandle self, Object target, int argnum); + /** Initialize the method handle to call as if by an invoke* instruction. */ + static native void init(DirectMethodHandle self, Object ref, boolean doDispatch, Class caller); + + /** Initialize a method type, once per form. */ + static native void init(MethodType self); + + /** Tell the JVM that we need to change the target of an invokedynamic. */ + static native void linkCallSite(CallSiteImpl site, MethodHandle target); + + /** Fetch the vmtarget field. + * It will be sanitized as necessary to avoid exposing non-Java references. + * This routine is for debugging and reflection. + */ + static native Object getTarget(MethodHandle self, int format); + + /** Fetch the name of the handled method, if available. + * This routine is for debugging and reflection. + */ + static MemberName getMethodName(MethodHandle self) { + if (!JVM_SUPPORT) return null; + return (MemberName) getTarget(self, ETF_METHOD_NAME); + } + + /** Fetch the reflective version of the handled method, if available. + */ + static AccessibleObject getTargetMethod(MethodHandle self) { + if (!JVM_SUPPORT) return null; + return (AccessibleObject) getTarget(self, ETF_REFLECT_METHOD); + } + + /** Fetch the target of this method handle. + * If it directly targets a method, return a tuple of method info. + * The info is of the form new Object[]{defclass, name, sig, refclass}. + * If it is chained to another method handle, return that handle. + */ + static Object getTargetInfo(MethodHandle self) { + if (!JVM_SUPPORT) return null; + return getTarget(self, ETF_HANDLE_OR_METHOD_NAME); + } + + static Object[] makeTarget(Class defc, String name, String sig, int mods, Class refc) { + return new Object[] { defc, name, sig, mods, refc }; + } + + /** Fetch MH-related JVM parameter. + * which=0 retrieves MethodHandlePushLimit + * which=1 retrieves stack slot push size (in address units) + */ + static native int getConstant(int which); + + /** True iff this HotSpot JVM has built-in support for method handles. + * If false, some test cases might run, but functionality will be missing. + */ + public static final boolean JVM_SUPPORT; + + /** Java copy of MethodHandlePushLimit in range 2..255. */ + static final int JVM_PUSH_LIMIT; + /** JVM stack motion (in words) after one slot is pushed, usually -1. + */ + static final int JVM_STACK_MOVE_UNIT; + + private static native void registerNatives(); + static { + boolean JVM_SUPPORT_; + int JVM_PUSH_LIMIT_; + int JVM_STACK_MOVE_UNIT_; + try { + registerNatives(); + JVM_SUPPORT_ = true; + JVM_PUSH_LIMIT_ = getConstant(Constants.GC_JVM_PUSH_LIMIT); + JVM_STACK_MOVE_UNIT_ = getConstant(Constants.GC_JVM_STACK_MOVE_LIMIT); + //sun.reflect.Reflection.registerMethodsToFilter(MethodHandleImpl.class, "init"); + } catch (UnsatisfiedLinkError ee) { + // ignore; if we use init() methods later we'll see linkage errors + JVM_SUPPORT_ = false; + JVM_PUSH_LIMIT_ = 3; // arbitrary + JVM_STACK_MOVE_UNIT_ = -1; // arbitrary + //System.out.println("Warning: Running with JVM_SUPPORT=false"); + //System.out.println(ee); + JVM_SUPPORT = JVM_SUPPORT_; + JVM_PUSH_LIMIT = JVM_PUSH_LIMIT_; + JVM_STACK_MOVE_UNIT = JVM_STACK_MOVE_UNIT_; + throw ee; // just die; hopeless to try to run with an older JVM + } + JVM_SUPPORT = JVM_SUPPORT_; + JVM_PUSH_LIMIT = JVM_PUSH_LIMIT_; + JVM_STACK_MOVE_UNIT = JVM_STACK_MOVE_UNIT_; + } + + // All compile-time constants go here. + // There is an opportunity to check them against the JVM's idea of them. + static class Constants { + Constants() { } // static only + // MethodHandleImpl + static final int // for getConstant + GC_JVM_PUSH_LIMIT = 0, + GC_JVM_STACK_MOVE_LIMIT = 1; + static final int + ETF_HANDLE_OR_METHOD_NAME = 0, // all available data (immediate MH or method) + ETF_DIRECT_HANDLE = 1, // ultimate method handle (will be a DMH, may be self) + ETF_METHOD_NAME = 2, // ultimate method as MemberName + ETF_REFLECT_METHOD = 3; // ultimate method as java.lang.reflect object (sans refClass) + + // MemberName + // The JVM uses values of -2 and above for vtable indexes. + // Field values are simple positive offsets. + // Ref: src/share/vm/oops/methodOop.hpp + // This value is negative enough to avoid such numbers, + // but not too negative. + static final int + 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; + + // AdapterMethodHandle + /** Conversions recognized by the JVM. + * They must align with the constants in sun.dyn_AdapterMethodHandle, + * in the JVM file hotspot/src/share/vm/classfile/javaClasses.hpp. + */ + static final int + OP_RETYPE_ONLY = 0x0, // no argument changes; straight retype + OP_CHECK_CAST = 0x1, // ref-to-ref conversion; requires a Class argument + OP_PRIM_TO_PRIM = 0x2, // converts from one primitive to another + OP_REF_TO_PRIM = 0x3, // unboxes a wrapper to produce a primitive + OP_PRIM_TO_REF = 0x4, // boxes a primitive into a wrapper (NYI) + OP_SWAP_ARGS = 0x5, // swap arguments (vminfo is 2nd arg) + OP_ROT_ARGS = 0x6, // rotate arguments (vminfo is displaced arg) + OP_DUP_ARGS = 0x7, // duplicates one or more arguments (at TOS) + OP_DROP_ARGS = 0x8, // remove one or more argument slots + OP_COLLECT_ARGS = 0x9, // combine one or more arguments into a varargs (NYI) + OP_SPREAD_ARGS = 0xA, // expand in place a varargs array (of known size) + OP_FLYBY = 0xB, // operate first on reified argument list (NYI) + OP_RICOCHET = 0xC, // run an adapter chain on the return value (NYI) + CONV_OP_LIMIT = 0xD; // limit of CONV_OP enumeration + /** Shift and mask values for decoding the AMH.conversion field. + * These numbers are shared with the JVM for creating AMHs. + */ + static final int + CONV_OP_MASK = 0xF00, // this nybble 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 2 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; + + /** Which conv-ops are implemented by the JVM? */ + static final int CONV_OP_IMPLEMENTED_MASK = + // TODO: The following expression should be replaced by + // a JVM query. + ((1< + * For an empirical discussion of the structure of method types, + * see + * the thread "Avoiding Boxing" on jvm-languages. + * There are approximately 2000 distinct erased method types in the JDK. + * There are a little over 10 times that number of unerased types. + * No more than half of these are likely to be loaded at once. + * @author John Rose + */ +public class MethodTypeImpl { + final int[] argToSlotTable, slotToArgTable; + final long argCounts; // packed slot & value counts + final long primCounts; // packed prim & double counts + final int vmslots; // total number of parameter slots + final MethodType erasedType; // the canonical erasure + /*lazy*/ MethodType primsAsBoxes; // replace prims by wrappers + /*lazy*/ MethodType primArgsAsBoxes; // wrap args only; make raw return + /*lazy*/ MethodType primsAsInts; // replace prims by int/long + /*lazy*/ MethodType primsAsLongs; // replace prims by long + /*lazy*/ MethodType primsAtEnd; // reorder primitives to the end + + // Cached adapter information: + /*lazy*/ ToGeneric toGeneric; // convert cs. with prims to w/o + /*lazy*/ FromGeneric fromGeneric; // convert cs. w/o prims to with + /*lazy*/ FilterGeneric filterGeneric; // convert argument(s) on the fly + ///*lazy*/ Invokers invokers; // cache of handy higher-order adapters + + public MethodType erasedType() { + return erasedType; + } + + public static MethodTypeImpl of(MethodType type) { + return METHOD_TYPE_FRIEND.form(type); + } + + /** Access methods for the internals of MethodType, supplied to + * MethodTypeForm as a trusted agent. + */ + static public interface MethodTypeFriend { + Class[] ptypes(MethodType mt); + MethodTypeImpl form(MethodType mt); + void setForm(MethodType mt, MethodTypeImpl form); + MethodType makeImpl(Class rtype, Class[] ptypes, boolean trusted); + MethodTypeImpl newMethodTypeForm(MethodType mt); + Invokers getInvokers(MethodType mt); + void setInvokers(MethodType mt, Invokers inv); + } + public static void setMethodTypeFriend(Access token, MethodTypeFriend am) { + Access.check(token); + if (METHOD_TYPE_FRIEND != null) + throw new InternalError(); // just once + METHOD_TYPE_FRIEND = am; + } + static private MethodTypeFriend METHOD_TYPE_FRIEND; + + protected MethodTypeImpl(MethodType erasedType) { + this.erasedType = erasedType; + + Class[] ptypes = METHOD_TYPE_FRIEND.ptypes(erasedType); + int ptypeCount = ptypes.length; + int pslotCount = ptypeCount; // temp. estimate + int rtypeCount = 1; // temp. estimate + int rslotCount = 1; // temp. estimate + + int[] argToSlotTab = null, slotToArgTab = null; + + // Walk the argument types, looking for primitives. + int pac = 0, lac = 0, prc = 0, lrc = 0; + Class epts[] = ptypes; + for (int i = 0; i < epts.length; i++) { + Class pt = epts[i]; + if (pt != Object.class) { + assert(pt.isPrimitive()); + ++pac; + if (hasTwoArgSlots(pt)) ++lac; + } + } + pslotCount += lac; // #slots = #args + #longs + Class rt = erasedType.returnType(); + if (rt != Object.class) { + ++prc; // even void.class counts as a prim here + if (hasTwoArgSlots(rt)) ++lrc; + // adjust #slots, #args + if (rt == void.class) + rtypeCount = rslotCount = 0; + else + rslotCount += lrc; + } + if (lac != 0) { + int slot = ptypeCount + lac; + slotToArgTab = new int[slot+1]; + argToSlotTab = new int[1+ptypeCount]; + argToSlotTab[0] = slot; // argument "-1" is past end of slots + for (int i = 0; i < epts.length; i++) { + Class pt = epts[i]; + if (hasTwoArgSlots(pt)) --slot; + --slot; + slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note + argToSlotTab[1+i] = slot; + } + assert(slot == 0); // filled the table + } + this.primCounts = pack(lrc, prc, lac, pac); + this.argCounts = pack(rslotCount, rtypeCount, pslotCount, ptypeCount); + if (slotToArgTab == null) { + int slot = ptypeCount; // first arg is deepest in stack + slotToArgTab = new int[slot+1]; + argToSlotTab = new int[1+ptypeCount]; + argToSlotTab[0] = slot; // argument "-1" is past end of slots + for (int i = 0; i < ptypeCount; i++) { + --slot; + slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note + argToSlotTab[1+i] = slot; + } + } + this.argToSlotTable = argToSlotTab; + this.slotToArgTable = slotToArgTab; + + if (pslotCount >= 256) throw new IllegalArgumentException("too many arguments"); + + // send a few bits down to the JVM: + this.vmslots = parameterSlotCount(); + + // short circuit some no-op canonicalizations: + if (!hasPrimitives()) { + primsAsBoxes = erasedType; + primArgsAsBoxes = erasedType; + primsAsInts = erasedType; + primsAsLongs = erasedType; + primsAtEnd = erasedType; + } + } + + /** Turn all primitive types to corresponding wrapper types. + */ + public MethodType primsAsBoxes() { + MethodType ct = primsAsBoxes; + if (ct != null) return ct; + MethodType t = erasedType; + ct = canonicalize(erasedType, WRAP, WRAP); + if (ct == null) ct = t; // no prims to box + return primsAsBoxes = ct; + } + + /** Turn all primitive argument types to corresponding wrapper types. + * Subword and void return types are promoted to int. + */ + public MethodType primArgsAsBoxes() { + MethodType ct = primArgsAsBoxes; + if (ct != null) return ct; + MethodType t = erasedType; + ct = canonicalize(erasedType, RAW_RETURN, WRAP); + if (ct == null) ct = t; // no prims to box + return primArgsAsBoxes = ct; + } + + /** Turn all primitive types to either int or long. + * Floating point return types are not changed, because + * they may require special calling sequences. + * A void return value is turned to int. + */ + public MethodType primsAsInts() { + MethodType ct = primsAsInts; + if (ct != null) return ct; + MethodType t = erasedType; + ct = canonicalize(t, RAW_RETURN, INTS); + if (ct == null) ct = t; // no prims to int-ify + return primsAsInts = ct; + } + + /** Turn all primitive types to either int or long. + * Floating point return types are not changed, because + * they may require special calling sequences. + * A void return value is turned to int. + */ + public MethodType primsAsLongs() { + MethodType ct = primsAsLongs; + if (ct != null) return ct; + MethodType t = erasedType; + ct = canonicalize(t, RAW_RETURN, LONGS); + if (ct == null) ct = t; // no prims to int-ify + return primsAsLongs = ct; + } + + /** Stably sort parameters into 3 buckets: ref, int, long. */ + public MethodType primsAtEnd() { + MethodType ct = primsAtEnd; + if (ct != null) return ct; + MethodType t = erasedType; + + int pac = primitiveParameterCount(); + if (pac == 0) + return primsAtEnd = t; + + int argc = parameterCount(); + int lac = longPrimitiveParameterCount(); + if (pac == argc && (lac == 0 || lac == argc)) + return primsAtEnd = t; + + // known to have a mix of 2 or 3 of ref, int, long + return primsAtEnd = reorderParameters(t, primsAtEndOrder(t), null); + + } + + /** Compute a new ordering of parameters so that all references + * are before all ints or longs, and all ints are before all longs. + * For this ordering, doubles count as longs, and all other primitive + * values count as ints. + * As a special case, if the parameters are already in the specified + * order, this method returns a null reference, rather than an array + * specifying a null permutation. + *

+ * For example, the type {@code (int,boolean,int,Object,String)void} + * produces the order {@code {3,4,0,1,2}}, the type + * {@code (long,int,String)void} produces {@code {2,1,2}}, and + * the type {@code (Object,int)Object} produces {@code null}. + */ + public static int[] primsAtEndOrder(MethodType mt) { + MethodTypeImpl form = METHOD_TYPE_FRIEND.form(mt); + if (form.primsAtEnd == form.erasedType) + // quick check shows no reordering is necessary + return null; + + int argc = form.parameterCount(); + int[] paramOrder = new int[argc]; + + // 3-way bucket sort: + int pac = form.primitiveParameterCount(); + int lac = form.longPrimitiveParameterCount(); + int rfill = 0, ifill = argc - pac, lfill = argc - lac; + + Class[] ptypes = METHOD_TYPE_FRIEND.ptypes(mt); + boolean changed = false; + for (int i = 0; i < ptypes.length; i++) { + Class pt = ptypes[i]; + int ord; + if (!pt.isPrimitive()) ord = rfill++; + else if (!hasTwoArgSlots(pt)) ord = ifill++; + else ord = lfill++; + if (ord != i) changed = true; + paramOrder[i] = ord; + } + assert(rfill == argc - pac && ifill == argc - lac && lfill == argc); + if (!changed) { + form.primsAtEnd = form.erasedType; + return null; + } + return paramOrder; + } + + /** Put the existing parameters of mt into a new order, given by newParamOrder. + * The third argument is logically appended to mt.parameterArray, + * so that elements of newParamOrder can index either pre-existing or + * new parameter types. + */ + public static MethodType reorderParameters(MethodType mt, int[] newParamOrder, Class[] moreParams) { + if (newParamOrder == null) return mt; // no-op reordering + Class[] ptypes = METHOD_TYPE_FRIEND.ptypes(mt); + Class[] ntypes = new Class[newParamOrder.length]; + int ordMax = ptypes.length + (moreParams == null ? 0 : moreParams.length); + boolean changed = (ntypes.length != ptypes.length); + for (int i = 0; i < newParamOrder.length; i++) { + int ord = newParamOrder[i]; + if (ord != i) changed = true; + Class nt; + if (ord < ptypes.length) nt = ptypes[ord]; + else if (ord == ordMax) nt = mt.returnType(); + else nt = moreParams[ord - ptypes.length]; + ntypes[i] = nt; + } + if (!changed) return mt; + return METHOD_TYPE_FRIEND.makeImpl(mt.returnType(), ntypes, true); + } + + private static boolean hasTwoArgSlots(Class type) { + return type == long.class || type == double.class; + } + + private static long pack(int a, int b, int c, int d) { + assert(((a|b|c|d) & ~0xFFFF) == 0); + long hw = ((a << 16) | b), lw = ((c << 16) | d); + return (hw << 32) | lw; + } + private static char unpack(long packed, int word) { // word==0 => return a, ==3 => return d + assert(word <= 3); + return (char)(packed >> ((3-word) * 16)); + } + + public int parameterCount() { // # outgoing values + return unpack(argCounts, 3); + } + public int parameterSlotCount() { // # outgoing interpreter slots + return unpack(argCounts, 2); + } + public int returnCount() { // = 0 (V), or 1 + return unpack(argCounts, 1); + } + public int returnSlotCount() { // = 0 (V), 2 (J/D), or 1 + return unpack(argCounts, 0); + } + public int primitiveParameterCount() { + return unpack(primCounts, 3); + } + public int longPrimitiveParameterCount() { + return unpack(primCounts, 2); + } + public int primitiveReturnCount() { // = 0 (obj), or 1 + return unpack(primCounts, 1); + } + public int longPrimitiveReturnCount() { // = 1 (J/D), or 0 + return unpack(primCounts, 0); + } + public boolean hasPrimitives() { + return primCounts != 0; + } +// public boolean hasNonVoidPrimitives() { +// if (primCounts == 0) return false; +// if (primitiveParameterCount() != 0) return true; +// return (primitiveReturnCount() != 0 && returnCount() != 0); +// } + public boolean hasLongPrimitives() { + return (longPrimitiveParameterCount() | longPrimitiveReturnCount()) != 0; + } + public int parameterToArgSlot(int i) { + return argToSlotTable[1+i]; + } + public int argSlotToParameter(int argSlot) { + // Note: Empty slots are represented by zero in this table. + // Valid arguments slots contain incremented entries, so as to be non-zero. + // We return -1 the caller to mean an empty slot. + return slotToArgTable[argSlot] - 1; + } + + public static void initForm(Access token, MethodType mt) { + Access.check(token); + MethodTypeImpl form = findForm(mt); + METHOD_TYPE_FRIEND.setForm(mt, form); + if (form.erasedType == mt) { + // This is a principal (erased) type; show it to the JVM. + MethodHandleImpl.init(token, mt); + } + } + + static MethodTypeImpl findForm(MethodType mt) { + MethodType erased = canonicalize(mt, ERASE, ERASE); + if (erased == null) { + // It is already erased. Make a new MethodTypeForm. + return METHOD_TYPE_FRIEND.newMethodTypeForm(mt); + } else { + // Share the MethodTypeForm with the erased version. + return METHOD_TYPE_FRIEND.form(erased); + } + } + + /** Codes for {@link #canonicalize(java.lang.Class, int). + * ERASE means change every reference to {@code Object}. + * WRAP means convert primitives (including {@code void} to their + * corresponding wrapper types. UNWRAP means the reverse of WRAP. + * INTS means convert all non-void primitive types to int or long, + * according to size. LONGS means convert all non-void primitives + * to long, regardless of size. RAW_RETURN means convert a type + * (assumed to be a return type) to int if it is smaller than an int, + * or if it is void. + */ + public static final int NO_CHANGE = 0, ERASE = 1, WRAP = 2, UNWRAP = 3, INTS = 4, LONGS = 5, RAW_RETURN = 6; + + /** Canonicalize the types in the given method type. + * If any types change, intern the new type, and return it. + * Otherwise return null. + */ + public static MethodType canonicalize(MethodType mt, int howRet, int howArgs) { + Class[] ptypes = METHOD_TYPE_FRIEND.ptypes(mt); + Class[] ptc = MethodTypeImpl.canonicalizes(ptypes, howArgs); + Class rtype = mt.returnType(); + Class rtc = MethodTypeImpl.canonicalize(rtype, howRet); + if (ptc == null && rtc == null) { + // It is already canonical. + return null; + } + // Find the erased version of the method type: + if (rtc == null) rtc = rtype; + if (ptc == null) ptc = ptypes; + return METHOD_TYPE_FRIEND.makeImpl(rtc, ptc, true); + } + + /** Canonicalize the given return or param type. + * Return null if the type is already canonicalized. + */ + static Class canonicalize(Class t, int how) { + Class ct; + if (t == Object.class) { + // no change, ever + } else if (!t.isPrimitive()) { + switch (how) { + case UNWRAP: + ct = Wrapper.asPrimitiveType(t); + if (ct != t) return ct; + break; + case RAW_RETURN: + case ERASE: + return Object.class; + } + } else if (t == void.class) { + // no change, usually + switch (how) { + case RAW_RETURN: + return int.class; + case WRAP: + return Void.class; + } + } else { + // non-void primitive + switch (how) { + case WRAP: + return Wrapper.asWrapperType(t); + case INTS: + if (t == int.class || t == long.class) + return null; // no change + if (t == double.class) + return long.class; + return int.class; + case LONGS: + if (t == long.class) + return null; // no change + return long.class; + case RAW_RETURN: + if (t == int.class || t == long.class || + t == float.class || t == double.class) + return null; // no change + // everything else returns as an int + return int.class; + } + } + // no change; return null to signify + return null; + } + + /** Canonicalize each param type in the given array. + * Return null if all types are already canonicalized. + */ + static Class[] canonicalizes(Class[] ts, int how) { + Class[] cs = null; + for (int imax = ts.length, i = 0; i < imax; i++) { + Class c = canonicalize(ts[i], how); + if (c != null) { + if (cs == null) + cs = ts.clone(); + cs[i] = c; + } + } + return cs; + } + + public static Invokers invokers(Access token, MethodType type) { + Access.check(token); + Invokers inv = METHOD_TYPE_FRIEND.getInvokers(type); + if (inv != null) return inv; + inv = new Invokers(token, type); + METHOD_TYPE_FRIEND.setInvokers(type, inv); + return inv; + } + + @Override + public String toString() { + return "Form"+erasedType; + } + +} diff --git a/jdk/src/share/classes/sun/dyn/ToGeneric.java b/jdk/src/share/classes/sun/dyn/ToGeneric.java new file mode 100644 index 00000000000..fd04d753e74 --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/ToGeneric.java @@ -0,0 +1,1018 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn; + +import java.dyn.JavaMethodHandle; +import java.dyn.MethodHandle; +import java.dyn.MethodHandles; +import java.dyn.MethodType; +import java.dyn.NoAccessException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import sun.dyn.util.ValueConversions; +import sun.dyn.util.Wrapper; + +/** + * Adapters which mediate between incoming calls which are not generic + * and outgoing calls which are. Any call can be represented generically + * boxing up its arguments, and (on return) unboxing the return value. + *

+ * A call is "generic" (in MethodHandle terms) if its MethodType features + * only Object arguments. A non-generic call therefore features + * primitives and/or reference types other than Object. + * An adapter has types for its incoming and outgoing calls. + * The incoming call type is simply determined by the adapter's type + * (the MethodType it presents to callers). The outgoing call type + * is determined by the adapter's target (a MethodHandle that the adapter + * either binds internally or else takes as a leading argument). + * (To stretch the term, adapter-like method handles may have multiple + * targets or be polymorphic across multiple call types.) + * @author jrose + */ +class ToGeneric { + // type for the incoming call (may be erased) + private final MethodType entryType; + // incoming type with primitives moved to the end and turned to int/long + private final MethodType rawEntryType; + // adapter for the erased type + private final Adapter adapter; + // entry point for adapter (Adapter mh, a...) => ... + private final MethodHandle entryPoint; + // permutation of arguments for primsAtEndType + private final int[] primsAtEndOrder; + // optional final argument list conversions (at least, invokes the target) + private final MethodHandle invoker; + // conversion which unboxes a primitive return value + private final MethodHandle returnConversion; + + /** Compute and cache information common to all collecting adapters + * that implement members of the erasure-family of the given erased type. + */ + private ToGeneric(MethodType entryType) { + assert(entryType.erase() == entryType); // for now + // incoming call will first "forget" all reference types except Object + this.entryType = entryType; + MethodHandle invoker0 = MethodHandles.exactInvoker(entryType.generic()); + MethodType rawEntryTypeInit; + Adapter ad = findAdapter(rawEntryTypeInit = entryType); + if (ad != null) { + // Immediate hit to exactly the adapter we want, + // with no monkeying around with primitive types. + this.returnConversion = computeReturnConversion(entryType, rawEntryTypeInit, false); + this.rawEntryType = rawEntryTypeInit; + this.adapter = ad; + this.entryPoint = ad.prototypeEntryPoint(); + this.primsAtEndOrder = null; + this.invoker = invoker0; + return; + } + + // next, it will reorder primitives after references + MethodType primsAtEnd = MethodTypeImpl.of(entryType).primsAtEnd(); + // at the same time, it will "forget" all primitive types except int/long + this.primsAtEndOrder = MethodTypeImpl.primsAtEndOrder(entryType); + if (primsAtEndOrder != null) { + // reordering is required; build on top of a simpler ToGeneric + ToGeneric va2 = ToGeneric.of(primsAtEnd); + this.adapter = va2.adapter; + this.entryPoint = MethodHandleImpl.convertArguments(Access.TOKEN, + va2.entryPoint, primsAtEnd, entryType, primsAtEndOrder); + // example: for entryType of (int,Object,Object), the reordered + // type is (Object,Object,int) and the order is {1,2,0}, + // and putPAE is (mh,int0,obj1,obj2) => mh.invoke(obj1,obj2,int0) + if (true) throw new UnsupportedOperationException("NYI"); + return; + } + + // after any needed argument reordering, it will reinterpret + // primitive arguments according to their "raw" types int/long + MethodType intsAtEnd = MethodTypeImpl.of(primsAtEnd).primsAsInts(); + ad = findAdapter(rawEntryTypeInit = intsAtEnd); + if (ad == null) { + // Perhaps the adapter is available only for longs. + // If so, we can use it, but there will have to be a little + // more stack motion on each call. + MethodType longsAtEnd = MethodTypeImpl.of(primsAtEnd).primsAsLongs(); + ad = findAdapter(rawEntryTypeInit = longsAtEnd); + if (ad == null) { + // If there is no statically compiled adapter, + // build one by means of dynamic bytecode generation. + ad = buildAdapterFromBytecodes(rawEntryTypeInit = intsAtEnd); + } + } + MethodHandle rawEntryPoint = ad.prototypeEntryPoint(); + MethodType tepType = entryType.insertParameterType(0, ad.getClass()); + this.entryPoint = + AdapterMethodHandle.makeRawRetypeOnly(Access.TOKEN, tepType, rawEntryPoint); + if (this.entryPoint == null) + throw new UnsupportedOperationException("cannot retype to "+entryType + +" from "+rawEntryPoint.type().dropParameterType(0)); + this.returnConversion = computeReturnConversion(entryType, rawEntryTypeInit, false); + this.rawEntryType = rawEntryTypeInit; + this.adapter = ad; + this.invoker = makeRawArgumentFilter(invoker0, + rawEntryPoint.type().dropParameterType(0), entryType); + } + + /** A generic argument list will be created by a call of type 'raw'. + * The values need to be reboxed for to match 'cooked'. + * Do this on the fly. + */ + // TO DO: Use a generic argument converter in a different file + static MethodHandle makeRawArgumentFilter(MethodHandle invoker, + MethodType raw, MethodType cooked) { + MethodHandle filteredInvoker = null; + for (int i = 0, nargs = raw.parameterCount(); i < nargs; i++) { + Class src = raw.parameterType(i); + Class dst = cooked.parameterType(i); + if (src == dst) continue; + assert(src.isPrimitive() && dst.isPrimitive()); + if (filteredInvoker == null) { + filteredInvoker = + AdapterMethodHandle.makeCheckCast(Access.TOKEN, + invoker.type().generic(), invoker, 0, MethodHandle.class); + if (filteredInvoker == null) throw new UnsupportedOperationException("NYI"); + } + MethodHandle reboxer = ValueConversions.rebox(dst, false); + FilterGeneric gen = new FilterGeneric(filteredInvoker.type(), (short)(1+i), (short)1, 'R'); + filteredInvoker = gen.makeInstance(reboxer, filteredInvoker); + } + if (filteredInvoker == null) return invoker; + return AdapterMethodHandle.makeRetypeOnly(Access.TOKEN, invoker.type(), filteredInvoker); + } + + /** + * Caller will be expecting a result from a call to {@code type}, + * while the internal adapter entry point is rawEntryType. + * Also, the internal target method will be returning a boxed value, + * as an untyped object. + *

+ * Produce a value converter which will be typed to convert from + * {@code Object} to the return value of {@code rawEntryType}, and will + * in fact ensure that the value is compatible with the return type of + * {@code type}. + */ + private static MethodHandle computeReturnConversion( + MethodType type, MethodType rawEntryType, boolean mustCast) { + Class tret = type.returnType(); + Class rret = rawEntryType.returnType(); + if (mustCast || !tret.isPrimitive()) { + assert(!tret.isPrimitive()); + assert(!rret.isPrimitive()); + if (rret == Object.class && !mustCast) + return null; + return ValueConversions.cast(tret, false); + } else if (tret == rret) { + return ValueConversions.unbox(tret, false); + } else { + assert(rret.isPrimitive()); + assert(tret == double.class ? rret == long.class : rret == int.class); + return ValueConversions.unboxRaw(tret, false); + } + } + + Adapter makeInstance(MethodType type, MethodHandle genericTarget) { + genericTarget.getClass(); // check for NPE + MethodHandle convert = returnConversion; + if (primsAtEndOrder != null) + // reorder arguments passed to genericTarget, if primsAtEndOrder + throw new UnsupportedOperationException("NYI"); + if (type == entryType) { + if (convert == null) convert = ValueConversions.identity(); + return adapter.makeInstance(entryPoint, invoker, convert, genericTarget); + } + // my erased-type is not exactly the same as the desired type + assert(type.erase() == entryType); // else we are busted + if (convert == null) + convert = computeReturnConversion(type, rawEntryType, true); + // retype erased reference arguments (the cast makes it safe to do this) + MethodType tepType = type.insertParameterType(0, adapter.getClass()); + MethodHandle typedEntryPoint = + AdapterMethodHandle.makeRawRetypeOnly(Access.TOKEN, tepType, entryPoint); + return adapter.makeInstance(typedEntryPoint, invoker, convert, genericTarget); + } + + /** Build an adapter of the given type, which invokes genericTarget + * on the incoming arguments, after boxing as necessary. + * The return value is unboxed if necessary. + * @param type the required type of the + * @param genericTarget the target, which must accept and return only Object values + * @return an adapter method handle + */ + public static MethodHandle make(MethodType type, MethodHandle genericTarget) { + MethodType gtype = genericTarget.type(); + if (type.generic() != gtype) + throw new IllegalArgumentException(); + if (type == gtype) return genericTarget; + return ToGeneric.of(type).makeInstance(type, genericTarget); + } + + /** Return the adapter information for this type's erasure. */ + static ToGeneric of(MethodType type) { + MethodTypeImpl form = MethodTypeImpl.of(type); + ToGeneric toGen = form.toGeneric; + if (toGen == null) + form.toGeneric = toGen = new ToGeneric(form.erasedType()); + return toGen; + } + + public String toString() { + return "ToGeneric"+entryType + +(primsAtEndOrder!=null?"[reorder]":""); + } + + /* Create an adapter for the given incoming call type. */ + static Adapter findAdapter(MethodType entryPointType) { + MethodTypeImpl form = MethodTypeImpl.of(entryPointType); + Class rtype = entryPointType.returnType(); + int argc = form.parameterCount(); + int lac = form.longPrimitiveParameterCount(); + int iac = form.primitiveParameterCount() - lac; + String intsAndLongs = (iac > 0 ? "I"+iac : "")+(lac > 0 ? "J"+lac : ""); + String rawReturn = String.valueOf(Wrapper.forPrimitiveType(rtype).basicTypeChar()); + String iname0 = "invoke_"+rawReturn; + String iname1 = "invoke"; + String[] inames = { iname0, iname1 }; + String cname0 = rawReturn + argc; + String cname1 = "A" + argc; + String[] cnames = { cname1, cname1+intsAndLongs, cname0, cname0+intsAndLongs }; + // e.g., D5I2, D5, L5I2, L5 + for (String cname : cnames) { + Class acls = Adapter.findSubClass(cname); + if (acls == null) continue; + // see if it has the required invoke method + for (String iname : inames) { + MethodHandle entryPoint = null; + try { + entryPoint = MethodHandleImpl.IMPL_LOOKUP. + findSpecial(acls, iname, entryPointType, acls); + } catch (NoAccessException ex) { + } + if (entryPoint == null) continue; + Constructor ctor = null; + try { + // Prototype builder: + ctor = acls.getDeclaredConstructor(MethodHandle.class); + } catch (NoSuchMethodException ex) { + } catch (SecurityException ex) { + } + if (ctor == null) continue; + try { + return ctor.newInstance(entryPoint); + } catch (IllegalArgumentException ex) { + } catch (InvocationTargetException ex) { + } catch (InstantiationException ex) { + } catch (IllegalAccessException ex) { + } + } + } + return null; + } + + static Adapter buildAdapterFromBytecodes(MethodType entryPointType) { + throw new UnsupportedOperationException("NYI"); + } + + /** + * The invoke method takes some particular but unconstrained spread + * of raw argument types, and returns a raw return type (in L/I/J/F/D). + * Internally, it converts the incoming arguments uniformly into objects. + * This series of objects is then passed to the {@code target} method, + * which returns a result object. This result is finally converted, + * via another method handle {@code convert}, which is responsible for + * converting the object result into the raw return value. + */ + static abstract class Adapter extends JavaMethodHandle { + /* + * class X<> extends Adapter { + * Object...=>Object target; + * Object=>R convert; + * R invoke(A... a...) = convert(invoker(target, a...))) + * } + */ + protected final MethodHandle invoker; // (MH, Object...) -> Object + protected final MethodHandle target; // Object... -> Object + protected final MethodHandle convert; // Object -> R + + protected boolean isPrototype() { return target == null; } + /* Prototype constructor. */ + protected Adapter(MethodHandle entryPoint) { + super(entryPoint); + this.invoker = null; + this.convert = entryPoint; + this.target = null; + assert(isPrototype()); + } + protected MethodHandle prototypeEntryPoint() { + if (!isPrototype()) throw new InternalError(); + return convert; + } + + protected Adapter(MethodHandle entryPoint, MethodHandle invoker, MethodHandle convert, MethodHandle target) { + super(entryPoint); + this.invoker = invoker; + this.convert = convert; + this.target = target; + } + + /** Make a copy of self, with new fields. */ + protected abstract Adapter makeInstance(MethodHandle entryPoint, + MethodHandle invoker, MethodHandle convert, MethodHandle target); + // { return new ThisType(entryPoint, convert, target); } + + // Code to run when the arguments (<= 4) have all been boxed. + protected Object target() { return invoker.invoke(target); } + protected Object target(Object a0) { return invoker.invoke(target, a0); } + protected Object target(Object a0, Object a1) + { return invoker.invoke(target, a0, a1); } + protected Object target(Object a0, Object a1, Object a2) + { return invoker.invoke(target, a0, a1, a2); } + protected Object target(Object a0, Object a1, Object a2, Object a3) + { return invoker.invoke(target, a0, a1, a2, a3); } + /* + protected Object target_0(Object... av) { return invoker.invoke(target, av); } + protected Object target_1(Object a0, Object... av) + { return invoker.invoke(target, a0, (Object)av); } + protected Object target_2(Object a0, Object a1, Object... av) + { return invoker.invoke(target, a0, a1, (Object)av); } + protected Object target_3(Object a0, Object a1, Object a2, Object... av) + { return invoker.invoke(target, a0, a1, a2, (Object)av); } + protected Object target_4(Object a0, Object a1, Object a2, Object a3, Object... av) + { return invoker.invoke(target, a0, a1, a2, a3, (Object)av); } + // */ + // (For more than 4 arguments, generate the code in the adapter itself.) + + // Code to run when the generic target has finished and produced a value. + protected Object return_L(Object res) { return convert.invoke(res); } + protected int return_I(Object res) { return convert.invoke(res); } + protected long return_J(Object res) { return convert.invoke(res); } + protected float return_F(Object res) { return convert.invoke(res); } + protected double return_D(Object res) { return convert.invoke(res); } + + static private final String CLASS_PREFIX; // "sun.dyn.ToGeneric$" + static { + String aname = Adapter.class.getName(); + String sname = Adapter.class.getSimpleName(); + if (!aname.endsWith(sname)) throw new InternalError(); + CLASS_PREFIX = aname.substring(0, aname.length() - sname.length()); + } + /** Find a sibing class of Adapter. */ + static Class findSubClass(String name) { + String cname = Adapter.CLASS_PREFIX + name; + try { + return Class.forName(cname).asSubclass(Adapter.class); + } catch (ClassNotFoundException ex) { + return null; + } catch (ClassCastException ex) { + return null; + } + } + } + + /* generated classes follow this pattern: + static class A1 extends Adapter { + protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A1(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } + protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A1(e, i, c, t); } + protected Object target(Object a0) { return invoker.invoke(target, a0); } + protected Object targetA1(Object a0) { return target(a0); } + protected Object targetA1(int a0) { return target(a0); } + protected Object targetA1(long a0) { return target(a0); } + protected Object invoke_L(Object a0) { return return_L(targetA1(a0)); } + protected int invoke_I(Object a0) { return return_I(targetA1(a0)); } + protected long invoke_J(Object a0) { return return_J(targetA1(a0)); } + protected float invoke_F(Object a0) { return return_F(targetA1(a0)); } + protected double invoke_D(Object a0) { return return_D(targetA1(a0)); } + protected Object invoke_L(int a0) { return return_L(targetA1(a0)); } + protected int invoke_I(int a0) { return return_I(targetA1(a0)); } + protected long invoke_J(int a0) { return return_J(targetA1(a0)); } + protected float invoke_F(int a0) { return return_F(targetA1(a0)); } + protected double invoke_D(int a0) { return return_D(targetA1(a0)); } + protected Object invoke_L(long a0) { return return_L(targetA1(a0)); } + protected int invoke_I(long a0) { return return_I(targetA1(a0)); } + protected long invoke_J(long a0) { return return_J(targetA1(a0)); } + protected float invoke_F(long a0) { return return_F(targetA1(a0)); } + protected double invoke_D(long a0) { return return_D(targetA1(a0)); } + } + // */ + +/* +: SHELL; n=ToGeneric; cp -p $n.java $n.java-; sed < $n.java- > $n.java+ -e '/{{*{{/,/}}*}}/w /tmp/genclasses.java' -e '/}}*}}/q'; (cd /tmp; javac -d . genclasses.java; java -cp . genclasses) >> $n.java+; echo '}' >> $n.java+; mv $n.java+ $n.java; mv $n.java- $n.java~ +//{{{ +import java.util.*; +class genclasses { + static String[] TYPES = { "Object", "int ", "long ", "float ", "double" }; + static String[] TCHARS = { "L", "I", "J", "F", "D", "A" }; + static String[][] TEMPLATES = { { + "@for@ arity=0..3 rcat<=4 nrefs<=99 nints<=99 nlongs<=99", + "@for@ arity=4..5 rcat<=2 nrefs<=99 nints<=99 nlongs<=99", + "@for@ arity=6..10 rcat<=2 nrefs<=99 nints=0 nlongs<=99", + " //@each-cat@", + " static class @cat@ extends Adapter {", + " protected @cat@(MethodHandle entryPoint) { super(entryPoint); } // to build prototype", + " protected @cat@(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }", + " protected @cat@ makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new @cat@(e, i, c, t); }", + " protected Object target(@Ovav@) { return invoker.invoke(target, @av@); }", + " //@each-Tv@", + " protected Object target@cat@(@Tvav@) { return target(@av@); }", + " //@end-Tv@", + " //@each-Tv@", + " //@each-R@", + " protected @R@ invoke_@Rc@(@Tvav@) { return return_@Rc@(target@cat@(@av@)); }", + " //@end-R@", + " //@end-Tv@", + " }", + } }; + enum VAR { + cat, R, Rc, Tv, av, Tvav, Ovav; + public final String pattern = "@"+toString().replace('_','.')+"@"; + public String binding; + static void makeBindings(boolean topLevel, int rcat, int nrefs, int nints, int nlongs) { + int nargs = nrefs + nints + nlongs; + if (topLevel) + VAR.cat.binding = catstr(ALL_RETURN_TYPES ? TYPES.length : rcat, nrefs, nints, nlongs); + VAR.R.binding = TYPES[rcat]; + VAR.Rc.binding = TCHARS[rcat]; + String[] Tv = new String[nargs]; + String[] av = new String[nargs]; + String[] Tvav = new String[nargs]; + String[] Ovav = new String[nargs]; + for (int i = 0; i < nargs; i++) { + int tcat = (i < nrefs) ? 0 : (i < nrefs + nints) ? 1 : 2; + Tv[i] = TYPES[tcat]; + av[i] = arg(i); + Tvav[i] = param(Tv[i], av[i]); + Ovav[i] = param("Object", av[i]); + } + VAR.Tv.binding = comma(Tv); + VAR.av.binding = comma(av); + VAR.Tvav.binding = comma(Tvav); + VAR.Ovav.binding = comma(Ovav); + } + static String arg(int i) { return "a"+i; } + static String param(String t, String a) { return t+" "+a; } + static String comma(String[] v) { return comma(v, ""); } + static String comma(String sep, String[] v) { + if (v.length == 0) return ""; + String res = sep+v[0]; + for (int i = 1; i < v.length; i++) res += ", "+v[i]; + return res; + } + static String transform(String string) { + for (VAR var : values()) + string = string.replaceAll(var.pattern, var.binding); + return string; + } + } + static String[] stringsIn(String[] strings, int beg, int end) { + return Arrays.copyOfRange(strings, beg, Math.min(end, strings.length)); + } + static String[] stringsBefore(String[] strings, int pos) { + return stringsIn(strings, 0, pos); + } + static String[] stringsAfter(String[] strings, int pos) { + return stringsIn(strings, pos, strings.length); + } + static int indexAfter(String[] strings, int pos, String tag) { + return Math.min(indexBefore(strings, pos, tag) + 1, strings.length); + } + static int indexBefore(String[] strings, int pos, String tag) { + for (int i = pos, end = strings.length; ; i++) { + if (i == end || strings[i].endsWith(tag)) return i; + } + } + static int MIN_ARITY, MAX_ARITY, MAX_RCAT, MAX_REFS, MAX_INTS, MAX_LONGS; + static boolean ALL_ARG_TYPES, ALL_RETURN_TYPES; + static HashSet done = new HashSet(); + public static void main(String... av) { + for (String[] template : TEMPLATES) { + int forLinesLimit = indexBefore(template, 0, "@each-cat@"); + String[] forLines = stringsBefore(template, forLinesLimit); + template = stringsAfter(template, forLinesLimit); + for (String forLine : forLines) + expandTemplate(forLine, template); + } + } + static void expandTemplate(String forLine, String[] template) { + String[] params = forLine.split("[^0-9]+"); + if (params[0].length() == 0) params = stringsAfter(params, 1); + System.out.println("//params="+Arrays.asList(params)); + int pcur = 0; + MIN_ARITY = Integer.valueOf(params[pcur++]); + MAX_ARITY = Integer.valueOf(params[pcur++]); + MAX_RCAT = Integer.valueOf(params[pcur++]); + MAX_REFS = Integer.valueOf(params[pcur++]); + MAX_INTS = Integer.valueOf(params[pcur++]); + MAX_LONGS = Integer.valueOf(params[pcur++]); + if (pcur != params.length) throw new RuntimeException("bad extra param: "+forLine); + if (MAX_RCAT >= TYPES.length) MAX_RCAT = TYPES.length - 1; + ALL_ARG_TYPES = (indexBefore(template, 0, "@each-Tv@") < template.length); + ALL_RETURN_TYPES = (indexBefore(template, 0, "@each-R@") < template.length); + for (int nargs = MIN_ARITY; nargs <= MAX_ARITY; nargs++) { + for (int rcat = 0; rcat <= MAX_RCAT; rcat++) { + expandTemplate(template, true, rcat, nargs, 0, 0); + if (ALL_ARG_TYPES) break; + expandTemplateForPrims(template, true, rcat, nargs, 1, 1); + if (ALL_RETURN_TYPES) break; + } + } + } + static String catstr(int rcat, int nrefs, int nints, int nlongs) { + int nargs = nrefs + nints + nlongs; + String cat = TCHARS[rcat] + nargs; + if (!ALL_ARG_TYPES) cat += (nints==0?"":"I"+nints)+(nlongs==0?"":"J"+nlongs); + return cat; + } + static void expandTemplateForPrims(String[] template, boolean topLevel, int rcat, int nargs, int minints, int minlongs) { + for (int isLong = 0; isLong <= 1; isLong++) { + for (int nprims = 1; nprims <= nargs; nprims++) { + int nrefs = nargs - nprims; + int nints = ((1-isLong) * nprims); + int nlongs = (isLong * nprims); + expandTemplate(template, topLevel, rcat, nrefs, nints, nlongs); + } + } + } + static void expandTemplate(String[] template, boolean topLevel, + int rcat, int nrefs, int nints, int nlongs) { + int nargs = nrefs + nints + nlongs; + if (nrefs > MAX_REFS || nints > MAX_INTS || nlongs > MAX_LONGS) return; + VAR.makeBindings(topLevel, rcat, nrefs, nints, nlongs); + if (topLevel && !done.add(VAR.cat.binding)) { + System.out.println(" //repeat "+VAR.cat.binding); + return; + } + for (int i = 0; i < template.length; i++) { + String line = template[i]; + if (line.endsWith("@each-cat@")) { + // ignore + } else if (line.endsWith("@each-R@")) { + int blockEnd = indexAfter(template, i, "@end-R@"); + String[] block = stringsIn(template, i+1, blockEnd-1); + for (int rcat1 = rcat; rcat1 <= MAX_RCAT; rcat1++) + expandTemplate(block, false, rcat1, nrefs, nints, nlongs); + VAR.makeBindings(topLevel, rcat, nrefs, nints, nlongs); + i = blockEnd-1; continue; + } else if (line.endsWith("@each-Tv@")) { + int blockEnd = indexAfter(template, i, "@end-Tv@"); + String[] block = stringsIn(template, i+1, blockEnd-1); + expandTemplate(block, false, rcat, nrefs, nints, nlongs); + expandTemplateForPrims(block, false, rcat, nargs, nints+1, nlongs+1); + VAR.makeBindings(topLevel, rcat, nrefs, nints, nlongs); + i = blockEnd-1; continue; + } else { + System.out.println(VAR.transform(line)); + } + } + } +} +//}}} */ +//params=[0, 3, 4, 99, 99, 99] + static class A0 extends Adapter { + protected A0(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A0(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } + protected A0 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A0(e, i, c, t); } + protected Object target() { return invoker.invoke(target); } + protected Object targetA0() { return target(); } + protected Object invoke_L() { return return_L(targetA0()); } + protected int invoke_I() { return return_I(targetA0()); } + protected long invoke_J() { return return_J(targetA0()); } + protected float invoke_F() { return return_F(targetA0()); } + protected double invoke_D() { return return_D(targetA0()); } + } + static class A1 extends Adapter { + protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A1(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } + protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A1(e, i, c, t); } + protected Object target(Object a0) { return invoker.invoke(target, a0); } + protected Object targetA1(Object a0) { return target(a0); } + protected Object targetA1(int a0) { return target(a0); } + protected Object targetA1(long a0) { return target(a0); } + protected Object invoke_L(Object a0) { return return_L(targetA1(a0)); } + protected int invoke_I(Object a0) { return return_I(targetA1(a0)); } + protected long invoke_J(Object a0) { return return_J(targetA1(a0)); } + protected float invoke_F(Object a0) { return return_F(targetA1(a0)); } + protected double invoke_D(Object a0) { return return_D(targetA1(a0)); } + protected Object invoke_L(int a0) { return return_L(targetA1(a0)); } + protected int invoke_I(int a0) { return return_I(targetA1(a0)); } + protected long invoke_J(int a0) { return return_J(targetA1(a0)); } + protected float invoke_F(int a0) { return return_F(targetA1(a0)); } + protected double invoke_D(int a0) { return return_D(targetA1(a0)); } + protected Object invoke_L(long a0) { return return_L(targetA1(a0)); } + protected int invoke_I(long a0) { return return_I(targetA1(a0)); } + protected long invoke_J(long a0) { return return_J(targetA1(a0)); } + protected float invoke_F(long a0) { return return_F(targetA1(a0)); } + protected double invoke_D(long a0) { return return_D(targetA1(a0)); } + } + static class A2 extends Adapter { + protected A2(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A2(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } + protected A2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A2(e, i, c, t); } + protected Object target(Object a0, Object a1) { return invoker.invoke(target, a0, a1); } + protected Object targetA2(Object a0, Object a1) { return target(a0, a1); } + protected Object targetA2(Object a0, int a1) { return target(a0, a1); } + protected Object targetA2(int a0, int a1) { return target(a0, a1); } + protected Object targetA2(Object a0, long a1) { return target(a0, a1); } + protected Object targetA2(long a0, long a1) { return target(a0, a1); } + protected Object invoke_L(Object a0, Object a1) { return return_L(targetA2(a0, a1)); } + protected int invoke_I(Object a0, Object a1) { return return_I(targetA2(a0, a1)); } + protected long invoke_J(Object a0, Object a1) { return return_J(targetA2(a0, a1)); } + protected float invoke_F(Object a0, Object a1) { return return_F(targetA2(a0, a1)); } + protected double invoke_D(Object a0, Object a1) { return return_D(targetA2(a0, a1)); } + protected Object invoke_L(Object a0, int a1) { return return_L(targetA2(a0, a1)); } + protected int invoke_I(Object a0, int a1) { return return_I(targetA2(a0, a1)); } + protected long invoke_J(Object a0, int a1) { return return_J(targetA2(a0, a1)); } + protected float invoke_F(Object a0, int a1) { return return_F(targetA2(a0, a1)); } + protected double invoke_D(Object a0, int a1) { return return_D(targetA2(a0, a1)); } + protected Object invoke_L(int a0, int a1) { return return_L(targetA2(a0, a1)); } + protected int invoke_I(int a0, int a1) { return return_I(targetA2(a0, a1)); } + protected long invoke_J(int a0, int a1) { return return_J(targetA2(a0, a1)); } + protected float invoke_F(int a0, int a1) { return return_F(targetA2(a0, a1)); } + protected double invoke_D(int a0, int a1) { return return_D(targetA2(a0, a1)); } + protected Object invoke_L(Object a0, long a1) { return return_L(targetA2(a0, a1)); } + protected int invoke_I(Object a0, long a1) { return return_I(targetA2(a0, a1)); } + protected long invoke_J(Object a0, long a1) { return return_J(targetA2(a0, a1)); } + protected float invoke_F(Object a0, long a1) { return return_F(targetA2(a0, a1)); } + protected double invoke_D(Object a0, long a1) { return return_D(targetA2(a0, a1)); } + protected Object invoke_L(long a0, long a1) { return return_L(targetA2(a0, a1)); } + protected int invoke_I(long a0, long a1) { return return_I(targetA2(a0, a1)); } + protected long invoke_J(long a0, long a1) { return return_J(targetA2(a0, a1)); } + protected float invoke_F(long a0, long a1) { return return_F(targetA2(a0, a1)); } + protected double invoke_D(long a0, long a1) { return return_D(targetA2(a0, a1)); } + } + static class A3 extends Adapter { + protected A3(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A3(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } + protected A3 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A3(e, i, c, t); } + protected Object target(Object a0, Object a1, Object a2) { return invoker.invoke(target, a0, a1, a2); } + protected Object targetA3(Object a0, Object a1, Object a2) { return target(a0, a1, a2); } + protected Object targetA3(Object a0, Object a1, int a2) { return target(a0, a1, a2); } + protected Object targetA3(Object a0, int a1, int a2) { return target(a0, a1, a2); } + protected Object targetA3(int a0, int a1, int a2) { return target(a0, a1, a2); } + protected Object targetA3(Object a0, Object a1, long a2) { return target(a0, a1, a2); } + protected Object targetA3(Object a0, long a1, long a2) { return target(a0, a1, a2); } + protected Object targetA3(long a0, long a1, long a2) { return target(a0, a1, a2); } + protected Object invoke_L(Object a0, Object a1, Object a2) { return return_L(targetA3(a0, a1, a2)); } + protected int invoke_I(Object a0, Object a1, Object a2) { return return_I(targetA3(a0, a1, a2)); } + protected long invoke_J(Object a0, Object a1, Object a2) { return return_J(targetA3(a0, a1, a2)); } + protected float invoke_F(Object a0, Object a1, Object a2) { return return_F(targetA3(a0, a1, a2)); } + protected double invoke_D(Object a0, Object a1, Object a2) { return return_D(targetA3(a0, a1, a2)); } + protected Object invoke_L(Object a0, Object a1, int a2) { return return_L(targetA3(a0, a1, a2)); } + protected int invoke_I(Object a0, Object a1, int a2) { return return_I(targetA3(a0, a1, a2)); } + protected long invoke_J(Object a0, Object a1, int a2) { return return_J(targetA3(a0, a1, a2)); } + protected float invoke_F(Object a0, Object a1, int a2) { return return_F(targetA3(a0, a1, a2)); } + protected double invoke_D(Object a0, Object a1, int a2) { return return_D(targetA3(a0, a1, a2)); } + protected Object invoke_L(Object a0, int a1, int a2) { return return_L(targetA3(a0, a1, a2)); } + protected int invoke_I(Object a0, int a1, int a2) { return return_I(targetA3(a0, a1, a2)); } + protected long invoke_J(Object a0, int a1, int a2) { return return_J(targetA3(a0, a1, a2)); } + protected float invoke_F(Object a0, int a1, int a2) { return return_F(targetA3(a0, a1, a2)); } + protected double invoke_D(Object a0, int a1, int a2) { return return_D(targetA3(a0, a1, a2)); } + protected Object invoke_L(int a0, int a1, int a2) { return return_L(targetA3(a0, a1, a2)); } + protected int invoke_I(int a0, int a1, int a2) { return return_I(targetA3(a0, a1, a2)); } + protected long invoke_J(int a0, int a1, int a2) { return return_J(targetA3(a0, a1, a2)); } + protected float invoke_F(int a0, int a1, int a2) { return return_F(targetA3(a0, a1, a2)); } + protected double invoke_D(int a0, int a1, int a2) { return return_D(targetA3(a0, a1, a2)); } + protected Object invoke_L(Object a0, Object a1, long a2) { return return_L(targetA3(a0, a1, a2)); } + protected int invoke_I(Object a0, Object a1, long a2) { return return_I(targetA3(a0, a1, a2)); } + protected long invoke_J(Object a0, Object a1, long a2) { return return_J(targetA3(a0, a1, a2)); } + protected float invoke_F(Object a0, Object a1, long a2) { return return_F(targetA3(a0, a1, a2)); } + protected double invoke_D(Object a0, Object a1, long a2) { return return_D(targetA3(a0, a1, a2)); } + protected Object invoke_L(Object a0, long a1, long a2) { return return_L(targetA3(a0, a1, a2)); } + protected int invoke_I(Object a0, long a1, long a2) { return return_I(targetA3(a0, a1, a2)); } + protected long invoke_J(Object a0, long a1, long a2) { return return_J(targetA3(a0, a1, a2)); } + protected float invoke_F(Object a0, long a1, long a2) { return return_F(targetA3(a0, a1, a2)); } + protected double invoke_D(Object a0, long a1, long a2) { return return_D(targetA3(a0, a1, a2)); } + protected Object invoke_L(long a0, long a1, long a2) { return return_L(targetA3(a0, a1, a2)); } + protected int invoke_I(long a0, long a1, long a2) { return return_I(targetA3(a0, a1, a2)); } + protected long invoke_J(long a0, long a1, long a2) { return return_J(targetA3(a0, a1, a2)); } + protected float invoke_F(long a0, long a1, long a2) { return return_F(targetA3(a0, a1, a2)); } + protected double invoke_D(long a0, long a1, long a2) { return return_D(targetA3(a0, a1, a2)); } + } +//params=[4, 5, 2, 99, 99, 99] + static class A4 extends Adapter { + protected A4(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A4(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } + protected A4 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A4(e, i, c, t); } + protected Object target(Object a0, Object a1, Object a2, Object a3) { return invoker.invoke(target, a0, a1, a2, a3); } + protected Object targetA4(Object a0, Object a1, Object a2, Object a3) { return target(a0, a1, a2, a3); } + protected Object targetA4(Object a0, Object a1, Object a2, int a3) { return target(a0, a1, a2, a3); } + protected Object targetA4(Object a0, Object a1, int a2, int a3) { return target(a0, a1, a2, a3); } + protected Object targetA4(Object a0, int a1, int a2, int a3) { return target(a0, a1, a2, a3); } + protected Object targetA4(int a0, int a1, int a2, int a3) { return target(a0, a1, a2, a3); } + protected Object targetA4(Object a0, Object a1, Object a2, long a3) { return target(a0, a1, a2, a3); } + protected Object targetA4(Object a0, Object a1, long a2, long a3) { return target(a0, a1, a2, a3); } + protected Object targetA4(Object a0, long a1, long a2, long a3) { return target(a0, a1, a2, a3); } + protected Object targetA4(long a0, long a1, long a2, long a3) { return target(a0, a1, a2, a3); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3) { return return_L(targetA4(a0, a1, a2, a3)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3) { return return_I(targetA4(a0, a1, a2, a3)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3) { return return_J(targetA4(a0, a1, a2, a3)); } + protected Object invoke_L(Object a0, Object a1, Object a2, int a3) { return return_L(targetA4(a0, a1, a2, a3)); } + protected int invoke_I(Object a0, Object a1, Object a2, int a3) { return return_I(targetA4(a0, a1, a2, a3)); } + protected long invoke_J(Object a0, Object a1, Object a2, int a3) { return return_J(targetA4(a0, a1, a2, a3)); } + protected Object invoke_L(Object a0, Object a1, int a2, int a3) { return return_L(targetA4(a0, a1, a2, a3)); } + protected int invoke_I(Object a0, Object a1, int a2, int a3) { return return_I(targetA4(a0, a1, a2, a3)); } + protected long invoke_J(Object a0, Object a1, int a2, int a3) { return return_J(targetA4(a0, a1, a2, a3)); } + protected Object invoke_L(Object a0, int a1, int a2, int a3) { return return_L(targetA4(a0, a1, a2, a3)); } + protected int invoke_I(Object a0, int a1, int a2, int a3) { return return_I(targetA4(a0, a1, a2, a3)); } + protected long invoke_J(Object a0, int a1, int a2, int a3) { return return_J(targetA4(a0, a1, a2, a3)); } + protected Object invoke_L(int a0, int a1, int a2, int a3) { return return_L(targetA4(a0, a1, a2, a3)); } + protected int invoke_I(int a0, int a1, int a2, int a3) { return return_I(targetA4(a0, a1, a2, a3)); } + protected long invoke_J(int a0, int a1, int a2, int a3) { return return_J(targetA4(a0, a1, a2, a3)); } + protected Object invoke_L(Object a0, Object a1, Object a2, long a3) { return return_L(targetA4(a0, a1, a2, a3)); } + protected int invoke_I(Object a0, Object a1, Object a2, long a3) { return return_I(targetA4(a0, a1, a2, a3)); } + protected long invoke_J(Object a0, Object a1, Object a2, long a3) { return return_J(targetA4(a0, a1, a2, a3)); } + protected Object invoke_L(Object a0, Object a1, long a2, long a3) { return return_L(targetA4(a0, a1, a2, a3)); } + protected int invoke_I(Object a0, Object a1, long a2, long a3) { return return_I(targetA4(a0, a1, a2, a3)); } + protected long invoke_J(Object a0, Object a1, long a2, long a3) { return return_J(targetA4(a0, a1, a2, a3)); } + protected Object invoke_L(Object a0, long a1, long a2, long a3) { return return_L(targetA4(a0, a1, a2, a3)); } + protected int invoke_I(Object a0, long a1, long a2, long a3) { return return_I(targetA4(a0, a1, a2, a3)); } + protected long invoke_J(Object a0, long a1, long a2, long a3) { return return_J(targetA4(a0, a1, a2, a3)); } + protected Object invoke_L(long a0, long a1, long a2, long a3) { return return_L(targetA4(a0, a1, a2, a3)); } + protected int invoke_I(long a0, long a1, long a2, long a3) { return return_I(targetA4(a0, a1, a2, a3)); } + protected long invoke_J(long a0, long a1, long a2, long a3) { return return_J(targetA4(a0, a1, a2, a3)); } + } + static class A5 extends Adapter { + protected A5(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A5(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } + protected A5 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A5(e, i, c, t); } + protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4) { return invoker.invoke(target, a0, a1, a2, a3, a4); } + protected Object targetA5(Object a0, Object a1, Object a2, Object a3, Object a4) { return target(a0, a1, a2, a3, a4); } + protected Object targetA5(Object a0, Object a1, Object a2, Object a3, int a4) { return target(a0, a1, a2, a3, a4); } + protected Object targetA5(Object a0, Object a1, Object a2, int a3, int a4) { return target(a0, a1, a2, a3, a4); } + protected Object targetA5(Object a0, Object a1, int a2, int a3, int a4) { return target(a0, a1, a2, a3, a4); } + protected Object targetA5(Object a0, int a1, int a2, int a3, int a4) { return target(a0, a1, a2, a3, a4); } + protected Object targetA5(int a0, int a1, int a2, int a3, int a4) { return target(a0, a1, a2, a3, a4); } + protected Object targetA5(Object a0, Object a1, Object a2, Object a3, long a4) { return target(a0, a1, a2, a3, a4); } + protected Object targetA5(Object a0, Object a1, Object a2, long a3, long a4) { return target(a0, a1, a2, a3, a4); } + protected Object targetA5(Object a0, Object a1, long a2, long a3, long a4) { return target(a0, a1, a2, a3, a4); } + protected Object targetA5(Object a0, long a1, long a2, long a3, long a4) { return target(a0, a1, a2, a3, a4); } + protected Object targetA5(long a0, long a1, long a2, long a3, long a4) { return target(a0, a1, a2, a3, a4); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, int a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, int a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, int a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); } + protected Object invoke_L(Object a0, Object a1, Object a2, int a3, int a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); } + protected int invoke_I(Object a0, Object a1, Object a2, int a3, int a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); } + protected long invoke_J(Object a0, Object a1, Object a2, int a3, int a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); } + protected Object invoke_L(Object a0, Object a1, int a2, int a3, int a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); } + protected int invoke_I(Object a0, Object a1, int a2, int a3, int a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); } + protected long invoke_J(Object a0, Object a1, int a2, int a3, int a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); } + protected Object invoke_L(Object a0, int a1, int a2, int a3, int a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); } + protected int invoke_I(Object a0, int a1, int a2, int a3, int a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); } + protected long invoke_J(Object a0, int a1, int a2, int a3, int a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); } + protected Object invoke_L(int a0, int a1, int a2, int a3, int a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); } + protected int invoke_I(int a0, int a1, int a2, int a3, int a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); } + protected long invoke_J(int a0, int a1, int a2, int a3, int a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); } + protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); } + protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); } + protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); } + protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); } + protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); } + protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); } + protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); } + protected int invoke_I(Object a0, long a1, long a2, long a3, long a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); } + protected long invoke_J(Object a0, long a1, long a2, long a3, long a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); } + protected Object invoke_L(long a0, long a1, long a2, long a3, long a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); } + protected int invoke_I(long a0, long a1, long a2, long a3, long a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); } + protected long invoke_J(long a0, long a1, long a2, long a3, long a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); } + } +//params=[6, 10, 2, 99, 0, 99] + static class A6 extends Adapter { + protected A6(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A6(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } + protected A6 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A6(e, i, c, t); } + protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return invoker.invoke(target, a0, a1, a2, a3, a4, a5); } + protected Object targetA6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return target(a0, a1, a2, a3, a4, a5); } + protected Object targetA6(Object a0, Object a1, Object a2, Object a3, Object a4, long a5) { return target(a0, a1, a2, a3, a4, a5); } + protected Object targetA6(Object a0, Object a1, Object a2, Object a3, long a4, long a5) { return target(a0, a1, a2, a3, a4, a5); } + protected Object targetA6(Object a0, Object a1, Object a2, long a3, long a4, long a5) { return target(a0, a1, a2, a3, a4, a5); } + protected Object targetA6(Object a0, Object a1, long a2, long a3, long a4, long a5) { return target(a0, a1, a2, a3, a4, a5); } + protected Object targetA6(Object a0, long a1, long a2, long a3, long a4, long a5) { return target(a0, a1, a2, a3, a4, a5); } + protected Object targetA6(long a0, long a1, long a2, long a3, long a4, long a5) { return target(a0, a1, a2, a3, a4, a5); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4, long a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4, long a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4, long a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); } + protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4, long a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); } + protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4, long a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); } + protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4, long a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); } + protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4, long a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); } + protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4, long a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); } + protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4, long a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); } + protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4, long a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); } + protected int invoke_I(Object a0, long a1, long a2, long a3, long a4, long a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); } + protected long invoke_J(Object a0, long a1, long a2, long a3, long a4, long a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); } + protected Object invoke_L(long a0, long a1, long a2, long a3, long a4, long a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); } + protected int invoke_I(long a0, long a1, long a2, long a3, long a4, long a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); } + protected long invoke_J(long a0, long a1, long a2, long a3, long a4, long a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); } + } + static class A7 extends Adapter { + protected A7(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A7(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } + protected A7 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A7(e, i, c, t); } + protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6); } + protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return target(a0, a1, a2, a3, a4, a5, a6); } + protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6) { return target(a0, a1, a2, a3, a4, a5, a6); } + protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6) { return target(a0, a1, a2, a3, a4, a5, a6); } + protected Object targetA7(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6) { return target(a0, a1, a2, a3, a4, a5, a6); } + protected Object targetA7(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6) { return target(a0, a1, a2, a3, a4, a5, a6); } + protected Object targetA7(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6) { return target(a0, a1, a2, a3, a4, a5, a6); } + protected Object targetA7(Object a0, long a1, long a2, long a3, long a4, long a5, long a6) { return target(a0, a1, a2, a3, a4, a5, a6); } + protected Object targetA7(long a0, long a1, long a2, long a3, long a4, long a5, long a6) { return target(a0, a1, a2, a3, a4, a5, a6); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4, long a5, long a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected int invoke_I(Object a0, long a1, long a2, long a3, long a4, long a5, long a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected long invoke_J(Object a0, long a1, long a2, long a3, long a4, long a5, long a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_L(long a0, long a1, long a2, long a3, long a4, long a5, long a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected int invoke_I(long a0, long a1, long a2, long a3, long a4, long a5, long a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected long invoke_J(long a0, long a1, long a2, long a3, long a4, long a5, long a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + } + static class A8 extends Adapter { + protected A8(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A8(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } + protected A8 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A8(e, i, c, t); } + protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object targetA8(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object targetA8(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object targetA8(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object targetA8(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object targetA8(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected int invoke_I(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected long invoke_J(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_L(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected int invoke_I(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected long invoke_J(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + } + static class A9 extends Adapter { + protected A9(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A9(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } + protected A9 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A9(e, i, c, t); } + protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object targetA9(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object targetA9(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object targetA9(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object targetA9(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object targetA9(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected int invoke_I(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected long invoke_J(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_L(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected int invoke_I(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected long invoke_J(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + } + static class A10 extends Adapter { + protected A10(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected A10(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } + protected A10 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A10(e, i, c, t); } + protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object targetA10(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object targetA10(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object targetA10(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object targetA10(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object targetA10(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected int invoke_I(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected long invoke_J(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_L(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected int invoke_I(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected long invoke_J(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + } +} diff --git a/jdk/src/share/classes/sun/dyn/anon/AnonymousClassLoader.java b/jdk/src/share/classes/sun/dyn/anon/AnonymousClassLoader.java new file mode 100644 index 00000000000..a182161271b --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/anon/AnonymousClassLoader.java @@ -0,0 +1,297 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn.anon; + +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. + *

+ * The access permissions of the anonymous class are borrowed from + * a host class. 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). + *

+ * 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.) + *

+ * 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. + * + *

%%% TO-DO: + *

    + *
  • needs better documentation
  • + *
  • needs more security work (for safe delegation)
  • + *
  • needs a clearer story about error processing
  • + *
  • patch member references also (use ';' as delimiter char)
  • + *
  • patch method references to (conforming) method handles
  • + *
+ * + * @author jrose + * @author Remi Forax + * @see + * http://blogs.sun.com/jrose/entry/anonymous_classes_in_the_vm + */ + +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., 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 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/jdk/src/share/classes/sun/dyn/anon/ConstantPoolParser.java b/jdk/src/share/classes/sun/dyn/anon/ConstantPoolParser.java new file mode 100644 index 00000000000..db12e950355 --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/anon/ConstantPoolParser.java @@ -0,0 +1,368 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn.anon; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; + +import static sun.dyn.anon.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/jdk/src/share/classes/sun/dyn/anon/ConstantPoolPatch.java b/jdk/src/share/classes/sun/dyn/anon/ConstantPoolPatch.java new file mode 100644 index 00000000000..2775ad2f67d --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/anon/ConstantPoolPatch.java @@ -0,0 +1,503 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn.anon; + +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 sun.dyn.anon.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 utf8Map, + final Map classMap, + final Map valueMap, + boolean deleteUsedEntries) throws InvalidConstantPoolFormatException { + final HashSet usedUtf8Keys; + final HashSet usedClassKeys; + final HashSet usedValueKeys; + if (deleteUsedEntries) { + usedUtf8Keys = (utf8Map == null) ? null : new HashSet(); + usedClassKeys = (classMap == null) ? null : new HashSet(); + usedValueKeys = (valueMap == null) ? null : new HashSet(); + } 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, Byte> CONSTANT_VALUE_CLASS_TAG + = new IdentityHashMap, 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/jdk/src/share/classes/sun/dyn/anon/ConstantPoolVisitor.java b/jdk/src/share/classes/sun/dyn/anon/ConstantPoolVisitor.java new file mode 100644 index 00000000000..4157f13e77f --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/anon/ConstantPoolVisitor.java @@ -0,0 +1,192 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn.anon; + +/** + * A visitor called by {@link ConstantPoolParser#parse(ConstantPoolVisitor)} + * when a constant pool entry is parsed. + *

+ * 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. + *

+ * 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. + *

+ * The following table shows the relation between constant pool entry + * types and the corresponding visit* methods: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Tag(s)Method
{@link #CONSTANT_Utf8}{@link #visitUTF8(int, byte, String)}
{@link #CONSTANT_Integer}, {@link #CONSTANT_Float}, + * {@link #CONSTANT_Long}, {@link #CONSTANT_Double}{@link #visitConstantValue(int, byte, Object)}
{@link #CONSTANT_String}, {@link #CONSTANT_Class}{@link #visitConstantString(int, byte, String, int)}
{@link #CONSTANT_NameAndType}{@link #visitDescriptor(int, byte, String, String, int, int)}
{@link #CONSTANT_Fieldref}, + * {@link #CONSTANT_Methodref}, + * {@link #CONSTANT_InterfaceMethodref}{@link #visitMemberRef(int, byte, String, String, String, int, int)}
+ * + * @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/jdk/src/share/classes/sun/dyn/anon/InvalidConstantPoolFormatException.java b/jdk/src/share/classes/sun/dyn/anon/InvalidConstantPoolFormatException.java new file mode 100644 index 00000000000..652f7318b05 --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/anon/InvalidConstantPoolFormatException.java @@ -0,0 +1,45 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn.anon; + +/** 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/jdk/src/share/classes/sun/dyn/empty/Empty.java b/jdk/src/share/classes/sun/dyn/empty/Empty.java new file mode 100644 index 00000000000..4fb72d0be67 --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/empty/Empty.java @@ -0,0 +1,36 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn.empty; + +/** + * An empty class in an empty package. + * Used as a proxy for unprivileged code, since making access checks + * against it will only succeed against public methods in public types. + * @author jrose + */ +public class Empty { + private Empty() { throw new InternalError(); } +} diff --git a/jdk/src/share/classes/sun/dyn/package-info.java b/jdk/src/share/classes/sun/dyn/package-info.java new file mode 100644 index 00000000000..93aa427f365 --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/package-info.java @@ -0,0 +1,35 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * Implementation details for JSR 292 RI, package java.dyn. + * This particular version is specific to Hotspot. + * There is also a backport version of this sub-package which uses reflection, + * and can therefore run (slowly) on older versions of Java. + * Other JVM vendors may create their own versions of this sub-package. + * @author jrose + */ + +package sun.dyn; diff --git a/jdk/src/share/classes/sun/dyn/util/BytecodeName.java b/jdk/src/share/classes/sun/dyn/util/BytecodeName.java new file mode 100644 index 00000000000..2abe780a5ef --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/util/BytecodeName.java @@ -0,0 +1,711 @@ +/* + * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn.util; + +/** + * Utility routines for dealing with bytecode-level names. + * Includes universal mangling rules for the JVM. + * + *

Avoiding Dangerous Characters

+ * + *

+ * The JVM defines a very small set of characters which are illegal + * in name spellings. We will slightly extend and regularize this set + * into a group of dangerous characters. + * These characters will then be replaced, in mangled names, by escape sequences. + * In addition, accidental escape sequences must be further escaped. + * Finally, a special prefix will be applied if and only if + * the mangling would otherwise fail to begin with the escape character. + * This happens to cover the corner case of the null string, + * and also clearly marks symbols which need demangling. + *

+ *

+ * Dangerous characters are the union of all characters forbidden + * or otherwise restricted by the JVM specification, + * plus their mates, if they are brackets + * ([ and ], + * < and >), + * plus, arbitrarily, the colon character :. + * There is no distinction between type, method, and field names. + * This makes it easier to convert between mangled names of different + * types, since they do not need to be decoded (demangled). + *

+ *

+ * The escape character is backslash \ + * (also known as reverse solidus). + * This character is, until now, unheard of in bytecode names, + * but traditional in the proposed role. + * + *

+ *

Replacement Characters

+ * + * + *

+ * Every escape sequence is two characters + * (in fact, two UTF8 bytes) beginning with + * the escape character and followed by a + * replacement character. + * (Since the replacement character is never a backslash, + * iterated manglings do not double in size.) + *

+ *

+ * Each dangerous character has some rough visual similarity + * to its corresponding replacement character. + * This makes mangled symbols easier to recognize by sight. + *

+ *

+ * The dangerous characters are + * / (forward slash, used to delimit package components), + * . (dot, also a package delimiter), + * ; (semicolon, used in signatures), + * $ (dollar, used in inner classes and synthetic members), + * < (left angle), + * > (right angle), + * [ (left square bracket, used in array types), + * ] (right square bracket, reserved in this scheme for language use), + * and : (colon, reserved in this scheme for language use). + * Their replacements are, respectively, + * | (vertical bar), + * , (comma), + * ? (question mark), + * % (percent), + * ^ (caret), + * _ (underscore), and + * { (left curly bracket), + * } (right curly bracket), + * ! (exclamation mark). + * In addition, the replacement character for the escape character itself is + * - (hyphen), + * and the replacement character for the null prefix is + * = (equal sign). + *

+ *

+ * An escape character \ + * followed by any of these replacement characters + * is an escape sequence, and there are no other escape sequences. + * An equal sign is only part of an escape sequence + * if it is the second character in the whole string, following a backslash. + * Two consecutive backslashes do not form an escape sequence. + *

+ *

+ * Each escape sequence replaces a so-called original character + * which is either one of the dangerous characters or the escape character. + * A null prefix replaces an initial null string, not a character. + *

+ *

+ * All this implies that escape sequences cannot overlap and may be + * determined all at once for a whole string. Note that a spelling + * string can contain accidental escapes, apparent escape + * sequences which must not be interpreted as manglings. + * These are disabled by replacing their leading backslash with an + * escape sequence (\-). To mangle a string, three logical steps + * are required, though they may be carried out in one pass: + *

+ *
    + *
  1. In each accidental escape, replace the backslash with an escape sequence + * (\-).
  2. + *
  3. Replace each dangerous character with an escape sequence + * (\| for /, etc.).
  4. + *
  5. If the first two steps introduced any change, and + * if the string does not already begin with a backslash, prepend a null prefix (\=).
  6. + *
+ * + * To demangle a mangled string that begins with an escape, + * remove any null prefix, and then replace (in parallel) + * each escape sequence by its original character. + *

Spelling strings which contain accidental + * escapes must have them replaced, even if those + * strings do not contain dangerous characters. + * This restriction means that mangling a string always + * requires a scan of the string for escapes. + * But then, a scan would be required anyway, + * to check for dangerous characters. + * + *

+ *

Nice Properties

+ * + *

+ * If a bytecode name does not contain any escape sequence, + * demangling is a no-op: The string demangles to itself. + * Such a string is called self-mangling. + * Almost all strings are self-mangling. + * In practice, to demangle almost any name “found in nature”, + * simply verify that it does not begin with a backslash. + *

+ *

+ * Mangling is a one-to-one function, while demangling + * is a many-to-one function. + * A mangled string is defined as validly mangled if + * it is in fact the unique mangling of its spelling string. + * Three examples of invalidly mangled strings are \=foo, + * \-bar, and baz\!, which demangle to foo, \bar, and + * baz\!, but then remangle to foo, \bar, and \=baz\-!. + * If a language back-end or runtime is using mangled names, + * it should never present an invalidly mangled bytecode + * name to the JVM. If the runtime encounters one, + * it should also report an error, since such an occurrence + * probably indicates a bug in name encoding which + * will lead to errors in linkage. + * However, this note does not propose that the JVM verifier + * detect invalidly mangled names. + *

+ *

+ * As a result of these rules, it is a simple matter to + * compute validly mangled substrings and concatenations + * of validly mangled strings, and (with a little care) + * these correspond to corresponding operations on their + * spelling strings. + *

+ *
    + *
  • Any prefix of a validly mangled string is also validly mangled, + * although a null prefix may need to be removed.
  • + *
  • Any suffix of a validly mangled string is also validly mangled, + * although a null prefix may need to be added.
  • + *
  • Two validly mangled strings, when concatenated, + * are also validly mangled, although any null prefix + * must be removed from the second string, + * and a trailing backslash on the first string may need escaping, + * if it would participate in an accidental escape when followed + * by the first character of the second string.
  • + *
+ *

If languages that include non-Java symbol spellings use this + * mangling convention, they will enjoy the following advantages: + *

+ *
    + *
  • They can interoperate via symbols they share in common.
  • + *
  • Low-level tools, such as backtrace printers, will have readable displays.
  • + *
  • Future JVM and language extensions can safely use the dangerous characters + * for structuring symbols, but will never interfere with valid spellings.
  • + *
  • Runtimes and compilers can use standard libraries for mangling and demangling.
  • + *
  • Occasional transliterations and name composition will be simple and regular, + * for classes, methods, and fields.
  • + *
  • Bytecode names will continue to be compact. + * When mangled, spellings will at most double in length, either in + * UTF8 or UTF16 format, and most will not change at all.
  • + *
+ * + * + *

Suggestions for Human Readable Presentations

+ * + * + *

+ * For human readable displays of symbols, + * it will be better to present a string-like quoted + * representation of the spelling, because JVM users + * are generally familiar with such tokens. + * We suggest using single or double quotes before and after + * mangled symbols which are not valid Java identifiers, + * with quotes, backslashes, and non-printing characters + * escaped as if for literals in the Java language. + *

+ *

+ * For example, an HTML-like spelling + * <pre> mangles to + * \^pre\_ and could + * display more cleanly as + * '<pre>', + * with the quotes included. + * Such string-like conventions are not suitable + * for mangled bytecode names, in part because + * dangerous characters must be eliminated, rather + * than just quoted. Otherwise internally structured + * strings like package prefixes and method signatures + * could not be reliably parsed. + *

+ *

+ * In such human-readable displays, invalidly mangled + * names should not be demangled and quoted, + * for this would be misleading. Likewise, JVM symbols + * which contain dangerous characters (like dots in field + * names or brackets in method names) should not be + * simply quoted. The bytecode names + * \=phase\,1 and + * phase.1 are distinct, + * and in demangled displays they should be presented as + * 'phase.1' and something like + * 'phase'.1, respectively. + *

+ * + * @author John Rose + * @version 1.2, 02/06/2008 + * @see http://blogs.sun.com/jrose/entry/symbolic_freedom_in_the_vm + */ +public class BytecodeName { + private BytecodeName() { } // static only class + + /** Given a source name, produce the corresponding bytecode name. + * The source name should not be qualified, because any syntactic + * markers (dots, slashes, dollar signs, colons, etc.) will be mangled. + * @param s the source name + * @return a valid bytecode name which represents the source name + */ + public static String toBytecodeName(String s) { + String bn = mangle(s); + assert((Object)bn == s || looksMangled(bn)) : bn; + assert(s.equals(toSourceName(bn))) : s; + return bn; + } + + /** Given an unqualified bytecode name, produce the corresponding source name. + * The bytecode name must not contain dangerous characters. + * In particular, it must not be qualified or segmented by colon {@code ':'}. + * @param s the bytecode name + * @return the source name, which may possibly have unsafe characters + * @throws IllegalArgumentException if the bytecode name is not {@link #isSafeBytecodeName safe} + * @see #isSafeBytecodeName(java.lang.String) + */ + public static String toSourceName(String s) { + checkSafeBytecodeName(s); + String sn = s; + if (looksMangled(s)) { + sn = demangle(s); + assert(s.equals(mangle(sn))) : s+" => "+sn+" => "+mangle(sn); + } + return sn; + } + + /** + * Given a bytecode name from a classfile, separate it into + * components delimited by dangerous characters. + * Each resulting array element will be either a dangerous character, + * or else a safe bytecode name. + * (The safe name might possibly be mangled to hide further dangerous characters.) + * For example, the qualified class name {@code java/lang/String} + * will be parsed into the array {@code {"java", '/', "lang", '/', "String"}}. + * The name {@code <init>} will be parsed into { '<', "init", '>'}} + * The name {@code foo/bar$:baz} will be parsed into + * {@code {"foo", '/', "bar", '$', ':', "baz"}}. + */ + public static Object[] parseBytecodeName(String s) { + int slen = s.length(); + Object[] res = null; + for (int pass = 0; pass <= 1; pass++) { + int fillp = 0; + int lasti = 0; + for (int i = 0; i <= slen; i++) { + int whichDC = -1; + if (i < slen) { + whichDC = DANGEROUS_CHARS.indexOf(s.charAt(i)); + if (whichDC < DANGEROUS_CHAR_FIRST_INDEX) continue; + } + // got to end of string or next dangerous char + if (lasti < i) { + // normal component + if (pass != 0) + res[fillp] = s.substring(lasti, i); + fillp++; + lasti = i+1; + } + if (whichDC >= DANGEROUS_CHAR_FIRST_INDEX) { + if (pass != 0) + res[fillp] = DANGEROUS_CHARS_CA[whichDC]; + fillp++; + } + } + if (pass != 0) break; + // between passes, build the result array + res = new String[fillp]; + if (fillp <= 1) { + if (fillp != 0) res[0] = s; + break; + } + } + return res; + } + + /** + * Given a series of components, create a bytecode name for a classfile. + * This is the inverse of {@link #parseBytecodeName(java.lang.String)}. + * Each component must either be an interned one-character string of + * a dangerous character, or else a safe bytecode name. + * @param components a series of name components + * @return the concatenation of all components + * @throws IllegalArgumentException if any component contains an unsafe + * character, and is not an interned one-character string + * @throws NullPointerException if any component is null + */ + public static String unparseBytecodeName(Object[] components) { + for (Object c : components) { + if (c instanceof String) + checkSafeBytecodeName((String) c); // may fail + } + return appendAll(components); + } + private static String appendAll(Object[] components) { + if (components.length <= 1) { + if (components.length == 1) { + return String.valueOf(components[0]); + } + return ""; + } + int slen = 0; + for (Object c : components) { + if (c instanceof String) + slen += String.valueOf(c).length(); + else + slen += 1; + } + StringBuilder sb = new StringBuilder(slen); + for (Object c : components) { + sb.append(c); + } + return sb.toString(); + } + + /** + * Given a bytecode name, produce the corresponding display name. + * This is the source name, plus quotes if needed. + * If the bytecode name contains dangerous characters, + * assume that they are being used as punctuation, + * and pass them through unchanged. + * @param s the original bytecode name (which may be qualified) + * @return a human-readable presentation + */ + public static String toDisplayName(String s) { + Object[] components = parseBytecodeName(s); + for (int i = 0; i < components.length; i++) { + if (!(components[i] instanceof String)) + continue; + String c = (String) components[i]; + // pretty up the name by demangling it + String sn = toSourceName(c); + if ((Object)sn != c || !isJavaIdent(sn)) { + components[i] = quoteDisplay(sn); + } + } + return appendAll(components); + } + private static boolean isJavaIdent(String s) { + int slen = s.length(); + if (slen == 0) return false; + if (!Character.isUnicodeIdentifierStart(s.charAt(0))) + return false; + for (int i = 1; i < slen; i++) { + if (!Character.isUnicodeIdentifierPart(s.charAt(0))) + return false; + } + return true; + } + private static String quoteDisplay(String s) { + // TO DO: Replace wierd characters in s by C-style escapes. + return "'"+s.replaceAll("['\\\\]", "\\\\$0")+"'"; + } + + private static void checkSafeBytecodeName(String s) + throws IllegalArgumentException { + if (!isSafeBytecodeName(s)) { + throw new IllegalArgumentException(s); + } + } + + /** + * Report whether a simple name is safe as a bytecode name. + * Such names are acceptable in class files as class, method, and field names. + * Additionally, they are free of "dangerous" characters, even if those + * characters are legal in some (or all) names in class files. + * @param s the proposed bytecode name + * @return true if the name is non-empty and all of its characters are safe + */ + public static boolean isSafeBytecodeName(String s) { + if (s.length() == 0) return false; + // check occurrences of each DANGEROUS char + for (char xc : DANGEROUS_CHARS_A) { + if (xc == ESCAPE_C) continue; // not really that dangerous + if (s.indexOf(xc) >= 0) return false; + } + return true; + } + + /** + * Report whether a character is safe in a bytecode name. + * This is true of any unicode character except the following + * dangerous characters: {@code ".;:$[]<>/"}. + * @param s the proposed character + * @return true if the character is safe to use in classfiles + */ + public static boolean isSafeBytecodeChar(char c) { + return DANGEROUS_CHARS.indexOf(c) < DANGEROUS_CHAR_FIRST_INDEX; + } + + private static boolean looksMangled(String s) { + return s.charAt(0) == ESCAPE_C; + } + + private static String mangle(String s) { + if (s.length() == 0) + return NULL_ESCAPE; + + // build this lazily, when we first need an escape: + StringBuilder sb = null; + + for (int i = 0, slen = s.length(); i < slen; i++) { + char c = s.charAt(i); + + boolean needEscape = false; + if (c == ESCAPE_C) { + if (i+1 < slen) { + char c1 = s.charAt(i+1); + if ((i == 0 && c1 == NULL_ESCAPE_C) + || c1 != originalOfReplacement(c1)) { + // an accidental escape + needEscape = true; + } + } + } else { + needEscape = isDangerous(c); + } + + if (!needEscape) { + if (sb != null) sb.append(c); + continue; + } + + // build sb if this is the first escape + if (sb == null) { + sb = new StringBuilder(s.length()+10); + // mangled names must begin with a backslash: + if (s.charAt(0) != ESCAPE_C && i > 0) + sb.append(NULL_ESCAPE); + // append the string so far, which is unremarkable: + sb.append(s.substring(0, i)); + } + + // rewrite \ to \-, / to \|, etc. + sb.append(ESCAPE_C); + sb.append(replacementOf(c)); + } + + if (sb != null) return sb.toString(); + + return s; + } + + private static String demangle(String s) { + // build this lazily, when we first meet an escape: + StringBuilder sb = null; + + int stringStart = 0; + if (s.startsWith(NULL_ESCAPE)) + stringStart = 2; + + for (int i = stringStart, slen = s.length(); i < slen; i++) { + char c = s.charAt(i); + + if (c == ESCAPE_C && i+1 < slen) { + // might be an escape sequence + char rc = s.charAt(i+1); + char oc = originalOfReplacement(rc); + if (oc != rc) { + // build sb if this is the first escape + if (sb == null) { + sb = new StringBuilder(s.length()); + // append the string so far, which is unremarkable: + sb.append(s.substring(stringStart, i)); + } + ++i; // skip both characters + c = oc; + } + } + + if (sb != null) + sb.append(c); + } + + if (sb != null) return sb.toString(); + + return s.substring(stringStart); + } + + static char ESCAPE_C = '\\'; + // empty escape sequence to avoid a null name or illegal prefix + static char NULL_ESCAPE_C = '='; + static String NULL_ESCAPE = ESCAPE_C+""+NULL_ESCAPE_C; + + static final String DANGEROUS_CHARS = "\\/.;:$[]<>"; // \\ must be first + static final String REPLACEMENT_CHARS = "-|,?!%{}^_"; + static final int DANGEROUS_CHAR_FIRST_INDEX = 1; // index after \\ + static char[] DANGEROUS_CHARS_A = DANGEROUS_CHARS.toCharArray(); + static char[] REPLACEMENT_CHARS_A = REPLACEMENT_CHARS.toCharArray(); + static final Character[] DANGEROUS_CHARS_CA; + static { + Character[] dcca = new Character[DANGEROUS_CHARS.length()]; + for (int i = 0; i < dcca.length; i++) + dcca[i] = Character.valueOf(DANGEROUS_CHARS.charAt(i)); + DANGEROUS_CHARS_CA = dcca; + } + + static final long[] SPECIAL_BITMAP = new long[2]; // 128 bits + static { + String SPECIAL = DANGEROUS_CHARS + REPLACEMENT_CHARS; + //System.out.println("SPECIAL = "+SPECIAL); + for (char c : SPECIAL.toCharArray()) { + SPECIAL_BITMAP[c >>> 6] |= 1L << c; + } + } + static boolean isSpecial(char c) { + if ((c >>> 6) < SPECIAL_BITMAP.length) + return ((SPECIAL_BITMAP[c >>> 6] >> c) & 1) != 0; + else + return false; + } + static char replacementOf(char c) { + if (!isSpecial(c)) return c; + int i = DANGEROUS_CHARS.indexOf(c); + if (i < 0) return c; + return REPLACEMENT_CHARS.charAt(i); + } + static char originalOfReplacement(char c) { + if (!isSpecial(c)) return c; + int i = REPLACEMENT_CHARS.indexOf(c); + if (i < 0) return c; + return DANGEROUS_CHARS.charAt(i); + } + static boolean isDangerous(char c) { + if (!isSpecial(c)) return false; + return (DANGEROUS_CHARS.indexOf(c) >= DANGEROUS_CHAR_FIRST_INDEX); + } + static int indexOfDangerousChar(String s, int from) { + for (int i = from, slen = s.length(); i < slen; i++) { + if (isDangerous(s.charAt(i))) + return i; + } + return -1; + } + static int lastIndexOfDangerousChar(String s, int from) { + for (int i = Math.min(from, s.length()-1); i >= 0; i--) { + if (isDangerous(s.charAt(i))) + return i; + } + return -1; + } + + // test driver + static void main(String[] av) { + // If verbose is enabled, quietly check everything. + // Otherwise, print the output for the user to check. + boolean verbose = false; + + int maxlen = 0; + + while (av.length > 0 && av[0].startsWith("-")) { + String flag = av[0].intern(); + av = java.util.Arrays.copyOfRange(av, 1, av.length); // Java 1.6 or later + if (flag == "-" || flag == "--") break; + else if (flag == "-q") + verbose = false; + else if (flag == "-v") + verbose = true; + else if (flag.startsWith("-l")) + maxlen = Integer.valueOf(flag.substring(2)); + else + throw new Error("Illegal flag argument: "+flag); + } + + if (maxlen == 0) + maxlen = (verbose ? 2 : 4); + if (verbose) System.out.println("Note: maxlen = "+maxlen); + + switch (av.length) { + case 0: av = new String[] { + DANGEROUS_CHARS.substring(0) + + REPLACEMENT_CHARS.substring(0, 1) + + NULL_ESCAPE + "x" + }; // and fall through: + case 1: + char[] cv = av[0].toCharArray(); + av = new String[cv.length]; + int avp = 0; + for (char c : cv) { + String s = String.valueOf(c); + if (c == 'x') s = "foo"; // tradition... + av[avp++] = s; + } + } + if (verbose) + System.out.println("Note: Verbose output mode enabled. Use '-q' to suppress."); + Tester t = new Tester(); + t.maxlen = maxlen; + t.verbose = verbose; + t.tokens = av; + t.test("", 0); + } + + static class Tester { + boolean verbose; + int maxlen; + java.util.Map map = new java.util.HashMap(); + String[] tokens; + + void test(String stringSoFar, int tokensSoFar) { + test(stringSoFar); + if (tokensSoFar <= maxlen) { + for (String token : tokens) { + if (token.length() == 0) continue; // skip empty tokens + if (stringSoFar.indexOf(token) != stringSoFar.lastIndexOf(token)) + continue; // there are already two occs. of this token + if (token.charAt(0) == ESCAPE_C && token.length() == 1 && maxlen < 4) + test(stringSoFar+token, tokensSoFar); // want lots of \'s + else if (tokensSoFar < maxlen) + test(stringSoFar+token, tokensSoFar+1); + } + } + } + + void test(String s) { + // for small batches, do not test the null string + if (s.length() == 0 && maxlen >=1 && maxlen <= 2) return; + String bn = testSourceName(s); + if (bn == null) return; + if (bn == s) { + //if (verbose) System.out.println(s+" == id"); + } else { + if (verbose) System.out.println(s+" => "+bn+" "+toDisplayName(bn)); + String bnbn = testSourceName(bn); + if (bnbn == null) return; + if (verbose) System.out.println(bn+" => "+bnbn+" "+toDisplayName(bnbn)); + /* + String bn3 = testSourceName(bnbn); + if (bn3 == null) return; + if (verbose) System.out.println(bnbn+" => "+bn3); + */ + } + } + + String testSourceName(String s) { + if (map.containsKey(s)) return null; + String bn = toBytecodeName(s); + map.put(s, bn); + String sn = toSourceName(bn); + if (!sn.equals(s)) { + String bad = (s+" => "+bn+" != "+sn); + if (!verbose) throw new Error("Bad mangling: "+bad); + System.out.println("*** "+bad); + return null; + } + return bn; + } + } +} diff --git a/jdk/src/share/classes/sun/dyn/util/BytecodeSignature.java b/jdk/src/share/classes/sun/dyn/util/BytecodeSignature.java new file mode 100644 index 00000000000..37d8708cb29 --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/util/BytecodeSignature.java @@ -0,0 +1,137 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn.util; + +import java.dyn.MethodType; +import java.util.ArrayList; +import java.util.List; + +/** + * Utility routines for dealing with bytecode-level signatures. + * @author jrose + */ +public class BytecodeSignature { + + private BytecodeSignature() { } // cannot instantiate + + public static List> parseMethod(String bytecodeSignature, ClassLoader loader) { + return parseMethod(bytecodeSignature, 0, bytecodeSignature.length(), loader); + } + + static List> parseMethod(String bytecodeSignature, + int start, int end, ClassLoader loader) { + if (loader == null) + loader = ClassLoader.getSystemClassLoader(); + String str = bytecodeSignature; + int[] i = {start}; + ArrayList> ptypes = new ArrayList>(); + if (i[0] < end && str.charAt(i[0]) == '(') { + ++i[0]; // skip '(' + while (i[0] < end && str.charAt(i[0]) != ')') { + Class pt = parseSig(str, i, end, loader); + if (pt == null || pt == void.class) + parseError(str, "bad argument type"); + ptypes.add(pt); + } + ++i[0]; // skip ')' + } else { + parseError(str, "not a method type"); + } + Class rtype = parseSig(str, i, end, loader); + if (rtype == null || i[0] != end) + parseError(str, "bad return type"); + ptypes.add(rtype); + return ptypes; + } + + static private void parseError(String str, String msg) { + throw new IllegalArgumentException("bad signature: "+str+": "+msg); + } + + static private Class parseSig(String str, int[] i, int end, ClassLoader loader) { + if (i[0] == end) return null; + char c = str.charAt(i[0]++); + if (c == 'L') { + int begc = i[0], endc = str.indexOf(';', begc); + if (endc < 0) return null; + i[0] = endc+1; + String name = str.substring(begc, endc).replace('/', '.'); + try { + return loader.loadClass(name); + } catch (ClassNotFoundException ex) { + throw new TypeNotPresentException(name, ex); + } + } else if (c == '[') { + Class t = parseSig(str, i, end, loader); + if (t != null) + t = java.lang.reflect.Array.newInstance(t, 0).getClass(); + return t; + } else { + return Wrapper.forBasicType(c).primitiveType(); + } + } + + public static String unparse(Class type) { + StringBuilder sb = new StringBuilder(); + unparseSig(type, sb); + return sb.toString(); + } + + public static String unparse(MethodType type) { + return unparseMethod(type.returnType(), type.parameterList()); + } + + public static String unparse(Object type) { + if (type instanceof Class) + return unparse((Class) type); + if (type instanceof MethodType) + return unparse((MethodType) type); + return (String) type; + } + + public static String unparseMethod(Class rtype, List> ptypes) { + StringBuilder sb = new StringBuilder(); + sb.append('('); + for (Class pt : ptypes) + unparseSig(pt, sb); + sb.append(')'); + unparseSig(rtype, sb); + return sb.toString(); + } + + static private void unparseSig(Class t, StringBuilder sb) { + char c = Wrapper.forBasicType(t).basicTypeChar(); + if (c != 'L') { + sb.append(c); + } else { + boolean lsemi = (!t.isArray()); + if (lsemi) sb.append('L'); + sb.append(t.getName().replace('.', '/')); + if (lsemi) sb.append(';'); + } + } + +} diff --git a/jdk/src/share/classes/sun/dyn/util/ValueConversions.java b/jdk/src/share/classes/sun/dyn/util/ValueConversions.java new file mode 100644 index 00000000000..817c1c5cc29 --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/util/ValueConversions.java @@ -0,0 +1,563 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn.util; + +import java.dyn.*; +import java.dyn.MethodHandles.Lookup; +import java.util.EnumMap; +import sun.dyn.Access; +import sun.dyn.AdapterMethodHandle; +import sun.dyn.MethodHandleImpl; + +public class ValueConversions { + private static final Access IMPL_TOKEN = Access.getToken(); + private static final Lookup IMPL_LOOKUP = MethodHandleImpl.getLookup(IMPL_TOKEN); + + private static EnumMap[] newWrapperCaches(int n) { + EnumMap[] caches + = (EnumMap[]) new EnumMap[n]; // unchecked warning expected here + for (int i = 0; i < n; i++) + caches[i] = new EnumMap(Wrapper.class); + return caches; + } + + /// Converting references to values. + + static int unboxInteger(Object x) { + if (x == null) return 0; // never NPE + return ((Integer) x).intValue(); + } + + static byte unboxByte(Object x) { + if (x == null) return 0; // never NPE + return ((Byte) x).byteValue(); + } + + static short unboxShort(Object x) { + if (x == null) return 0; // never NPE + return ((Short) x).shortValue(); + } + + static boolean unboxBoolean(Object x) { + if (x == null) return false; // never NPE + return ((Boolean) x).booleanValue(); + } + + static char unboxCharacter(Object x) { + if (x == null) return 0; // never NPE + return ((Character) x).charValue(); + } + + static long unboxLong(Object x) { + if (x == null) return 0; // never NPE + return ((Long) x).longValue(); + } + + static float unboxFloat(Object x) { + if (x == null) return 0; // never NPE + return ((Float) x).floatValue(); + } + + static double unboxDouble(Object x) { + if (x == null) return 0; // never NPE + return ((Double) x).doubleValue(); + } + + /// Converting references to "raw" values. + /// A raw primitive value is always an int or long. + + static int unboxByteRaw(Object x) { + return unboxByte(x); + } + + static int unboxShortRaw(Object x) { + return unboxShort(x); + } + + static int unboxBooleanRaw(Object x) { + return unboxBoolean(x) ? 1 : 0; + } + + static int unboxCharacterRaw(Object x) { + return unboxCharacter(x); + } + + static int unboxFloatRaw(Object x) { + return Float.floatToIntBits(unboxFloat(x)); + } + + static long unboxDoubleRaw(Object x) { + return Double.doubleToRawLongBits(unboxDouble(x)); + } + + private static MethodType unboxType(Wrapper wrap, boolean raw) { + return MethodType.make(rawWrapper(wrap, raw).primitiveType(), wrap.wrapperType()); + } + + private static final EnumMap[] + UNBOX_CONVERSIONS = newWrapperCaches(4); + + private static MethodHandle unbox(Wrapper wrap, boolean exact, boolean raw) { + EnumMap cache = UNBOX_CONVERSIONS[(exact?1:0)+(raw?2:0)]; + MethodHandle mh = cache.get(wrap); + if (mh != null) { + return mh; + } + // slow path + switch (wrap) { + case OBJECT: + mh = IDENTITY; break; + case VOID: + mh = raw ? ALWAYS_ZERO : IGNORE; break; + case INT: case LONG: + // these guys don't need separate raw channels + if (raw) mh = unbox(wrap, exact, false); + break; + } + if (mh != null) { + cache.put(wrap, mh); + return mh; + } + // look up the method + String name = "unbox" + wrap.simpleName() + (raw ? "Raw" : ""); + MethodType type = unboxType(wrap, raw); + if (!exact) + // actually, type is wrong; the Java method takes Object + mh = IMPL_LOOKUP.findStatic(ValueConversions.class, name, type.erase()); + else + mh = retype(type, unbox(wrap, !exact, raw)); + if (mh != null) { + cache.put(wrap, mh); + return mh; + } + throw new IllegalArgumentException("cannot find unbox adapter for " + wrap + (raw ? " (raw)" : "")); + } + + public static MethodHandle unbox(Wrapper type, boolean exact) { + return unbox(type, exact, false); + } + + public static MethodHandle unboxRaw(Wrapper type, boolean exact) { + return unbox(type, exact, true); + } + + public static MethodHandle unbox(Class type, boolean exact) { + return unbox(Wrapper.forPrimitiveType(type), exact, false); + } + + public static MethodHandle unboxRaw(Class type, boolean exact) { + return unbox(Wrapper.forPrimitiveType(type), exact, true); + } + + /// Converting primitives to references + + static Integer boxInteger(int x) { + return x; + } + + static Byte boxByte(byte x) { + return x; + } + + static Short boxShort(short x) { + return x; + } + + static Boolean boxBoolean(boolean x) { + return x; + } + + static Character boxCharacter(char x) { + return x; + } + + static Long boxLong(long x) { + return x; + } + + static Float boxFloat(float x) { + return x; + } + + static Double boxDouble(double x) { + return x; + } + + /// Converting raw primitives to references + + static Byte boxByteRaw(int x) { + return boxByte((byte)x); + } + + static Short boxShortRaw(int x) { + return boxShort((short)x); + } + + static Boolean boxBooleanRaw(int x) { + return boxBoolean(x != 0); + } + + static Character boxCharacterRaw(int x) { + return boxCharacter((char)x); + } + + static Float boxFloatRaw(int x) { + return boxFloat(Float.intBitsToFloat(x)); + } + + static Double boxDoubleRaw(long x) { + return boxDouble(Double.longBitsToDouble(x)); + } + + // a raw void value is (arbitrarily) a garbage int + static Void boxVoidRaw(int x) { + return null; + } + + private static MethodType boxType(Wrapper wrap, boolean raw) { + // be exact, since return casts are hard to compose + Class boxType = wrap.wrapperType(); + return MethodType.make(boxType, rawWrapper(wrap, raw).primitiveType()); + } + + private static Wrapper rawWrapper(Wrapper wrap, boolean raw) { + if (raw) return wrap.isDoubleWord() ? Wrapper.LONG : Wrapper.INT; + return wrap; + } + + private static final EnumMap[] + BOX_CONVERSIONS = newWrapperCaches(4); + + private static MethodHandle box(Wrapper wrap, boolean exact, boolean raw) { + EnumMap cache = BOX_CONVERSIONS[(exact?1:0)+(raw?2:0)]; + MethodHandle mh = cache.get(wrap); + if (mh != null) { + return mh; + } + // slow path + switch (wrap) { + case OBJECT: + mh = IDENTITY; break; + case VOID: + if (!raw) mh = ZERO_OBJECT; + break; + case INT: case LONG: + // these guys don't need separate raw channels + if (raw) mh = box(wrap, exact, false); + break; + } + if (mh != null) { + cache.put(wrap, mh); + return mh; + } + // look up the method + String name = "box" + wrap.simpleName() + (raw ? "Raw" : ""); + MethodType type = boxType(wrap, raw); + if (exact) + mh = IMPL_LOOKUP.findStatic(ValueConversions.class, name, type); + else + mh = retype(type.erase(), box(wrap, !exact, raw)); + if (mh != null) { + cache.put(wrap, mh); + return mh; + } + throw new IllegalArgumentException("cannot find box adapter for " + wrap + (raw ? " (raw)" : "")); + } + + public static MethodHandle box(Class type, boolean exact) { + return box(Wrapper.forPrimitiveType(type), exact, false); + } + + public static MethodHandle boxRaw(Class type, boolean exact) { + return box(Wrapper.forPrimitiveType(type), exact, true); + } + + public static MethodHandle box(Wrapper type, boolean exact) { + return box(type, exact, false); + } + + public static MethodHandle boxRaw(Wrapper type, boolean exact) { + return box(type, exact, true); + } + + /// Kludges for when raw values get accidentally boxed. + + static Byte reboxRawByte(Object x) { + if (x instanceof Byte) return (Byte) x; + return boxByteRaw(unboxInteger(x)); + } + + static Short reboxRawShort(Object x) { + if (x instanceof Short) return (Short) x; + return boxShortRaw(unboxInteger(x)); + } + + static Boolean reboxRawBoolean(Object x) { + if (x instanceof Boolean) return (Boolean) x; + return boxBooleanRaw(unboxInteger(x)); + } + + static Character reboxRawCharacter(Object x) { + if (x instanceof Character) return (Character) x; + return boxCharacterRaw(unboxInteger(x)); + } + + static Float reboxRawFloat(Object x) { + if (x instanceof Float) return (Float) x; + return boxFloatRaw(unboxInteger(x)); + } + + static Double reboxRawDouble(Object x) { + if (x instanceof Double) return (Double) x; + return boxDoubleRaw(unboxLong(x)); + } + + private static MethodType reboxType(Wrapper wrap) { + Class boxType = wrap.wrapperType(); + return MethodType.make(boxType, Object.class); + } + + private static final EnumMap[] + REBOX_CONVERSIONS = newWrapperCaches(2); + + public static MethodHandle rebox(Wrapper wrap, boolean exact) { + EnumMap cache = REBOX_CONVERSIONS[exact?1:0]; + MethodHandle mh = cache.get(wrap); + if (mh != null) { + return mh; + } + // slow path + switch (wrap) { + case OBJECT: + mh = IDENTITY; break; + case VOID: + throw new IllegalArgumentException("cannot rebox a void"); + case INT: case LONG: + mh = cast(wrap.wrapperType(), exact); + break; + } + if (mh != null) { + cache.put(wrap, mh); + return mh; + } + // look up the method + String name = "reboxRaw" + wrap.simpleName(); + MethodType type = reboxType(wrap); + if (exact) + mh = IMPL_LOOKUP.findStatic(ValueConversions.class, name, type); + else + mh = retype(IDENTITY.type(), rebox(wrap, !exact)); + if (mh != null) { + cache.put(wrap, mh); + return mh; + } + throw new IllegalArgumentException("cannot find rebox adapter for " + wrap); + } + + public static MethodHandle rebox(Class type, boolean exact) { + return rebox(Wrapper.forPrimitiveType(type), exact); + } + + /// Width-changing conversions between int and long. + + static long widenInt(int x) { + return x; + } + + static int narrowLong(long x) { + return (int) x; + } + + /// Constant functions + + static void ignore(Object x) { + // no value to return; this is an unbox of null + return; + } + + static void empty() { + return; + } + + static Object zeroObject() { + return null; + } + + static int zeroInteger() { + return 0; + } + + static long zeroLong() { + return 0; + } + + static float zeroFloat() { + return 0; + } + + static double zeroDouble() { + return 0; + } + + private static final EnumMap[] + ZERO_CONSTANT_FUNCTIONS = newWrapperCaches(1); + + public static MethodHandle zeroConstantFunction(Wrapper wrap) { + EnumMap cache = ZERO_CONSTANT_FUNCTIONS[0]; + MethodHandle mh = cache.get(wrap); + if (mh != null) { + return mh; + } + // slow path + MethodType type = MethodType.make(wrap.primitiveType()); + switch (wrap) { + case VOID: + mh = EMPTY; + break; + case INT: case LONG: case FLOAT: case DOUBLE: + mh = IMPL_LOOKUP.findStatic(ValueConversions.class, "zero"+wrap.simpleName(), type); + break; + } + if (mh != null) { + cache.put(wrap, mh); + return mh; + } + + // use the raw method + Wrapper rawWrap = wrap.rawPrimitive(); + if (rawWrap != wrap) { + mh = retype(type, zeroConstantFunction(rawWrap)); + } + if (mh != null) { + cache.put(wrap, mh); + return mh; + } + throw new IllegalArgumentException("cannot find zero constant for " + wrap); + } + + /// Converting references to references. + + /** + * Value-killing function. + * @param x an arbitrary reference value + * @return a null + */ + static Object alwaysNull(Object x) { + return null; + } + + /** + * Value-killing function. + * @param x an arbitrary reference value + * @return a zero + */ + static int alwaysZero(Object x) { + return 0; + } + + /** + * Identity function. + * @param x an arbitrary reference value + * @return the same value x + */ + static T identity(T x) { + return x; + } + + /** + * Identity function, with reference cast. + * @param t an arbitrary reference type + * @param x an arbitrary reference value + * @return the same value x + */ + static T castReference(Class t, U x) { + return t.cast(x); + } + + private static final MethodHandle IDENTITY, CAST_REFERENCE, ALWAYS_NULL, ALWAYS_ZERO, ZERO_OBJECT, IGNORE, EMPTY; + static { + try { + MethodType idType = MethodType.makeGeneric(1); + MethodType castType = idType.insertParameterType(0, Class.class); + MethodType alwaysZeroType = idType.changeReturnType(int.class); + MethodType ignoreType = idType.changeReturnType(void.class); + MethodType zeroObjectType = MethodType.makeGeneric(0); + IDENTITY = IMPL_LOOKUP.findStatic(ValueConversions.class, "identity", idType); + //CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType); + CAST_REFERENCE = IMPL_LOOKUP.findStatic(ValueConversions.class, "castReference", castType); + ALWAYS_NULL = IMPL_LOOKUP.findStatic(ValueConversions.class, "alwaysNull", idType); + ALWAYS_ZERO = IMPL_LOOKUP.findStatic(ValueConversions.class, "alwaysZero", alwaysZeroType); + ZERO_OBJECT = IMPL_LOOKUP.findStatic(ValueConversions.class, "zeroObject", zeroObjectType); + IGNORE = IMPL_LOOKUP.findStatic(ValueConversions.class, "ignore", ignoreType); + EMPTY = IMPL_LOOKUP.findStatic(ValueConversions.class, "empty", ignoreType.dropParameterType(0)); + } catch (RuntimeException ex) { + throw ex; + } + } + + private static final EnumMap WRAPPER_CASTS + = new EnumMap(Wrapper.class); + + private static final EnumMap EXACT_WRAPPER_CASTS + = new EnumMap(Wrapper.class); + + /** Return a method that casts its sole argument (an Object) to the given type + * and returns it as the given type (if exact is true), or as plain Object (if erase is true). + */ + public static MethodHandle cast(Class type, boolean exact) { + if (type.isPrimitive()) throw new IllegalArgumentException("cannot cast primitive type "+type); + MethodHandle mh = null; + Wrapper wrap = null; + EnumMap cache = null; + if (Wrapper.isWrapperType(type)) { + wrap = Wrapper.forWrapperType(type); + cache = (exact ? EXACT_WRAPPER_CASTS : WRAPPER_CASTS); + mh = cache.get(wrap); + if (mh != null) return mh; + } + if (VerifyType.isNullReferenceConversion(Object.class, type)) + mh = IDENTITY; + else if (VerifyType.isNullType(type)) + mh = ALWAYS_NULL; + else + mh = MethodHandles.insertArgument(CAST_REFERENCE, 0, type); + if (exact) { + MethodType xmt = MethodType.make(type, Object.class); + mh = AdapterMethodHandle.makeRawRetypeOnly(IMPL_TOKEN, xmt, mh); + } + if (cache != null) + cache.put(wrap, mh); + return mh; + } + + public static MethodHandle identity() { + return IDENTITY; + } + + private static MethodHandle retype(MethodType type, MethodHandle mh) { + return AdapterMethodHandle.makeRetypeOnly(IMPL_TOKEN, type, mh); + } +} diff --git a/jdk/src/share/classes/sun/dyn/util/VerifyAccess.java b/jdk/src/share/classes/sun/dyn/util/VerifyAccess.java new file mode 100644 index 00000000000..8bee85017ba --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/util/VerifyAccess.java @@ -0,0 +1,169 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn.util; + +import java.dyn.LinkagePermission; +import java.lang.reflect.Modifier; +import sun.dyn.Access; + +/** + * This class centralizes information about the JVM's linkage access control. + * @author jrose + */ +public class VerifyAccess { + + private VerifyAccess() { } // cannot instantiate + + /** + * Evaluate the JVM linkage rules for access to the given method on behalf of caller. + * Return non-null if and only if the given accessing class has at least partial + * privileges to invoke the given method. The return value {@code Object.class} + * denotes unlimited privileges. + *

+ * Some circumstances require an additional check on the + * leading parameter (the receiver) of the method, if it is non-static. + * In the case of {@code invokespecial} ({@code doDispatch} is false), + * the leading parameter must be the accessing class or a subclass. + * In the case of a call to a {@code protected} method outside the same + * package, the same constraint applies. + * @param m the proposed callee + * @param doDispatch if false, a non-static m will be invoked as if by {@code invokespecial} + * @param lookupClass the class for which the access check is being made + * @return null if the method is not accessible, else a receiver type constraint, else {@code Object.class} + */ + public static Class isAccessible(Class defc, int mods, + boolean doDispatch, Class lookupClass) { + if (!isAccessible(defc, lookupClass)) + return null; + Class constraint = Object.class; + if (!doDispatch && !Modifier.isStatic(mods)) { + constraint = lookupClass; + } + if (Modifier.isPublic(mods)) + return constraint; + if (Modifier.isPrivate(mods)) + return isSamePackageMember(defc, lookupClass) ? constraint : null; + if (isSamePackage(defc, lookupClass)) + return constraint; + if (Modifier.isProtected(mods) && defc.isAssignableFrom(lookupClass)) + return constraint; + // else it is private or package scoped, and not close enough + return null; + } + + /** + * Evaluate the JVM linkage rules for access to the given class on behalf of caller. + */ + public static boolean isAccessible(Class refc, Class lookupClass) { + int mods = refc.getModifiers(); + if (Modifier.isPublic(mods)) + return true; + if (isSamePackage(lookupClass, refc)) + return true; + return false; + } + + /** + * Test if two classes have the same class loader and package qualifier. + * @param class1 + * @param class2 + * @return whether they are in the same package + */ + public static boolean isSamePackage(Class class1, Class class2) { + if (class1 == class2) + return true; + if (!loadersAreRelated(class1.getClassLoader(), class2.getClassLoader())) + return false; + String name1 = class1.getName(), name2 = class2.getName(); + int dot = name1.lastIndexOf('.'); + if (dot != name2.lastIndexOf('.')) + return false; + for (int i = 0; i < dot; i++) { + if (name1.charAt(i) != name2.charAt(i)) + return false; + } + return true; + } + + /** + * Test if two classes are defined as part of the same package member (top-level class). + * If this is true, they can share private access with each other. + * @param class1 + * @param class2 + * @return whether they are identical or nested together + */ + public static boolean isSamePackageMember(Class class1, Class class2) { + if (class1 == class2) + return true; + if (!isSamePackage(class1, class2)) + return false; + if (getOutermostEnclosingClass(class1) != getOutermostEnclosingClass(class2)) + return false; + return true; + } + + private static Class getOutermostEnclosingClass(Class c) { + Class pkgmem = c; + for (Class enc = c; (enc = enc.getEnclosingClass()) != null; ) + pkgmem = enc; + return pkgmem; + } + + private static boolean loadersAreRelated(ClassLoader loader1, ClassLoader loader2) { + if (loader1 == loader2 || loader1 == null || loader2 == null) { + return true; + } + for (ClassLoader scan1 = loader1; + scan1 != null; scan1 = scan1.getParent()) { + if (scan1 == loader2) return true; + } + for (ClassLoader scan2 = loader2; + scan2 != null; scan2 = scan2.getParent()) { + if (scan2 == loader1) return true; + } + return false; + } + + /** + * Ensure the requesting class have privileges to perform invokedynamic + * linkage operations on subjectClass. True if requestingClass is + * Access.class (meaning the request originates from the JVM) or if the + * classes are in the same package and have consistent class loaders. + * (The subject class loader must be identical with or be a child of + * the requesting class loader.) + * @param requestingClass + * @param subjectClass + */ + public static void checkBootstrapPrivilege(Class requestingClass, Class subjectClass, + String permissionName) { + if (requestingClass == null) return; + if (requestingClass == subjectClass) return; + SecurityManager security = System.getSecurityManager(); + if (security == null) return; // open season + if (isSamePackage(requestingClass, subjectClass)) return; + security.checkPermission(new LinkagePermission(permissionName, requestingClass)); + } +} diff --git a/jdk/src/share/classes/sun/dyn/util/VerifyType.java b/jdk/src/share/classes/sun/dyn/util/VerifyType.java new file mode 100644 index 00000000000..9d12c74afa9 --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/util/VerifyType.java @@ -0,0 +1,219 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn.util; + +import java.dyn.MethodType; + +/** + * This class centralizes information about the JVM verifier + * and its requirements about type correctness. + * @author jrose + */ +public class VerifyType { + + private VerifyType() { } // cannot instantiate + + /** + * True if a value can be stacked as the source type and unstacked as the + * destination type, without violating the JVM's type consistency. + * + * @param call the type of a stacked value + * @param recv the type by which we'd like to treat it + * @return whether the retyping can be done without motion or reformatting + */ + public static boolean isNullConversion(Class src, Class dst) { + if (src == dst) return true; + // Verifier allows any interface to be treated as Object: + if (dst.isInterface()) dst = Object.class; + if (src.isInterface()) src = Object.class; + if (src == dst) return true; // check again + if (dst == void.class) return true; // drop any return value + if (isNullType(src)) return !dst.isPrimitive(); + if (!src.isPrimitive()) return dst.isAssignableFrom(src); + // Verifier allows an int to carry byte, short, char, or even boolean: + if (dst == int.class) return Wrapper.forPrimitiveType(src).isSubwordOrInt(); + return false; + } + + /** + * Specialization of isNullConversion to reference types. + + * @param call the type of a stacked value + * @param recv the reference type by which we'd like to treat it + * @return whether the retyping can be done without a cast + */ + public static boolean isNullReferenceConversion(Class src, Class dst) { + assert(!dst.isPrimitive()); + if (dst.isInterface()) return true; // verifier allows this + if (isNullType(src)) return true; + return dst.isAssignableFrom(src); + } + + /** + * Is the given type either java.lang.Void or java.lang.Null? + * These types serve as markers for bare nulls and therefore + * may be promoted to any type. This is secure, since + */ + public static boolean isNullType(Class type) { + if (type == null) return false; + return type == NULL_CLASS_1 || type == NULL_CLASS_2; + } + private static final Class NULL_CLASS_1, NULL_CLASS_2; + static { + Class nullClass1 = null, nullClass2 = null; + try { + nullClass1 = Class.forName("java.lang.Null"); + } catch (ClassNotFoundException ex) { + // OK, we'll cope + } + NULL_CLASS_1 = nullClass1; + + // This one may also be used as a null type. + // TO DO: Decide if we really want to legitimize it here. + // Probably we do, unless java.lang.Null really makes it into Java 7 + nullClass2 = Void.class; + NULL_CLASS_2 = nullClass2; + } + + /** + * True if a method handle can receive a call under a slightly different + * method type, without moving or reformatting any stack elements. + * + * @param call the type of call being made + * @param recv the type of the method handle receiving the call + * @return whether the retyping can be done without motion or reformatting + */ + public static boolean isNullConversion(MethodType call, MethodType recv) { + if (call == recv) return true; + int len = call.parameterCount(); + if (len != recv.parameterCount()) return false; + for (int i = 0; i < len; i++) + if (!isNullConversion(call.parameterType(i), recv.parameterType(i))) + return false; + return isNullConversion(recv.returnType(), call.returnType()); + } + + //TO DO: isRawConversion + + /** + * Determine if the JVM verifier allows a value of type call to be + * passed to a formal parameter (or return variable) of type recv. + * Returns 1 if the verifier allows the types to match without conversion. + * Returns -1 if the types can be made to match by a JVM-supported adapter. + * Cases supported are: + *

  • checkcast + *
  • conversion between any two integral types (but not floats) + *
  • unboxing from a wrapper to its corresponding primitive type + *
  • conversion in either direction between float and double + *
+ * (Autoboxing is not supported here; it must be done via Java code.) + * Returns 0 otherwise. + */ + public static int canPassUnchecked(Class src, Class dst) { + if (src == dst) + return 1; + + if (dst.isPrimitive()) { + if (dst == void.class) + // Return anything to a caller expecting void. + // This is a property of the implementation, which links + // return values via a register rather than via a stack push. + // This makes it possible to ignore cleanly. + return 1; + if (src == void.class) + return 0; // void-to-something? + if (!src.isPrimitive()) + // Cannot pass a reference to any primitive type (exc. void). + return 0; + Wrapper sw = Wrapper.forPrimitiveType(src); + Wrapper dw = Wrapper.forPrimitiveType(dst); + if (sw.isSubwordOrInt() && dw.isSubwordOrInt()) { + if (sw.bitWidth() >= dw.bitWidth()) + return -1; // truncation may be required + if (!dw.isSigned() && sw.isSigned()) + return -1; // sign elimination may be required + } + if (src == float.class || dst == float.class) { + if (src == double.class || dst == double.class) + return -1; // floating conversion may be required + else + return 0; // other primitive conversions NYI + } else { + // all fixed-point conversions are supported + return 0; + } + } else if (src.isPrimitive()) { + // Cannot pass a primitive to any reference type. + // (Maybe allow null.class?) + return 0; + } + + // Handle reference types in the rest of the block: + + // The verifier treats interfaces exactly like Object. + if (isNullReferenceConversion(src, dst)) + // pass any reference to object or an arb. interface + return 1; + // else it's a definite "maybe" (cast is required) + return -1; + } + + public static int canPassRaw(Class src, Class dst) { + if (dst.isPrimitive()) { + if (dst == void.class) + // As above, return anything to a caller expecting void. + return 1; + if (src == void.class) + // Special permission for raw conversions: allow a void + // to be captured as a garbage int. + // Caller promises that the actual value will be disregarded. + return dst == int.class ? 1 : 0; + if (!src.isPrimitive()) + return 0; + Wrapper sw = Wrapper.forPrimitiveType(src); + Wrapper dw = Wrapper.forPrimitiveType(dst); + if (sw.stackSlots() == dw.stackSlots()) + return 1; // can do a reinterpret-cast on a stacked primitive + if (sw.isSubwordOrInt() && dw == Wrapper.VOID) + return 1; // can drop an outgoing int value + return 0; + } else if (src.isPrimitive()) { + return 0; + } + + // Both references. + if (isNullReferenceConversion(src, dst)) + return 1; + return -1; + } + + public static boolean isSpreadArgType(Class spreadArg) { + return spreadArg.isArray(); + } + public static Class spreadArgElementType(Class spreadArg, int i) { + return spreadArg.getComponentType(); + } +} diff --git a/jdk/src/share/classes/sun/dyn/util/Wrapper.java b/jdk/src/share/classes/sun/dyn/util/Wrapper.java new file mode 100644 index 00000000000..556fda3bc7b --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/util/Wrapper.java @@ -0,0 +1,467 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.dyn.util; + +public enum Wrapper { + INT(Integer.class, int.class, 'I', (Integer)(int)0, Format.signed(32)), + LONG(Long.class, long.class, 'J', (Long)(long)0, Format.signed(64)), + BYTE(Byte.class, byte.class, 'B', (Byte)(byte)0, Format.signed(8)), + SHORT(Short.class, short.class, 'S', (Short)(short)0, Format.signed(16)), + CHAR(Character.class, char.class, 'C', (Character)(char)0, Format.unsigned(16)), + BOOLEAN(Boolean.class, boolean.class, 'Z', (Boolean)false, Format.unsigned(1)), + FLOAT(Float.class, float.class, 'F', (Float)(float)0, Format.floating(32)), + DOUBLE(Double.class, double.class, 'D', (Double)(double)0, Format.floating(64)), + VOID(Void.class, void.class, 'V', null, Format.other(0)), + //NULL(Null.class, null.class, 'N', null, Format.other(1)), + OBJECT(Object.class, Object.class, 'L', null, Format.other(1)), + ; + + private final Class wrapperType; + private final Class primitiveType; + private final char basicTypeChar; + private final Object zero; + private final int format; + private final String simpleName; + + private Wrapper(Class wtype, Class ptype, char tchar, Object zero, int format) { + this.wrapperType = wtype; + this.primitiveType = ptype; + this.basicTypeChar = tchar; + this.zero = zero; + this.format = format; + this.simpleName = wtype.getSimpleName(); + } + + private static abstract class Format { + static final int SLOT_SHIFT = 0, SIZE_SHIFT = 2, KIND_SHIFT = 12; + static final int + SIGNED = (-1) << KIND_SHIFT, + UNSIGNED = 0 << KIND_SHIFT, + FLOATING = 1 << KIND_SHIFT; + static final int + SLOT_MASK = ((1<<(SIZE_SHIFT-SLOT_SHIFT))-1), + SIZE_MASK = ((1<<(KIND_SHIFT-SIZE_SHIFT))-1); + static int format(int kind, int size, int slots) { + assert(((kind >> KIND_SHIFT) << KIND_SHIFT) == kind); + assert((size & (size-1)) == 0); // power of two + assert((kind == SIGNED) ? (size > 0) : + (kind == UNSIGNED) ? (size > 0) : + (kind == FLOATING) ? (size == 32 || size == 64) : + false); + assert((slots == 2) ? (size == 64) : + (slots == 1) ? (size <= 32) : + false); + return kind | (size << SIZE_SHIFT) | (slots << SLOT_SHIFT); + } + static int + INT = SIGNED | (32 << SIZE_SHIFT) | (1 << SLOT_SHIFT), + BOOLEAN = UNSIGNED | (1 << SIZE_SHIFT) | (1 << SLOT_SHIFT), + FLOAT = FLOATING | (32 << SIZE_SHIFT) | (1 << SLOT_SHIFT), + VOID = UNSIGNED | (0 << SIZE_SHIFT) | (0 << SLOT_SHIFT), + NUM_MASK = (-1) << SIZE_SHIFT; + static int signed(int size) { return format(SIGNED, size, (size > 32 ? 2 : 1)); } + static int unsigned(int size) { return format(UNSIGNED, size, (size > 32 ? 2 : 1)); } + static int floating(int size) { return format(FLOATING, size, (size > 32 ? 2 : 1)); } + static int other(int slots) { return slots << SLOT_SHIFT; } + } + + /// format queries: + + /** How many bits are in the wrapped value? Returns 0 for OBJECT or VOID. */ + public int bitWidth() { return (format >> Format.SIZE_SHIFT) & Format.SIZE_MASK; } + /** How many JVM stack slots occupied by the wrapped value? Returns 0 for VOID. */ + public int stackSlots() { return (format >> Format.SLOT_SHIFT) & Format.SLOT_MASK; } + /** Does the wrapped value occupy a single JVM stack slot? */ + public boolean isSingleWord() { return (format & (1 << Format.SLOT_SHIFT)) != 0; } + /** Does the wrapped value occupy two JVM stack slots? */ + public boolean isDoubleWord() { return (format & (2 << Format.SLOT_SHIFT)) != 0; } + /** Is the wrapped type numeric (not void or object)? */ + public boolean isNumeric() { return (format & Format.NUM_MASK) != 0; } + /** Is the wrapped type a primitive other than float, double, or void? */ + public boolean isIntegral() { return isNumeric() && format < Format.FLOAT; } + /** Is the wrapped type one of int, boolean, byte, char, or short? */ + public boolean isSubwordOrInt() { return isIntegral() && isSingleWord(); } + /* Is the wrapped value a signed integral type (one of byte, short, int, or long)? */ + public boolean isSigned() { return format < Format.VOID; } + /* Is the wrapped value an unsigned integral type (one of boolean or char)? */ + public boolean isUnsigned() { return format >= Format.BOOLEAN && format < Format.FLOAT; } + /** Is the wrapped type either float or double? */ + public boolean isFloating() { return format >= Format.FLOAT; } + + /** Produce a zero value for the given wrapper type. + * This will be a numeric zero for a number or character, + * false for a boolean, and null for a reference or void. + * The common thread is that this is what is contained + * in a default-initialized variable of the given primitive + * type. (For void, it is what a reflective method returns + * instead of no value at all.) + */ + public Object zero() { return zero; } + + /** Produce a zero value for the given wrapper type T. + * The optinoal argument must a type compatible with this wrapper. + * Equivalent to {@code this.cast(this.zero(), type)}. + */ + public T zero(Class type) { return cast(zero, type); } + +// /** Produce a wrapper for the given wrapper or primitive type. */ +// public static Wrapper valueOf(Class type) { +// if (isPrimitiveType(type)) +// return forPrimitiveType(type); +// else +// return forWrapperType(type); +// } + + /** Return the wrapper that wraps values of the given type. + * The type may be {@code Object}, meaning the {@code OBJECT} wrapper. + * Otherwise, the type must be a primitive. + * @throws IllegalArgumentException for unexpected types + */ + public static Wrapper forPrimitiveType(Class type) { + Wrapper w = FROM_PRIM[hashPrim(type)]; + if (w != null && w.primitiveType == type) { + return w; + } + if (type.isPrimitive()) + throw new InternalError(); // redo hash function + throw newIllegalArgumentException("not primitive: "+type); + } + + /** Return the wrapper that wraps values into the given wrapper type. + * If it is {@code Object} or an interface, return {@code OBJECT}. + * Otherwise, it must be a wrapper type. + * The type must not be a primitive type. + * @throws IllegalArgumentException for unexpected types + */ + public static Wrapper forWrapperType(Class type) { + Wrapper w = findWrapperType(type); + if (w != null) return w; + for (Wrapper x : values()) + if (w.wrapperType == type) + throw new InternalError(); // redo hash function + throw newIllegalArgumentException("not wrapper: "+type); + } + + static Wrapper findWrapperType(Class type) { + Wrapper w = FROM_WRAP[hashWrap(type)]; + if (w != null && w.wrapperType == type) { + return w; + } + if (type.isInterface()) + return OBJECT; + return null; + } + + /** Return the wrapper that corresponds to the given bytecode + * signature character. Return {@code OBJECT} for the character 'L'. + * @throws IllegalArgumentException for any non-signature character or {@code '['}. + */ + public static Wrapper forBasicType(char type) { + Wrapper w = FROM_CHAR[hashChar(type)]; + if (w != null && w.basicTypeChar == type) { + return w; + } + for (Wrapper x : values()) + if (w.basicTypeChar == type) + throw new InternalError(); // redo hash function + throw newIllegalArgumentException("not basic type char: "+type); + } + + /** Return the wrapper for the given type, if it is + * a primitive type, else return {@code OBJECT}. + */ + public static Wrapper forBasicType(Class type) { + if (type.isPrimitive()) + return forPrimitiveType(type); + return OBJECT; // any reference, including wrappers or arrays + } + + // Note on perfect hashes: + // for signature chars c, do (c + (c >> 1)) % 16 + // for primitive type names n, do (n[0] + n[2]) % 16 + // The type name hash works for both primitive and wrapper names. + // You can add "java/lang/Object" to the primitive names. + // But you add the wrapper name Object, use (n[2] + (3*n[1])) % 16. + private static final Wrapper[] FROM_PRIM = new Wrapper[16]; + private static final Wrapper[] FROM_WRAP = new Wrapper[16]; + private static final Wrapper[] FROM_CHAR = new Wrapper[16]; + private static int hashPrim(Class x) { + String xn = x.getName(); + if (xn.length() < 3) return 0; + return (xn.charAt(0) + xn.charAt(2)) % 16; + } + private static int hashWrap(Class x) { + String xn = x.getName(); + final int offset = 10; assert(offset == "java.lang.".length()); + if (xn.length() < offset+3) return 0; + return (3*xn.charAt(offset+1) + xn.charAt(offset+2)) % 16; + } + private static int hashChar(char x) { + return (x + (x >> 1)) % 16; + } + static { + for (Wrapper w : values()) { + int pi = hashPrim(w.primitiveType); + int wi = hashWrap(w.wrapperType); + int ci = hashChar(w.basicTypeChar); + assert(FROM_PRIM[pi] == null); + assert(FROM_WRAP[wi] == null); + assert(FROM_CHAR[ci] == null); + FROM_PRIM[pi] = w; + FROM_WRAP[wi] = w; + FROM_CHAR[ci] = w; + } + //assert(jdk.sun.dyn.util.WrapperTest.test(false)); + } + + /** What is the primitive type wrapped by this wrapper? */ + public Class primitiveType() { return primitiveType; } + + /** What is the wrapper type for this wrapper? */ + public Class wrapperType() { return wrapperType; } + + /** What is the wrapper type for this wrapper? + * The example type must be the wrapper type, + * or the corresponding primitive type. + * The resulting class type has the same type parameter. + */ + public Class wrapperType(Class exampleType) { + if (exampleType == wrapperType) { + return exampleType; + } else if (exampleType == primitiveType || + wrapperType == Object.class || + exampleType.isInterface()) { + return forceType(wrapperType, exampleType); + } + throw new ClassCastException(exampleType + " not <:" + wrapperType); + } + + /** If {@code type} is a primitive type, return the corresponding + * wrapper type, else return {@code type} unchanged. + */ + public static Class asWrapperType(Class type) { + if (type.isPrimitive()) { + return forPrimitiveType(type).wrapperType(type); + } + return type; + } + + /** If {@code type} is a wrapper type, return the corresponding + * primitive type, else return {@code type} unchanged. + */ + public static Class asPrimitiveType(Class type) { + Wrapper w = findWrapperType(type); + if (w != null) { + return forceType(w.primitiveType(), type); + } + return type; + } + + /** Query: Is the given type a wrapper, such as {@code Integer} or {@code Void}? */ + public static boolean isWrapperType(Class type) { + return findWrapperType(type) != null; + } + + /** Query: Is the given type a primitive, such as {@code int} or {@code void}? */ + public static boolean isPrimitiveType(Class type) { + return type.isPrimitive(); + } + + /** What is the bytecode signature character for this wrapper's + * primitive type? + */ + public char basicTypeChar() { return basicTypeChar; } + + /** What is the simple name of the wrapper type? + */ + public String simpleName() { return simpleName; } + +// /** Wrap a value in the given type, which may be either a primitive or wrapper type. +// * Performs standard primitive conversions, including truncation and float conversions. +// */ +// public static T wrap(Object x, Class type) { +// return Wrapper.valueOf(type).cast(x, type); +// } + + /** Cast a wrapped value to the given type, which may be either a primitive or wrapper type. + * Performs standard primitive conversions, including truncation and float conversions. + * The given type must be compatible with this wrapper. That is, it must either + * be the wrapper type (or a subtype, in the case of {@code OBJECT} or else + * it must be the wrapper's primitive type. + * @throws ClassCastException if the given type is not compatible with this wrapper + */ + public T cast(Object x, Class type) { + Class wtype = wrapperType(type); + if (wtype.isInstance(x)) + return wtype.cast(x); + return wtype.cast(wrap(x)); + } + + /** Cast a reference type to another reference type. + * If the target type is an interface, perform no runtime check. + * (This loophole is safe, and is allowed by the JVM verifier.) + * If the target type is a primitive, change it to a wrapper. + */ + static Class forceType(Class type, Class exampleType) { + assert(type == exampleType || + type == asWrapperType(exampleType) || + type == Object.class && exampleType.isInterface()); + Class result = (Class) type; // unchecked warning is expected here + return result; + } + + /** Wrap a value in this wrapper's type. + * Performs standard primitive conversions, including truncation and float conversions. + * Performs returns the unchanged reference for {@code OBJECT}. + * Returns null for {@code VOID}. + * Returns a zero value for a null input. + * @throws ClassCastException if this wrapper is numeric and the operand + * is not a number, character, boolean, or null + */ + public Object wrap(Object x) { + // do non-numeric wrappers first + switch (basicTypeChar) { + case 'L': return x; + case 'V': return null; + } + Number xn = numberValue(x); + switch (basicTypeChar) { + case 'I': return Integer.valueOf(xn.intValue()); + case 'J': return Long.valueOf(xn.longValue()); + case 'F': return Float.valueOf(xn.floatValue()); + case 'D': return Double.valueOf(xn.doubleValue()); + case 'S': return Short.valueOf((short) xn.intValue()); + case 'B': return Byte.valueOf((byte) xn.intValue()); + case 'C': return Character.valueOf((char) xn.intValue()); + case 'Z': return Boolean.valueOf(boolValue(xn.longValue())); + } + throw new InternalError("bad wrapper"); + } + + /** Wrap a value (an int or smaller value) in this wrapper's type. + * Performs standard primitive conversions, including truncation and float conversions. + * Produces an {@code Integer} for {@code OBJECT}, although the exact type + * of the operand is not known. + * Returns null for {@code VOID}. + */ + public Object wrap(int x) { + if (basicTypeChar == 'L') return (Integer)x; + switch (basicTypeChar) { + case 'L': throw newIllegalArgumentException("cannot wrap to object type"); + case 'V': return null; + case 'I': return Integer.valueOf((int)x); + case 'J': return Long.valueOf(x); + case 'F': return Float.valueOf(x); + case 'D': return Double.valueOf(x); + case 'S': return Short.valueOf((short) x); + case 'B': return Byte.valueOf((byte) x); + case 'C': return Character.valueOf((char) x); + case 'Z': return Boolean.valueOf(boolValue(x)); + } + throw new InternalError("bad wrapper"); + } + + /** Wrap a value (a long or smaller value) in this wrapper's type. + * Does not perform floating point conversion. + * Produces a {@code Long} for {@code OBJECT}, although the exact type + * of the operand is not known. + * Returns null for {@code VOID}. + */ + public Object wrapRaw(long x) { + switch (basicTypeChar) { + case 'F': return Float.valueOf(Float.intBitsToFloat((int)x)); + case 'D': return Double.valueOf(Double.longBitsToDouble(x)); + case 'L': // same as 'J': + case 'J': return (Long) x; + } + // Other wrapping operations are just the same, given that the + // operand is already promoted to an int. + return wrap((int)x); + } + + /** Produce bitwise value which encodes the given wrapped value. + * Does not perform floating point conversion. + * Returns zero for {@code VOID}. + */ + public long unwrapRaw(Object x) { + switch (basicTypeChar) { + case 'F': return Float.floatToRawIntBits((Float) x); + case 'D': return Double.doubleToRawLongBits((Double) x); + + case 'L': throw newIllegalArgumentException("cannot unwrap from sobject type"); + case 'V': return 0; + case 'I': return (int)(Integer) x; + case 'J': return (long)(Long) x; + case 'S': return (short)(Short) x; + case 'B': return (byte)(Byte) x; + case 'C': return (char)(Character) x; + case 'Z': return (boolean)(Boolean) x ? 1 : 0; + } + throw new InternalError("bad wrapper"); + } + + /** Report what primitive type holds this guy's raw value. */ + public Class rawPrimitiveType() { + return rawPrimitive().primitiveType(); + } + + /** Report, as a wrapper, what primitive type holds this guy's raw value. + * Returns self for INT, LONG, OBJECT; returns LONG for DOUBLE, + * else returns INT. + */ + public Wrapper rawPrimitive() { + switch (basicTypeChar) { + case 'S': case 'B': + case 'C': case 'Z': + case 'V': + case 'F': + return INT; + case 'D': + return LONG; + } + return this; + } + + private static Number numberValue(Object x) { + if (x instanceof Number) return (Number)x; + if (x instanceof Character) return (int)(Character)x; + if (x instanceof Boolean) return (Boolean)x ? 1 : 0; + // Remaining allowed case of void: Must be a null reference. + return (Number)x; + } + + private static boolean boolValue(long bits) { + //bits &= 1; // simple 31-bit zero extension + return (bits != 0); + } + + private static RuntimeException newIllegalArgumentException(String message, Object x) { + return newIllegalArgumentException(message + x); + } + private static RuntimeException newIllegalArgumentException(String message) { + return new IllegalArgumentException(message); + } +} diff --git a/jdk/src/share/classes/sun/dyn/util/package-info.java b/jdk/src/share/classes/sun/dyn/util/package-info.java new file mode 100644 index 00000000000..257d7df1c26 --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/util/package-info.java @@ -0,0 +1,31 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * Extra support for using JSR 292 RI, package java.dyn. + * @author jrose + */ + +package sun.dyn.util; diff --git a/jdk/src/share/classes/sun/misc/JavaLangAccess.java b/jdk/src/share/classes/sun/misc/JavaLangAccess.java index c288bc8402f..846a671b78d 100644 --- a/jdk/src/share/classes/sun/misc/JavaLangAccess.java +++ b/jdk/src/share/classes/sun/misc/JavaLangAccess.java @@ -55,6 +55,22 @@ public interface JavaLangAccess { /** Set thread's blocker field. */ void blockedOn(Thread t, Interruptible b); - /** register shutdown hook */ - void registerShutdownHook(int slot, Runnable r); + /** + * Registers a shutdown hook. + * + * It is expected that this method with registerShutdownInProgress=true + * is only used to register DeleteOnExitHook since the first file + * may be added to the delete on exit list by the application shutdown + * hooks. + * + * @params slot the slot in the shutdown hook array, whose element + * will be invoked in order during shutdown + * @params registerShutdownInProgress true to allow the hook + * to be registered even if the shutdown is in progress. + * @params hook the hook to be registered + * + * @throw IllegalStateException if shutdown is in progress and + * the slot is not valid to register. + */ + void registerShutdownHook(int slot, boolean registerShutdownInProgress, Runnable hook); } diff --git a/jdk/src/share/classes/sun/misc/Unsafe.java b/jdk/src/share/classes/sun/misc/Unsafe.java index 3a3fde82de0..c81c1eb8737 100644 --- a/jdk/src/share/classes/sun/misc/Unsafe.java +++ b/jdk/src/share/classes/sun/misc/Unsafe.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -811,6 +811,25 @@ public final class Unsafe { 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. + *

+ * For each CP entry, the corresponding CP patch must either be null or have + * the a format that matches its tag: + *

    + *
  • Integer, Long, Float, Double: the corresponding wrapper object type from java.lang + *
  • Utf8: a string (must have suitable syntax if used as signature or name) + *
  • Class: any java.lang.Class object + *
  • String: any object (not just a java.lang.String) + *
  • InterfaceMethodRef: (NYI) a method handle to invoke on that call site's arguments + *
+ * @params hostClass context for linkage, access control, protection domain, and class loader + * @params data bytes of a 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) diff --git a/jdk/src/share/javavm/export/classfile_constants.h b/jdk/src/share/javavm/export/classfile_constants.h index 8906ba5f390..d225fa4ce7e 100644 --- a/jdk/src/share/javavm/export/classfile_constants.h +++ b/jdk/src/share/javavm/export/classfile_constants.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2004-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -306,7 +306,7 @@ enum { JVM_OPC_invokespecial = 183, JVM_OPC_invokestatic = 184, JVM_OPC_invokeinterface = 185, - JVM_OPC_xxxunusedxxx = 186, + JVM_OPC_invokedynamic = 186, JVM_OPC_new = 187, JVM_OPC_newarray = 188, JVM_OPC_anewarray = 189, @@ -515,7 +515,7 @@ enum { 3, /* invokespecial */ \ 3, /* invokestatic */ \ 5, /* invokeinterface */ \ - 0, /* xxxunusedxxx */ \ + 5, /* invokedynamic */ \ 3, /* new */ \ 2, /* newarray */ \ 3, /* anewarray */ \ diff --git a/jdk/src/share/native/common/check_code.c b/jdk/src/share/native/common/check_code.c index 7e1613255dc..f76c8f81735 100644 --- a/jdk/src/share/native/common/check_code.c +++ b/jdk/src/share/native/common/check_code.c @@ -1,5 +1,5 @@ /* - * Copyright 1994-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1994-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1223,16 +1223,20 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) case JVM_OPC_invokevirtual: case JVM_OPC_invokespecial: case JVM_OPC_invokestatic: + case JVM_OPC_invokedynamic: case JVM_OPC_invokeinterface: { /* Make sure the constant pool item is the right type. */ int key = (code[offset + 1] << 8) + code[offset + 2]; const char *methodname; jclass cb = context->class; fullinfo_type clazz_info; - int is_constructor, is_internal; + int is_constructor, is_internal, is_invokedynamic; int kind = (opcode == JVM_OPC_invokeinterface ? 1 << JVM_CONSTANT_InterfaceMethodref + : opcode == JVM_OPC_invokedynamic + ? 1 << JVM_CONSTANT_NameAndType : 1 << JVM_CONSTANT_Methodref); + is_invokedynamic = opcode == JVM_OPC_invokedynamic; /* Make sure the constant pool item is the right type. */ verify_constant_pool_type(context, key, kind); methodname = JVM_GetCPMethodNameUTF(env, cb, key); @@ -1241,8 +1245,11 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) is_internal = methodname[0] == '<'; pop_and_free(context); - clazz_info = cp_index_to_class_fullinfo(context, key, - JVM_CONSTANT_Methodref); + if (is_invokedynamic) + clazz_info = context->object_info; // anything will do + else + clazz_info = cp_index_to_class_fullinfo(context, key, + JVM_CONSTANT_Methodref); this_idata->operand.i = key; this_idata->operand2.fi = clazz_info; if (is_constructor) { @@ -1304,6 +1311,11 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) "Fourth operand byte of invokeinterface must be zero"); } pop_and_free(context); + } else if (opcode == JVM_OPC_invokedynamic) { + if (code[offset + 3] != 0 || code[offset + 4] != 0) { + CCerror(context, + "Third and fourth operand bytes of invokedynamic must be zero"); + } } else if (opcode == JVM_OPC_invokevirtual || opcode == JVM_OPC_invokespecial) set_protected(context, inumber, key, opcode); @@ -1990,6 +2002,7 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac case JVM_OPC_invokevirtual: case JVM_OPC_invokespecial: case JVM_OPC_invokeinit: /* invokespecial call to */ + case JVM_OPC_invokedynamic: case JVM_OPC_invokestatic: case JVM_OPC_invokeinterface: { /* The top stuff on the stack depends on the method signature */ int operand = this_idata->operand.i; @@ -2005,7 +2018,8 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac print_formatted_methodname(context, operand); } #endif - if (opcode != JVM_OPC_invokestatic) + if (opcode != JVM_OPC_invokestatic && + opcode != JVM_OPC_invokedynamic) /* First, push the object */ *ip++ = (opcode == JVM_OPC_invokeinit ? '@' : 'A'); for (p = signature + 1; *p != JVM_SIGNATURE_ENDFUNC; ) { @@ -2290,6 +2304,7 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac case JVM_OPC_invokevirtual: case JVM_OPC_invokespecial: case JVM_OPC_invokeinit: + case JVM_OPC_invokedynamic: case JVM_OPC_invokeinterface: case JVM_OPC_invokestatic: { int operand = this_idata->operand.i; const char *signature = @@ -2299,7 +2314,8 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac int item; const char *p; check_and_push(context, signature, VM_STRING_UTF); - if (opcode == JVM_OPC_invokestatic) { + if (opcode == JVM_OPC_invokestatic || + opcode == JVM_OPC_invokedynamic) { item = 0; } else if (opcode == JVM_OPC_invokeinit) { fullinfo_type init_type = this_idata->operand2.fi; @@ -2680,6 +2696,7 @@ push_stack(context_type *context, unsigned int inumber, stack_info_type *new_sta case JVM_OPC_invokevirtual: case JVM_OPC_invokespecial: case JVM_OPC_invokeinit: + case JVM_OPC_invokedynamic: case JVM_OPC_invokestatic: case JVM_OPC_invokeinterface: { /* Look to signature to determine correct result. */ int operand = this_idata->operand.i; diff --git a/jdk/src/share/native/common/opcodes.in_out b/jdk/src/share/native/common/opcodes.in_out index 364e8abdda5..757532c7b08 100644 --- a/jdk/src/share/native/common/opcodes.in_out +++ b/jdk/src/share/native/common/opcodes.in_out @@ -1,5 +1,5 @@ /* - * Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -210,7 +210,7 @@ char * const opcode_in_out[][2] = { {"?", "?"}, /* invokespecial */ {"?", "?"}, /* invokestatic */ {"?", "?"}, /* invokeinterface */ - {"?", "?"}, /* xxxunusedxxx */ + {"?", "?"}, /* invokedynamic */ {"", "A"}, /* new */ {"I", "A"}, /* newarray */ {"I", "A"}, /* anewarray */ diff --git a/jdk/src/solaris/classes/sun/java2d/x11/X11SurfaceData.java b/jdk/src/solaris/classes/sun/java2d/x11/X11SurfaceData.java index 54f79769343..5f353c342df 100644 --- a/jdk/src/solaris/classes/sun/java2d/x11/X11SurfaceData.java +++ b/jdk/src/solaris/classes/sun/java2d/x11/X11SurfaceData.java @@ -530,6 +530,7 @@ public abstract class X11SurfaceData extends SurfaceData { sType = transparent ? X11SurfaceData.IntBgrX11_BM : X11SurfaceData.IntBgrX11; } } else { + throw new sun.java2d.InvalidPipeException("Unsupported bit " + "depth/cm combo: " + cm.getPixelSize() + diff --git a/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java index d1f8c9307d5..5ec0af0468f 100644 --- a/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java @@ -475,49 +475,40 @@ class WindowsAsynchronousSocketChannelImpl // get an OVERLAPPED structure (from the cache or allocate) overlapped = ioCache.add(result); - // synchronize on result to allow this thread handle the case - // where the read completes immediately. - synchronized (result) { - int n = read0(handle, numBufs, readBufferArray, overlapped); - if (n == IOStatus.UNAVAILABLE) { - // I/O is pending - pending = true; - return; - } - // read completed immediately: - // 1. update buffer position - // 2. reset read flag - // 3. release waiters - if (n == 0) { - n = -1; - } else { - updateBuffers(n); - } + // initiate read + int n = read0(handle, numBufs, readBufferArray, overlapped); + if (n == IOStatus.UNAVAILABLE) { + // I/O is pending + pending = true; + return; + } + if (n == IOStatus.EOF) { + // input shutdown enableReading(); - if (scatteringRead) { - result.setResult((V)Long.valueOf(n)); + result.setResult((V)Long.valueOf(-1L)); } else { - result.setResult((V)Integer.valueOf(n)); + result.setResult((V)Integer.valueOf(-1)); } + } else { + throw new InternalError("Read completed immediately"); } } catch (Throwable x) { - // failed to initiate read: - // 1. reset read flag - // 2. free resources - // 3. release waiters + // failed to initiate read + // reset read flag before releasing waiters enableReading(); - if (overlapped != 0L) - ioCache.remove(overlapped); if (x instanceof ClosedChannelException) x = new AsynchronousCloseException(); if (!(x instanceof IOException)) x = new IOException(x); result.setFailure(x); } finally { - if (prepared && !pending) { - // return direct buffer(s) to cache if substituted - releaseBuffers(); + // release resources if I/O not pending + if (!pending) { + if (overlapped != 0L) + ioCache.remove(overlapped); + if (prepared) + releaseBuffers(); } end(); } @@ -721,7 +712,6 @@ class WindowsAsynchronousSocketChannelImpl @Override @SuppressWarnings("unchecked") public void run() { - int n = -1; long overlapped = 0L; boolean prepared = false; boolean pending = false; @@ -736,56 +726,34 @@ class WindowsAsynchronousSocketChannelImpl // get an OVERLAPPED structure (from the cache or allocate) overlapped = ioCache.add(result); - - // synchronize on result to allow this thread handle the case - // where the read completes immediately. - synchronized (result) { - n = write0(handle, numBufs, writeBufferArray, overlapped); - if (n == IOStatus.UNAVAILABLE) { - // I/O is pending - pending = true; - return; - } - - enableWriting(); - - if (n == IOStatus.EOF) { - // special case for shutdown output - shutdown = true; - throw new ClosedChannelException(); - } - - // write completed immediately: - // 1. enable writing - // 2. update buffer position - // 3. release waiters - updateBuffers(n); - - // result is a Long or Integer - if (gatheringWrite) { - result.setResult((V)Long.valueOf(n)); - } else { - result.setResult((V)Integer.valueOf(n)); - } + int n = write0(handle, numBufs, writeBufferArray, overlapped); + if (n == IOStatus.UNAVAILABLE) { + // I/O is pending + pending = true; + return; } + if (n == IOStatus.EOF) { + // special case for shutdown output + shutdown = true; + throw new ClosedChannelException(); + } + // write completed immediately + throw new InternalError("Write completed immediately"); } catch (Throwable x) { + // write failed. Enable writing before releasing waiters. enableWriting(); - - // failed to initiate read: if (!shutdown && (x instanceof ClosedChannelException)) x = new AsynchronousCloseException(); if (!(x instanceof IOException)) x = new IOException(x); result.setFailure(x); - - // release resources - if (overlapped != 0L) - ioCache.remove(overlapped); - } finally { - if (prepared && !pending) { - // return direct buffer(s) to cache if substituted - releaseBuffers(); + // release resources if I/O not pending + if (!pending) { + if (overlapped != 0L) + ioCache.remove(overlapped); + if (prepared) + releaseBuffers(); } end(); } diff --git a/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.c b/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.c index 97c49f60a71..c9a1972f45f 100644 --- a/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.c +++ b/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.c @@ -157,14 +157,13 @@ Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_read0(JNIEnv* env, jclass t WSABUF* lpWsaBuf = (WSABUF*) jlong_to_ptr(address); OVERLAPPED* lpOverlapped = (OVERLAPPED*) jlong_to_ptr(ov); BOOL res; - DWORD nread = 0; DWORD flags = 0; ZeroMemory((PVOID)lpOverlapped, sizeof(OVERLAPPED)); res = WSARecv(s, lpWsaBuf, (DWORD)count, - &nread, + NULL, &flags, lpOverlapped, NULL); @@ -175,17 +174,12 @@ Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_read0(JNIEnv* env, jclass t return IOS_UNAVAILABLE; } if (error == WSAESHUTDOWN) { - return 0; // input shutdown + return IOS_EOF; // input shutdown } JNU_ThrowIOExceptionWithLastError(env, "WSARecv failed"); return IOS_THROWN; } - if (nread == 0) { - // Handle graceful close or bytes not yet available cases - // via completion port notification. - return IOS_UNAVAILABLE; - } - return (jint)nread; + return IOS_UNAVAILABLE; } JNIEXPORT jint JNICALL @@ -196,13 +190,12 @@ Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_write0(JNIEnv* env, jclass WSABUF* lpWsaBuf = (WSABUF*) jlong_to_ptr(address); OVERLAPPED* lpOverlapped = (OVERLAPPED*) jlong_to_ptr(ov); BOOL res; - DWORD nwritten; ZeroMemory((PVOID)lpOverlapped, sizeof(OVERLAPPED)); res = WSASend(s, lpWsaBuf, (DWORD)count, - &nwritten, + NULL, 0, lpOverlapped, NULL); @@ -218,5 +211,5 @@ Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_write0(JNIEnv* env, jclass JNU_ThrowIOExceptionWithLastError(env, "WSASend failed"); return IOS_THROWN; } - return (jint)nwritten; + return IOS_UNAVAILABLE; } diff --git a/jdk/test/java/awt/FullScreen/TranslucentWindow/TranslucentWindow.java b/jdk/test/java/awt/FullScreen/TranslucentWindow/TranslucentWindow.java new file mode 100644 index 00000000000..9facaaeb965 --- /dev/null +++ b/jdk/test/java/awt/FullScreen/TranslucentWindow/TranslucentWindow.java @@ -0,0 +1,83 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +/* + * @test + * @bug 6837004 + * @summary Checks that non-opaque window can be made a fullscreen window + * @author Artem Ananiev + * @run main TranslucentWindow + */ + +import java.awt.*; +import java.awt.geom.*; + +import static java.awt.GraphicsDevice.WindowTranslucency.*; + +import sun.awt.SunToolkit; + +public class TranslucentWindow { + public static void main(String args[]) { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice gd = ge.getDefaultScreenDevice(); + + Frame f = new Frame("Test frame"); + f.setBounds(100, 100, 320, 240); + + // First, check it can be made fullscreen window without any effects applied + gd.setFullScreenWindow(f); + ((SunToolkit)Toolkit.getDefaultToolkit()).realSync(); + + gd.setFullScreenWindow(null); + ((SunToolkit)Toolkit.getDefaultToolkit()).realSync(); + + // Second, check if it applying any effects doesn't prevent the window + // from going into the fullscreen mode + if (gd.isWindowTranslucencySupported(PERPIXEL_TRANSPARENT)) { + f.setShape(new Ellipse2D.Float(0, 0, f.getWidth(), f.getHeight())); + } + if (gd.isWindowTranslucencySupported(TRANSLUCENT)) { + f.setOpacity(0.5f); + } + if (gd.isWindowTranslucencySupported(PERPIXEL_TRANSLUCENT)) { + f.setBackground(new Color(0, 0, 0, 128)); + } + gd.setFullScreenWindow(f); + ((SunToolkit)Toolkit.getDefaultToolkit()).realSync(); + + // Third, make sure all the effects are unset when entering the fullscreen mode + if (f.getShape() != null) { + throw new RuntimeException("Test FAILED: fullscreen window shape is not null"); + } + if (Math.abs(f.getOpacity() - 1.0f) > 1e-4) { + throw new RuntimeException("Test FAILED: fullscreen window opacity is not 1.0f"); + } + Color bgColor = f.getBackground(); + if ((bgColor != null) && (bgColor.getAlpha() != 255)) { + throw new RuntimeException("Test FAILED: fullscreen window background color is not opaque"); + } + + f.dispose(); + System.out.println("Test PASSED"); + } +} diff --git a/jdk/test/java/lang/Runtime/shutdown/ShutdownHooks.java b/jdk/test/java/lang/Runtime/shutdown/ShutdownHooks.java new file mode 100644 index 00000000000..8e6fe1ae212 --- /dev/null +++ b/jdk/test/java/lang/Runtime/shutdown/ShutdownHooks.java @@ -0,0 +1,69 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +/* + * @bug 6829503 + * @summary 1) Test Console and DeleteOnExitHook can be initialized + * while shutdown is in progress + * 2) Test if files that are added by the application shutdown + * hook are deleted on exit during shutdown + */ +import java.io.*; +public class ShutdownHooks { + private static File file; + public static void main(String[] args) throws Exception { + if (args.length != 2) { + throw new IllegalArgumentException("Usage: ShutdownHooks "); + } + + // Add a shutdown hook + Runtime.getRuntime().addShutdownHook(new Cleaner()); + + File dir = new File(args[0]); + file = new File(dir, args[1]); + // write to file + System.out.println("writing to "+ file); + PrintWriter pw = new PrintWriter(file); + pw.println("Shutdown begins"); + pw.close(); + } + + public static class Cleaner extends Thread { + public void run() { + // register the Console's shutdown hook while the application + // shutdown hook is running + Console cons = System.console(); + // register the DeleteOnExitHook while the application + // shutdown hook is running + file.deleteOnExit(); + try { + PrintWriter pw = new PrintWriter(file); + pw.println("file is being deleted"); + pw.close(); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + } + } + +} diff --git a/jdk/test/java/lang/Runtime/shutdown/ShutdownHooks.sh b/jdk/test/java/lang/Runtime/shutdown/ShutdownHooks.sh new file mode 100644 index 00000000000..a06420936bd --- /dev/null +++ b/jdk/test/java/lang/Runtime/shutdown/ShutdownHooks.sh @@ -0,0 +1,57 @@ +#!/bin/sh + +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# 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. +# + + +# @test +# @bug 6829503 +# @summary 1) Test Console and DeleteOnExitHook can be initialized +# while shutdown is in progress +# 2) Test if files that are added by the application shutdown +# hook are deleted on exit during shutdown +# +# @build ShutdownHooks +# @run shell ShutdownHooks.sh + +if [ "${TESTJAVA}" = "" ] +then + echo "TESTJAVA not set. Test cannot execute. Failed." + exit 1 +fi + +FILENAME=fileToBeDeleted +rm -f ${TESTCLASSES}/${FILENAME} + +# create the file to be deleted on exit +echo "testing shutdown" > ${TESTCLASSES}/${FILENAME} + +${TESTJAVA}/bin/java ${TESTVMOPTS} -classpath ${TESTCLASSES} ShutdownHooks ${TESTCLASSES} $FILENAME +if [ $? != 0 ] ; then + echo "Test Failed"; exit 1 +fi + +if [ -f ${TESTCLASSES}/${FILENAME} ]; then + echo "Test Failed: ${TESTCLASSES}/${FILENAME} not deleted"; exit 2 +fi +echo "ShutdownHooks test passed."; diff --git a/jdk/test/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java b/jdk/test/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java new file mode 100644 index 00000000000..d3426ba08c0 --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java @@ -0,0 +1,183 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +/* @test + * @bug 6834246 + * @summary Stress test connections through the loopback interface + */ + +import java.nio.ByteBuffer; +import java.net.*; +import java.nio.channels.*; +import java.util.Random; +import java.io.IOException; + +public class StressLoopback { + static final Random rand = new Random(); + + public static void main(String[] args) throws Exception { + // setup listener + AsynchronousServerSocketChannel listener = + AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(0)); + int port =((InetSocketAddress)(listener.getLocalAddress())).getPort(); + InetAddress lh = InetAddress.getLocalHost(); + SocketAddress remote = new InetSocketAddress(lh, port); + + // create sources and sinks + int count = 2 + rand.nextInt(9); + Source[] source = new Source[count]; + Sink[] sink = new Sink[count]; + for (int i=0; i %d (%s)\n", + nwrote, nread, (failed) ? "FAIL" : "PASS"); + total += nwrote; + } + if (failed) + throw new RuntimeException("Test failed - see log for details"); + System.out.format("Total sent %d MB\n", total / (1024L * 1024L)); + } + + /** + * Writes bytes to a channel until "done". When done the channel is closed. + */ + static class Source { + private final AsynchronousByteChannel channel; + private final ByteBuffer sentBuffer; + private volatile long bytesSent; + private volatile boolean finished; + + Source(AsynchronousByteChannel channel) { + this.channel = channel; + int size = 1024 + rand.nextInt(10000); + this.sentBuffer = (rand.nextBoolean()) ? + ByteBuffer.allocateDirect(size) : ByteBuffer.allocate(size); + } + + void start() { + sentBuffer.position(0); + sentBuffer.limit(sentBuffer.capacity()); + channel.write(sentBuffer, null, new CompletionHandler () { + public void completed(Integer nwrote, Void att) { + bytesSent += nwrote; + if (finished) { + closeUnchecked(channel); + } else { + sentBuffer.position(0); + sentBuffer.limit(sentBuffer.capacity()); + channel.write(sentBuffer, null, this); + } + } + public void failed(Throwable exc, Void att) { + exc.printStackTrace(); + closeUnchecked(channel); + } + public void cancelled(Void att) { + } + }); + } + + long finish() { + finished = true; + waitUntilClosed(channel); + return bytesSent; + } + } + + /** + * Read bytes from a channel until EOF is received. + */ + static class Sink { + private final AsynchronousByteChannel channel; + private final ByteBuffer readBuffer; + private volatile long bytesRead; + + Sink(AsynchronousByteChannel channel) { + this.channel = channel; + int size = 1024 + rand.nextInt(10000); + this.readBuffer = (rand.nextBoolean()) ? + ByteBuffer.allocateDirect(size) : ByteBuffer.allocate(size); + } + + void start() { + channel.read(readBuffer, null, new CompletionHandler () { + public void completed(Integer nread, Void att) { + if (nread < 0) { + closeUnchecked(channel); + } else { + bytesRead += nread; + readBuffer.clear(); + channel.read(readBuffer, null, this); + } + } + public void failed(Throwable exc, Void att) { + exc.printStackTrace(); + closeUnchecked(channel); + } + public void cancelled(Void att) { + } + }); + } + + long finish() { + waitUntilClosed(channel); + return bytesRead; + } + } + + static void waitUntilClosed(Channel c) { + while (c.isOpen()) { + try { + Thread.sleep(100); + } catch (InterruptedException ignore) { } + } + } + + static void closeUnchecked(Channel c) { + try { + c.close(); + } catch (IOException ignore) { } + } +} diff --git a/langtools/.hgtags b/langtools/.hgtags index 241f51c31a6..1fe132607c1 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -31,3 +31,5 @@ dbdeb4a7581b2a8699644b91cae6793cb01953f7 jdk7-b53 197a7f881937d406a01214aa9ded49c073f7d380 jdk7-b54 7394a8694cedea574c7dbd38de87f4cbe0e27b8a jdk7-b55 825f23a4f262eb06cfc94406140f3bfecb17ffe8 jdk7-b56 +4030cc469205bbd517ca629fb170afb81760bbc5 jdk7-b57 +5bcac54d408b436d2364925ee7947b5609e07962 jdk7-b58 diff --git a/langtools/src/share/classes/com/sun/tools/classfile/Opcode.java b/langtools/src/share/classes/com/sun/tools/classfile/Opcode.java index 562c3876934..b4bdc77b6df 100644 --- a/langtools/src/share/classes/com/sun/tools/classfile/Opcode.java +++ b/langtools/src/share/classes/com/sun/tools/classfile/Opcode.java @@ -226,7 +226,7 @@ public enum Opcode { INVOKESPECIAL(0xb7, CPREF_W), INVOKESTATIC(0xb8, CPREF_W), INVOKEINTERFACE(0xb9, CPREF_W_UBYTE_ZERO), - // unused 0xba + INVOKEDYNAMIC(0xba, CPREF_W_UBYTE_ZERO), NEW(0xbb, CPREF_W), NEWARRAY(0xbc, ATYPE), ANEWARRAY(0xbd, CPREF_W), diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java b/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java index a16101f0417..0b2316c6615 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java @@ -119,6 +119,8 @@ public class Symtab { public final Type stringBuilderType; public final Type cloneableType; public final Type serializableType; + public final Type methodHandleType; + public final Type invokeDynamicType; public final Type throwableType; public final Type errorType; public final Type illegalArgumentExceptionType; @@ -289,6 +291,24 @@ public class Symtab { } } + public void synthesizeMHTypeIfMissing(final Type type) { + final Completer completer = type.tsym.completer; + if (completer != null) { + type.tsym.completer = new Completer() { + public void complete(Symbol sym) throws CompletionFailure { + try { + completer.complete(sym); + } catch (CompletionFailure e) { + sym.flags_field |= (PUBLIC | ABSTRACT); + ((ClassType) sym.type).supertype_field = objectType; + // do not bother to create MH.type if not visibly declared + // this sym just accumulates invoke(...) methods + } + } + }; + } + } + public void synthesizeBoxTypeIfMissing(final Type type) { ClassSymbol sym = reader.enterClass(boxedName[type.tag]); final Completer completer = sym.completer; @@ -405,6 +425,8 @@ public class Symtab { cloneableType = enterClass("java.lang.Cloneable"); throwableType = enterClass("java.lang.Throwable"); serializableType = enterClass("java.io.Serializable"); + methodHandleType = enterClass("java.dyn.MethodHandle"); + invokeDynamicType = enterClass("java.dyn.InvokeDynamic"); errorType = enterClass("java.lang.Error"); illegalArgumentExceptionType = enterClass("java.lang.IllegalArgumentException"); exceptionType = enterClass("java.lang.Exception"); @@ -441,6 +463,8 @@ public class Symtab { synthesizeEmptyInterfaceIfMissing(cloneableType); synthesizeEmptyInterfaceIfMissing(serializableType); + synthesizeMHTypeIfMissing(methodHandleType); + synthesizeMHTypeIfMissing(invokeDynamicType); synthesizeBoxTypeIfMissing(doubleType); synthesizeBoxTypeIfMissing(floatType); diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java index a920623806b..2ea19c5f51d 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java @@ -118,6 +118,7 @@ public class Attr extends JCTree.Visitor { relax = (options.get("-retrofit") != null || options.get("-relax") != null); useBeforeDeclarationWarning = options.get("useBeforeDeclarationWarning") != null; + allowInvokedynamic = options.get("invokedynamic") != null; } /** Switch: relax some constraints for retrofit mode. @@ -149,6 +150,10 @@ public class Attr extends JCTree.Visitor { */ boolean allowAnonOuterThis; + /** Switch: allow invokedynamic syntax + */ + boolean allowInvokedynamic; + /** * Switch: warn about use of variable before declaration? * RFE: 6425594 @@ -438,14 +443,22 @@ public class Attr extends JCTree.Visitor { } /** Attribute a type argument list, returning a list of types. + * Caller is responsible for calling checkRefTypes. */ - List attribTypes(List trees, Env env) { + List attribAnyTypes(List trees, Env env) { ListBuffer argtypes = new ListBuffer(); for (List l = trees; l.nonEmpty(); l = l.tail) - argtypes.append(chk.checkRefType(l.head.pos(), attribType(l.head, env))); + argtypes.append(attribType(l.head, env)); return argtypes.toList(); } + /** Attribute a type argument list, returning a list of types. + * Check that all the types are references. + */ + List attribTypes(List trees, Env env) { + List types = attribAnyTypes(trees, env); + return chk.checkRefTypes(trees, types); + } /** * Attribute type variables (of generic classes or methods). @@ -1194,6 +1207,7 @@ public class Attr extends JCTree.Visitor { // The types of the actual method type arguments. List typeargtypes = null; + boolean typeargtypesNonRefOK = false; Name methName = TreeInfo.name(tree.meth); @@ -1281,7 +1295,7 @@ public class Attr extends JCTree.Visitor { // Otherwise, we are seeing a regular method call. // Attribute the arguments, yielding list of argument types, ... argtypes = attribArgs(tree.args, localEnv); - typeargtypes = attribTypes(tree.typeargs, localEnv); + typeargtypes = attribAnyTypes(tree.typeargs, localEnv); // ... and attribute the method using as a prototype a methodtype // whose formal argument types is exactly the list of actual @@ -1318,6 +1332,20 @@ public class Attr extends JCTree.Visitor { restype.tsym); } + // as a special case, MethodHandle.invoke(abc) and InvokeDynamic.foo(abc) + // has type , and T can be a primitive type. + if (tree.meth.getTag() == JCTree.SELECT && !typeargtypes.isEmpty()) { + Type selt = ((JCFieldAccess) tree.meth).selected.type; + if ((selt == syms.methodHandleType && methName == names.invoke) || selt == syms.invokeDynamicType) { + assert types.isSameType(restype, typeargtypes.head) : mtype; + typeargtypesNonRefOK = true; + } + } + + if (!typeargtypesNonRefOK) { + chk.checkRefTypes(tree.typeargs, typeargtypes); + } + // Check that value of resulting type is admissible in the // current context. Also, capture the return type result = check(tree, capture(restype), VAL, pkind, pt); diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java index 0f9f8d98c44..402f310783e 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java @@ -207,6 +207,12 @@ public class Check { * @param found The type that was found. */ Type typeTagError(DiagnosticPosition pos, Object required, Object found) { + // this error used to be raised by the parser, + // but has been delayed to this point: + if (found instanceof Type && ((Type)found).tag == VOID) { + log.error(pos, "illegal.start.of.type"); + return syms.errType; + } log.error(pos, "type.found.req", found, required); return types.createErrorType(found instanceof Type ? (Type)found : syms.errType); } @@ -547,6 +553,20 @@ public class Check { } } + /** Check that each type is a reference type, i.e. a class, interface or array type + * or a type variable. + * @param trees Original trees, used for error reporting. + * @param types The types to be checked. + */ + List checkRefTypes(List trees, List types) { + List tl = trees; + for (List l = types; l.nonEmpty(); l = l.tail) { + l.head = checkRefType(tl.head.pos(), l.head); + tl = tl.tail; + } + return types; + } + /** Check that type is a null or reference type. * @param pos Position to be used for error reporting. * @param t The type to be checked. diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java index ca4908830cc..c73bf174d70 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -67,6 +67,7 @@ public class Resolve { JCDiagnostic.Factory diags; public final boolean boxingEnabled; // = source.allowBoxing(); public final boolean varargsEnabled; // = source.allowVarargs(); + public final boolean allowInvokedynamic; // = options.get("invokedynamic"); private final boolean debugResolve; public static Resolve instance(Context context) { @@ -104,6 +105,7 @@ public class Resolve { varargsEnabled = source.allowVarargs(); Options options = Options.instance(context); debugResolve = options.get("debugresolve") != null; + allowInvokedynamic = options.get("invokedynamic") != null; } /** error symbols, which are returned when resolution fails @@ -881,6 +883,79 @@ public class Resolve { return bestSoFar; } + /** Find or create an implicit method of exactly the given type (after erasure). + * Searches in a side table, not the main scope of the site. + * This emulates the lookup process required by JSR 292 in JVM. + * @param env The current environment. + * @param site The original type from where the selection + * takes place. + * @param name The method's name. + * @param argtypes The method's value arguments. + * @param typeargtypes The method's type arguments + */ + Symbol findImplicitMethod(Env env, + Type site, + Name name, + List argtypes, + List typeargtypes) { + assert allowInvokedynamic; + assert site == syms.invokeDynamicType || (site == syms.methodHandleType && name == names.invoke); + ClassSymbol c = (ClassSymbol) site.tsym; + Scope implicit = c.members().next; + if (implicit == null) { + c.members().next = implicit = new Scope(c); + } + Type restype; + if (typeargtypes.isEmpty()) { + restype = syms.objectType; + } else { + restype = typeargtypes.head; + if (!typeargtypes.tail.isEmpty()) + return methodNotFound; + } + List paramtypes = Type.map(argtypes, implicitArgType); + MethodType mtype = new MethodType(paramtypes, + restype, + List.nil(), + syms.methodClass); + int flags = PUBLIC | ABSTRACT; + if (site == syms.invokeDynamicType) flags |= STATIC; + Symbol m = null; + for (Scope.Entry e = implicit.lookup(name); + e.scope != null; + e = e.next()) { + Symbol sym = e.sym; + assert sym.kind == MTH; + if (types.isSameType(mtype, sym.type) + && (sym.flags() & STATIC) == (flags & STATIC)) { + m = sym; + break; + } + } + if (m == null) { + // create the desired method + m = new MethodSymbol(flags, name, mtype, c); + implicit.enter(m); + } + assert argumentsAcceptable(argtypes, types.memberType(site, m).getParameterTypes(), + false, false, Warner.noWarnings); + assert null != instantiate(env, site, m, argtypes, typeargtypes, false, false, Warner.noWarnings); + return m; + } + //where + Mapping implicitArgType = new Mapping ("implicitArgType") { + public Type apply(Type t) { return implicitArgType(t); } + }; + Type implicitArgType(Type argType) { + argType = types.erasure(argType); + if (argType.tag == BOT) + // nulls type as the marker type Null (which has no instances) + // TO DO: figure out how to access java.lang.Null safely, else throw nice error + //argType = types.boxedClass(syms.botType).type; + argType = types.boxedClass(syms.voidType).type; // REMOVE + return argType; + } + /** Load toplevel or member class with given fully qualified name and * verify that it is accessible. * @param env The current environment. @@ -1265,6 +1340,14 @@ public class Resolve { methodResolutionCache.put(steps.head, sym); steps = steps.tail; } + if (sym.kind >= AMBIGUOUS && + allowInvokedynamic && + (site == syms.invokeDynamicType || + site == syms.methodHandleType && name == names.invoke)) { + // lookup failed; supply an exactly-typed implicit method + sym = findImplicitMethod(env, site, name, argtypes, typeargtypes); + env.info.varArgs = false; + } if (sym.kind >= AMBIGUOUS) {//if nothing is found return the 'first' error MethodResolutionPhase errPhase = firstErroneousResolutionPhase(); diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/ByteCodes.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/ByteCodes.java index 72a186e8609..3100c2a5061 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ByteCodes.java +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ByteCodes.java @@ -225,7 +225,7 @@ public interface ByteCodes { invokespecial = 183, invokestatic = 184, invokeinterface = 185, - // ___unused___ = 186, + invokedynamic = 186, new_ = 187, newarray = 188, anewarray = 189, diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java index 263ca3c0b0a..c9e68cf8b33 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -2309,6 +2309,7 @@ public class ClassReader implements Completer { String binaryName = fileManager.inferBinaryName(currentLoc, fo); String simpleName = binaryName.substring(binaryName.lastIndexOf(".") + 1); if (SourceVersion.isIdentifier(simpleName) || + fo.getKind() == JavaFileObject.Kind.CLASS || simpleName.equals("package-info")) includeClassFile(p, fo); break; diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/Code.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/Code.java index 18162918601..67fc168fc33 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Code.java +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Code.java @@ -456,6 +456,19 @@ public class Code { state.push(mtype.getReturnType()); } + /** Emit an invokedynamic instruction. + */ + public void emitInvokedynamic(int desc, Type mtype) { + // N.B. this format is under consideration by the JSR 292 EG + int argsize = width(mtype.getParameterTypes()); + emitop(invokedynamic); + if (!alive) return; + emit2(desc); + emit2(0); + state.pop(argsize); + state.push(mtype.getReturnType()); + } + /** Emit an opcode with no operand field. */ public void emitop0(int op) { @@ -2156,7 +2169,7 @@ public class Code { mnem[invokespecial] = "invokespecial"; mnem[invokestatic] = "invokestatic"; mnem[invokeinterface] = "invokeinterface"; - // mnem[___unused___] = "___unused___"; + mnem[invokedynamic] = "invokedynamic"; mnem[new_] = "new_"; mnem[newarray] = "newarray"; mnem[anewarray] = "anewarray"; diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java index 94f46d489bc..7180cf613c9 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java @@ -119,6 +119,7 @@ public class Gen extends JCTree.Visitor { : options.get("-g:vars") != null; genCrt = options.get("-Xjcov") != null; debugCode = options.get("debugcode") != null; + allowInvokedynamic = options.get("invokedynamic") != null; generateIproxies = target.requiresIproxy() || @@ -155,6 +156,7 @@ public class Gen extends JCTree.Visitor { private final boolean varDebugInfo; private final boolean genCrt; private final boolean debugCode; + private final boolean allowInvokedynamic; /** Default limit of (approximate) size of finalizer to inline. * Zero means always use jsr. 100 or greater means never use @@ -2140,6 +2142,9 @@ public class Gen extends JCTree.Visitor { } result = items. makeImmediateItem(sym.type, ((VarSymbol) sym).getConstValue()); + } else if (allowInvokedynamic && sym.kind == MTH && ssym == syms.invokeDynamicType.tsym) { + base.drop(); + result = items.makeDynamicItem(sym); } else { if (!accessSuper) sym = binaryQualifier(sym, tree.selected.type); diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/Items.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/Items.java index 8f18c7a8b92..0cc968f0ff5 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Items.java +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Items.java @@ -139,6 +139,13 @@ public class Items { return new StaticItem(member); } + /** Make an item representing a dynamically invoked method. + * @param member The represented symbol. + */ + Item makeDynamicItem(Symbol member) { + return new DynamicItem(member); + } + /** Make an item representing an instance variable or method. * @param member The represented symbol. * @param nonvirtual Is the reference not virtual? (true for constructors @@ -457,6 +464,38 @@ public class Items { } } + /** An item representing a dynamic call site. + */ + class DynamicItem extends StaticItem { + DynamicItem(Symbol member) { + super(member); + assert member.owner == syms.invokeDynamicType.tsym; + } + + Item load() { + assert false; + return null; + } + + void store() { + assert false; + } + + Item invoke() { + // assert target.hasNativeInvokeDynamic(); + MethodType mtype = (MethodType)member.erasure(types); + int rescode = Code.typecode(mtype.restype); + ClassFile.NameAndType descr = new ClassFile.NameAndType(member.name, mtype); + code.emitInvokedynamic(pool.put(descr), mtype); + return stackItem[rescode]; + } + + public String toString() { + return "dynamic(" + member + ")"; + } + } + + /** An item representing an instance variable or method. */ class MemberItem extends Item { diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/Target.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/Target.java index b447b7ef01e..f3828fdd5c0 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Target.java +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Target.java @@ -253,6 +253,12 @@ public enum Target { return compareTo(JDK1_5) >= 0; } + /** Does the VM support an invokedynamic instruction? + */ + public boolean hasInvokedynamic() { + return compareTo(JDK1_7) >= 0; + } + /** Although we may not have support for class literals, should we * avoid initializing the class that the literal refers to? * See 4468823 diff --git a/langtools/src/share/classes/com/sun/tools/javac/main/Main.java b/langtools/src/share/classes/com/sun/tools/javac/main/Main.java index 0ae7cd1c6b8..57b0219e7c3 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/main/Main.java +++ b/langtools/src/share/classes/com/sun/tools/javac/main/Main.java @@ -268,14 +268,19 @@ public class Main { } return null; } else { - options.put("-target", source.requiredTarget().name); + target = source.requiredTarget(); + options.put("-target", target.name); } } else { if (targetString == null && !source.allowGenerics()) { - options.put("-target", Target.JDK1_4.name); + target = Target.JDK1_4; + options.put("-target", target.name); } } } + if (target.hasInvokedynamic()) { + options.put("invokedynamic", "invokedynamic"); + } return filenames.toList(); } // where diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java index e3668716283..312db12f830 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -1034,7 +1034,13 @@ public class JavacParser implements Parser { return illegal(pos); } } else { - return illegal(); + // Support the corner case of myMethodHandle.invoke() by passing + // a void type (like other primitive types) to the next phase. + // The error will be reported in Attr.attribTypes or Attr.visitApply. + JCPrimitiveTypeTree ti = to(F.at(pos).TypeIdent(TypeTags.VOID)); + S.nextToken(); + return ti; + //return illegal(); } break; default: diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/Scanner.java b/langtools/src/share/classes/com/sun/tools/javac/parser/Scanner.java index 15020bf833c..ad556a970f6 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/Scanner.java +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/Scanner.java @@ -317,7 +317,7 @@ public class Scanner implements Lexer { /** Read next character in character or string literal and copy into sbuf. */ - private void scanLitChar() { + private void scanLitChar(boolean forBytecodeName) { if (ch == '\\') { if (buf[bp+1] == '\\' && unicodeConversionBp != bp) { bp++; @@ -357,6 +357,18 @@ public class Scanner implements Lexer { putChar('\"'); scanChar(); break; case '\\': putChar('\\'); scanChar(); break; + case '|': case ',': case '?': case '%': + case '^': case '_': case '{': case '}': + case '!': case '-': case '=': + if (forBytecodeName) { + // Accept escape sequences for dangerous bytecode chars. + // This is illegal in normal Java string or character literals. + // Note that the escape sequence itself is passed through. + putChar('\\'); putChar(ch); scanChar(); + } else { + lexError(bp, "illegal.esc.char"); + } + break; default: lexError(bp, "illegal.esc.char"); } @@ -365,6 +377,24 @@ public class Scanner implements Lexer { putChar(ch); scanChar(); } } + private void scanLitChar() { + scanLitChar(false); + } + + /** Read next character in an exotic name #"foo" + */ + private void scanBytecodeNameChar() { + switch (ch) { + // reject any "dangerous" char which is illegal somewhere in the JVM spec + // cf. http://blogs.sun.com/jrose/entry/symbolic_freedom_in_the_vm + case '/': case '.': case ';': // illegal everywhere + case '<': case '>': // illegal in methods, dangerous in classes + case '[': // illegal in classes + lexError(bp, "illegal.bytecode.ident.char", String.valueOf((int)ch)); + break; + } + scanLitChar(true); + } /** Read fractional part of hexadecimal floating point number. */ @@ -915,6 +945,26 @@ public class Scanner implements Lexer { lexError(pos, "unclosed.str.lit"); } return; + case '#': + scanChar(); + if (ch == '\"') { + scanChar(); + if (ch == '\"') + lexError(pos, "empty.bytecode.ident"); + while (ch != '\"' && ch != CR && ch != LF && bp < buflen) { + scanBytecodeNameChar(); + } + if (ch == '\"') { + name = names.fromChars(sbuf, 0, sp); + token = IDENTIFIER; // even if #"int" or #"do" + scanChar(); + } else { + lexError(pos, "unclosed.bytecode.ident"); + } + } else { + lexError("illegal.char", String.valueOf((int)'#')); + } + return; default: if (isSpecial(ch)) { scanOperator(); diff --git a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties index ea8f2d245d1..6bce5c55ad8 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -144,6 +144,8 @@ compiler.err.duplicate.default.label=\ compiler.err.else.without.if=\ ''else'' without ''if'' +compiler.err.empty.bytecode.ident=\ + empty bytecode identifier compiler.err.empty.char.lit=\ empty character literal compiler.err.encl.class.required=\ @@ -186,6 +188,8 @@ compiler.err.generic.throwable=\ compiler.err.icls.cant.have.static.decl=\ inner classes cannot have static declarations +compiler.err.illegal.bytecode.ident.char=\ + illegal bytecode identifier character: \\{0} compiler.err.illegal.char=\ illegal character: \\{0} compiler.err.illegal.char.for.encoding=\ @@ -445,6 +449,8 @@ compiler.err.type.var.more.than.once.in.result=\ compiler.err.types.incompatible.diff.ret=\ types {0} and {1} are incompatible; both define {2}, but with unrelated return types +compiler.err.unclosed.bytecode.ident=\ + unclosed bytecode identifier compiler.err.unclosed.char.lit=\ unclosed character literal compiler.err.unclosed.comment=\ diff --git a/langtools/src/share/classes/com/sun/tools/javac/util/Names.java b/langtools/src/share/classes/com/sun/tools/javac/util/Names.java index 663ff824c4e..86d3e510de4 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/util/Names.java +++ b/langtools/src/share/classes/com/sun/tools/javac/util/Names.java @@ -73,6 +73,8 @@ public class Names { public final Name java_io_Serializable; public final Name serialVersionUID; public final Name java_lang_Enum; + public final Name java_dyn_MethodHandle; + public final Name java_dyn_InvokeDynamic; public final Name package_info; public final Name ConstantValue; public final Name LineNumberTable; @@ -111,6 +113,7 @@ public class Names { public final Name value; public final Name getMessage; public final Name getClass; + public final Name invoke; public final Name TYPE; public final Name FIELD; public final Name METHOD; @@ -175,6 +178,8 @@ public class Names { java_lang_Cloneable = fromString("java.lang.Cloneable"); java_io_Serializable = fromString("java.io.Serializable"); java_lang_Enum = fromString("java.lang.Enum"); + java_dyn_MethodHandle = fromString("java.dyn.MethodHandle"); + java_dyn_InvokeDynamic = fromString("java.dyn.InvokeDynamic"); package_info = fromString("package-info"); serialVersionUID = fromString("serialVersionUID"); ConstantValue = fromString("ConstantValue"); @@ -216,6 +221,7 @@ public class Names { value = fromString("value"); getMessage = fromString("getMessage"); getClass = fromString("getClass"); + invoke = fromString("invoke"); TYPE = fromString("TYPE"); FIELD = fromString("FIELD"); diff --git a/langtools/src/share/classes/com/sun/tools/javap/ConstantWriter.java b/langtools/src/share/classes/com/sun/tools/javap/ConstantWriter.java index af5476e0940..b8710d496a1 100644 --- a/langtools/src/share/classes/com/sun/tools/javap/ConstantWriter.java +++ b/langtools/src/share/classes/com/sun/tools/javap/ConstantWriter.java @@ -339,7 +339,7 @@ public class ConstantWriter extends BasicWriter { cp = name.codePointAt(k); if ((cc == '/' && !Character.isJavaIdentifierStart(cp)) || (cp != '/' && !Character.isJavaIdentifierPart(cp))) { - return "\"" + name + "\""; + return "\"" + addEscapes(name) + "\""; } cc = cp; } @@ -347,6 +347,33 @@ public class ConstantWriter extends BasicWriter { return name; } + /* If name requires escapes, put them in, so it can be a string body. */ + private static String addEscapes(String name) { + String esc = "\\\"\n\t"; + String rep = "\\\"nt"; + StringBuilder buf = null; + int nextk = 0; + int len = name.length(); + for (int k = 0; k < len; k++) { + char cp = name.charAt(k); + int n = esc.indexOf(cp); + if (n >= 0) { + if (buf == null) + buf = new StringBuilder(len * 2); + if (nextk < k) + buf.append(name, nextk, k); + buf.append('\\'); + buf.append(rep.charAt(n)); + nextk = k+1; + } + } + if (buf == null) + return name; + if (nextk < len) + buf.append(name, nextk, len); + return buf.toString(); + } + private ClassWriter classWriter; private Options options; } diff --git a/langtools/src/share/classes/sun/tools/javap/JavapPrinter.java b/langtools/src/share/classes/sun/tools/javap/JavapPrinter.java index 5f693e7fb24..2d7d3c262c0 100644 --- a/langtools/src/share/classes/sun/tools/javap/JavapPrinter.java +++ b/langtools/src/share/classes/sun/tools/javap/JavapPrinter.java @@ -475,6 +475,13 @@ public class JavapPrinter { return 5; } + case opc_invokedynamic: { + int index = getUShort(pc+1); + out.print("\t#"+index+"; //"); + PrintConstant(index); + return 5; + } + case opc_multianewarray: { int index = getUShort(pc+1), dimensions=getUbyte(pc+3); out.print("\t#"+index+", "+dimensions+"; //"); diff --git a/langtools/src/share/classes/sun/tools/javap/RuntimeConstants.java b/langtools/src/share/classes/sun/tools/javap/RuntimeConstants.java index 0ca2caf04ec..b9085ec3008 100644 --- a/langtools/src/share/classes/sun/tools/javap/RuntimeConstants.java +++ b/langtools/src/share/classes/sun/tools/javap/RuntimeConstants.java @@ -318,7 +318,7 @@ public interface RuntimeConstants { public static final int opc_invokespecial = 183; public static final int opc_invokestatic = 184; public static final int opc_invokeinterface = 185; -// public static final int opc_xxxunusedxxx = 186; + public static final int opc_invokedynamic = 186; public static final int opc_new = 187; public static final int opc_newarray = 188; public static final int opc_anewarray = 189; @@ -549,7 +549,7 @@ public interface RuntimeConstants { "invokespecial", // was "invokenonvirtual", "invokestatic", "invokeinterface", - "bytecode 186", //"xxxunusedxxx", + "invokedynamic", "new", "newarray", "anewarray", diff --git a/langtools/test/tools/javac/meth/InvokeDyn.java b/langtools/test/tools/javac/meth/InvokeDyn.java new file mode 100644 index 00000000000..3a4a631d8c7 --- /dev/null +++ b/langtools/test/tools/javac/meth/InvokeDyn.java @@ -0,0 +1,59 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test + * @bug 6754038 + * @summary Generate call sites for method handle + * @author jrose + * + * @library .. + * @compile -source 7 -target 7 InvokeDyn.java + */ +//No: @run main/othervm -XX:+EnableInvokeDynamic meth.InvokeDyn + +/* + * Standalone testing: + * + * $ cd $MY_REPO_DIR/langtools + * $ (cd make; make) + * $ ./dist/bootstrap/bin/javac -d dist test/tools/javac/meth/InvokeDyn.java + * $ javap -c -classpath dist meth.InvokeDyn + * + */ + +package meth; + +import java.dyn.InvokeDynamic; + +public class InvokeDyn { + void test() { + Object x = "hello"; + InvokeDynamic.greet(x, "world", 123); + InvokeDynamic.greet(x, "mundus", 456); + InvokeDynamic.greet(x, "kosmos", 789); + InvokeDynamic.cogitate(10.11121, 3.14); + InvokeDynamic.#"yow: what I mean to say is, please treat this one specially"(null); + InvokeDynamic.invoke("goodbye"); + } +} diff --git a/langtools/test/tools/javac/meth/InvokeMH.java b/langtools/test/tools/javac/meth/InvokeMH.java new file mode 100644 index 00000000000..cfd4ab30972 --- /dev/null +++ b/langtools/test/tools/javac/meth/InvokeMH.java @@ -0,0 +1,75 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test + * @bug 6754038 + * @summary Generate call sites for method handle + * @author jrose + * + * @compile -source 7 -target 7 InvokeMH.java + */ + +/* + * Standalone testing: + * + * $ cd $MY_REPO_DIR/langtools + * $ (cd make; make) + * $ ./dist/bootstrap/bin/javac -d dist test/tools/javac/meth/InvokeMH.java + * $ javap -c -classpath dist meth.InvokeMH + * + */ + +package meth; + +import java.dyn.MethodHandle; + +public class InvokeMH { + void test(MethodHandle mh_SiO, + MethodHandle mh_vS, + MethodHandle mh_vi, + MethodHandle mh_vv) { + Object o; String s; int i; // for return type testing + + // next five must have sig = (String,int)Object + mh_SiO.invoke("world", 123); + mh_SiO.invoke("mundus", 456); + Object k = "kosmos"; + mh_SiO.invoke((String)k, 789); + o = mh_SiO.invoke((String)null, 000); + o = mh_SiO.invoke("arda", -123); + + // sig = ()String + s = mh_vS.invoke(); + + // sig = ()int + i = mh_vi.invoke(); + o = mh_vi.invoke(); + //s = mh_vi.invoke(); //BAD + mh_vi.invoke(); + + // sig = ()void + //o = mh_vv.invoke(); //BAD + mh_vv.invoke(); + } +} diff --git a/langtools/test/tools/javac/meth/MakeNegTests.sh b/langtools/test/tools/javac/meth/MakeNegTests.sh new file mode 100644 index 00000000000..587fa767830 --- /dev/null +++ b/langtools/test/tools/javac/meth/MakeNegTests.sh @@ -0,0 +1,98 @@ +#!/bin/sh + +# +# 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. +# +# 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. +# + +# @test +# @bug 6754038 +# @summary Verify correct rejection of strongly typed return values +# @run shell MakeNegTests.sh + +default_template=InvokeMH.java +javacflags='-source 7 -target 7' +# the rest of this file is a generic "//BAD"-line tester + +: ${TESTSRC=.} ${TESTCLASSES=.} +javac="${TESTJAVA+${TESTJAVA}/bin/}javac" + +verbose=false quiet=false + +main() { + case "${@-}" in + *.java*) + for template in "$@"; do + expand_and_test "$template" + done;; + *) expand_and_test "${TESTSRC}/$default_template";; + esac +} + +expand_and_test() { + template=$1 + expand "$@" + testneg "$@" +} + +expand() { + template=$1 + badlines=` grep -n < "$template" '//BAD' ` + badcount=` echo "$badlines" | wc -l ` + [ $badcount -gt 0 ] || { echo "No negative test cases in $template"; exit 1; } + $quiet || echo "Expanding $badcount negative test cases from $template:" + $quiet || echo "$badlines" + badnums=` echo "$badlines" | sed 's/:.*//' ` + casestem=` getcasestem "$template" ` + tclassname=` basename "$template" .java ` + rm -f "$casestem"*.java + for badnum in $badnums; do + casefile="$casestem"${badnum}.java + cclassname=` basename "$casefile" .java ` + sed < "$template" > "$casefile" " + s|@compile|@compile/fail| + / @[a-z]/s|@|##| + ${badnum}s:^ *[/*]*: : + s/${tclassname}/${cclassname}/g + " + $verbose && diff -u "$template" "$casefile" + done +} + +getcasestem() { + echo "$1" | sed 's/\.java$//;s/_BAD[0-9]*$//;s/$/_BAD/' +} + +testneg() { + template=$1 + for casefile in ` getcasestem "$template" `*.java; do + $quiet || echo -------- $javac $javacflags "$casefile" + $javac $javacflags "$casefile" > "$casefile".errlog 2>&1 && { + echo "*** Compilation unexpectedly succeeded: $casefile" + exit 1 + } + $quiet || echo "Compilation failed as expected" + $quiet || head ` $verbose || echo -3 ` < "$casefile".errlog + rm "$casefile".errlog + done +} + +main "$@" diff --git a/langtools/test/tools/javac/quid/MakeNegTests.sh b/langtools/test/tools/javac/quid/MakeNegTests.sh new file mode 100644 index 00000000000..16fc724ba62 --- /dev/null +++ b/langtools/test/tools/javac/quid/MakeNegTests.sh @@ -0,0 +1,97 @@ +#!/bin/sh + +# +# 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. +# +# 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. +# + +# @test +# @bug 6746458 +# @summary Verify correct rejection of illegal quoted identifiers. +# @run shell MakeNegTests.sh + +default_template=QuotedIdent.java +# the rest of this file is a generic "//BAD"-line tester + +: ${TESTSRC=.} ${TESTCLASSES=.} +javac="${TESTJAVA+${TESTJAVA}/bin/}javac" + +verbose=false quiet=false + +main() { + case "${@-}" in + *.java*) + for template in "$@"; do + expand_and_test "$template" + done;; + *) expand_and_test "${TESTSRC}/$default_template";; + esac +} + +expand_and_test() { + template=$1 + expand "$@" + testneg "$@" +} + +expand() { + template=$1 + badlines=` grep -n < "$template" '//BAD' ` + badcount=` echo "$badlines" | wc -l ` + [ $badcount -gt 0 ] || { echo "No negative test cases in $template"; exit 1; } + $quiet || echo "Expanding $badcount negative test cases from $template:" + $quiet || echo "$badlines" + badnums=` echo "$badlines" | sed 's/:.*//' ` + casestem=` getcasestem "$template" ` + tclassname=` basename "$template" .java ` + rm "$casestem"*.java + for badnum in $badnums; do + casefile="$casestem"${badnum}.java + cclassname=` basename "$casefile" .java ` + sed < "$template" > "$casefile" " + s|@compile|@compile/fail| + / @[a-z]/s|@|##| + ${badnum}s:^ *[/*]*: : + s/${tclassname}/${cclassname}/g + " + $verbose && diff -u "$template" "$casefile" + done +} + +getcasestem() { + echo "$1" | sed 's/\.java$//;s/_BAD[0-9]*$//;s/$/_BAD/' +} + +testneg() { + template=$1 + for casefile in ` getcasestem "$template" `*.java; do + $quiet || echo -------- $javac "$casefile" + $javac "$casefile" > "$casefile".errlog 2>&1 && { + echo "*** Compilation unexpectedly succeeded: $casefile" + exit 1 + } + $quiet || echo "Compilation failed as expected" + $quiet || head ` $verbose || echo -3 ` < "$casefile".errlog + rm "$casefile".errlog + done +} + +main "$@" diff --git a/langtools/test/tools/javac/quid/QuotedIdent.java b/langtools/test/tools/javac/quid/QuotedIdent.java new file mode 100644 index 00000000000..10e34dbc555 --- /dev/null +++ b/langtools/test/tools/javac/quid/QuotedIdent.java @@ -0,0 +1,132 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test + * @bug 6746458 + * @summary Verify correct lexing of quoted identifiers. + * @author jrose + * + * @library .. + * @run main quid.QuotedIdent + */ + +/* + * Standalone testing: + * + * $ cd $MY_REPO_DIR/langtools + * $ (cd make; make) + * $ ./dist/bootstrap/bin/javac -d dist test/tools/javac/quid/QuotedIdent.java + * $ java -version # should print 1.6 or later + * $ java -cp dist quid.QuotedIdent + * + */ + +package quid; + +public class QuotedIdent { + static void check(int testid, String have, String expect) + throws RuntimeException { + if ((have == null && have != expect) || + (have != null && !have.equals(expect))) { + String msg = + "TEST " + testid + ": HAVE \"" + + have + "\" EXPECT \"" + expect + "\""; + System.out.println("StringConversion: " + msg); + throw new RuntimeException(msg); + } + } + + // negative tests: + //static class #"" { } //BAD empty ident name + //static class #"" { } //BAD bad char in ident name + /*static class /*(//BAD ident name interrupted by newline) #"jump: + " { } /* uncomment previous line to attempt class w/ bad name */ + + static class #"int" extends Number { + final int #"int"; + #"int"(int #"int") { + this.#"int" = #"int"; + } + static #"int" valueOf(int #"int") { + return new #"int"(#"int"); + } + public int intValue() { return #"int"; } + public long longValue() { return #"int"; } + public float floatValue() { return #"int"; } + public double doubleValue() { return #"int"; } + public String toString() { return String.valueOf(#"int"); } + } + + class #"*86" { + String #"555-1212"() { return "[*86.555-1212]"; } + } + static#"*86"#"MAKE-*86"() { // note close spacing + return new QuotedIdent().new#"*86"(); + } + + static String bar() { return "[bar]"; } + + public static void main(String[] args) throws Exception { + String s; + + String #"sticky \' wicket" = "wicked ' stick"; + s = #"sticky ' wicket"; + check(11, s, "wicked \' stick"); + check(12, #"s", s); + check(13, #"\163", s); + + s = #"QuotedIdent".bar(); + check(21, s, "[bar]"); + + s = #"int".valueOf(123).toString(); + check(22, s, "123"); + + s = #"MAKE-*86"().#"555-1212"(); + check(23, s, "[*86.555-1212]"); + + class#"{{{inmost}}}" { } + s = new#"{{{inmost}}}"().getClass().getName(); + if (!s.endsWith("{{{inmost}}}")) + check(24, s, "should end with \"{{{inmost}}}\""); + + s = #"Yog-Shoggoth".#"(nameless ululation)"; + check(25, s, "Tekeli-li!"); + + s = #"int".class.getName(); + check(31, s, QuotedIdent.class.getName()+"$int"); + + Class x86 = Class.forName(QuotedIdent.class.getName()+"$*86"); + if (x86 != #"*86".class) + check(32, "reflected "+x86, "static "+#"*86".class); + + s = (String) x86.getDeclaredMethod("555-1212").invoke(#"MAKE-*86"()); + check(31, s, "[*86.555-1212]"); + + System.out.println("OK"); + } +} + +interface #"Yog-Shoggoth" { + final String #"(nameless ululation)" = "Tekeli-li!"; +} diff --git a/langtools/test/tools/javac/quid/QuotedIdent2.java b/langtools/test/tools/javac/quid/QuotedIdent2.java new file mode 100644 index 00000000000..2df94cd927b --- /dev/null +++ b/langtools/test/tools/javac/quid/QuotedIdent2.java @@ -0,0 +1,81 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test + * @bug 6746458 + * @summary Verify correct separate compilation of classes with extended identifiers. + * @author jrose + * + * @library .. + * @run main quid.QuotedIdent2 + */ +/* + * Standalone testing: + * + * $ cd $MY_REPO_DIR/langtools + * $ (cd make; make) + * $ ./dist/bootstrap/bin/javac -d dist test/tools/javac/quid/QuotedIdent.java + * $ ./dist/bootstrap/bin/javac -d dist -cp dist test/tools/javac/quid/QuotedIdent2.java + * $ java -version # should print 1.6 or later + * $ java -cp dist QuotedIdent2 + * + */ + +package quid; + +import quid.QuotedIdent.*; +import quid.QuotedIdent.#"*86"; +import static quid.QuotedIdent.#"MAKE-*86"; + +public class QuotedIdent2 { + static void check(int testid, String have, String expect) + throws RuntimeException { + QuotedIdent.check(testid, have, expect); + } + + public static void main(String[] args) throws Exception { + String s; + + s = #"int".valueOf(123).toString(); + check(22, s, "123"); + + s = #"MAKE-*86"().#"555-1212"(); + check(23, s, "[*86.555-1212]"); + + s = #"Yog-Shoggoth".#"(nameless ululation)"; + check(25, s, "Tekeli-li!"); + + s = QuotedIdent.#"int".class.getName(); + check(31, s, QuotedIdent.class.getName()+"$int"); + + Class x86 = Class.forName(QuotedIdent.class.getName()+"$*86"); + if (x86 != #"*86".class) + check(32, "reflected "+x86, "static "+#"*86".class); + + s = (String) x86.getDeclaredMethod("555-1212").invoke(QuotedIdent.#"MAKE-*86"()); + check(31, s, "[*86.555-1212]"); + + System.out.println("OK"); + } +}