diff --git a/Makefile.in b/Makefile.in index 9c57bec974..322c2eb5a6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -84,8 +84,8 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/configure $(am__configure_deps) \ $(srcdir)/config.h.in mkinstalldirs \ $(srcdir)/mono-uninstalled.pc.in COPYING.LIB ChangeLog NEWS \ - compile config.guess config.rpath config.sub depcomp \ - install-sh missing ltmain.sh + compile config.guess config.rpath config.sub install-sh \ + missing ltmain.sh ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ diff --git a/configure.REMOVED.git-id b/configure.REMOVED.git-id index 425c48f592..087dddf6e9 100644 --- a/configure.REMOVED.git-id +++ b/configure.REMOVED.git-id @@ -1 +1 @@ -2c2c33e9b3b238b9af81df41107a0b6b0127ed10 \ No newline at end of file +1895650fb1b5a365ada5bcdf3fef86a448da51d2 \ No newline at end of file diff --git a/configure.ac.REMOVED.git-id b/configure.ac.REMOVED.git-id index 95fcf98d21..2af5adf10d 100644 --- a/configure.ac.REMOVED.git-id +++ b/configure.ac.REMOVED.git-id @@ -1 +1 @@ -fa754128cfe42ebd98f8fc68209473d8cc272fc0 \ No newline at end of file +2317c4f2abf300ae9f452f4dbfd8b9d63c944e1c \ No newline at end of file diff --git a/external/ikvm/HOWTO b/external/ikvm/HOWTO index 1d2e5e8bd9..1a244122da 100644 --- a/external/ikvm/HOWTO +++ b/external/ikvm/HOWTO @@ -1,11 +1,11 @@ IKVM.NET Build Instructions --------------------------- -This IKVM.NET source bundle requires OpenJDK 7u6 b24 sources (and build artifacts). +This IKVM.NET source bundle requires OpenJDK 8u45 b14 sources (and build artifacts). They can be downloaded from the SourceForge IKVM project, or from: -http://www.frijters.net/openjdk-7u6-b24-stripped.zip +http://www.frijters.net/openjdk-8u45-b14-stripped.zip This file should be unzipped in the same directory as where the ikvm directory (that contains this unzipped source bundle) lives. @@ -13,8 +13,8 @@ This file should be unzipped in the same directory as where the ikvm directory Download ICSharpCode.SharpZipLib.dll (from http://www.icsharpcode.net/opensource/sharpziplib/ or from the ikvmbin-x.y.z.r.zip in the SourceForge IKVM project) and copy it to ikvm/bin. -Add the bin directory of NAnt 0.85 and JDK 7 to the PATH. It is recommend to use the 64 bit -version of Java 7. +Add the bin directory of NAnt 0.85 and JDK 8 to the PATH. Java 8 is required to build +the Java class library. It is recommend to use the 64 bit version. From the ikvm directory run "nant". diff --git a/external/ikvm/awt/native.cs b/external/ikvm/awt/native.cs index b5dee44995..62b92dd24a 100644 --- a/external/ikvm/awt/native.cs +++ b/external/ikvm/awt/native.cs @@ -566,7 +566,7 @@ namespace IKVM.NativeCode.sun.awt.shell { return; } - Marshal.Release(pIDL); + Marshal.FreeCoTaskMem(pIDL); } /// @@ -608,8 +608,8 @@ namespace IKVM.NativeCode.sun.awt.shell return (int)atts[0]; } - [System.Security.SecurityCritical] - public static String getFileSystemPath(int csidl) + [System.Security.SecuritySafeCritical] + public static String getFileSystemPath0(int csidl) { IntPtr pIDL = new IntPtr(); int hRes = ShellApi.SHGetSpecialFolderLocation(IntPtr.Zero, (ShellApi.CSIDL)csidl, ref pIDL); diff --git a/external/ikvm/awt/toolkit-0.95.cs.REMOVED.git-id b/external/ikvm/awt/toolkit-0.95.cs.REMOVED.git-id index fcd9e0eed9..2f072d9986 100644 --- a/external/ikvm/awt/toolkit-0.95.cs.REMOVED.git-id +++ b/external/ikvm/awt/toolkit-0.95.cs.REMOVED.git-id @@ -1 +1 @@ -a8a055aaac9ad8e98b1c9c47fcd85f5d82ba8ef1 \ No newline at end of file +3326c8c8b604536ceedce48c5646eef4d04d2a8f \ No newline at end of file diff --git a/external/ikvm/ikvmc/AotTypeWrapper.cs b/external/ikvm/ikvmc/AotTypeWrapper.cs index cc13e7a239..272a2d9172 100644 --- a/external/ikvm/ikvmc/AotTypeWrapper.cs +++ b/external/ikvm/ikvmc/AotTypeWrapper.cs @@ -1,5 +1,5 @@ /* - Copyright (C) 2002-2014 Jeroen Frijters + Copyright (C) 2002-2015 Jeroen Frijters This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -507,7 +507,7 @@ namespace IKVM.Internal } } - private static void MapModifiers(MapXml.MapModifiers mapmods, bool isConstructor, out bool setmodifiers, ref MethodAttributes attribs) + private static void MapModifiers(MapXml.MapModifiers mapmods, bool isConstructor, out bool setmodifiers, ref MethodAttributes attribs, bool isNewSlot) { setmodifiers = false; Modifiers modifiers = (Modifiers)mapmods; @@ -543,6 +543,10 @@ namespace IKVM.Internal // remove NewSlot, because it doesn't make sense on a non-virtual method attribs &= ~MethodAttributes.NewSlot; } + else if(((modifiers & (Modifiers.Public | Modifiers.Final)) == Modifiers.Final && isNewSlot && (attribs & MethodAttributes.Virtual) == 0)) + { + // final method that doesn't need to be virtual + } else { if((modifiers & Modifiers.Private) == 0) @@ -630,7 +634,7 @@ namespace IKVM.Internal } bool setmodifiers = false; MethodAttributes attribs = 0; - MapModifiers(constructor.Modifiers, true, out setmodifiers, ref attribs); + MapModifiers(constructor.Modifiers, true, out setmodifiers, ref attribs, false); Type returnType; Type[] parameterTypes; MapSignature(constructor.Sig, out returnType, out parameterTypes); @@ -683,7 +687,7 @@ namespace IKVM.Internal { bool setmodifiers = false; MethodAttributes attribs = method.MethodAttributes; - MapModifiers(method.Modifiers, false, out setmodifiers, ref attribs); + MapModifiers(method.Modifiers, false, out setmodifiers, ref attribs, BaseTypeWrapper == null || BaseTypeWrapper.GetMethodWrapper(method.Name, method.Sig, true) == null); if(method.body == null && (attribs & MethodAttributes.Abstract) == 0) { Console.Error.WriteLine("Error: Method {0}.{1}{2} in xml remap file doesn't have a body.", clazz.Name, method.Name, method.Sig); diff --git a/external/ikvm/ikvmc/Compiler.cs b/external/ikvm/ikvmc/Compiler.cs index 659d4751df..159052cddb 100644 --- a/external/ikvm/ikvmc/Compiler.cs +++ b/external/ikvm/ikvmc/Compiler.cs @@ -838,7 +838,7 @@ sealed class IkvmcCompiler } else if(s == "-opt:fields") { - options.removeUnusedFields = true; + options.codegenoptions |= CodeGenOptions.RemoveUnusedFields; } else if(s == "-compressresources") { diff --git a/external/ikvm/ikvmc/CompilerClassLoader.cs.REMOVED.git-id b/external/ikvm/ikvmc/CompilerClassLoader.cs.REMOVED.git-id index 4d2490a898..4a1d36be9c 100644 --- a/external/ikvm/ikvmc/CompilerClassLoader.cs.REMOVED.git-id +++ b/external/ikvm/ikvmc/CompilerClassLoader.cs.REMOVED.git-id @@ -1 +1 @@ -c27a31eb1803a411aadc8b97ad081614b07dd615 \ No newline at end of file +1d6e66a3d816d572409fee7c6c4b27cc07cfb43d \ No newline at end of file diff --git a/external/ikvm/ikvmstub/ikvmstub.cs b/external/ikvm/ikvmstub/ikvmstub.cs index 5f882cae28..955eb27d2f 100644 --- a/external/ikvm/ikvmstub/ikvmstub.cs +++ b/external/ikvm/ikvmstub/ikvmstub.cs @@ -577,6 +577,7 @@ sealed class BootstrapBootstrapClassLoader : ClassLoaderWrapper RegisterInitiatingLoader(new StubTypeWrapper(Modifiers.Public, "java.lang.Enum", javaLangObject, false)); RegisterInitiatingLoader(new StubTypeWrapper(Modifiers.Public | Modifiers.Abstract | Modifiers.Interface, "java.lang.annotation.Annotation", null, false)); RegisterInitiatingLoader(new StubTypeWrapper(Modifiers.Public | Modifiers.Final, "java.lang.Class", javaLangObject, false)); + RegisterInitiatingLoader(new StubTypeWrapper(Modifiers.Public | Modifiers.Abstract, "java.lang.invoke.MethodHandle", javaLangObject, false)); } } @@ -607,25 +608,6 @@ sealed class StubTypeWrapper : TypeWrapper get { throw new NotSupportedException(); } } - internal override TypeWrapper[] Interfaces - { - get { return TypeWrapper.EmptyArray; } - } - - internal override TypeWrapper[] InnerClasses - { - get { return TypeWrapper.EmptyArray; } - } - - internal override TypeWrapper DeclaringTypeWrapper - { - get { return null; } - } - - internal override void Finish() - { - } - internal override bool IsRemapped { get { return remapped; } diff --git a/external/ikvm/openjdk/FORKED b/external/ikvm/openjdk/FORKED index 52a8921f36..74fcc71da4 100644 --- a/external/ikvm/openjdk/FORKED +++ b/external/ikvm/openjdk/FORKED @@ -4,9 +4,9 @@ # This file list all forked OpenJDK files in their original OpenJDK location and their forked ikvm/openjdk location. # Each line not starting with # contains a mapping: = # -build/linux-amd64/gensrc/sun/misc/Version.java=sun/misc/Version.java -build/linux-amd64/gensrc/sun/nio/ch/SocketOptionRegistry.java=sun/nio/ch/SocketOptionRegistry.java -build/linux-amd64/gensrc/sun/nio/cs/StandardCharsets.java=sun/nio/cs/StandardCharsets.java +build/linux-x86_64-normal-server-release/jdk/gensrc/sun/misc/Version.java=sun/misc/Version.java +build/linux-x86_64-normal-server-release/jdk/gensrc/sun/nio/ch/SocketOptionRegistry.java=sun/nio/ch/SocketOptionRegistry.java +build/linux-x86_64-normal-server-release/jdk/gensrc/sun/nio/cs/StandardCharsets.java=sun/nio/cs/StandardCharsets.java jdk/src/macosx/classes/java/lang/ClassLoaderHelper.java=java/lang/ClassLoaderHelper.java jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java=com/sun/imageio/plugins/jpeg/JPEGImageReader.java jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java=com/sun/imageio/plugins/jpeg/JPEGImageWriter.java @@ -22,17 +22,16 @@ jdk/src/share/classes/java/awt/image/DataBufferInt.java=java/awt/image/DataBuffe jdk/src/share/classes/java/awt/image/DataBufferShort.java=java/awt/image/DataBufferShort.java jdk/src/share/classes/java/awt/image/DataBufferUShort.java=java/awt/image/DataBufferUShort.java jdk/src/share/classes/java/awt/image/IndexColorModel.java=java/awt/image/IndexColorModel.java -jdk/src/share/classes/java/io/FileInputStream.java=java/io/FileInputStream.java -jdk/src/share/classes/java/io/FileOutputStream.java=java/io/FileOutputStream.java jdk/src/share/classes/java/io/ObjectStreamClass.java=java/io/ObjectStreamClass.java jdk/src/share/classes/java/io/ObjectStreamField.java=java/io/ObjectStreamField.java -jdk/src/share/classes/java/io/RandomAccessFile.java=java/io/RandomAccessFile.java jdk/src/share/classes/java/lang/Class.java=java/lang/Class.java jdk/src/share/classes/java/lang/ClassLoader.java=java/lang/ClassLoader.java jdk/src/share/classes/java/lang/Enum.java=java/lang/Enum.java +jdk/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java=../runtime/openjdk/NativeInvokerBytecodeGenerator.cs jdk/src/share/classes/java/lang/management/PlatformComponent.java=java/lang/management/PlatformComponent.java jdk/src/share/classes/java/lang/ref/SoftReference.java=java/lang/ref/SoftReference.java jdk/src/share/classes/java/lang/reflect/Constructor.java=java/lang/reflect/Constructor.java +jdk/src/share/classes/java/lang/reflect/Executable.java=java/lang/reflect/Executable.java jdk/src/share/classes/java/lang/reflect/Field.java=java/lang/reflect/Field.java jdk/src/share/classes/java/lang/reflect/Method.java=java/lang/reflect/Method.java jdk/src/share/classes/java/lang/reflect/Proxy.java=java/lang/reflect/Proxy.java @@ -41,8 +40,6 @@ jdk/src/share/classes/java/lang/String.java=java/lang/StringHelper.java jdk/src/share/classes/java/lang/System.java=java/lang/System.java jdk/src/share/classes/java/lang/Thread.java=java/lang/Thread.java jdk/src/share/classes/java/lang/Throwable.java=java/lang/ThrowableHelper.java -jdk/src/share/classes/java/net/SocketInputStream.java=java/net/SocketInputStream.java -jdk/src/share/classes/java/net/SocketOutputStream.java=java/net/SocketOutputStream.java jdk/src/share/classes/java/nio/Bits.java=java/nio/Bits.java jdk/src/share/classes/java/security/AccessController.java=java/security/AccessController.java jdk/src/share/classes/java/security/ProtectionDomain.java=java/security/ProtectionDomain.java @@ -53,7 +50,6 @@ jdk/src/share/classes/java/util/concurrent/atomic/AtomicLong.java=../classpath/j jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java=../classpath/java/util/concurrent/atomic/AtomicLongArray.java jdk/src/share/classes/java/util/concurrent/atomic/AtomicReference.java=../classpath/java/util/concurrent/atomic/AtomicReference.java jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java=../classpath/java/util/concurrent/atomic/AtomicReferenceArray.java -jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java=java/util/concurrent/ForkJoinPool.java jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java=java/util/concurrent/locks/AbstractQueuedSynchronizer.java jdk/src/share/classes/java/util/concurrent/locks/LockSupport.java=java/util/concurrent/locks/LockSupport.java jdk/src/share/classes/sun/awt/EmbeddedFrame.java=sun/awt/EmbeddedFrame.java @@ -62,7 +58,6 @@ jdk/src/share/classes/sun/awt/image/ImagingLib.java=sun/awt/image/ImagingLib.jav jdk/src/share/classes/sun/awt/image/IntegerInterleavedRaster.java=sun/awt/image/IntegerInterleavedRaster.java jdk/src/share/classes/sun/awt/image/SunWritableRaster.java=sun/awt/image/SunWritableRaster.java jdk/src/share/classes/sun/awt/image/ToolkitImage.java=sun/awt/image/ToolkitImage.java -jdk/src/share/classes/sun/awt/SunToolkit.java=sun/awt/SunToolkit.java jdk/src/share/classes/sun/font/FontManager.java=sun/font/FontManager.java jdk/src/share/classes/sun/font/StrikeCache.java=sun/font/StrikeCache.java jdk/src/share/classes/sun/management/ManagementFactoryHelper.java=sun/management/ManagementFactoryHelper.java @@ -99,7 +94,6 @@ jdk/src/windows/classes/sun/net/www/protocol/jar/JarFileFactory.java=sun/net/www jdk/src/windows/classes/sun/nio/ch/DefaultSelectorProvider.java=sun/nio/ch/DefaultSelectorProvider.java jdk/src/windows/classes/sun/nio/ch/FileDispatcherImpl.java=sun/nio/ch/FileDispatcherImpl.java jdk/src/windows/classes/sun/nio/ch/Iocp.java=sun/nio/ch/Iocp.java -jdk/src/windows/classes/sun/nio/ch/PollArrayWrapper.java=sun/nio/ch/PollArrayWrapper.java jdk/src/windows/classes/sun/nio/ch/SocketDispatcher.java=sun/nio/ch/SocketDispatcher.java jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java=sun/nio/ch/WindowsAsynchronousFileChannelImpl.java jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java=sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java diff --git a/external/ikvm/openjdk/allsources.lst.REMOVED.git-id b/external/ikvm/openjdk/allsources.lst.REMOVED.git-id index 7917379dd1..b922b306bc 100644 --- a/external/ikvm/openjdk/allsources.lst.REMOVED.git-id +++ b/external/ikvm/openjdk/allsources.lst.REMOVED.git-id @@ -1 +1 @@ -9893116e072094e4cdaec2c5e493ef7f7799c5e6 \ No newline at end of file +935b3a93896a85d98a39a3ab7e9795dc58c56bdf \ No newline at end of file diff --git a/external/ikvm/openjdk/ikvm/internal/Winsock.java b/external/ikvm/openjdk/ikvm/internal/Winsock.java index ce05de0305..69a1eb28d5 100644 --- a/external/ikvm/openjdk/ikvm/internal/Winsock.java +++ b/external/ikvm/openjdk/ikvm/internal/Winsock.java @@ -138,6 +138,7 @@ public final class Winsock public static final int IPV6_ADD_MEMBERSHIP = SocketOptionName.AddMembership; public static final int IPV6_DROP_MEMBERSHIP = SocketOptionName.DropMembership; public static final int IPV6_V6ONLY = 27; + public static final int IPV6_TCLASS = 39; public static final int SIO_UDP_CONNRESET = 0x9800000C; @@ -147,6 +148,8 @@ public final class Winsock public static final int FIONREAD = (int)IOControlCode.DataToRead; public static final int FIONBIO = (int)IOControlCode.NonBlockingIO; + public static final int MAX_PACKET_LEN = 0xFFFF; + public static int WSAGetLastError() { return lastError; diff --git a/external/ikvm/openjdk/java/io/FileInputStream.java b/external/ikvm/openjdk/java/io/FileInputStream.java deleted file mode 100644 index 3547947f07..0000000000 --- a/external/ikvm/openjdk/java/io/FileInputStream.java +++ /dev/null @@ -1,451 +0,0 @@ -/* - * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.io; - -import java.nio.channels.FileChannel; -import sun.nio.ch.FileChannelImpl; -import sun.misc.IoTrace; - - -/** - * A FileInputStream obtains input bytes - * from a file in a file system. What files - * are available depends on the host environment. - * - *

FileInputStream is meant for reading streams of raw bytes - * such as image data. For reading streams of characters, consider using - * FileReader. - * - * @author Arthur van Hoff - * @see java.io.File - * @see java.io.FileDescriptor - * @see java.io.FileOutputStream - * @see java.nio.file.Files#newInputStream - * @since JDK1.0 - */ -public -class FileInputStream extends InputStream -{ - /* File Descriptor - handle to the open file */ - private final FileDescriptor fd; - - /* The path of the referenced file (null if the stream is created with a file descriptor) */ - private final String path; - - private FileChannel channel = null; - - private final Object closeLock = new Object(); - private volatile boolean closed = false; - - private static final ThreadLocal runningFinalize = - new ThreadLocal<>(); - - private static boolean isRunningFinalize() { - Boolean val; - if ((val = runningFinalize.get()) != null) - return val.booleanValue(); - return false; - } - - /** - * Creates a FileInputStream by - * opening a connection to an actual file, - * the file named by the path name name - * in the file system. A new FileDescriptor - * object is created to represent this file - * connection. - *

- * First, if there is a security - * manager, its checkRead method - * is called with the name argument - * as its argument. - *

- * If the named file does not exist, is a directory rather than a regular - * file, or for some other reason cannot be opened for reading then a - * FileNotFoundException is thrown. - * - * @param name the system-dependent file name. - * @exception FileNotFoundException if the file does not exist, - * is a directory rather than a regular file, - * or for some other reason cannot be opened for - * reading. - * @exception SecurityException if a security manager exists and its - * checkRead method denies read access - * to the file. - * @see java.lang.SecurityManager#checkRead(java.lang.String) - */ - public FileInputStream(String name) throws FileNotFoundException { - this(name != null ? new File(name) : null); - } - - /** - * Creates a FileInputStream by - * opening a connection to an actual file, - * the file named by the File - * object file in the file system. - * A new FileDescriptor object - * is created to represent this file connection. - *

- * First, if there is a security manager, - * its checkRead method is called - * with the path represented by the file - * argument as its argument. - *

- * If the named file does not exist, is a directory rather than a regular - * file, or for some other reason cannot be opened for reading then a - * FileNotFoundException is thrown. - * - * @param file the file to be opened for reading. - * @exception FileNotFoundException if the file does not exist, - * is a directory rather than a regular file, - * or for some other reason cannot be opened for - * reading. - * @exception SecurityException if a security manager exists and its - * checkRead method denies read access to the file. - * @see java.io.File#getPath() - * @see java.lang.SecurityManager#checkRead(java.lang.String) - */ - public FileInputStream(File file) throws FileNotFoundException { - String name = (file != null ? file.getPath() : null); - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkRead(name); - } - if (name == null) { - throw new NullPointerException(); - } - /* - if (file.isInvalid()) { - throw new FileNotFoundException("Invalid file path"); - } - */ - fd = new FileDescriptor(); - fd.incrementAndGetUseCount(); - this.path = name; - open(name); - } - - /** - * Creates a FileInputStream by using the file descriptor - * fdObj, which represents an existing connection to an - * actual file in the file system. - *

- * If there is a security manager, its checkRead method is - * called with the file descriptor fdObj as its argument to - * see if it's ok to read the file descriptor. If read access is denied - * to the file descriptor a SecurityException is thrown. - *

- * If fdObj is null then a NullPointerException - * is thrown. - *

- * This constructor does not throw an exception if fdObj - * is {@link java.io.FileDescriptor#valid() invalid}. - * However, if the methods are invoked on the resulting stream to attempt - * I/O on the stream, an IOException is thrown. - * - * @param fdObj the file descriptor to be opened for reading. - * @throws SecurityException if a security manager exists and its - * checkRead method denies read access to the - * file descriptor. - * @see SecurityManager#checkRead(java.io.FileDescriptor) - */ - public FileInputStream(FileDescriptor fdObj) { - SecurityManager security = System.getSecurityManager(); - if (fdObj == null) { - throw new NullPointerException(); - } - if (security != null) { - security.checkRead(fdObj); - } - fd = fdObj; - path = null; - - /* - * FileDescriptor is being shared by streams. - * Ensure that it's GC'ed only when all the streams/channels are done - * using it. - */ - fd.incrementAndGetUseCount(); - } - - /** - * Opens the specified file for reading. - * @param name the name of the file - */ - private void open(String name) throws FileNotFoundException - { - fd.openReadOnly(name); - } - - /** - * Reads a byte of data from this input stream. This method blocks - * if no input is yet available. - * - * @return the next byte of data, or -1 if the end of the - * file is reached. - * @exception IOException if an I/O error occurs. - */ - public int read() throws IOException { - Object traceContext = IoTrace.fileReadBegin(path); - int b = 0; - try { - b = fd.read(); - } finally { - IoTrace.fileReadEnd(traceContext, b == -1 ? 0 : 1); - } - return b; - } - - /** - * Reads a subarray as a sequence of bytes. - * @param b the data to be written - * @param off the start offset in the data - * @param len the number of bytes that are written - * @exception IOException If an I/O error has occurred. - */ - private int readBytes(byte b[], int off, int len) throws IOException - { - return fd.readBytes(b, off, len); - } - - /** - * Reads up to b.length bytes of data from this input - * stream into an array of bytes. This method blocks until some input - * is available. - * - * @param b the buffer into which the data is read. - * @return the total number of bytes read into the buffer, or - * -1 if there is no more data because the end of - * the file has been reached. - * @exception IOException if an I/O error occurs. - */ - public int read(byte b[]) throws IOException { - Object traceContext = IoTrace.fileReadBegin(path); - int bytesRead = 0; - try { - bytesRead = readBytes(b, 0, b.length); - } finally { - IoTrace.fileReadEnd(traceContext, bytesRead == -1 ? 0 : bytesRead); - } - return bytesRead; - } - - /** - * Reads up to len bytes of data from this input stream - * into an array of bytes. If len is not zero, the method - * blocks until some input is available; otherwise, no - * bytes are read and 0 is returned. - * - * @param b the buffer into which the data is read. - * @param off the start offset in the destination array b - * @param len the maximum number of bytes read. - * @return the total number of bytes read into the buffer, or - * -1 if there is no more data because the end of - * the file has been reached. - * @exception NullPointerException If b is null. - * @exception IndexOutOfBoundsException If off is negative, - * len is negative, or len is greater than - * b.length - off - * @exception IOException if an I/O error occurs. - */ - public int read(byte b[], int off, int len) throws IOException { - Object traceContext = IoTrace.fileReadBegin(path); - int bytesRead = 0; - try { - bytesRead = readBytes(b, off, len); - } finally { - IoTrace.fileReadEnd(traceContext, bytesRead == -1 ? 0 : bytesRead); - } - return bytesRead; - } - - /** - * Skips over and discards n bytes of data from the - * input stream. - * - *

The skip method may, for a variety of - * reasons, end up skipping over some smaller number of bytes, - * possibly 0. If n is negative, an - * IOException is thrown, even though the skip - * method of the {@link InputStream} superclass does nothing in this case. - * The actual number of bytes skipped is returned. - * - *

This method may skip more bytes than are remaining in the backing - * file. This produces no exception and the number of bytes skipped - * may include some number of bytes that were beyond the EOF of the - * backing file. Attempting to read from the stream after skipping past - * the end will result in -1 indicating the end of the file. - * - * @param n the number of bytes to be skipped. - * @return the actual number of bytes skipped. - * @exception IOException if n is negative, if the stream does not - * support seek, or if an I/O error occurs. - */ - public long skip(long n) throws IOException - { - return fd.skip(n); - } - - /** - * Returns an estimate of the number of remaining bytes that can be read (or - * skipped over) from this input stream without blocking by the next - * invocation of a method for this input stream. The next invocation might be - * the same thread or another thread. A single read or skip of this - * many bytes will not block, but may read or skip fewer bytes. - * - *

In some cases, a non-blocking read (or skip) may appear to be - * blocked when it is merely slow, for example when reading large - * files over slow networks. - * - * @return an estimate of the number of remaining bytes that can be read - * (or skipped over) from this input stream without blocking. - * @exception IOException if this file input stream has been closed by calling - * {@code close} or an I/O error occurs. - */ - public int available() throws IOException - { - return fd.available(); - } - - /** - * Closes this file input stream and releases any system resources - * associated with the stream. - * - *

If this stream has an associated channel then the channel is closed - * as well. - * - * @exception IOException if an I/O error occurs. - * - * @revised 1.4 - * @spec JSR-51 - */ - public void close() throws IOException { - synchronized (closeLock) { - if (closed) { - return; - } - closed = true; - } - if (channel != null) { - /* - * Decrement the FD use count associated with the channel - * The use count is incremented whenever a new channel - * is obtained from this stream. - */ - fd.decrementAndGetUseCount(); - channel.close(); - } - - /* - * Decrement the FD use count associated with this stream - */ - int useCount = fd.decrementAndGetUseCount(); - - /* - * If FileDescriptor is still in use by another stream, the finalizer - * will not close it. - */ - if ((useCount <= 0) || !isRunningFinalize()) { - close0(); - } - } - - /** - * Returns the FileDescriptor - * object that represents the connection to - * the actual file in the file system being - * used by this FileInputStream. - * - * @return the file descriptor object associated with this stream. - * @exception IOException if an I/O error occurs. - * @see java.io.FileDescriptor - */ - public final FileDescriptor getFD() throws IOException { - if (fd != null) return fd; - throw new IOException(); - } - - /** - * Returns the unique {@link java.nio.channels.FileChannel FileChannel} - * object associated with this file input stream. - * - *

The initial {@link java.nio.channels.FileChannel#position() - * position} of the returned channel will be equal to the - * number of bytes read from the file so far. Reading bytes from this - * stream will increment the channel's position. Changing the channel's - * position, either explicitly or by reading, will change this stream's - * file position. - * - * @return the file channel associated with this file input stream - * - * @since 1.4 - * @spec JSR-51 - */ - public FileChannel getChannel() { - synchronized (this) { - if (channel == null) { - channel = FileChannelImpl.open(fd, path, true, false, this); - - /* - * Increment fd's use count. Invoking the channel's close() - * method will result in decrementing the use count set for - * the channel. - */ - fd.incrementAndGetUseCount(); - } - return channel; - } - } - - private void close0() throws IOException - { - fd.close(); - } - - /** - * Ensures that the close method of this file input stream is - * called when there are no more references to it. - * - * @exception IOException if an I/O error occurs. - * @see java.io.FileInputStream#close() - */ - protected void finalize() throws IOException { - if ((fd != null) && (fd != FileDescriptor.in)) { - - /* - * Finalizer should not release the FileDescriptor if another - * stream is still using it. If the user directly invokes - * close() then the FileDescriptor is also released. - */ - runningFinalize.set(Boolean.TRUE); - try { - close(); - } finally { - runningFinalize.set(Boolean.FALSE); - } - } - } -} diff --git a/external/ikvm/openjdk/java/io/FileOutputStream.java b/external/ikvm/openjdk/java/io/FileOutputStream.java deleted file mode 100644 index dae9d4bc5e..0000000000 --- a/external/ikvm/openjdk/java/io/FileOutputStream.java +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.io; - -import java.nio.channels.FileChannel; -import sun.nio.ch.FileChannelImpl; -import sun.misc.IoTrace; - - -/** - * A file output stream is an output stream for writing data to a - * File or to a FileDescriptor. Whether or not - * a file is available or may be created depends upon the underlying - * platform. Some platforms, in particular, allow a file to be opened - * for writing by only one FileOutputStream (or other - * file-writing object) at a time. In such situations the constructors in - * this class will fail if the file involved is already open. - * - *

FileOutputStream is meant for writing streams of raw bytes - * such as image data. For writing streams of characters, consider using - * FileWriter. - * - * @author Arthur van Hoff - * @see java.io.File - * @see java.io.FileDescriptor - * @see java.io.FileInputStream - * @see java.nio.file.Files#newOutputStream - * @since JDK1.0 - */ -public -class FileOutputStream extends OutputStream -{ - /** - * The system dependent file descriptor. - */ - private final FileDescriptor fd; - - /** - * The path of the referenced file (null if the stream is created with a file descriptor) - */ - private final String path; - - /** - * True if the file is opened for append. - */ - private final boolean append; - - /** - * The associated channel, initalized lazily. - */ - private FileChannel channel; - - private final Object closeLock = new Object(); - private volatile boolean closed = false; - private static final ThreadLocal runningFinalize = - new ThreadLocal<>(); - - private static boolean isRunningFinalize() { - Boolean val; - if ((val = runningFinalize.get()) != null) - return val.booleanValue(); - return false; - } - - /** - * Creates a file output stream to write to the file with the - * specified name. A new FileDescriptor object is - * created to represent this file connection. - *

- * First, if there is a security manager, its checkWrite - * method is called with name as its argument. - *

- * If the file exists but is a directory rather than a regular file, does - * not exist but cannot be created, or cannot be opened for any other - * reason then a FileNotFoundException is thrown. - * - * @param name the system-dependent filename - * @exception FileNotFoundException if the file exists but is a directory - * rather than a regular file, does not exist but cannot - * be created, or cannot be opened for any other reason - * @exception SecurityException if a security manager exists and its - * checkWrite method denies write access - * to the file. - * @see java.lang.SecurityManager#checkWrite(java.lang.String) - */ - public FileOutputStream(String name) throws FileNotFoundException { - this(name != null ? new File(name) : null, false); - } - - /** - * Creates a file output stream to write to the file with the specified - * name. If the second argument is true, then - * bytes will be written to the end of the file rather than the beginning. - * A new FileDescriptor object is created to represent this - * file connection. - *

- * First, if there is a security manager, its checkWrite - * method is called with name as its argument. - *

- * If the file exists but is a directory rather than a regular file, does - * not exist but cannot be created, or cannot be opened for any other - * reason then a FileNotFoundException is thrown. - * - * @param name the system-dependent file name - * @param append if true, then bytes will be written - * to the end of the file rather than the beginning - * @exception FileNotFoundException if the file exists but is a directory - * rather than a regular file, does not exist but cannot - * be created, or cannot be opened for any other reason. - * @exception SecurityException if a security manager exists and its - * checkWrite method denies write access - * to the file. - * @see java.lang.SecurityManager#checkWrite(java.lang.String) - * @since JDK1.1 - */ - public FileOutputStream(String name, boolean append) - throws FileNotFoundException - { - this(name != null ? new File(name) : null, append); - } - - /** - * Creates a file output stream to write to the file represented by - * the specified File object. A new - * FileDescriptor object is created to represent this - * file connection. - *

- * First, if there is a security manager, its checkWrite - * method is called with the path represented by the file - * argument as its argument. - *

- * If the file exists but is a directory rather than a regular file, does - * not exist but cannot be created, or cannot be opened for any other - * reason then a FileNotFoundException is thrown. - * - * @param file the file to be opened for writing. - * @exception FileNotFoundException if the file exists but is a directory - * rather than a regular file, does not exist but cannot - * be created, or cannot be opened for any other reason - * @exception SecurityException if a security manager exists and its - * checkWrite method denies write access - * to the file. - * @see java.io.File#getPath() - * @see java.lang.SecurityException - * @see java.lang.SecurityManager#checkWrite(java.lang.String) - */ - public FileOutputStream(File file) throws FileNotFoundException { - this(file, false); - } - - /** - * Creates a file output stream to write to the file represented by - * the specified File object. If the second argument is - * true, then bytes will be written to the end of the file - * rather than the beginning. A new FileDescriptor object is - * created to represent this file connection. - *

- * First, if there is a security manager, its checkWrite - * method is called with the path represented by the file - * argument as its argument. - *

- * If the file exists but is a directory rather than a regular file, does - * not exist but cannot be created, or cannot be opened for any other - * reason then a FileNotFoundException is thrown. - * - * @param file the file to be opened for writing. - * @param append if true, then bytes will be written - * to the end of the file rather than the beginning - * @exception FileNotFoundException if the file exists but is a directory - * rather than a regular file, does not exist but cannot - * be created, or cannot be opened for any other reason - * @exception SecurityException if a security manager exists and its - * checkWrite method denies write access - * to the file. - * @see java.io.File#getPath() - * @see java.lang.SecurityException - * @see java.lang.SecurityManager#checkWrite(java.lang.String) - * @since 1.4 - */ - public FileOutputStream(File file, boolean append) - throws FileNotFoundException - { - String name = (file != null ? file.getPath() : null); - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkWrite(name); - } - if (name == null) { - throw new NullPointerException(); - } - /* - if (file.isInvalid()) { - throw new FileNotFoundException("Invalid file path"); - } - */ - this.fd = new FileDescriptor(); - this.append = append; - this.path = name; - fd.incrementAndGetUseCount(); - open(name, append); - } - - /** - * Creates a file output stream to write to the specified file - * descriptor, which represents an existing connection to an actual - * file in the file system. - *

- * First, if there is a security manager, its checkWrite - * method is called with the file descriptor fdObj - * argument as its argument. - *

- * If fdObj is null then a NullPointerException - * is thrown. - *

- * This constructor does not throw an exception if fdObj - * is {@link java.io.FileDescriptor#valid() invalid}. - * However, if the methods are invoked on the resulting stream to attempt - * I/O on the stream, an IOException is thrown. - * - * @param fdObj the file descriptor to be opened for writing - * @exception SecurityException if a security manager exists and its - * checkWrite method denies - * write access to the file descriptor - * @see java.lang.SecurityManager#checkWrite(java.io.FileDescriptor) - */ - public FileOutputStream(FileDescriptor fdObj) { - SecurityManager security = System.getSecurityManager(); - if (fdObj == null) { - throw new NullPointerException(); - } - if (security != null) { - security.checkWrite(fdObj); - } - this.fd = fdObj; - this.path = null; - this.append = false; - - /* - * FileDescriptor is being shared by streams. - * Ensure that it's GC'ed only when all the streams/channels are done - * using it. - */ - fd.incrementAndGetUseCount(); - } - - /** - * Opens a file, with the specified name, for overwriting or appending. - * @param name name of file to be opened - * @param append whether the file is to be opened in append mode - */ - private void open(String name, boolean append) - throws FileNotFoundException { - if (append) { - fd.openAppend(name); - } else { - fd.openWriteOnly(name); - } - } - - /** - * Writes the specified byte to this file output stream. - * - * @param b the byte to be written. - * @param append {@code true} if the write operation first - * advances the position to the end of file - */ - private void write(int b, boolean append) throws IOException { - fd.write(b); - } - - /** - * Writes the specified byte to this file output stream. Implements - * the write method of OutputStream. - * - * @param b the byte to be written. - * @exception IOException if an I/O error occurs. - */ - public void write(int b) throws IOException { - Object traceContext = IoTrace.fileWriteBegin(path); - int bytesWritten = 0; - try { - write(b, append); - bytesWritten = 1; - } finally { - IoTrace.fileWriteEnd(traceContext, bytesWritten); - } - } - - /** - * Writes a sub array as a sequence of bytes. - * @param b the data to be written - * @param off the start offset in the data - * @param len the number of bytes that are written - * @param append {@code true} to first advance the position to the - * end of file - * @exception IOException If an I/O error has occurred. - */ - private void writeBytes(byte b[], int off, int len, boolean append) - throws IOException { - fd.writeBytes(b, off, len); - } - - /** - * Writes b.length bytes from the specified byte array - * to this file output stream. - * - * @param b the data. - * @exception IOException if an I/O error occurs. - */ - public void write(byte b[]) throws IOException { - Object traceContext = IoTrace.fileWriteBegin(path); - int bytesWritten = 0; - try { - writeBytes(b, 0, b.length, append); - bytesWritten = b.length; - } finally { - IoTrace.fileWriteEnd(traceContext, bytesWritten); - } - } - - /** - * Writes len bytes from the specified byte array - * starting at offset off to this file output stream. - * - * @param b the data. - * @param off the start offset in the data. - * @param len the number of bytes to write. - * @exception IOException if an I/O error occurs. - */ - public void write(byte b[], int off, int len) throws IOException { - Object traceContext = IoTrace.fileWriteBegin(path); - int bytesWritten = 0; - try { - writeBytes(b, off, len, append); - bytesWritten = len; - } finally { - IoTrace.fileWriteEnd(traceContext, bytesWritten); - } - } - - /** - * Closes this file output stream and releases any system resources - * associated with this stream. This file output stream may no longer - * be used for writing bytes. - * - *

If this stream has an associated channel then the channel is closed - * as well. - * - * @exception IOException if an I/O error occurs. - * - * @revised 1.4 - * @spec JSR-51 - */ - public void close() throws IOException { - synchronized (closeLock) { - if (closed) { - return; - } - closed = true; - } - - if (channel != null) { - /* - * Decrement FD use count associated with the channel - * The use count is incremented whenever a new channel - * is obtained from this stream. - */ - fd.decrementAndGetUseCount(); - channel.close(); - } - - /* - * Decrement FD use count associated with this stream - */ - int useCount = fd.decrementAndGetUseCount(); - - /* - * If FileDescriptor is still in use by another stream, the finalizer - * will not close it. - */ - if ((useCount <= 0) || !isRunningFinalize()) { - close0(); - } - } - - /** - * Returns the file descriptor associated with this stream. - * - * @return the FileDescriptor object that represents - * the connection to the file in the file system being used - * by this FileOutputStream object. - * - * @exception IOException if an I/O error occurs. - * @see java.io.FileDescriptor - */ - public final FileDescriptor getFD() throws IOException { - if (fd != null) return fd; - throw new IOException(); - } - - /** - * Returns the unique {@link java.nio.channels.FileChannel FileChannel} - * object associated with this file output stream.

- * - *

The initial {@link java.nio.channels.FileChannel#position() - * position} of the returned channel will be equal to the - * number of bytes written to the file so far unless this stream is in - * append mode, in which case it will be equal to the size of the file. - * Writing bytes to this stream will increment the channel's position - * accordingly. Changing the channel's position, either explicitly or by - * writing, will change this stream's file position. - * - * @return the file channel associated with this file output stream - * - * @since 1.4 - * @spec JSR-51 - */ - public FileChannel getChannel() { - synchronized (this) { - if (channel == null) { - channel = FileChannelImpl.open(fd, path, false, true, append, this); - - /* - * Increment fd's use count. Invoking the channel's close() - * method will result in decrementing the use count set for - * the channel. - */ - fd.incrementAndGetUseCount(); - } - return channel; - } - } - - /** - * Cleans up the connection to the file, and ensures that the - * close method of this file output stream is - * called when there are no more references to this stream. - * - * @exception IOException if an I/O error occurs. - * @see java.io.FileInputStream#close() - */ - protected void finalize() throws IOException { - if (fd != null) { - if (fd == FileDescriptor.out || fd == FileDescriptor.err) { - flush(); - } else { - - /* - * Finalizer should not release the FileDescriptor if another - * stream is still using it. If the user directly invokes - * close() then the FileDescriptor is also released. - */ - runningFinalize.set(Boolean.TRUE); - try { - close(); - } finally { - runningFinalize.set(Boolean.FALSE); - } - } - } - } - - private void close0() throws IOException - { - fd.close(); - } - -} diff --git a/external/ikvm/openjdk/java/io/RandomAccessFile.java b/external/ikvm/openjdk/java/io/RandomAccessFile.java deleted file mode 100644 index 61fc27a7e4..0000000000 --- a/external/ikvm/openjdk/java/io/RandomAccessFile.java +++ /dev/null @@ -1,1191 +0,0 @@ -/* - * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.io; - -import java.nio.channels.FileChannel; -import sun.nio.ch.FileChannelImpl; -import sun.misc.IoTrace; - - -/** - * Instances of this class support both reading and writing to a - * random access file. A random access file behaves like a large - * array of bytes stored in the file system. There is a kind of cursor, - * or index into the implied array, called the file pointer; - * input operations read bytes starting at the file pointer and advance - * the file pointer past the bytes read. If the random access file is - * created in read/write mode, then output operations are also available; - * output operations write bytes starting at the file pointer and advance - * the file pointer past the bytes written. Output operations that write - * past the current end of the implied array cause the array to be - * extended. The file pointer can be read by the - * getFilePointer method and set by the seek - * method. - *

- * It is generally true of all the reading routines in this class that - * if end-of-file is reached before the desired number of bytes has been - * read, an EOFException (which is a kind of - * IOException) is thrown. If any byte cannot be read for - * any reason other than end-of-file, an IOException other - * than EOFException is thrown. In particular, an - * IOException may be thrown if the stream has been closed. - * - * @author unascribed - * @since JDK1.0 - */ - -public class RandomAccessFile implements DataOutput, DataInput, Closeable { - - private FileDescriptor fd; - private FileChannel channel = null; - private boolean rw; - - /* The path of the referenced file */ - private final String path; - - private Object closeLock = new Object(); - private volatile boolean closed = false; - - private static final int O_RDONLY = 1; - private static final int O_RDWR = 2; - private static final int O_SYNC = 4; - private static final int O_DSYNC = 8; - - /** - * Creates a random access file stream to read from, and optionally - * to write to, a file with the specified name. A new - * {@link FileDescriptor} object is created to represent the - * connection to the file. - * - *

The mode argument specifies the access mode with which the - * file is to be opened. The permitted values and their meanings are as - * specified for the RandomAccessFile(File,String) constructor. - * - *

- * If there is a security manager, its checkRead method - * is called with the name argument - * as its argument to see if read access to the file is allowed. - * If the mode allows writing, the security manager's - * checkWrite method - * is also called with the name argument - * as its argument to see if write access to the file is allowed. - * - * @param name the system-dependent filename - * @param mode the access mode - * @exception IllegalArgumentException if the mode argument is not equal - * to one of "r", "rw", "rws", or - * "rwd" - * @exception FileNotFoundException - * if the mode is "r" but the given string does not - * denote an existing regular file, or if the mode begins with - * "rw" but the given string does not denote an - * existing, writable regular file and a new regular file of - * that name cannot be created, or if some other error occurs - * while opening or creating the file - * @exception SecurityException if a security manager exists and its - * checkRead method denies read access to the file - * or the mode is "rw" and the security manager's - * checkWrite method denies write access to the file - * @see java.lang.SecurityException - * @see java.lang.SecurityManager#checkRead(java.lang.String) - * @see java.lang.SecurityManager#checkWrite(java.lang.String) - * @revised 1.4 - * @spec JSR-51 - */ - public RandomAccessFile(String name, String mode) - throws FileNotFoundException - { - this(name != null ? new File(name) : null, mode); - } - - /** - * Creates a random access file stream to read from, and optionally to - * write to, the file specified by the {@link File} argument. A new {@link - * FileDescriptor} object is created to represent this file connection. - * - *

The mode argument specifies the access mode - * in which the file is to be opened. The permitted values and their - * meanings are: - * - *

- * - * - * - * - * - * - * - * - * - *

Value

Meaning

"r" Open for reading only. Invoking any of the write - * methods of the resulting object will cause an {@link - * java.io.IOException} to be thrown.
"rw" Open for reading and writing. If the file does not already - * exist then an attempt will be made to create it.
"rws" Open for reading and writing, as with "rw", and also - * require that every update to the file's content or metadata be - * written synchronously to the underlying storage device.
"rwd"   Open for reading and writing, as with "rw", and also - * require that every update to the file's content be written - * synchronously to the underlying storage device.
- * - * The "rws" and "rwd" modes work much like the {@link - * java.nio.channels.FileChannel#force(boolean) force(boolean)} method of - * the {@link java.nio.channels.FileChannel} class, passing arguments of - * true and false, respectively, except that they always - * apply to every I/O operation and are therefore often more efficient. If - * the file resides on a local storage device then when an invocation of a - * method of this class returns it is guaranteed that all changes made to - * the file by that invocation will have been written to that device. This - * is useful for ensuring that critical information is not lost in the - * event of a system crash. If the file does not reside on a local device - * then no such guarantee is made. - * - *

The "rwd" mode can be used to reduce the number of I/O - * operations performed. Using "rwd" only requires updates to the - * file's content to be written to storage; using "rws" requires - * updates to both the file's content and its metadata to be written, which - * generally requires at least one more low-level I/O operation. - * - *

If there is a security manager, its checkRead method is - * called with the pathname of the file argument as its - * argument to see if read access to the file is allowed. If the mode - * allows writing, the security manager's checkWrite method is - * also called with the path argument to see if write access to the file is - * allowed. - * - * @param file the file object - * @param mode the access mode, as described - * above - * @exception IllegalArgumentException if the mode argument is not equal - * to one of "r", "rw", "rws", or - * "rwd" - * @exception FileNotFoundException - * if the mode is "r" but the given file object does - * not denote an existing regular file, or if the mode begins - * with "rw" but the given file object does not denote - * an existing, writable regular file and a new regular file of - * that name cannot be created, or if some other error occurs - * while opening or creating the file - * @exception SecurityException if a security manager exists and its - * checkRead method denies read access to the file - * or the mode is "rw" and the security manager's - * checkWrite method denies write access to the file - * @see java.lang.SecurityManager#checkRead(java.lang.String) - * @see java.lang.SecurityManager#checkWrite(java.lang.String) - * @see java.nio.channels.FileChannel#force(boolean) - * @revised 1.4 - * @spec JSR-51 - */ - public RandomAccessFile(File file, String mode) - throws FileNotFoundException - { - String name = (file != null ? file.getPath() : null); - int imode = -1; - if (mode.equals("r")) - imode = O_RDONLY; - else if (mode.startsWith("rw")) { - imode = O_RDWR; - rw = true; - if (mode.length() > 2) { - if (mode.equals("rws")) - imode |= O_SYNC; - else if (mode.equals("rwd")) - imode |= O_DSYNC; - else - imode = -1; - } - } - if (imode < 0) - throw new IllegalArgumentException("Illegal mode \"" + mode - + "\" must be one of " - + "\"r\", \"rw\", \"rws\"," - + " or \"rwd\""); - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkRead(name); - if (rw) { - security.checkWrite(name); - } - } - if (name == null) { - throw new NullPointerException(); - } - /* - if (file.isInvalid()) { - throw new FileNotFoundException("Invalid file path"); - } - */ - fd = new FileDescriptor(); - fd.incrementAndGetUseCount(); - this.path = name; - open(name, imode); - } - - /** - * Returns the opaque file descriptor object associated with this - * stream.

- * - * @return the file descriptor object associated with this stream. - * @exception IOException if an I/O error occurs. - * @see java.io.FileDescriptor - */ - public final FileDescriptor getFD() throws IOException { - if (fd != null) return fd; - throw new IOException(); - } - - /** - * Returns the unique {@link java.nio.channels.FileChannel FileChannel} - * object associated with this file. - * - *

The {@link java.nio.channels.FileChannel#position() - * position} of the returned channel will always be equal to - * this object's file-pointer offset as returned by the {@link - * #getFilePointer getFilePointer} method. Changing this object's - * file-pointer offset, whether explicitly or by reading or writing bytes, - * will change the position of the channel, and vice versa. Changing the - * file's length via this object will change the length seen via the file - * channel, and vice versa. - * - * @return the file channel associated with this file - * - * @since 1.4 - * @spec JSR-51 - */ - public final FileChannel getChannel() { - synchronized (this) { - if (channel == null) { - channel = FileChannelImpl.open(fd, path, true, rw, this); - - /* - * FileDescriptor could be shared by FileInputStream or - * FileOutputStream. - * Ensure that FD is GC'ed only when all the streams/channels - * are done using it. - * Increment fd's use count. Invoking the channel's close() - * method will result in decrementing the use count set for - * the channel. - */ - fd.incrementAndGetUseCount(); - } - return channel; - } - } - - /** - * Opens a file and returns the file descriptor. The file is - * opened in read-write mode if the O_RDWR bit in mode - * is true, else the file is opened as read-only. - * If the name refers to a directory, an IOException - * is thrown. - * - * @param name the name of the file - * @param mode the mode flags, a combination of the O_ constants - * defined above - */ - private void open(String name, int mode) - throws FileNotFoundException - { - if ((mode & O_RDWR) == O_RDWR) - { - fd.openReadWrite(name); - } - else - { - fd.openReadOnly(name); - } - } - - // 'Read' primitives - - /** - * Reads a byte of data from this file. The byte is returned as an - * integer in the range 0 to 255 (0x00-0x0ff). This - * method blocks if no input is yet available. - *

- * Although RandomAccessFile is not a subclass of - * InputStream, this method behaves in exactly the same - * way as the {@link InputStream#read()} method of - * InputStream. - * - * @return the next byte of data, or -1 if the end of the - * file has been reached. - * @exception IOException if an I/O error occurs. Not thrown if - * end-of-file has been reached. - */ - public int read() throws IOException { - Object traceContext = IoTrace.fileReadBegin(path); - int b = 0; - try { - b = fd.read(); - } finally { - IoTrace.fileReadEnd(traceContext, b == -1 ? 0 : 1); - } - return b; - } - - /** - * Reads a sub array as a sequence of bytes. - * @param b the buffer into which the data is read. - * @param off the start offset of the data. - * @param len the number of bytes to read. - * @exception IOException If an I/O error has occurred. - */ - private int readBytes(byte b[], int off, int len) throws IOException - { - Object traceContext = IoTrace.fileReadBegin(path); - int bytesRead = 0; - try { - bytesRead = fd.readBytes(b, off, len); - } finally { - IoTrace.fileReadEnd(traceContext, bytesRead == -1 ? 0 : bytesRead); - } - return bytesRead; - } - - /** - * Reads up to len bytes of data from this file into an - * array of bytes. This method blocks until at least one byte of input - * is available. - *

- * Although RandomAccessFile is not a subclass of - * InputStream, this method behaves in exactly the - * same way as the {@link InputStream#read(byte[], int, int)} method of - * InputStream. - * - * @param b the buffer into which the data is read. - * @param off the start offset in array b - * at which the data is written. - * @param len the maximum number of bytes read. - * @return the total number of bytes read into the buffer, or - * -1 if there is no more data because the end of - * the file has been reached. - * @exception IOException If the first byte cannot be read for any reason - * other than end of file, or if the random access file has been closed, or if - * some other I/O error occurs. - * @exception NullPointerException If b is null. - * @exception IndexOutOfBoundsException If off is negative, - * len is negative, or len is greater than - * b.length - off - */ - public int read(byte b[], int off, int len) throws IOException { - return readBytes(b, off, len); - } - - /** - * Reads up to b.length bytes of data from this file - * into an array of bytes. This method blocks until at least one byte - * of input is available. - *

- * Although RandomAccessFile is not a subclass of - * InputStream, this method behaves in exactly the - * same way as the {@link InputStream#read(byte[])} method of - * InputStream. - * - * @param b the buffer into which the data is read. - * @return the total number of bytes read into the buffer, or - * -1 if there is no more data because the end of - * this file has been reached. - * @exception IOException If the first byte cannot be read for any reason - * other than end of file, or if the random access file has been closed, or if - * some other I/O error occurs. - * @exception NullPointerException If b is null. - */ - public int read(byte b[]) throws IOException { - return readBytes(b, 0, b.length); - } - - /** - * Reads b.length bytes from this file into the byte - * array, starting at the current file pointer. This method reads - * repeatedly from the file until the requested number of bytes are - * read. This method blocks until the requested number of bytes are - * read, the end of the stream is detected, or an exception is thrown. - * - * @param b the buffer into which the data is read. - * @exception EOFException if this file reaches the end before reading - * all the bytes. - * @exception IOException if an I/O error occurs. - */ - public final void readFully(byte b[]) throws IOException { - readFully(b, 0, b.length); - } - - /** - * Reads exactly len bytes from this file into the byte - * array, starting at the current file pointer. This method reads - * repeatedly from the file until the requested number of bytes are - * read. This method blocks until the requested number of bytes are - * read, the end of the stream is detected, or an exception is thrown. - * - * @param b the buffer into which the data is read. - * @param off the start offset of the data. - * @param len the number of bytes to read. - * @exception EOFException if this file reaches the end before reading - * all the bytes. - * @exception IOException if an I/O error occurs. - */ - public final void readFully(byte b[], int off, int len) throws IOException { - int n = 0; - do { - int count = this.read(b, off + n, len - n); - if (count < 0) - throw new EOFException(); - n += count; - } while (n < len); - } - - /** - * Attempts to skip over n bytes of input discarding the - * skipped bytes. - *

- * - * This method may skip over some smaller number of bytes, possibly zero. - * This may result from any of a number of conditions; reaching end of - * file before n bytes have been skipped is only one - * possibility. This method never throws an EOFException. - * The actual number of bytes skipped is returned. If n - * is negative, no bytes are skipped. - * - * @param n the number of bytes to be skipped. - * @return the actual number of bytes skipped. - * @exception IOException if an I/O error occurs. - */ - public int skipBytes(int n) throws IOException { - long pos; - long len; - long newpos; - - if (n <= 0) { - return 0; - } - pos = getFilePointer(); - len = length(); - newpos = pos + n; - if (newpos > len) { - newpos = len; - } - seek(newpos); - - /* return the actual number of bytes skipped */ - return (int) (newpos - pos); - } - - // 'Write' primitives - - /** - * Writes the specified byte to this file. The write starts at - * the current file pointer. - * - * @param b the byte to be written. - * @exception IOException if an I/O error occurs. - */ - public void write(int b) throws IOException { - Object traceContext = IoTrace.fileWriteBegin(path); - int bytesWritten = 0; - try { - fd.write(b); - bytesWritten = 1; - } finally { - IoTrace.fileWriteEnd(traceContext, bytesWritten); - } - } - - /** - * Writes a sub array as a sequence of bytes. - * @param b the data to be written - - * @param off the start offset in the data - * @param len the number of bytes that are written - * @exception IOException If an I/O error has occurred. - */ - private void writeBytes(byte b[], int off, int len) throws IOException { - Object traceContext = IoTrace.fileWriteBegin(path); - int bytesWritten = 0; - try { - fd.writeBytes(b, off, len); - bytesWritten = len; - } finally { - IoTrace.fileWriteEnd(traceContext, bytesWritten); - } - } - - /** - * Writes b.length bytes from the specified byte array - * to this file, starting at the current file pointer. - * - * @param b the data. - * @exception IOException if an I/O error occurs. - */ - public void write(byte b[]) throws IOException { - writeBytes(b, 0, b.length); - } - - /** - * Writes len bytes from the specified byte array - * starting at offset off to this file. - * - * @param b the data. - * @param off the start offset in the data. - * @param len the number of bytes to write. - * @exception IOException if an I/O error occurs. - */ - public void write(byte b[], int off, int len) throws IOException { - writeBytes(b, off, len); - } - - // 'Random access' stuff - - /** - * Returns the current offset in this file. - * - * @return the offset from the beginning of the file, in bytes, - * at which the next read or write occurs. - * @exception IOException if an I/O error occurs. - */ - public long getFilePointer() throws IOException - { - return fd.getFilePointer(); - } - - /** - * Sets the file-pointer offset, measured from the beginning of this - * file, at which the next read or write occurs. The offset may be - * set beyond the end of the file. Setting the offset beyond the end - * of the file does not change the file length. The file length will - * change only by writing after the offset has been set beyond the end - * of the file. - * - * @param pos the offset position, measured in bytes from the - * beginning of the file, at which to set the file - * pointer. - * @exception IOException if pos is less than - * 0 or if an I/O error occurs. - */ - public void seek(long pos) throws IOException - { - fd.seek(pos); - } - - /** - * Returns the length of this file. - * - * @return the length of this file, measured in bytes. - * @exception IOException if an I/O error occurs. - */ - public long length() throws IOException - { - return fd.length(); - } - - /** - * Sets the length of this file. - * - *

If the present length of the file as returned by the - * length method is greater than the newLength - * argument then the file will be truncated. In this case, if the file - * offset as returned by the getFilePointer method is greater - * than newLength then after this method returns the offset - * will be equal to newLength. - * - *

If the present length of the file as returned by the - * length method is smaller than the newLength - * argument then the file will be extended. In this case, the contents of - * the extended portion of the file are not defined. - * - * @param newLength The desired length of the file - * @exception IOException If an I/O error occurs - * @since 1.2 - */ - public void setLength(long newLength) throws IOException - { - fd.setLength(newLength); - } - - /** - * Closes this random access file stream and releases any system - * resources associated with the stream. A closed random access - * file cannot perform input or output operations and cannot be - * reopened. - * - *

If this file has an associated channel then the channel is closed - * as well. - * - * @exception IOException if an I/O error occurs. - * - * @revised 1.4 - * @spec JSR-51 - */ - public void close() throws IOException { - synchronized (closeLock) { - if (closed) { - return; - } - closed = true; - } - if (channel != null) { - /* - * Decrement FD use count associated with the channel. The FD use - * count is incremented whenever a new channel is obtained from - * this stream. - */ - fd.decrementAndGetUseCount(); - channel.close(); - } - - /* - * Decrement FD use count associated with this stream. - * The count got incremented by FileDescriptor during its construction. - */ - fd.decrementAndGetUseCount(); - close0(); - } - - // - // Some "reading/writing Java data types" methods stolen from - // DataInputStream and DataOutputStream. - // - - /** - * Reads a boolean from this file. This method reads a - * single byte from the file, starting at the current file pointer. - * A value of 0 represents - * false. Any other value represents true. - * This method blocks until the byte is read, the end of the stream - * is detected, or an exception is thrown. - * - * @return the boolean value read. - * @exception EOFException if this file has reached the end. - * @exception IOException if an I/O error occurs. - */ - public final boolean readBoolean() throws IOException { - int ch = this.read(); - if (ch < 0) - throw new EOFException(); - return (ch != 0); - } - - /** - * Reads a signed eight-bit value from this file. This method reads a - * byte from the file, starting from the current file pointer. - * If the byte read is b, where - * 0 <= b <= 255, - * then the result is: - *

-     *     (byte)(b)
-     * 
- *

- * This method blocks until the byte is read, the end of the stream - * is detected, or an exception is thrown. - * - * @return the next byte of this file as a signed eight-bit - * byte. - * @exception EOFException if this file has reached the end. - * @exception IOException if an I/O error occurs. - */ - public final byte readByte() throws IOException { - int ch = this.read(); - if (ch < 0) - throw new EOFException(); - return (byte)(ch); - } - - /** - * Reads an unsigned eight-bit number from this file. This method reads - * a byte from this file, starting at the current file pointer, - * and returns that byte. - *

- * This method blocks until the byte is read, the end of the stream - * is detected, or an exception is thrown. - * - * @return the next byte of this file, interpreted as an unsigned - * eight-bit number. - * @exception EOFException if this file has reached the end. - * @exception IOException if an I/O error occurs. - */ - public final int readUnsignedByte() throws IOException { - int ch = this.read(); - if (ch < 0) - throw new EOFException(); - return ch; - } - - /** - * Reads a signed 16-bit number from this file. The method reads two - * bytes from this file, starting at the current file pointer. - * If the two bytes read, in order, are - * b1 and b2, where each of the two values is - * between 0 and 255, inclusive, then the - * result is equal to: - *

-     *     (short)((b1 << 8) | b2)
-     * 
- *

- * This method blocks until the two bytes are read, the end of the - * stream is detected, or an exception is thrown. - * - * @return the next two bytes of this file, interpreted as a signed - * 16-bit number. - * @exception EOFException if this file reaches the end before reading - * two bytes. - * @exception IOException if an I/O error occurs. - */ - public final short readShort() throws IOException { - int ch1 = this.read(); - int ch2 = this.read(); - if ((ch1 | ch2) < 0) - throw new EOFException(); - return (short)((ch1 << 8) + (ch2 << 0)); - } - - /** - * Reads an unsigned 16-bit number from this file. This method reads - * two bytes from the file, starting at the current file pointer. - * If the bytes read, in order, are - * b1 and b2, where - * 0 <= b1, b2 <= 255, - * then the result is equal to: - *

-     *     (b1 << 8) | b2
-     * 
- *

- * This method blocks until the two bytes are read, the end of the - * stream is detected, or an exception is thrown. - * - * @return the next two bytes of this file, interpreted as an unsigned - * 16-bit integer. - * @exception EOFException if this file reaches the end before reading - * two bytes. - * @exception IOException if an I/O error occurs. - */ - public final int readUnsignedShort() throws IOException { - int ch1 = this.read(); - int ch2 = this.read(); - if ((ch1 | ch2) < 0) - throw new EOFException(); - return (ch1 << 8) + (ch2 << 0); - } - - /** - * Reads a character from this file. This method reads two - * bytes from the file, starting at the current file pointer. - * If the bytes read, in order, are - * b1 and b2, where - * 0 <= b1, b2 <= 255, - * then the result is equal to: - *

-     *     (char)((b1 << 8) | b2)
-     * 
- *

- * This method blocks until the two bytes are read, the end of the - * stream is detected, or an exception is thrown. - * - * @return the next two bytes of this file, interpreted as a - * char. - * @exception EOFException if this file reaches the end before reading - * two bytes. - * @exception IOException if an I/O error occurs. - */ - public final char readChar() throws IOException { - int ch1 = this.read(); - int ch2 = this.read(); - if ((ch1 | ch2) < 0) - throw new EOFException(); - return (char)((ch1 << 8) + (ch2 << 0)); - } - - /** - * Reads a signed 32-bit integer from this file. This method reads 4 - * bytes from the file, starting at the current file pointer. - * If the bytes read, in order, are b1, - * b2, b3, and b4, where - * 0 <= b1, b2, b3, b4 <= 255, - * then the result is equal to: - *

-     *     (b1 << 24) | (b2 << 16) + (b3 << 8) + b4
-     * 
- *

- * This method blocks until the four bytes are read, the end of the - * stream is detected, or an exception is thrown. - * - * @return the next four bytes of this file, interpreted as an - * int. - * @exception EOFException if this file reaches the end before reading - * four bytes. - * @exception IOException if an I/O error occurs. - */ - public final int readInt() throws IOException { - int ch1 = this.read(); - int ch2 = this.read(); - int ch3 = this.read(); - int ch4 = this.read(); - if ((ch1 | ch2 | ch3 | ch4) < 0) - throw new EOFException(); - return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0)); - } - - /** - * Reads a signed 64-bit integer from this file. This method reads eight - * bytes from the file, starting at the current file pointer. - * If the bytes read, in order, are - * b1, b2, b3, - * b4, b5, b6, - * b7, and b8, where: - *

-     *     0 <= b1, b2, b3, b4, b5, b6, b7, b8 <=255,
-     * 
- *

- * then the result is equal to: - *

-     *     ((long)b1 << 56) + ((long)b2 << 48)
-     *     + ((long)b3 << 40) + ((long)b4 << 32)
-     *     + ((long)b5 << 24) + ((long)b6 << 16)
-     *     + ((long)b7 << 8) + b8
-     * 
- *

- * This method blocks until the eight bytes are read, the end of the - * stream is detected, or an exception is thrown. - * - * @return the next eight bytes of this file, interpreted as a - * long. - * @exception EOFException if this file reaches the end before reading - * eight bytes. - * @exception IOException if an I/O error occurs. - */ - public final long readLong() throws IOException { - return ((long)(readInt()) << 32) + (readInt() & 0xFFFFFFFFL); - } - - /** - * Reads a float from this file. This method reads an - * int value, starting at the current file pointer, - * as if by the readInt method - * and then converts that int to a float - * using the intBitsToFloat method in class - * Float. - *

- * This method blocks until the four bytes are read, the end of the - * stream is detected, or an exception is thrown. - * - * @return the next four bytes of this file, interpreted as a - * float. - * @exception EOFException if this file reaches the end before reading - * four bytes. - * @exception IOException if an I/O error occurs. - * @see java.io.RandomAccessFile#readInt() - * @see java.lang.Float#intBitsToFloat(int) - */ - public final float readFloat() throws IOException { - return Float.intBitsToFloat(readInt()); - } - - /** - * Reads a double from this file. This method reads a - * long value, starting at the current file pointer, - * as if by the readLong method - * and then converts that long to a double - * using the longBitsToDouble method in - * class Double. - *

- * This method blocks until the eight bytes are read, the end of the - * stream is detected, or an exception is thrown. - * - * @return the next eight bytes of this file, interpreted as a - * double. - * @exception EOFException if this file reaches the end before reading - * eight bytes. - * @exception IOException if an I/O error occurs. - * @see java.io.RandomAccessFile#readLong() - * @see java.lang.Double#longBitsToDouble(long) - */ - public final double readDouble() throws IOException { - return Double.longBitsToDouble(readLong()); - } - - /** - * Reads the next line of text from this file. This method successively - * reads bytes from the file, starting at the current file pointer, - * until it reaches a line terminator or the end - * of the file. Each byte is converted into a character by taking the - * byte's value for the lower eight bits of the character and setting the - * high eight bits of the character to zero. This method does not, - * therefore, support the full Unicode character set. - * - *

A line of text is terminated by a carriage-return character - * ('\r'), a newline character ('\n'), a - * carriage-return character immediately followed by a newline character, - * or the end of the file. Line-terminating characters are discarded and - * are not included as part of the string returned. - * - *

This method blocks until a newline character is read, a carriage - * return and the byte following it are read (to see if it is a newline), - * the end of the file is reached, or an exception is thrown. - * - * @return the next line of text from this file, or null if end - * of file is encountered before even one byte is read. - * @exception IOException if an I/O error occurs. - */ - - public final String readLine() throws IOException { - StringBuffer input = new StringBuffer(); - int c = -1; - boolean eol = false; - - while (!eol) { - switch (c = read()) { - case -1: - case '\n': - eol = true; - break; - case '\r': - eol = true; - long cur = getFilePointer(); - if ((read()) != '\n') { - seek(cur); - } - break; - default: - input.append((char)c); - break; - } - } - - if ((c == -1) && (input.length() == 0)) { - return null; - } - return input.toString(); - } - - /** - * Reads in a string from this file. The string has been encoded - * using a - * modified UTF-8 - * format. - *

- * The first two bytes are read, starting from the current file - * pointer, as if by - * readUnsignedShort. This value gives the number of - * following bytes that are in the encoded string, not - * the length of the resulting string. The following bytes are then - * interpreted as bytes encoding characters in the modified UTF-8 format - * and are converted into characters. - *

- * This method blocks until all the bytes are read, the end of the - * stream is detected, or an exception is thrown. - * - * @return a Unicode string. - * @exception EOFException if this file reaches the end before - * reading all the bytes. - * @exception IOException if an I/O error occurs. - * @exception UTFDataFormatException if the bytes do not represent - * valid modified UTF-8 encoding of a Unicode string. - * @see java.io.RandomAccessFile#readUnsignedShort() - */ - public final String readUTF() throws IOException { - return DataInputStream.readUTF(this); - } - - /** - * Writes a boolean to the file as a one-byte value. The - * value true is written out as the value - * (byte)1; the value false is written out - * as the value (byte)0. The write starts at - * the current position of the file pointer. - * - * @param v a boolean value to be written. - * @exception IOException if an I/O error occurs. - */ - public final void writeBoolean(boolean v) throws IOException { - write(v ? 1 : 0); - //written++; - } - - /** - * Writes a byte to the file as a one-byte value. The - * write starts at the current position of the file pointer. - * - * @param v a byte value to be written. - * @exception IOException if an I/O error occurs. - */ - public final void writeByte(int v) throws IOException { - write(v); - //written++; - } - - /** - * Writes a short to the file as two bytes, high byte first. - * The write starts at the current position of the file pointer. - * - * @param v a short to be written. - * @exception IOException if an I/O error occurs. - */ - public final void writeShort(int v) throws IOException { - write((v >>> 8) & 0xFF); - write((v >>> 0) & 0xFF); - //written += 2; - } - - /** - * Writes a char to the file as a two-byte value, high - * byte first. The write starts at the current position of the - * file pointer. - * - * @param v a char value to be written. - * @exception IOException if an I/O error occurs. - */ - public final void writeChar(int v) throws IOException { - write((v >>> 8) & 0xFF); - write((v >>> 0) & 0xFF); - //written += 2; - } - - /** - * Writes an int to the file as four bytes, high byte first. - * The write starts at the current position of the file pointer. - * - * @param v an int to be written. - * @exception IOException if an I/O error occurs. - */ - public final void writeInt(int v) throws IOException { - write((v >>> 24) & 0xFF); - write((v >>> 16) & 0xFF); - write((v >>> 8) & 0xFF); - write((v >>> 0) & 0xFF); - //written += 4; - } - - /** - * Writes a long to the file as eight bytes, high byte first. - * The write starts at the current position of the file pointer. - * - * @param v a long to be written. - * @exception IOException if an I/O error occurs. - */ - public final void writeLong(long v) throws IOException { - write((int)(v >>> 56) & 0xFF); - write((int)(v >>> 48) & 0xFF); - write((int)(v >>> 40) & 0xFF); - write((int)(v >>> 32) & 0xFF); - write((int)(v >>> 24) & 0xFF); - write((int)(v >>> 16) & 0xFF); - write((int)(v >>> 8) & 0xFF); - write((int)(v >>> 0) & 0xFF); - //written += 8; - } - - /** - * Converts the float argument to an int using the - * floatToIntBits method in class Float, - * and then writes that int value to the file as a - * four-byte quantity, high byte first. The write starts at the - * current position of the file pointer. - * - * @param v a float value to be written. - * @exception IOException if an I/O error occurs. - * @see java.lang.Float#floatToIntBits(float) - */ - public final void writeFloat(float v) throws IOException { - writeInt(Float.floatToIntBits(v)); - } - - /** - * Converts the double argument to a long using the - * doubleToLongBits method in class Double, - * and then writes that long value to the file as an - * eight-byte quantity, high byte first. The write starts at the current - * position of the file pointer. - * - * @param v a double value to be written. - * @exception IOException if an I/O error occurs. - * @see java.lang.Double#doubleToLongBits(double) - */ - public final void writeDouble(double v) throws IOException { - writeLong(Double.doubleToLongBits(v)); - } - - /** - * Writes the string to the file as a sequence of bytes. Each - * character in the string is written out, in sequence, by discarding - * its high eight bits. The write starts at the current position of - * the file pointer. - * - * @param s a string of bytes to be written. - * @exception IOException if an I/O error occurs. - */ - public final void writeBytes(String s) throws IOException { - int len = s.length(); - byte[] b = new byte[len]; - s.getBytes(0, len, b, 0); - writeBytes(b, 0, len); - } - - /** - * Writes a string to the file as a sequence of characters. Each - * character is written to the data output stream as if by the - * writeChar method. The write starts at the current - * position of the file pointer. - * - * @param s a String value to be written. - * @exception IOException if an I/O error occurs. - * @see java.io.RandomAccessFile#writeChar(int) - */ - public final void writeChars(String s) throws IOException { - int clen = s.length(); - int blen = 2*clen; - byte[] b = new byte[blen]; - char[] c = new char[clen]; - s.getChars(0, clen, c, 0); - for (int i = 0, j = 0; i < clen; i++) { - b[j++] = (byte)(c[i] >>> 8); - b[j++] = (byte)(c[i] >>> 0); - } - writeBytes(b, 0, blen); - } - - /** - * Writes a string to the file using - * modified UTF-8 - * encoding in a machine-independent manner. - *

- * First, two bytes are written to the file, starting at the - * current file pointer, as if by the - * writeShort method giving the number of bytes to - * follow. This value is the number of bytes actually written out, - * not the length of the string. Following the length, each character - * of the string is output, in sequence, using the modified UTF-8 encoding - * for each character. - * - * @param str a string to be written. - * @exception IOException if an I/O error occurs. - */ - public final void writeUTF(String str) throws IOException { - DataOutputStream.writeUTF(str, this); - } - - private void close0() throws IOException - { - fd.close(); - } -} diff --git a/external/ikvm/openjdk/java/lang/Class.java.REMOVED.git-id b/external/ikvm/openjdk/java/lang/Class.java.REMOVED.git-id index dd598adddb..4076490aed 100644 --- a/external/ikvm/openjdk/java/lang/Class.java.REMOVED.git-id +++ b/external/ikvm/openjdk/java/lang/Class.java.REMOVED.git-id @@ -1 +1 @@ -07fd7bd567e5b0ae8b3ae9c32741b56f6f363b0a \ No newline at end of file +b11e668d455d97412eca312477103a8e19b9b2b6 \ No newline at end of file diff --git a/external/ikvm/openjdk/java/lang/ClassLoader.java b/external/ikvm/openjdk/java/lang/ClassLoader.java index 57c1ee3e39..280a6889ee 100644 --- a/external/ikvm/openjdk/java/lang/ClassLoader.java +++ b/external/ikvm/openjdk/java/lang/ClassLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,13 +51,13 @@ import java.util.Vector; import java.util.Hashtable; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; -import sun.misc.ClassFileTransformer; import sun.misc.CompoundEnumeration; import sun.misc.Resource; import sun.misc.URLClassPath; import sun.misc.VM; import sun.reflect.CallerSensitive; import sun.reflect.Reflection; +import sun.reflect.misc.ReflectUtil; import sun.security.util.SecurityConstants; /** @@ -158,7 +158,7 @@ import sun.security.util.SecurityConstants; * } * * - *

Binary names

+ *

Binary names

* *

Any class name provided as a {@link String} parameter to methods in * ClassLoader must be a binary name as defined by @@ -245,7 +245,7 @@ public abstract class ClassLoader { // Shared among all packages with unsigned classes private static final Certificate[] nocerts = new Certificate[0]; - // The classes loaded by this class loader. The only purpose of this table + // The classes loaded by this class loader. The only purpose of this table // is to keep the classes from being GC'ed until the loader is GC'ed. private final Vector> classes = new Vector<>(); @@ -259,7 +259,7 @@ public abstract class ClassLoader { private final Set domains; // Invoked by the VM to record every loaded class with this loader. - void addClass(Class c) { + void addClass(Class c) { classes.addElement(c); } @@ -361,7 +361,7 @@ public abstract class ClassLoader { * #loadClass(String, boolean)} method. It is invoked by the Java virtual * machine to resolve class references. Invoking this method is equivalent * to invoking {@link #loadClass(String, boolean) loadClass(name, - * false)}.

+ * false)}. * * @param name * The binary name of the class @@ -380,7 +380,7 @@ public abstract class ClassLoader { * default implementation of this method searches for classes in the * following order: * - *

    + *
      * *
    1. Invoke {@link #findLoadedClass(String)} to check if the class * has already been loaded.

    2. @@ -421,7 +421,7 @@ public abstract class ClassLoader { { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded - Class c = findLoadedClass(name); + Class c = findLoadedClass(name); if (c == null) { try { if (parent != null) { @@ -453,7 +453,7 @@ public abstract class ClassLoader { * behaves as follows. If this ClassLoader object is registered as * parallel capable, the method returns a dedicated object associated * with the specified class name. Otherwise, the method returns this - * ClassLoader object.

      + * ClassLoader object. * * @param className * The name of the to-be-loaded class @@ -480,7 +480,7 @@ public abstract class ClassLoader { } // This method is invoked by the virtual machine to load a class. - final Class loadClassInternal(String name) + final Class loadClassInternal(String name) throws ClassNotFoundException { // For backward compatibility, explicitly lock on 'this' when @@ -495,9 +495,16 @@ public abstract class ClassLoader { } // Invoked by the VM after loading class with this loader. - final void checkPackageAccess(Class cls, ProtectionDomain pd) { + final void checkPackageAccess(Class cls, ProtectionDomain pd) { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { + if (ReflectUtil.isNonPublicProxyClass(cls)) { + for (Class intf: cls.getInterfaces()) { + checkPackageAccess(intf, pd); + } + return; + } + final String name = cls.getName(); final int i = name.lastIndexOf('.'); if (i != -1) { @@ -518,7 +525,7 @@ public abstract class ClassLoader { * follow the delegation model for loading classes, and will be invoked by * the {@link #loadClass loadClass} method after checking the * parent class loader for the requested class. The default implementation - * throws a ClassNotFoundException.

      + * throws a ClassNotFoundException. * * @param name * The binary name of the class @@ -681,42 +688,7 @@ public abstract class ClassLoader { return source; } - private Class defineTransformedClass(String name, byte[] b, int off, int len, - ProtectionDomain pd, - ClassFormatError cfe, String source) - throws ClassFormatError - { - // Class format error - try to transform the bytecode and - // define the class again - // - ClassFileTransformer[] transformers = - ClassFileTransformer.getTransformers(); - Class c = null; - - if (transformers != null) { - for (ClassFileTransformer transformer : transformers) { - try { - // Transform byte code using transformer - byte[] tb = transformer.transform(b, off, len); - c = defineClass1(name, tb, 0, tb.length, - pd, source); - break; - } catch (ClassFormatError cfe2) { - // If ClassFormatError occurs, try next transformer - } - } - } - - // Rethrow original ClassFormatError if unable to transform - // bytecode to well-formed - // - if (c == null) - throw cfe; - - return c; - } - - private void postDefineClass(Class c, ProtectionDomain pd) + private void postDefineClass(Class c, ProtectionDomain pd) { if (pd.getCodeSource() != null) { Certificate certs[] = pd.getCodeSource().getCertificates(); @@ -749,7 +721,7 @@ public abstract class ClassLoader { * bootstrap class loader. If name is not null, it * must be equal to the binary name of the class * specified by the byte array "b", otherwise a {@link - * NoClassDefFoundError} will be thrown.

      + * NoClassDefFoundError NoClassDefFoundError} will be thrown.

      * * @param name * The expected binary name of the class, or @@ -796,17 +768,8 @@ public abstract class ClassLoader { { check(); protectionDomain = preDefineClass(name, protectionDomain); - - Class c = null; String source = defineClassSourceLocation(protectionDomain); - - try { - c = defineClass1(name, b, off, len, protectionDomain, source); - } catch (ClassFormatError cfe) { - c = defineTransformedClass(name, b, off, len, protectionDomain, cfe, - source); - } - + Class c = defineClass1(name, b, off, len, protectionDomain, source); postDefineClass(c, protectionDomain); return c; } @@ -829,16 +792,16 @@ public abstract class ClassLoader { * bBuffer, pd) yields exactly the same * result as the statements * - *
      + *

      * ...
      - * byte[] temp = new byte[
      bBuffer.{@link + * byte[] temp = new byte[bBuffer.{@link * java.nio.ByteBuffer#remaining remaining}()];
      - *
      bBuffer.{@link java.nio.ByteBuffer#get(byte[]) + * bBuffer.{@link java.nio.ByteBuffer#get(byte[]) * get}(temp);
      * return {@link #defineClass(String, byte[], int, int, ProtectionDomain) - *
      cl.defineClass}(name, temp, 0, - * temp.length, pd);
      - *

      + * cl.defineClass}(name, temp, 0, + * temp.length, pd);
      + *

      * * @param name * The expected binary name. of the class, or @@ -896,33 +859,21 @@ public abstract class ClassLoader { } protectionDomain = preDefineClass(name, protectionDomain); - - Class c = null; String source = defineClassSourceLocation(protectionDomain); - - try { - c = defineClass2(name, b, b.position(), len, protectionDomain, - source); - } catch (ClassFormatError cfe) { - byte[] tb = new byte[len]; - b.get(tb); // get bytes out of byte buffer. - c = defineTransformedClass(name, tb, 0, len, protectionDomain, cfe, - source); - } - + Class c = defineClass2(name, b, b.position(), len, protectionDomain, source); postDefineClass(c, protectionDomain); return c; } - private native Class defineClass0(String name, byte[] b, int off, int len, - ProtectionDomain pd); + private native Class defineClass0(String name, byte[] b, int off, int len, + ProtectionDomain pd); - private native Class defineClass1(String name, byte[] b, int off, int len, - ProtectionDomain pd, String source); + private native Class defineClass1(String name, byte[] b, int off, int len, + ProtectionDomain pd, String source); - private native Class defineClass2(String name, java.nio.ByteBuffer b, - int off, int len, ProtectionDomain pd, - String source); + private native Class defineClass2(String name, java.nio.ByteBuffer b, + int off, int len, ProtectionDomain pd, + String source); // true if the name is null or has the potential to be a valid binary name static boolean checkName(String name) { @@ -1011,7 +962,6 @@ public abstract class ClassLoader { * already been linked, then this method simply returns. Otherwise, the * class is linked as described in the "Execution" chapter of * The Java™ Language Specification. - *

      * * @param c * The class to link @@ -1026,7 +976,7 @@ public abstract class ClassLoader { resolveClass0(c); } - private native void resolveClass0(Class c); + private native void resolveClass0(Class c); /** * Finds a class with the specified binary name, @@ -1058,7 +1008,7 @@ public abstract class ClassLoader { if (system == null) { if (!checkName(name)) throw new ClassNotFoundException(name); - Class cls = findBootstrapClass(name); + Class cls = findBootstrapClass(name); if (cls == null) { throw new ClassNotFoundException(name); } @@ -1071,7 +1021,7 @@ public abstract class ClassLoader { * Returns a class loaded by the bootstrap class loader; * or return null if not found. */ - private Class findBootstrapClassOrNull(String name) + private Class findBootstrapClassOrNull(String name) { check(); if (!checkName(name)) return null; @@ -1080,7 +1030,7 @@ public abstract class ClassLoader { } // return null if not found - private native Class findBootstrapClass(String name); + private native Class findBootstrapClass(String name); // Check to make sure the class loader has been initialized. private void check() { @@ -1093,7 +1043,7 @@ public abstract class ClassLoader { * Returns the class with the given binary name if this * loader has been recorded by the Java virtual machine as an initiating * loader of a class with that binary name. Otherwise - * null is returned.

      + * null is returned. * * @param name * The binary name of the class @@ -1110,11 +1060,11 @@ public abstract class ClassLoader { return findLoadedClass0(name); } - private native final Class findLoadedClass0(String name); + private native final Class findLoadedClass0(String name); /** * Sets the signers of a class. This should be invoked after defining a - * class.

      + * class. * * @param c * The Class object @@ -1145,6 +1095,10 @@ public abstract class ClassLoader { * built-in to the virtual machine is searched. That failing, this method * will invoke {@link #findResource(String)} to find the resource.

      * + * @apiNote When overriding this method it is recommended that an + * implementation ensures that any delegation is consistent with the {@link + * #getResources(java.lang.String) getResources(String)} method. + * * @param name * The resource name * @@ -1178,6 +1132,13 @@ public abstract class ClassLoader { *

      The search order is described in the documentation for {@link * #getResource(String)}.

      * + * @apiNote When overriding this method it is recommended that an + * implementation ensures that any delegation is consistent with the {@link + * #getResource(java.lang.String) getResource(String)} method. This should + * ensure that the first element returned by the Enumeration's + * {@code nextElement} method is the same resource that the + * {@code getResource(String)} method would return. + * * @param name * The resource name * @@ -1194,7 +1155,8 @@ public abstract class ClassLoader { * @since 1.2 */ public Enumeration getResources(String name) throws IOException { - Enumeration[] tmp = new Enumeration[2]; + @SuppressWarnings("unchecked") + Enumeration[] tmp = (Enumeration[]) new Enumeration[2]; if (parent != null) { tmp[0] = parent.getResources(name); } else { @@ -1207,7 +1169,7 @@ public abstract class ClassLoader { /** * Finds the resource with the given name. Class loader implementations - * should override this method to specify where to find resources.

      + * should override this method to specify where to find resources. * * @param name * The resource name @@ -1225,7 +1187,7 @@ public abstract class ClassLoader { * Returns an enumeration of {@link java.net.URL URL} objects * representing all the resources with the given name. Class loader * implementations should override this method to specify where to load - * resources from.

      + * resources from. * * @param name * The resource name @@ -1243,14 +1205,16 @@ public abstract class ClassLoader { } /** - * Registers the caller as parallel capable.

      + * Registers the caller as parallel capable. * The registration succeeds if and only if all of the following - * conditions are met:
      - * 1. no instance of the caller has been created

      - * 2. all of the super classes (except class Object) of the caller are - * registered as parallel capable

      - * Note that once a class loader is registered as parallel capable, there - * is no way to change it back.

      + * conditions are met: + *
        + *
      1. no instance of the caller has been created
      2. + *
      3. all of the super classes (except class Object) of the caller are + * registered as parallel capable
      4. + *
      + *

      Note that once a class loader is registered as parallel capable, there + * is no way to change it back.

      * * @return true if the caller is successfully registered as * parallel capable and false if otherwise. @@ -1267,7 +1231,7 @@ public abstract class ClassLoader { /** * Find a resource of the specified name from the search path used to load * classes. This method locates the resource through the system class - * loader (see {@link #getSystemClassLoader()}).

      + * loader (see {@link #getSystemClassLoader()}). * * @param name * The resource name @@ -1358,7 +1322,7 @@ public abstract class ClassLoader { /** * Open for reading, a resource of the specified name from the search path * used to load classes. This method locates the resource through the - * system class loader (see {@link #getSystemClassLoader()}).

      + * system class loader (see {@link #getSystemClassLoader()}). * * @param name * The resource name @@ -1411,6 +1375,9 @@ public abstract class ClassLoader { return null; SecurityManager sm = System.getSecurityManager(); if (sm != null) { + // Check access to the parent class loader + // If the caller's class loader is same as this class loader, + // permission check is performed. checkClassLoaderPermission(parent, Reflection.getCallerClass()); } return parent; @@ -1554,6 +1521,11 @@ public abstract class ClassLoader { return caller.getClassLoader0(); } + /* + * Checks RuntimePermission("getClassLoader") permission + * if caller's class loader is not null and caller's class loader + * is not the same as or an ancestor of the given cl argument. + */ static void checkClassLoaderPermission(ClassLoader cl, Class caller) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { @@ -1581,7 +1553,7 @@ public abstract class ClassLoader { * class loaders to define the packages for their classes. Packages must * be created before the class is defined, and package names must be * unique within a class loader and cannot be redefined or changed once - * created.

      + * created. * * @param name * The package name @@ -1638,7 +1610,7 @@ public abstract class ClassLoader { /** * Returns a Package that has been defined by this class loader - * or any of its ancestors.

      + * or any of its ancestors. * * @param name * The package name @@ -1675,7 +1647,7 @@ public abstract class ClassLoader { /** * Returns all of the Packages defined by this class loader and - * its ancestors.

      + * its ancestors. * * @return The array of Package objects defined by this * ClassLoader @@ -1712,7 +1684,7 @@ public abstract class ClassLoader { * method to locate the native libraries that belong to classes loaded with * this class loader. If this method returns null, the VM * searches the library along the path specified as the - * "java.library.path" property.

      + * "java.library.path" property. * * @param libname * The library name @@ -1750,22 +1722,29 @@ public abstract class ClassLoader { private int jniVersion; // the class from which the library is loaded, also indicates // the loader this native library belongs. - Class fromClass; + private final Class fromClass; // the canonicalized name of the native library. + // or static library name String name; + // Indicates if the native library is linked into the VM + boolean isBuiltin; + // Indicates if the native library is loaded + boolean loaded; + native void load(String name, boolean isBuiltin); - native void load(String name); native long find(String name); - native void unload(); + native void unload(String name, boolean isBuiltin); + static native String findBuiltinLib(String name); - public NativeLibrary(Class fromClass, String name) { + public NativeLibrary(Class fromClass, String name, boolean isBuiltin) { this.name = name; this.fromClass = fromClass; + this.isBuiltin = isBuiltin; } protected void finalize() { synchronized (loadedLibraryNames) { - if (fromClass.getClassLoader() != null && handle != 0) { + if (fromClass.getClassLoader() != null && loaded) { /* remove the native library name */ int size = loadedLibraryNames.size(); for (int i = 0; i < size; i++) { @@ -1777,7 +1756,7 @@ public abstract class ClassLoader { /* unload the library. */ ClassLoader.nativeLibraryContext.push(this); try { - unload(); + unload(name, isBuiltin); } finally { ClassLoader.nativeLibraryContext.pop(); } @@ -1786,7 +1765,7 @@ public abstract class ClassLoader { } // Invoked in the VM to determine the context class in // JNI_Load/JNI_Unload - static Class getFromClass() { + static Class getFromClass() { return ClassLoader.nativeLibraryContext.peek().fromClass; } } @@ -1849,7 +1828,7 @@ public abstract class ClassLoader { } // Invoked in the java.lang.Runtime class to implement load and loadLibrary. - static void loadLibrary(Class fromClass, String name, + static void loadLibrary(Class fromClass, String name, boolean isAbsolute) { ClassLoader loader = (fromClass == null) ? null : fromClass.getClassLoader(); @@ -1882,6 +1861,10 @@ public abstract class ClassLoader { if (loadLibrary0(fromClass, libfile)) { return; } + libfile = ClassLoaderHelper.mapAlternativeName(libfile); + if (libfile != null && loadLibrary0(fromClass, libfile)) { + return; + } } if (loader != null) { for (int i = 0 ; i < usr_paths.length ; i++) { @@ -1890,38 +1873,35 @@ public abstract class ClassLoader { if (loadLibrary0(fromClass, libfile)) { return; } + libfile = ClassLoaderHelper.mapAlternativeName(libfile); + if (libfile != null && loadLibrary0(fromClass, libfile)) { + return; + } } } // Oops, it failed throw new UnsatisfiedLinkError("no " + name + " in java.library.path"); } - private static boolean loadLibrary0(Class fromClass, final File file) { - if (loadLibrary1(fromClass, file)) { - return true; - } - final File libfile = ClassLoaderHelper.mapAlternativeName(file); - if (libfile != null && loadLibrary1(fromClass, libfile)) { - return true; - } - return false; - } - - private static boolean loadLibrary1(Class fromClass, final File file) { - boolean exists = AccessController.doPrivileged( - new PrivilegedAction() { - public Object run() { - return file.exists() ? Boolean.TRUE : null; - }}) - != null; - if (!exists) { - return false; - } - String name; - try { - name = file.getCanonicalPath(); - } catch (IOException e) { - return false; + private static boolean loadLibrary0(Class fromClass, final File file) { + // Check to see if we're attempting to access a static library + String name = NativeLibrary.findBuiltinLib(file.getName()); + boolean isBuiltin = (name != null); + if (!isBuiltin) { + boolean exists = AccessController.doPrivileged( + new PrivilegedAction() { + public Object run() { + return file.exists() ? Boolean.TRUE : null; + }}) + != null; + if (!exists) { + return false; + } + try { + name = file.getCanonicalPath(); + } catch (IOException e) { + return false; + } } ClassLoader loader = (fromClass == null) ? null : fromClass.getClassLoader(); @@ -1969,14 +1949,14 @@ public abstract class ClassLoader { } } } - NativeLibrary lib = new NativeLibrary(fromClass, name); + NativeLibrary lib = new NativeLibrary(fromClass, name, isBuiltin); nativeLibraryContext.push(lib); try { - lib.load(name); + lib.load(name, isBuiltin); } finally { nativeLibraryContext.pop(); } - if (lib.handle != 0) { + if (lib.loaded) { loadedLibraryNames.addElement(name); libs.addElement(lib); return true; @@ -2032,7 +2012,7 @@ public abstract class ClassLoader { * in the future will have assertions enabled or disabled by default. * This setting may be overridden on a per-package or per-class basis by * invoking {@link #setPackageAssertionStatus(String, boolean)} or {@link - * #setClassAssertionStatus(String, boolean)}.

      + * #setClassAssertionStatus(String, boolean)}. * * @param enabled * true if classes loaded by this class loader will @@ -2134,7 +2114,6 @@ public abstract class ClassLoader { * status settings associated with the class loader. This method is * provided so that class loaders can be made to ignore any command line or * persistent assertion status settings and "start with a clean slate." - *

      * * @since 1.4 */ @@ -2251,8 +2230,8 @@ class SystemClassLoaderAction return parent; } - Constructor ctor = Class.forName(cls, true, parent) - .getDeclaredConstructor(new Class[] { ClassLoader.class }); + Constructor ctor = Class.forName(cls, true, parent) + .getDeclaredConstructor(new Class[] { ClassLoader.class }); ClassLoader sys = (ClassLoader) ctor.newInstance( new Object[] { parent }); Thread.currentThread().setContextClassLoader(sys); diff --git a/external/ikvm/openjdk/java/lang/ClassSerializationProxy.java b/external/ikvm/openjdk/java/lang/ClassSerializationProxy.java new file mode 100644 index 0000000000..aae7675810 --- /dev/null +++ b/external/ikvm/openjdk/java/lang/ClassSerializationProxy.java @@ -0,0 +1,85 @@ +/* + Copyright (C) 2009-2015 Jeroen Frijters + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jeroen Frijters + jeroen@frijters.net + +*/ +package java.lang; + +import cli.System.Runtime.Serialization.IObjectReference; +import cli.System.Runtime.Serialization.SerializationException; +import cli.System.Runtime.Serialization.StreamingContext; + +@cli.System.SerializableAttribute.Annotation +final class ClassSerializationProxy implements IObjectReference +{ + private cli.System.Type type; + private String sig; + + @cli.System.Security.SecurityCriticalAttribute.Annotation + public Object GetRealObject(StreamingContext context) + { + if (sig != null) + { + if (sig.length() == 1) + { + switch (sig.charAt(0)) + { + case 'B': + return Byte.TYPE; + case 'C': + return Character.TYPE; + case 'D': + return Double.TYPE; + case 'F': + return Float.TYPE; + case 'I': + return Integer.TYPE; + case 'J': + return Long.TYPE; + case 'S': + return Short.TYPE; + case 'Z': + return Boolean.TYPE; + case 'V': + return Void.TYPE; + } + } + String className; + if (sig.charAt(0) == 'L') + { + className = sig.substring(1, sig.length() - 1); + } + else + { + className = sig; + } + try + { + return Class.forName(className, false, Thread.currentThread().getContextClassLoader()); + } + catch (ClassNotFoundException x) + { + ikvm.runtime.Util.throwException(new SerializationException(x.getMessage(), x)); + } + } + return ikvm.runtime.Util.getClassFromTypeHandle(type.get_TypeHandle()); + } +} diff --git a/external/ikvm/openjdk/java/lang/StringHelper.java.REMOVED.git-id b/external/ikvm/openjdk/java/lang/StringHelper.java.REMOVED.git-id index ac1488b4a3..d00acfbe2b 100644 --- a/external/ikvm/openjdk/java/lang/StringHelper.java.REMOVED.git-id +++ b/external/ikvm/openjdk/java/lang/StringHelper.java.REMOVED.git-id @@ -1 +1 @@ -98f7816c72a28907d154c1848447b1fda97ef6ca \ No newline at end of file +de318623b06f63349c8a73909bc6fac4716b99ec \ No newline at end of file diff --git a/external/ikvm/openjdk/java/lang/System.java b/external/ikvm/openjdk/java/lang/System.java index e74187b9d3..796d99dcb2 100644 --- a/external/ikvm/openjdk/java/lang/System.java +++ b/external/ikvm/openjdk/java/lang/System.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,24 +25,30 @@ package java.lang; import java.io.*; +import java.lang.reflect.Executable; +import java.lang.annotation.Annotation; +import java.security.AccessControlContext; import java.util.Properties; import java.util.PropertyPermission; import java.util.StringTokenizer; +import java.util.Map; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.AllPermission; import java.nio.channels.Channel; import java.nio.channels.spi.SelectorProvider; +import sun.nio.ch.Interruptible; import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.security.util.SecurityConstants; +import sun.reflect.annotation.AnnotationType; final class StdIO { private StdIO() { } static InputStream in = new BufferedInputStream(new FileInputStream(FileDescriptor.in)); - static PrintStream out = new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.out), 128), true); - static PrintStream err = new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.err), 128), true); + static PrintStream out = System.newPrintStream(new FileOutputStream(FileDescriptor.out), Props.props.getProperty("sun.stdout.encoding")); + static PrintStream err = System.newPrintStream(new FileOutputStream(FileDescriptor.err), Props.props.getProperty("sun.stderr.encoding")); } final class Props @@ -85,6 +91,18 @@ final class Props */ public final class System { + /* register the natives via the static initializer. + * + * VM will invoke the initializeSystemClass method to complete + * the initialization for this class separated from clinit. + * Note that to use properties set by the VM, see the constraints + * described in the initializeSystemClass method. + */ + private static native void registerNatives(); + static { + //registerNatives(); + } + /** Don't let anyone instantiate this class */ private System() { } @@ -96,10 +114,8 @@ public final class System { * the host environment or user. */ @ikvm.lang.Property(get="get_in") - public final static InputStream in; - - static { in = null; } - + public final static InputStream in = null; + private static InputStream get_in() { return StdIO.in; @@ -131,10 +147,8 @@ public final class System { * @see java.io.PrintStream#println(java.lang.String) */ @ikvm.lang.Property(get="get_out") - public final static PrintStream out; - - static { out = null; } - + public final static PrintStream out = null; + private static PrintStream get_out() { return StdIO.out; @@ -153,9 +167,7 @@ public final class System { * destination that is typically not continuously monitored. */ @ikvm.lang.Property(get="get_err") - public final static PrintStream err; - - static { err = null ; } + public final static PrintStream err = null; private static PrintStream get_err() { @@ -164,7 +176,7 @@ public final class System { /* The security manager for the system. */ - private static volatile SecurityManager security; + private static volatile SecurityManager security = null; /** * Reassigns the "standard" input stream. @@ -188,7 +200,7 @@ public final class System { */ public static void setIn(InputStream in) { checkIO(); - StdIO.in = in; + setIn0(in); } /** @@ -212,7 +224,7 @@ public final class System { */ public static void setOut(PrintStream out) { checkIO(); - StdIO.out = out; + setOut0(out); } /** @@ -236,10 +248,10 @@ public final class System { */ public static void setErr(PrintStream err) { checkIO(); - StdIO.err = err; + setErr0(err); } - private static volatile Console cons; + private static volatile Console cons = null; /** * Returns the unique {@link java.io.Console Console} object associated * with the current Java virtual machine, if any. @@ -293,6 +305,10 @@ public final class System { } } + private static native void setIn0(InputStream in); + private static native void setOut0(PrintStream out); + private static native void setErr0(PrintStream err); + /** * Sets the System security. * @@ -576,7 +592,12 @@ public final class System { * */ - //private static native Properties initProperties(Properties props); + @ikvm.lang.Property(get="get_props", set="set_props") + private static Properties props; + private static native Properties initProperties(Properties props); + + private static Properties get_props() { return Props.props; } + private static void set_props(Properties value) { Props.props = value; } /** * Determines the current system properties. @@ -597,7 +618,7 @@ public final class System { * java.version * Java Runtime Environment version * java.vendor - * Java Runtime Environment vendorJava Runtime Environment vendor * java.vendor.url * Java vendor URL * java.home @@ -631,7 +652,10 @@ public final class System { * java.compiler * Name of JIT compiler to use * java.ext.dirs - * Path of extension directory or directories + * Path of extension directory or directories + * Deprecated. This property, and the mechanism + * which implements it, may be removed in a future + * release. * os.name * Operating system name * os.arch @@ -674,7 +698,7 @@ public final class System { sm.checkPropertiesAccess(); } - return Props.props; + return props; } /** @@ -684,11 +708,20 @@ public final class System { * *

      On UNIX systems, it returns {@code "\n"}; on Microsoft * Windows systems it returns {@code "\r\n"}. + * + * @return the system-dependent line separator string + * @since 1.7 */ public static String lineSeparator() { - return Props.lineSeparator; + return lineSeparator; } + @ikvm.lang.Property(get="get_lineSeparator", set="set_lineSeparator") + private static String lineSeparator; + + private static String get_lineSeparator() { return Props.lineSeparator; } + private static void set_lineSeparator(String value) { Props.lineSeparator = value; } + /** * Sets the system properties to the Properties * argument. @@ -718,9 +751,9 @@ public final class System { } if (props == null) { props = new Properties(); - VMSystemProperties.initProperties(props); + initProperties(props); } - Props.props = props; + System.props = props; } /** @@ -756,7 +789,7 @@ public final class System { sm.checkPropertyAccess(key); } - return Props.props.getProperty(key); + return props.getProperty(key); } /** @@ -792,7 +825,7 @@ public final class System { sm.checkPropertyAccess(key); } - return Props.props.getProperty(key, def); + return props.getProperty(key, def); } /** @@ -832,7 +865,7 @@ public final class System { SecurityConstants.PROPERTY_WRITE_ACTION)); } - return (String) Props.props.setProperty(key, value); + return (String) props.setProperty(key, value); } /** @@ -869,7 +902,7 @@ public final class System { sm.checkPermission(new PropertyPermission(key, "write")); } - return (String) Props.props.remove(key); + return (String) props.remove(key); } private static void checkKey(String key) { @@ -1081,13 +1114,25 @@ public final class System { */ @Deprecated public static void runFinalizersOnExit(boolean value) { - Runtime.getRuntime().runFinalizersOnExit(value); + Runtime.runFinalizersOnExit(value); } /** - * Loads a code file with the specified filename from the local file - * system as a dynamic library. The filename - * argument must be a complete path name. + * Loads the native library specified by the filename argument. The filename + * argument must be an absolute path name. + * + * If the filename argument, when stripped of any platform-specific library + * prefix, path, and file extension, indicates a library whose name is, + * for example, L, and a native library called L is statically linked + * with the VM, then the JNI_OnLoad_L function exported by the library + * is invoked rather than attempting to load a dynamic library. + * A filename matching the argument does not have to exist in the + * file system. + * See the JNI Specification for more details. + * + * Otherwise, the filename argument is mapped to a native library image in + * an implementation-dependent manner. + * *

      * The call System.load(name) is effectively equivalent * to the call: @@ -1099,7 +1144,10 @@ public final class System { * @exception SecurityException if a security manager exists and its * checkLink method doesn't allow * loading of the specified dynamic library - * @exception UnsatisfiedLinkError if the file does not exist. + * @exception UnsatisfiedLinkError if either the filename is not an + * absolute path name, the native library is not statically + * linked with the VM, or the library cannot be mapped to + * a native library image by the host system. * @exception NullPointerException if filename is * null * @see java.lang.Runtime#load(java.lang.String) @@ -1111,9 +1159,16 @@ public final class System { } /** - * Loads the system library specified by the libname - * argument. The manner in which a library name is mapped to the - * actual system library is system dependent. + * Loads the native library specified by the libname + * argument. The libname argument must not contain any platform + * specific prefix, file extension or path. If a native library + * called libname is statically linked with the VM, then the + * JNI_OnLoad_libname function exported by the library is invoked. + * See the JNI Specification for more details. + * + * Otherwise, the libname argument is loaded from a system library + * location and mapped to a native library image in an implementation- + * dependent manner. *

      * The call System.loadLibrary(name) is effectively * equivalent to the call @@ -1125,7 +1180,10 @@ public final class System { * @exception SecurityException if a security manager exists and its * checkLink method doesn't allow * loading of the specified dynamic library - * @exception UnsatisfiedLinkError if the library does not exist. + * @exception UnsatisfiedLinkError if either the libname argument + * contains a file path, the native library is not statically + * linked with the VM, or the library cannot be mapped to a + * native library image by the host system. * @exception NullPointerException if libname is * null * @see java.lang.Runtime#loadLibrary(java.lang.String) @@ -1148,21 +1206,17 @@ public final class System { * @see java.lang.ClassLoader#findLibrary(java.lang.String) * @since 1.2 */ - public static String mapLibraryName(String libname) { - if (libname == null) { - throw new NullPointerException(); + public static native String mapLibraryName(String libname); + + /** + * Create PrintStream for stdout/err based on encoding. + */ + /*private*/ static PrintStream newPrintStream(FileOutputStream fos, String enc) { + if (enc != null) { + try { + return new PrintStream(new BufferedOutputStream(fos, 128), true, enc); + } catch (UnsupportedEncodingException uee) {} } - if (ikvm.internal.Util.WINDOWS) { - return libname + ".dll"; - } else if (ikvm.internal.Util.MACOSX) { - return "lib" + libname + ".jnilib"; - } else { - return "lib" + libname + ".so"; - } - } - /* returns the class of the caller. */ - static Class getCallerClass() { - // NOTE use of more generic Reflection.getCallerClass() - return Reflection.getCallerClass(3); + return new PrintStream(new BufferedOutputStream(fos, 128), true); } } diff --git a/external/ikvm/openjdk/java/lang/Thread.java.REMOVED.git-id b/external/ikvm/openjdk/java/lang/Thread.java.REMOVED.git-id index e6d930d530..406c714833 100644 --- a/external/ikvm/openjdk/java/lang/Thread.java.REMOVED.git-id +++ b/external/ikvm/openjdk/java/lang/Thread.java.REMOVED.git-id @@ -1 +1 @@ -0ed6057830f61276302f31aec193002ca38ab39a \ No newline at end of file +1341a0148621a18e4c88e2815a5d0e8f837fa015 \ No newline at end of file diff --git a/external/ikvm/openjdk/java/lang/VMSystemProperties.java b/external/ikvm/openjdk/java/lang/VMSystemProperties.java index c982e2dd0c..5c79248b65 100644 --- a/external/ikvm/openjdk/java/lang/VMSystemProperties.java +++ b/external/ikvm/openjdk/java/lang/VMSystemProperties.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2004-2011 Jeroen Frijters + Copyright (C) 2004-2015 Jeroen Frijters This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -24,6 +24,7 @@ package java.lang; import java.util.Properties; +import cli.System.Diagnostics.FileVersionInfo; import static ikvm.internal.Util.SafeGetEnvironmentVariable; final class VMSystemProperties @@ -31,7 +32,7 @@ final class VMSystemProperties private VMSystemProperties() { } public static final String SPEC_TITLE = "Java Platform API Specification"; - public static final String SPEC_VERSION = "1.7"; + public static final String SPEC_VERSION = "1.8"; public static final String SPEC_VENDOR = "Oracle Corporation"; private static String getLibraryPath() @@ -114,11 +115,11 @@ final class VMSystemProperties private static void initCommonProperties(Properties p) { - p.setProperty("java.version", "1.7.0"); + p.setProperty("java.version", "1.8.0"); p.setProperty("java.vendor", "Jeroen Frijters"); p.setProperty("java.vendor.url", "http://ikvm.net/"); p.setProperty("java.vendor.url.bug", "http://www.ikvm.net/bugs"); - p.setProperty("java.vm.specification.version", "1.7"); + p.setProperty("java.vm.specification.version", "1.8"); p.setProperty("java.vm.specification.vendor", "Oracle Corporation"); p.setProperty("java.vm.specification.name", "Java Virtual Machine Specification"); p.setProperty("java.vm.version", PropertyConstants.java_vm_version); @@ -129,7 +130,7 @@ final class VMSystemProperties p.setProperty("java.specification.version", SPEC_VERSION); p.setProperty("java.specification.vendor", SPEC_VENDOR); p.setProperty("java.specification.name", SPEC_TITLE); - p.setProperty("java.class.version", "51.0"); + p.setProperty("java.class.version", "52.0"); p.setProperty("java.class.path", ""); p.setProperty("java.library.path", getLibraryPath()); try @@ -152,6 +153,13 @@ final class VMSystemProperties switch(os.get_Platform().Value) { case cli.System.PlatformID.Win32NT: + // Windows lies about the version, so we extract the real version from kernel32.dll + FileVersionInfo kernel32 = getKernel32FileVersionInfo(); + if (kernel32 != null) + { + major = kernel32.get_ProductMajorPart(); + minor = kernel32.get_ProductMinorPart(); + } osname = "Windows NT (unknown)"; switch(major) { @@ -189,6 +197,23 @@ final class VMSystemProperties osver = "6.1"; osname = "Windows 7"; break; + case 2: + osver = "6.2"; + osname = "Windows 8"; + break; + case 3: + osver = "6.3"; + osname = "Windows 8.1"; + break; + } + break; + case 10: + switch(minor) + { + case 0: + osver = "10.0"; + osname = "Windows 10"; + break; } break; } @@ -322,12 +347,32 @@ final class VMSystemProperties p.setProperty("sun.nio.MaxDirectMemorySize", "-1"); p.setProperty("java.awt.graphicsenv", PropertyConstants.java_awt_graphicsenv); p.setProperty("java.awt.printerjob", "sun.awt.windows.WPrinterJob"); + + String stdoutEncoding = getStdoutEncoding(); + if(stdoutEncoding != null) + { + p.setProperty("sun.stdout.encoding", stdoutEncoding); + } + String stderrEncoding = getStderrEncoding(); + if(stderrEncoding != null) + { + p.setProperty("sun.stderr.encoding", stderrEncoding); + } + + if(ikvm.internal.Util.MACOSX) + { + p.setProperty("sun.jnu.encoding", "UTF-8"); + } + else + { + p.setProperty("sun.jnu.encoding", cli.System.Text.Encoding.get_Default().get_WebName()); + } + // TODO // sun.cpu.isalist:=pentium_pro+mmx pentium_pro pentium+mmx pentium i486 i386 i86 // sun.desktop:=windows // sun.io.unicode.encoding:=UnicodeLittle - // sun.jnu.encoding:=Cp1252 // sun.management.compiler:=HotSpot Client Compiler try { @@ -418,4 +463,7 @@ final class VMSystemProperties private static native String getVirtualFileSystemRoot(); private static native String getBootClassPath(); + private static native String getStdoutEncoding(); + private static native String getStderrEncoding(); + private static native FileVersionInfo getKernel32FileVersionInfo(); } diff --git a/external/ikvm/openjdk/java/lang/invoke/LightWeightMethodHandle.java b/external/ikvm/openjdk/java/lang/invoke/LightWeightMethodHandle.java new file mode 100644 index 0000000000..7476ab7428 --- /dev/null +++ b/external/ikvm/openjdk/java/lang/invoke/LightWeightMethodHandle.java @@ -0,0 +1,47 @@ +/* + Copyright (C) 2015 Jeroen Frijters + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jeroen Frijters + jeroen@frijters.net + +*/ +package java.lang.invoke; + +/* + * This class represents a MethodHandle to an IKVM specific LambdaForm. + */ +final class LightWeightMethodHandle extends MethodHandle +{ + LightWeightMethodHandle(MethodType type, LambdaForm form) + { + super(type, form); + } + + @Override + BoundMethodHandle rebind() + { + return BoundMethodHandle.makeReinvoker(this); + } + + @Override + MethodHandle copyWith(MethodType type, LambdaForm form) + { + return new LightWeightMethodHandle(type, form); + } +} diff --git a/external/ikvm/openjdk/java/lang/reflect/Constructor.java b/external/ikvm/openjdk/java/lang/reflect/Constructor.java index b13d30a543..9e01975de0 100644 --- a/external/ikvm/openjdk/java/lang/reflect/Constructor.java +++ b/external/ikvm/openjdk/java/lang/reflect/Constructor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,15 +28,14 @@ package java.lang.reflect; import sun.reflect.CallerSensitive; import sun.reflect.ConstructorAccessor; import sun.reflect.Reflection; +import sun.reflect.annotation.TypeAnnotation; +import sun.reflect.annotation.TypeAnnotationParser; import sun.reflect.generics.repository.ConstructorRepository; import sun.reflect.generics.factory.CoreReflectionFactory; import sun.reflect.generics.factory.GenericsFactory; import sun.reflect.generics.scope.ConstructorScope; import java.lang.annotation.Annotation; -import java.util.Map; -import sun.reflect.annotation.AnnotationParser; import java.lang.annotation.AnnotationFormatError; -import java.lang.reflect.Modifier; /** * {@code Constructor} provides information about, and access to, a single @@ -58,11 +57,7 @@ import java.lang.reflect.Modifier; * @author Kenneth Russell * @author Nakul Saraiya */ -public final - class Constructor extends AccessibleObject implements - GenericDeclaration, - Member { - +public final class Constructor extends Executable { private Class clazz; private int slot; private Class[] parameterTypes; @@ -81,7 +76,8 @@ public final } // Accessor for generic info repository - private ConstructorRepository getGenericInfo() { + @Override + ConstructorRepository getGenericInfo() { // lazily initialize repository if necessary if (genericInfo == null) { // create and cache generic info repository @@ -96,8 +92,19 @@ public final // For sharing of ConstructorAccessors. This branching structure // is currently only two levels deep (i.e., one root Constructor // and potentially many Constructor objects pointing to it.) + // + // If this branching structure would ever contain cycles, deadlocks can + // occur in annotation code. private Constructor root; + /** + * Used by Excecutable for annotation sharing. + */ + @Override + Executable getRoot() { + return root; + } + /** * Package-private constructor used by ReflectAccess to enable * instantiation of these objects in Java code from the java.lang @@ -110,8 +117,7 @@ public final int slot, String signature, byte[] unused1, - byte[] unused2) - { + byte[] unused2) { this.clazz = declaringClass; this.parameterTypes = parameterTypes; this.exceptionTypes = checkedExceptions; @@ -133,22 +139,30 @@ public final // which implicitly requires that new java.lang.reflect // objects be fabricated for each reflective call on Class // objects.) + if (this.root != null) + throw new IllegalArgumentException("Can not copy a non-root Constructor"); + Constructor res = new Constructor<>(clazz, - parameterTypes, - exceptionTypes, modifiers, slot, - signature, - null, - null); + parameterTypes, + exceptionTypes, modifiers, slot, + signature, + null, + null); res.root = this; // Might as well eagerly propagate this if already present res.constructorAccessor = constructorAccessor; return res; } + @Override + boolean hasGenericInformation() { + return (getSignature() != null); + } + /** - * Returns the {@code Class} object representing the class that declares - * the constructor represented by this {@code Constructor} object. + * {@inheritDoc} */ + @Override public Class getDeclaringClass() { return clazz; } @@ -157,36 +171,26 @@ public final * Returns the name of this constructor, as a string. This is * the binary name of the constructor's declaring class. */ + @Override public String getName() { return getDeclaringClass().getName(); } /** - * Returns the Java language modifiers for the constructor - * represented by this {@code Constructor} object, as an integer. The - * {@code Modifier} class should be used to decode the modifiers. - * - * @see Modifier + * {@inheritDoc} */ + @Override public int getModifiers() { return modifiers; } /** - * Returns an array of {@code TypeVariable} objects that represent the - * type variables declared by the generic declaration represented by this - * {@code GenericDeclaration} object, in declaration order. Returns an - * array of length 0 if the underlying generic declaration declares no type - * variables. - * - * @return an array of {@code TypeVariable} objects that represent - * the type variables declared by this generic declaration - * @throws GenericSignatureFormatError if the generic - * signature of this generic declaration does not conform to - * the format specified in - * The Java™ Virtual Machine Specification + * {@inheritDoc} + * @throws GenericSignatureFormatError {@inheritDoc} * @since 1.5 */ + @Override + @SuppressWarnings({"rawtypes", "unchecked"}) public TypeVariable>[] getTypeParameters() { if (getSignature() != null) { return (TypeVariable>[])getGenericInfo().getTypeParameters(); @@ -196,98 +200,50 @@ public final /** - * Returns an array of {@code Class} objects that represent the formal - * parameter types, in declaration order, of the constructor - * represented by this {@code Constructor} object. Returns an array of - * length 0 if the underlying constructor takes no parameters. - * - * @return the parameter types for the constructor this object - * represents + * {@inheritDoc} */ + @Override public Class[] getParameterTypes() { - return (Class[]) parameterTypes.clone(); + return parameterTypes.clone(); } + /** + * {@inheritDoc} + */ + public int getParameterCount() { return parameterTypes.length; } /** - * Returns an array of {@code Type} objects that represent the formal - * parameter types, in declaration order, of the method represented by - * this {@code Constructor} object. Returns an array of length 0 if the - * underlying method takes no parameters. - * - *

      If a formal parameter type is a parameterized type, - * the {@code Type} object returned for it must accurately reflect - * the actual type parameters used in the source code. - * - *

      If a formal parameter type is a type variable or a parameterized - * type, it is created. Otherwise, it is resolved. - * - * @return an array of {@code Type}s that represent the formal - * parameter types of the underlying method, in declaration order - * @throws GenericSignatureFormatError - * if the generic method signature does not conform to the format - * specified in - * The Java™ Virtual Machine Specification - * @throws TypeNotPresentException if any of the parameter - * types of the underlying method refers to a non-existent type - * declaration - * @throws MalformedParameterizedTypeException if any of - * the underlying method's parameter types refer to a parameterized - * type that cannot be instantiated for any reason + * {@inheritDoc} + * @throws GenericSignatureFormatError {@inheritDoc} + * @throws TypeNotPresentException {@inheritDoc} + * @throws MalformedParameterizedTypeException {@inheritDoc} * @since 1.5 */ + @Override public Type[] getGenericParameterTypes() { - if (getSignature() != null) - return getGenericInfo().getParameterTypes(); - else - return getParameterTypes(); + return super.getGenericParameterTypes(); } - /** - * Returns an array of {@code Class} objects that represent the types - * of exceptions declared to be thrown by the underlying constructor - * represented by this {@code Constructor} object. Returns an array of - * length 0 if the constructor declares no exceptions in its {@code throws} clause. - * - * @return the exception types declared as being thrown by the - * constructor this object represents + * {@inheritDoc} */ + @Override public Class[] getExceptionTypes() { - return (Class[])exceptionTypes.clone(); + return exceptionTypes.clone(); } /** - * Returns an array of {@code Type} objects that represent the - * exceptions declared to be thrown by this {@code Constructor} object. - * Returns an array of length 0 if the underlying method declares - * no exceptions in its {@code throws} clause. - * - *

      If an exception type is a type variable or a parameterized - * type, it is created. Otherwise, it is resolved. - * - * @return an array of Types that represent the exception types - * thrown by the underlying method - * @throws GenericSignatureFormatError - * if the generic method signature does not conform to the format - * specified in - * The Java™ Virtual Machine Specification - * @throws TypeNotPresentException if the underlying method's - * {@code throws} clause refers to a non-existent type declaration - * @throws MalformedParameterizedTypeException if - * the underlying method's {@code throws} clause refers to a - * parameterized type that cannot be instantiated for any reason + * {@inheritDoc} + * @throws GenericSignatureFormatError {@inheritDoc} + * @throws TypeNotPresentException {@inheritDoc} + * @throws MalformedParameterizedTypeException {@inheritDoc} * @since 1.5 */ - public Type[] getGenericExceptionTypes() { - Type[] result; - if (getSignature() != null && - ( (result = getGenericInfo().getExceptionTypes()).length > 0 )) - return result; - else - return getExceptionTypes(); - } + @Override + public Type[] getGenericExceptionTypes() { + return super.getGenericExceptionTypes(); + } /** * Compares this {@code Constructor} against the specified object. @@ -299,16 +255,7 @@ public final if (obj != null && obj instanceof Constructor) { Constructor other = (Constructor)obj; if (getDeclaringClass() == other.getDeclaringClass()) { - /* Avoid unnecessary cloning */ - Class[] params1 = parameterTypes; - Class[] params2 = other.parameterTypes; - if (params1.length == params2.length) { - for (int i = 0; i < params1.length; i++) { - if (params1[i] != params2[i]) - return false; - } - return true; - } + return equalParamTypes(parameterTypes, other.parameterTypes); } } return false; @@ -337,36 +284,20 @@ public final * modifiers {@code public}, {@code protected} or * {@code private}. Only one of these may appear, or none if the * constructor has default (package) access. + * + * @return a string describing this {@code Constructor} + * @jls 8.8.3. Constructor Modifiers */ public String toString() { - try { - StringBuffer sb = new StringBuffer(); - int mod = getModifiers() & Modifier.constructorModifiers(); - if (mod != 0) { - sb.append(Modifier.toString(mod) + " "); - } - sb.append(Field.getTypeName(getDeclaringClass())); - sb.append("("); - Class[] params = parameterTypes; // avoid clone - for (int j = 0; j < params.length; j++) { - sb.append(Field.getTypeName(params[j])); - if (j < (params.length - 1)) - sb.append(","); - } - sb.append(")"); - Class[] exceptions = exceptionTypes; // avoid clone - if (exceptions.length > 0) { - sb.append(" throws "); - for (int k = 0; k < exceptions.length; k++) { - sb.append(exceptions[k].getName()); - if (k < (exceptions.length - 1)) - sb.append(","); - } - } - return sb.toString(); - } catch (Exception e) { - return "<" + e + ">"; - } + return sharedToString(Modifier.constructorModifiers(), + false, + parameterTypes, + exceptionTypes); + } + + @Override + void specificToStringHeader(StringBuilder sb) { + sb.append(getDeclaringClass().getTypeName()); } /** @@ -401,57 +332,16 @@ public final * include type parameters * * @since 1.5 + * @jls 8.8.3. Constructor Modifiers */ + @Override public String toGenericString() { - try { - StringBuilder sb = new StringBuilder(); - int mod = getModifiers() & Modifier.constructorModifiers(); - if (mod != 0) { - sb.append(Modifier.toString(mod) + " "); - } - TypeVariable[] typeparms = getTypeParameters(); - if (typeparms.length > 0) { - boolean first = true; - sb.append("<"); - for(TypeVariable typeparm: typeparms) { - if (!first) - sb.append(","); - // Class objects can't occur here; no need to test - // and call Class.getName(). - sb.append(typeparm.toString()); - first = false; - } - sb.append("> "); - } - sb.append(Field.getTypeName(getDeclaringClass())); - sb.append("("); - Type[] params = getGenericParameterTypes(); - for (int j = 0; j < params.length; j++) { - String param = (params[j] instanceof Class)? - Field.getTypeName((Class)params[j]): - (params[j].toString()); - if (isVarArgs() && (j == params.length - 1)) // replace T[] with T... - param = param.replaceFirst("\\[\\]$", "..."); - sb.append(param); - if (j < (params.length - 1)) - sb.append(","); - } - sb.append(")"); - Type[] exceptions = getGenericExceptionTypes(); - if (exceptions.length > 0) { - sb.append(" throws "); - for (int k = 0; k < exceptions.length; k++) { - sb.append((exceptions[k] instanceof Class)? - ((Class)exceptions[k]).getName(): - exceptions[k].toString()); - if (k < (exceptions.length - 1)) - sb.append(","); - } - } - return sb.toString(); - } catch (Exception e) { - return "<" + e + ">"; - } + return sharedToGenericString(Modifier.constructorModifiers(), false); + } + + @Override + void specificToGenericStringHeader(StringBuilder sb) { + specificToStringHeader(sb); } /** @@ -519,33 +409,28 @@ public final if (ca == null) { ca = acquireConstructorAccessor(); } - return (T) ca.newInstance(initargs); + @SuppressWarnings("unchecked") + T inst = (T) ca.newInstance(initargs); + return inst; } /** - * Returns {@code true} if this constructor was declared to take - * a variable number of arguments; returns {@code false} - * otherwise. - * - * @return {@code true} if an only if this constructor was declared to - * take a variable number of arguments. + * {@inheritDoc} * @since 1.5 */ + @Override public boolean isVarArgs() { - return (getModifiers() & Modifier.VARARGS) != 0; + return super.isVarArgs(); } /** - * Returns {@code true} if this constructor is a synthetic - * constructor; returns {@code false} otherwise. - * - * @return true if and only if this constructor is a synthetic - * constructor as defined by - * The Java™ Language Specification. + * {@inheritDoc} + * @jls 13.1 The Form of a Binary * @since 1.5 */ + @Override public boolean isSynthetic() { - return Modifier.isSynthetic(getModifiers()); + return super.isSynthetic(); } // NOTE that there is no synchronization used here. It is correct @@ -589,9 +474,9 @@ public final return slot; } - String getSignature() { - return signature; - } + String getSignature() { + return signature; + } byte[] getRawAnnotations() { return null; @@ -601,74 +486,77 @@ public final return null; } + /** - * @throws NullPointerException {@inheritDoc} + * {@inheritDoc} + * @throws NullPointerException {@inheritDoc} * @since 1.5 */ public T getAnnotation(Class annotationClass) { - if (annotationClass == null) - throw new NullPointerException(); - - return (T) declaredAnnotations().get(annotationClass); + return super.getAnnotation(annotationClass); } - private static final Annotation[] EMPTY_ANNOTATION_ARRAY=new Annotation[0]; - /** + * {@inheritDoc} * @since 1.5 */ public Annotation[] getDeclaredAnnotations() { - return declaredAnnotations().values().toArray(EMPTY_ANNOTATION_ARRAY); - } - - private transient Map, Annotation> declaredAnnotations; - - private synchronized Map, Annotation> declaredAnnotations() { - if (declaredAnnotations == null) { - declaredAnnotations = Method.getDeclaredAnnotationsImpl(this); - } - return declaredAnnotations; + return super.getDeclaredAnnotations(); } /** - * Returns an array of arrays that represent the annotations on the formal - * parameters, in declaration order, of the method represented by - * this {@code Constructor} object. (Returns an array of length zero if the - * underlying method is parameterless. If the method has one or more - * parameters, a nested array of length zero is returned for each parameter - * with no annotations.) The annotation objects contained in the returned - * arrays are serializable. The caller of this method is free to modify - * the returned arrays; it will have no effect on the arrays returned to - * other callers. - * - * @return an array of arrays that represent the annotations on the formal - * parameters, in declaration order, of the method represented by this - * Constructor object + * {@inheritDoc} * @since 1.5 */ + @Override public Annotation[][] getParameterAnnotations() { - int numParameters = parameterTypes.length; - Annotation[][] result = Method.getParameterAnnotationsImpl(this); - if (result == null) - return new Annotation[numParameters][0]; - if (result.length != numParameters) { - Class declaringClass = getDeclaringClass(); - if (declaringClass.isEnum() || - declaringClass.isAnonymousClass() || - declaringClass.isLocalClass() ) - ; // Can't do reliable parameter counting - else { - if (!declaringClass.isMemberClass() || // top-level - // Check for the enclosing instance parameter for - // non-static member classes - (declaringClass.isMemberClass() && - ((declaringClass.getModifiers() & Modifier.STATIC) == 0) && - result.length + 1 != numParameters) ) { - throw new AnnotationFormatError( - "Parameter annotations don't match number of parameters"); - } + return sharedGetParameterAnnotations(parameterTypes); + } + + @Override + void handleParameterNumberMismatch(int resultLength, int numParameters) { + Class declaringClass = getDeclaringClass(); + if (declaringClass.isEnum() || + declaringClass.isAnonymousClass() || + declaringClass.isLocalClass() ) + return ; // Can't do reliable parameter counting + else { + if (!declaringClass.isMemberClass() || // top-level + // Check for the enclosing instance parameter for + // non-static member classes + (declaringClass.isMemberClass() && + ((declaringClass.getModifiers() & Modifier.STATIC) == 0) && + resultLength + 1 != numParameters) ) { + throw new AnnotationFormatError( + "Parameter annotations don't match number of parameters"); } } - return result; + } + + /** + * {@inheritDoc} + * @since 1.8 + */ + @Override + public AnnotatedType getAnnotatedReturnType() { + return getAnnotatedReturnType0(getDeclaringClass()); + } + + /** + * {@inheritDoc} + * @since 1.8 + */ + @Override + public AnnotatedType getAnnotatedReceiverType() { + if (getDeclaringClass().getEnclosingClass() == null) + return super.getAnnotatedReceiverType(); + + return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes0(), + sun.misc.SharedSecrets.getJavaLangAccess(). + getConstantPool(getDeclaringClass()), + this, + getDeclaringClass(), + getDeclaringClass().getEnclosingClass(), + TypeAnnotation.TypeAnnotationTarget.METHOD_RECEIVER); } } diff --git a/external/ikvm/openjdk/java/lang/reflect/Executable.java b/external/ikvm/openjdk/java/lang/reflect/Executable.java new file mode 100644 index 0000000000..be6ac0dd12 --- /dev/null +++ b/external/ikvm/openjdk/java/lang/reflect/Executable.java @@ -0,0 +1,720 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang.reflect; + +import java.lang.annotation.*; +import java.util.Map; +import java.util.Objects; +import sun.reflect.annotation.AnnotationParser; +import sun.reflect.annotation.AnnotationSupport; +import sun.reflect.annotation.TypeAnnotationParser; +import sun.reflect.annotation.TypeAnnotation; +import sun.reflect.generics.repository.ConstructorRepository; + +/** + * A shared superclass for the common functionality of {@link Method} + * and {@link Constructor}. + * + * @since 1.8 + */ +public abstract class Executable extends AccessibleObject + implements Member, GenericDeclaration { + /* + * Only grant package-visibility to the constructor. + */ + Executable() {} + + /** + * Accessor method to allow code sharing + */ + abstract Executable getRoot(); + + /** + * Does the Executable have generic information. + */ + abstract boolean hasGenericInformation(); + + abstract ConstructorRepository getGenericInfo(); + + boolean equalParamTypes(Class[] params1, Class[] params2) { + /* Avoid unnecessary cloning */ + if (params1.length == params2.length) { + for (int i = 0; i < params1.length; i++) { + if (params1[i] != params2[i]) + return false; + } + return true; + } + return false; + } + + void separateWithCommas(Class[] types, StringBuilder sb) { + for (int j = 0; j < types.length; j++) { + sb.append(types[j].getTypeName()); + if (j < (types.length - 1)) + sb.append(","); + } + + } + + void printModifiersIfNonzero(StringBuilder sb, int mask, boolean isDefault) { + int mod = getModifiers() & mask; + + if (mod != 0 && !isDefault) { + sb.append(Modifier.toString(mod)).append(' '); + } else { + int access_mod = mod & Modifier.ACCESS_MODIFIERS; + if (access_mod != 0) + sb.append(Modifier.toString(access_mod)).append(' '); + if (isDefault) + sb.append("default "); + mod = (mod & ~Modifier.ACCESS_MODIFIERS); + if (mod != 0) + sb.append(Modifier.toString(mod)).append(' '); + } + } + + String sharedToString(int modifierMask, + boolean isDefault, + Class[] parameterTypes, + Class[] exceptionTypes) { + try { + StringBuilder sb = new StringBuilder(); + + printModifiersIfNonzero(sb, modifierMask, isDefault); + specificToStringHeader(sb); + + sb.append('('); + separateWithCommas(parameterTypes, sb); + sb.append(')'); + if (exceptionTypes.length > 0) { + sb.append(" throws "); + separateWithCommas(exceptionTypes, sb); + } + return sb.toString(); + } catch (Exception e) { + return "<" + e + ">"; + } + } + + /** + * Generate toString header information specific to a method or + * constructor. + */ + abstract void specificToStringHeader(StringBuilder sb); + + String sharedToGenericString(int modifierMask, boolean isDefault) { + try { + StringBuilder sb = new StringBuilder(); + + printModifiersIfNonzero(sb, modifierMask, isDefault); + + TypeVariable[] typeparms = getTypeParameters(); + if (typeparms.length > 0) { + boolean first = true; + sb.append('<'); + for(TypeVariable typeparm: typeparms) { + if (!first) + sb.append(','); + // Class objects can't occur here; no need to test + // and call Class.getName(). + sb.append(typeparm.toString()); + first = false; + } + sb.append("> "); + } + + specificToGenericStringHeader(sb); + + sb.append('('); + Type[] params = getGenericParameterTypes(); + for (int j = 0; j < params.length; j++) { + String param = params[j].getTypeName(); + if (isVarArgs() && (j == params.length - 1)) // replace T[] with T... + param = param.replaceFirst("\\[\\]$", "..."); + sb.append(param); + if (j < (params.length - 1)) + sb.append(','); + } + sb.append(')'); + Type[] exceptions = getGenericExceptionTypes(); + if (exceptions.length > 0) { + sb.append(" throws "); + for (int k = 0; k < exceptions.length; k++) { + sb.append((exceptions[k] instanceof Class)? + ((Class)exceptions[k]).getName(): + exceptions[k].toString()); + if (k < (exceptions.length - 1)) + sb.append(','); + } + } + return sb.toString(); + } catch (Exception e) { + return "<" + e + ">"; + } + } + + /** + * Generate toGenericString header information specific to a + * method or constructor. + */ + abstract void specificToGenericStringHeader(StringBuilder sb); + + /** + * Returns the {@code Class} object representing the class or interface + * that declares the executable represented by this object. + */ + public abstract Class getDeclaringClass(); + + /** + * Returns the name of the executable represented by this object. + */ + public abstract String getName(); + + /** + * Returns the Java language {@linkplain Modifier modifiers} for + * the executable represented by this object. + */ + public abstract int getModifiers(); + + /** + * Returns an array of {@code TypeVariable} objects that represent the + * type variables declared by the generic declaration represented by this + * {@code GenericDeclaration} object, in declaration order. Returns an + * array of length 0 if the underlying generic declaration declares no type + * variables. + * + * @return an array of {@code TypeVariable} objects that represent + * the type variables declared by this generic declaration + * @throws GenericSignatureFormatError if the generic + * signature of this generic declaration does not conform to + * the format specified in + * The Java™ Virtual Machine Specification + */ + public abstract TypeVariable[] getTypeParameters(); + + /** + * Returns an array of {@code Class} objects that represent the formal + * parameter types, in declaration order, of the executable + * represented by this object. Returns an array of length + * 0 if the underlying executable takes no parameters. + * + * @return the parameter types for the executable this object + * represents + */ + public abstract Class[] getParameterTypes(); + + /** + * Returns the number of formal parameters (whether explicitly + * declared or implicitly declared or neither) for the executable + * represented by this object. + * + * @since 1.8 + * @return The number of formal parameters for the executable this + * object represents + */ + public int getParameterCount() { + throw new AbstractMethodError(); + } + + /** + * Returns an array of {@code Type} objects that represent the formal + * parameter types, in declaration order, of the executable represented by + * this object. Returns an array of length 0 if the + * underlying executable takes no parameters. + * + *

      If a formal parameter type is a parameterized type, + * the {@code Type} object returned for it must accurately reflect + * the actual type parameters used in the source code. + * + *

      If a formal parameter type is a type variable or a parameterized + * type, it is created. Otherwise, it is resolved. + * + * @return an array of {@code Type}s that represent the formal + * parameter types of the underlying executable, in declaration order + * @throws GenericSignatureFormatError + * if the generic method signature does not conform to the format + * specified in + * The Java™ Virtual Machine Specification + * @throws TypeNotPresentException if any of the parameter + * types of the underlying executable refers to a non-existent type + * declaration + * @throws MalformedParameterizedTypeException if any of + * the underlying executable's parameter types refer to a parameterized + * type that cannot be instantiated for any reason + */ + public Type[] getGenericParameterTypes() { + if (hasGenericInformation()) + return getGenericInfo().getParameterTypes(); + else + return getParameterTypes(); + } + + /** + * Behaves like {@code getGenericParameterTypes}, but returns type + * information for all parameters, including synthetic parameters. + */ + Type[] getAllGenericParameterTypes() { + final boolean genericInfo = hasGenericInformation(); + + // Easy case: we don't have generic parameter information. In + // this case, we just return the result of + // getParameterTypes(). + if (!genericInfo) { + return getParameterTypes(); + } else { + final boolean realParamData = hasRealParameterData(); + final Type[] genericParamTypes = getGenericParameterTypes(); + final Type[] nonGenericParamTypes = getParameterTypes(); + final Type[] out = new Type[nonGenericParamTypes.length]; + final Parameter[] params = getParameters(); + int fromidx = 0; + // If we have real parameter data, then we use the + // synthetic and mandate flags to our advantage. + if (realParamData) { + for (int i = 0; i < out.length; i++) { + final Parameter param = params[i]; + if (param.isSynthetic() || param.isImplicit()) { + // If we hit a synthetic or mandated parameter, + // use the non generic parameter info. + out[i] = nonGenericParamTypes[i]; + } else { + // Otherwise, use the generic parameter info. + out[i] = genericParamTypes[fromidx]; + fromidx++; + } + } + } else { + // Otherwise, use the non-generic parameter data. + // Without method parameter reflection data, we have + // no way to figure out which parameters are + // synthetic/mandated, thus, no way to match up the + // indexes. + return genericParamTypes.length == nonGenericParamTypes.length ? + genericParamTypes : nonGenericParamTypes; + } + return out; + } + } + + /** + * Returns an array of {@code Parameter} objects that represent + * all the parameters to the underlying executable represented by + * this object. Returns an array of length 0 if the executable + * has no parameters. + * + *

      The parameters of the underlying executable do not necessarily + * have unique names, or names that are legal identifiers in the + * Java programming language (JLS 3.8). + * + * @since 1.8 + * @throws MalformedParametersException if the class file contains + * a MethodParameters attribute that is improperly formatted. + * @return an array of {@code Parameter} objects representing all + * the parameters to the executable this object represents. + */ + public Parameter[] getParameters() { + // TODO: This may eventually need to be guarded by security + // mechanisms similar to those in Field, Method, etc. + // + // Need to copy the cached array to prevent users from messing + // with it. Since parameters are immutable, we can + // shallow-copy. + return privateGetParameters().clone(); + } + + private Parameter[] synthesizeAllParams() { + final int realparams = getParameterCount(); + final Parameter[] out = new Parameter[realparams]; + for (int i = 0; i < realparams; i++) + // TODO: is there a way to synthetically derive the + // modifiers? Probably not in the general case, since + // we'd have no way of knowing about them, but there + // may be specific cases. + out[i] = new Parameter("arg" + i, 0, this, i); + return out; + } + + private void verifyParameters(final Parameter[] parameters) { + final int mask = Modifier.FINAL | Modifier.SYNTHETIC | Modifier.MANDATED; + + if (getParameterTypes().length != parameters.length) + throw new MalformedParametersException("Wrong number of parameters in MethodParameters attribute"); + + for (Parameter parameter : parameters) { + final String name = parameter.getRealName(); + final int mods = parameter.getModifiers(); + + if (name != null) { + if (name.isEmpty() || name.indexOf('.') != -1 || + name.indexOf(';') != -1 || name.indexOf('[') != -1 || + name.indexOf('/') != -1) { + throw new MalformedParametersException("Invalid parameter name \"" + name + "\""); + } + } + + if (mods != (mods & mask)) { + throw new MalformedParametersException("Invalid parameter modifiers"); + } + } + } + + private Parameter[] privateGetParameters() { + // Use tmp to avoid multiple writes to a volatile. + Parameter[] tmp = parameters; + + if (tmp == null) { + + // Otherwise, go to the JVM to get them + try { + tmp = getParameters0(); + } catch(IllegalArgumentException e) { + // Rethrow ClassFormatErrors + throw new MalformedParametersException("Invalid constant pool index"); + } + + // If we get back nothing, then synthesize parameters + if (tmp == null) { + hasRealParameterData = false; + tmp = synthesizeAllParams(); + } else { + hasRealParameterData = true; + verifyParameters(tmp); + } + + parameters = tmp; + } + + return tmp; + } + + boolean hasRealParameterData() { + // If this somehow gets called before parameters gets + // initialized, force it into existence. + if (parameters == null) { + privateGetParameters(); + } + return hasRealParameterData; + } + + private transient volatile boolean hasRealParameterData; + private transient volatile Parameter[] parameters; + + private native Parameter[] getParameters0(); + native byte[] getTypeAnnotationBytes0(); + + // Needed by reflectaccess + byte[] getTypeAnnotationBytes() { + return getTypeAnnotationBytes0(); + } + + /** + * Returns an array of {@code Class} objects that represent the + * types of exceptions declared to be thrown by the underlying + * executable represented by this object. Returns an array of + * length 0 if the executable declares no exceptions in its {@code + * throws} clause. + * + * @return the exception types declared as being thrown by the + * executable this object represents + */ + public abstract Class[] getExceptionTypes(); + + /** + * Returns an array of {@code Type} objects that represent the + * exceptions declared to be thrown by this executable object. + * Returns an array of length 0 if the underlying executable declares + * no exceptions in its {@code throws} clause. + * + *

      If an exception type is a type variable or a parameterized + * type, it is created. Otherwise, it is resolved. + * + * @return an array of Types that represent the exception types + * thrown by the underlying executable + * @throws GenericSignatureFormatError + * if the generic method signature does not conform to the format + * specified in + * The Java™ Virtual Machine Specification + * @throws TypeNotPresentException if the underlying executable's + * {@code throws} clause refers to a non-existent type declaration + * @throws MalformedParameterizedTypeException if + * the underlying executable's {@code throws} clause refers to a + * parameterized type that cannot be instantiated for any reason + */ + public Type[] getGenericExceptionTypes() { + Type[] result; + if (hasGenericInformation() && + ((result = getGenericInfo().getExceptionTypes()).length > 0)) + return result; + else + return getExceptionTypes(); + } + + /** + * Returns a string describing this {@code Executable}, including + * any type parameters. + * @return a string describing this {@code Executable}, including + * any type parameters + */ + public abstract String toGenericString(); + + /** + * Returns {@code true} if this executable was declared to take a + * variable number of arguments; returns {@code false} otherwise. + * + * @return {@code true} if an only if this executable was declared + * to take a variable number of arguments. + */ + public boolean isVarArgs() { + return (getModifiers() & Modifier.VARARGS) != 0; + } + + /** + * Returns {@code true} if this executable is a synthetic + * construct; returns {@code false} otherwise. + * + * @return true if and only if this executable is a synthetic + * construct as defined by + * The Java™ Language Specification. + * @jls 13.1 The Form of a Binary + */ + public boolean isSynthetic() { + return Modifier.isSynthetic(getModifiers()); + } + + /** + * Returns an array of arrays of {@code Annotation}s that + * represent the annotations on the formal parameters, in + * declaration order, of the {@code Executable} represented by + * this object. Synthetic and mandated parameters (see + * explanation below), such as the outer "this" parameter to an + * inner class constructor will be represented in the returned + * array. If the executable has no parameters (meaning no formal, + * no synthetic, and no mandated parameters), a zero-length array + * will be returned. If the {@code Executable} has one or more + * parameters, a nested array of length zero is returned for each + * parameter with no annotations. The annotation objects contained + * in the returned arrays are serializable. The caller of this + * method is free to modify the returned arrays; it will have no + * effect on the arrays returned to other callers. + * + * A compiler may add extra parameters that are implicitly + * declared in source ("mandated"), as well as parameters that + * are neither implicitly nor explicitly declared in source + * ("synthetic") to the parameter list for a method. See {@link + * java.lang.reflect.Parameter} for more information. + * + * @see java.lang.reflect.Parameter + * @see java.lang.reflect.Parameter#getAnnotations + * @return an array of arrays that represent the annotations on + * the formal and implicit parameters, in declaration order, of + * the executable represented by this object + */ + public abstract Annotation[][] getParameterAnnotations(); + + Annotation[][] sharedGetParameterAnnotations(Class[] parameterTypes) { + int numParameters = parameterTypes.length; + + Annotation[][] result = sharedGetParameterAnnotationsImpl(); + if (result == null) + return new Annotation[numParameters][0]; + + if (result.length != numParameters) + handleParameterNumberMismatch(result.length, numParameters); + return result; + } + + private native Annotation[][] sharedGetParameterAnnotationsImpl(); + + abstract void handleParameterNumberMismatch(int resultLength, int numParameters); + + /** + * {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public T getAnnotation(Class annotationClass) { + Objects.requireNonNull(annotationClass); + return annotationClass.cast(declaredAnnotations().get(annotationClass)); + } + + /** + * {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @since 1.8 + */ + @Override + public T[] getAnnotationsByType(Class annotationClass) { + Objects.requireNonNull(annotationClass); + + return AnnotationSupport.getDirectlyAndIndirectlyPresent(declaredAnnotations(), annotationClass); + } + + /** + * {@inheritDoc} + */ + public Annotation[] getDeclaredAnnotations() { + return AnnotationParser.toArray(declaredAnnotations()); + } + + private transient Map, Annotation> declaredAnnotations; + + private synchronized Map, Annotation> declaredAnnotations() { + if (declaredAnnotations == null) { + Executable root = getRoot(); + if (root != null) { + declaredAnnotations = root.declaredAnnotations(); + } else { + declaredAnnotations = declaredAnnotationsImpl(); + } + } + return declaredAnnotations; + } + + private native Map, Annotation> declaredAnnotationsImpl(); + + /** + * Returns an {@code AnnotatedType} object that represents the use of a type to + * specify the return type of the method/constructor represented by this + * Executable. + * + * If this {@code Executable} object represents a constructor, the {@code + * AnnotatedType} object represents the type of the constructed object. + * + * If this {@code Executable} object represents a method, the {@code + * AnnotatedType} object represents the use of a type to specify the return + * type of the method. + * + * @return an object representing the return type of the method + * or constructor represented by this {@code Executable} + * + * @since 1.8 + */ + public abstract AnnotatedType getAnnotatedReturnType(); + + /* Helper for subclasses of Executable. + * + * Returns an AnnotatedType object that represents the use of a type to + * specify the return type of the method/constructor represented by this + * Executable. + * + * @since 1.8 + */ + AnnotatedType getAnnotatedReturnType0(Type returnType) { + return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes0(), + sun.misc.SharedSecrets.getJavaLangAccess(). + getConstantPool(getDeclaringClass()), + this, + getDeclaringClass(), + returnType, + TypeAnnotation.TypeAnnotationTarget.METHOD_RETURN); + } + + /** + * Returns an {@code AnnotatedType} object that represents the use of a + * type to specify the receiver type of the method/constructor represented + * by this Executable object. The receiver type of a method/constructor is + * available only if the method/constructor has a receiver + * parameter (JLS 8.4.1). + * + * If this {@code Executable} object represents a constructor or instance + * method that does not have a receiver parameter, or has a receiver + * parameter with no annotations on its type, then the return value is an + * {@code AnnotatedType} object representing an element with no + * annotations. + * + * If this {@code Executable} object represents a static method, then the + * return value is null. + * + * @return an object representing the receiver type of the method or + * constructor represented by this {@code Executable} + * + * @since 1.8 + */ + public AnnotatedType getAnnotatedReceiverType() { + if (Modifier.isStatic(this.getModifiers())) + return null; + return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes0(), + sun.misc.SharedSecrets.getJavaLangAccess(). + getConstantPool(getDeclaringClass()), + this, + getDeclaringClass(), + getDeclaringClass(), + TypeAnnotation.TypeAnnotationTarget.METHOD_RECEIVER); + } + + /** + * Returns an array of {@code AnnotatedType} objects that represent the use + * of types to specify formal parameter types of the method/constructor + * represented by this Executable. The order of the objects in the array + * corresponds to the order of the formal parameter types in the + * declaration of the method/constructor. + * + * Returns an array of length 0 if the method/constructor declares no + * parameters. + * + * @return an array of objects representing the types of the + * formal parameters of the method or constructor represented by this + * {@code Executable} + * + * @since 1.8 + */ + public AnnotatedType[] getAnnotatedParameterTypes() { + return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes0(), + sun.misc.SharedSecrets.getJavaLangAccess(). + getConstantPool(getDeclaringClass()), + this, + getDeclaringClass(), + getAllGenericParameterTypes(), + TypeAnnotation.TypeAnnotationTarget.METHOD_FORMAL_PARAMETER); + } + + /** + * Returns an array of {@code AnnotatedType} objects that represent the use + * of types to specify the declared exceptions of the method/constructor + * represented by this Executable. The order of the objects in the array + * corresponds to the order of the exception types in the declaration of + * the method/constructor. + * + * Returns an array of length 0 if the method/constructor declares no + * exceptions. + * + * @return an array of objects representing the declared + * exceptions of the method or constructor represented by this {@code + * Executable} + * + * @since 1.8 + */ + public AnnotatedType[] getAnnotatedExceptionTypes() { + return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes0(), + sun.misc.SharedSecrets.getJavaLangAccess(). + getConstantPool(getDeclaringClass()), + this, + getDeclaringClass(), + getGenericExceptionTypes(), + TypeAnnotation.TypeAnnotationTarget.THROWS); + } + +} diff --git a/external/ikvm/openjdk/java/lang/reflect/Field.java b/external/ikvm/openjdk/java/lang/reflect/Field.java index b2cb46b3f0..a683e59a99 100644 --- a/external/ikvm/openjdk/java/lang/reflect/Field.java +++ b/external/ikvm/openjdk/java/lang/reflect/Field.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,8 +34,11 @@ import sun.reflect.generics.factory.GenericsFactory; import sun.reflect.generics.scope.ClassScope; import java.lang.annotation.Annotation; import java.util.Map; +import java.util.Objects; import sun.reflect.annotation.AnnotationParser; - +import sun.reflect.annotation.AnnotationSupport; +import sun.reflect.annotation.TypeAnnotation; +import sun.reflect.annotation.TypeAnnotationParser; /** * A {@code Field} provides information about, and dynamic access to, a @@ -77,6 +80,9 @@ class Field extends AccessibleObject implements Member { // For sharing of FieldAccessors. This branching structure is // currently only two levels deep (i.e., one root Field and // potentially many Field objects pointing to it.) + // + // If this branching structure would ever contain cycles, deadlocks can + // occur in annotation code. private Field root; // Generics infrastructure @@ -136,11 +142,15 @@ class Field extends AccessibleObject implements Member { // which implicitly requires that new java.lang.reflect // objects be fabricated for each reflective call on Class // objects.) + if (this.root != null) + throw new IllegalArgumentException("Can not copy a non-root Field"); + Field res = new Field(clazz, name, type, modifiers, slot, signature, null); res.root = this; // Might as well eagerly propagate this if already present res.fieldAccessor = fieldAccessor; res.overrideFieldAccessor = overrideFieldAccessor; + return res; } @@ -280,12 +290,15 @@ class Field extends AccessibleObject implements Member { * {@code protected} or {@code private} first, and then other * modifiers in the following order: {@code static}, {@code final}, * {@code transient}, {@code volatile}. + * + * @return a string describing this {@code Field} + * @jls 8.3.1 Field Modifiers */ public String toString() { int mod = getModifiers(); return (((mod == 0) ? "" : (Modifier.toString(mod) + " ")) - + getTypeName(getType()) + " " - + getTypeName(getDeclaringClass()) + "." + + getType().getTypeName() + " " + + getDeclaringClass().getTypeName() + "." + getName()); } @@ -307,14 +320,14 @@ class Field extends AccessibleObject implements Member { * its generic type * * @since 1.5 + * @jls 8.3.1 Field Modifiers */ public String toGenericString() { int mod = getModifiers(); Type fieldType = getGenericType(); return (((mod == 0) ? "" : (Modifier.toString(mod) + " ")) - + ((fieldType instanceof Class) ? - getTypeName((Class)fieldType): fieldType.toString())+ " " - + getTypeName(getDeclaringClass()) + "." + + fieldType.getTypeName() + " " + + getDeclaringClass().getTypeName() + "." + getName()); } @@ -371,7 +384,8 @@ class Field extends AccessibleObject implements Member { { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } } return getFieldAccessor(obj).get(obj); @@ -405,7 +419,8 @@ class Field extends AccessibleObject implements Member { { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } } return getFieldAccessor(obj).getBoolean(obj); @@ -439,7 +454,8 @@ class Field extends AccessibleObject implements Member { { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } } return getFieldAccessor(obj).getByte(obj); @@ -475,7 +491,8 @@ class Field extends AccessibleObject implements Member { { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } } return getFieldAccessor(obj).getChar(obj); @@ -511,7 +528,8 @@ class Field extends AccessibleObject implements Member { { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } } return getFieldAccessor(obj).getShort(obj); @@ -547,7 +565,8 @@ class Field extends AccessibleObject implements Member { { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } } return getFieldAccessor(obj).getInt(obj); @@ -583,7 +602,8 @@ class Field extends AccessibleObject implements Member { { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } } return getFieldAccessor(obj).getLong(obj); @@ -619,7 +639,8 @@ class Field extends AccessibleObject implements Member { { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } } return getFieldAccessor(obj).getFloat(obj); @@ -655,7 +676,8 @@ class Field extends AccessibleObject implements Member { { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } } return getFieldAccessor(obj).getDouble(obj); @@ -733,7 +755,8 @@ class Field extends AccessibleObject implements Member { { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } } getFieldAccessor(obj).set(obj, value); @@ -769,7 +792,8 @@ class Field extends AccessibleObject implements Member { { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } } getFieldAccessor(obj).setBoolean(obj, z); @@ -805,7 +829,8 @@ class Field extends AccessibleObject implements Member { { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } } getFieldAccessor(obj).setByte(obj, b); @@ -841,7 +866,8 @@ class Field extends AccessibleObject implements Member { { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } } getFieldAccessor(obj).setChar(obj, c); @@ -877,7 +903,8 @@ class Field extends AccessibleObject implements Member { { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } } getFieldAccessor(obj).setShort(obj, s); @@ -913,7 +940,8 @@ class Field extends AccessibleObject implements Member { { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } } getFieldAccessor(obj).setInt(obj, i); @@ -949,7 +977,8 @@ class Field extends AccessibleObject implements Member { { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } } getFieldAccessor(obj).setLong(obj, l); @@ -985,7 +1014,8 @@ class Field extends AccessibleObject implements Member { { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } } getFieldAccessor(obj).setFloat(obj, f); @@ -1021,7 +1051,8 @@ class Field extends AccessibleObject implements Member { { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } } getFieldAccessor(obj).setDouble(obj, d); @@ -1078,57 +1109,66 @@ class Field extends AccessibleObject implements Member { } } - /* - * Utility routine to paper over array type names - */ - static String getTypeName(Class type) { - if (type.isArray()) { - try { - Class cl = type; - int dimensions = 0; - while (cl.isArray()) { - dimensions++; - cl = cl.getComponentType(); - } - StringBuffer sb = new StringBuffer(); - sb.append(cl.getName()); - for (int i = 0; i < dimensions; i++) { - sb.append("[]"); - } - return sb.toString(); - } catch (Throwable e) { /*FALLTHRU*/ } - } - return type.getName(); - } - /** * @throws NullPointerException {@inheritDoc} * @since 1.5 */ public T getAnnotation(Class annotationClass) { - if (annotationClass == null) - throw new NullPointerException(); - - return (T) declaredAnnotations().get(annotationClass); + Objects.requireNonNull(annotationClass); + return annotationClass.cast(declaredAnnotations().get(annotationClass)); } - private static final Annotation[] EMPTY_ANNOTATION_ARRAY=new Annotation[0]; + /** + * {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @since 1.8 + */ + @Override + public T[] getAnnotationsByType(Class annotationClass) { + Objects.requireNonNull(annotationClass); + + return AnnotationSupport.getDirectlyAndIndirectlyPresent(declaredAnnotations(), annotationClass); + } /** - * @since 1.5 + * {@inheritDoc} */ public Annotation[] getDeclaredAnnotations() { - return declaredAnnotations().values().toArray(EMPTY_ANNOTATION_ARRAY); + return AnnotationParser.toArray(declaredAnnotations()); } private transient Map, Annotation> declaredAnnotations; private synchronized Map, Annotation> declaredAnnotations() { if (declaredAnnotations == null) { - declaredAnnotations = getDeclaredAnnotationsImpl(); + Field root = this.root; + if (root != null) { + declaredAnnotations = root.declaredAnnotations(); + } else { + declaredAnnotations = getDeclaredAnnotationsImpl(); + } } return declaredAnnotations; } - + private native Map, Annotation> getDeclaredAnnotationsImpl(); + private native byte[] getTypeAnnotationBytes0(); + + /** + * Returns an AnnotatedType object that represents the use of a type to specify + * the declared type of the field represented by this Field. + * @return an object representing the declared type of the field + * represented by this Field + * + * @since 1.8 + */ + public AnnotatedType getAnnotatedType() { + return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes0(), + sun.misc.SharedSecrets.getJavaLangAccess(). + getConstantPool(getDeclaringClass()), + this, + getDeclaringClass(), + getGenericType(), + TypeAnnotation.TypeAnnotationTarget.FIELD); +} } diff --git a/external/ikvm/openjdk/java/lang/reflect/Method.java b/external/ikvm/openjdk/java/lang/reflect/Method.java index dce789a4f1..c8705ba1ed 100644 --- a/external/ikvm/openjdk/java/lang/reflect/Method.java +++ b/external/ikvm/openjdk/java/lang/reflect/Method.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package java.lang.reflect; -import ikvm.internal.CallerID; import sun.reflect.CallerSensitive; import sun.reflect.MethodAccessor; import sun.reflect.Reflection; @@ -38,7 +37,6 @@ import sun.reflect.annotation.AnnotationParser; import java.lang.annotation.Annotation; import java.lang.annotation.AnnotationFormatError; import java.nio.ByteBuffer; -import java.util.Map; /** * A {@code Method} provides information about, and access to, a single method @@ -60,9 +58,7 @@ import java.util.Map; * @author Kenneth Russell * @author Nakul Saraiya */ -public final - class Method extends AccessibleObject implements GenericDeclaration, - Member { +public final class Method extends Executable { private Class clazz; private int slot; // This is guaranteed to be interned by the VM in the 1.4 @@ -80,10 +76,12 @@ public final // For sharing of MethodAccessors. This branching structure is // currently only two levels deep (i.e., one root Method and // potentially many Method objects pointing to it.) + // + // If this branching structure would ever contain cycles, deadlocks can + // occur in annotation code. private Method root; - // Generics infrastructure - + // Generics infrastructure private String getGenericSignature() {return signature;} // Accessor for factory @@ -93,7 +91,8 @@ public final } // Accessor for generic info repository - private MethodRepository getGenericInfo() { + @Override + MethodRepository getGenericInfo() { // lazily initialize repository if necessary if (genericInfo == null) { // create and cache generic info repository @@ -118,8 +117,7 @@ public final String signature, byte[] unused1, byte[] unused2, - byte[] unused3) - { + byte[] unused3) { this.clazz = declaringClass; this.name = name; this.parameterTypes = parameterTypes; @@ -143,6 +141,9 @@ public final // which implicitly requires that new java.lang.reflect // objects be fabricated for each reflective call on Class // objects.) + if (this.root != null) + throw new IllegalArgumentException("Can not copy a non-root Method"); + Method res = new Method(clazz, name, parameterTypes, returnType, exceptionTypes, modifiers, slot, signature, null, null, null); @@ -153,9 +154,22 @@ public final } /** - * Returns the {@code Class} object representing the class or interface - * that declares the method represented by this {@code Method} object. + * Used by Excecutable for annotation sharing. */ + @Override + Executable getRoot() { + return root; + } + + @Override + boolean hasGenericInformation() { + return (getGenericSignature() != null); + } + + /** + * {@inheritDoc} + */ + @Override public Class getDeclaringClass() { return clazz; } @@ -164,36 +178,26 @@ public final * Returns the name of the method represented by this {@code Method} * object, as a {@code String}. */ + @Override public String getName() { return name; } /** - * Returns the Java language modifiers for the method represented - * by this {@code Method} object, as an integer. The {@code Modifier} class should - * be used to decode the modifiers. - * - * @see Modifier + * {@inheritDoc} */ + @Override public int getModifiers() { return modifiers; } /** - * Returns an array of {@code TypeVariable} objects that represent the - * type variables declared by the generic declaration represented by this - * {@code GenericDeclaration} object, in declaration order. Returns an - * array of length 0 if the underlying generic declaration declares no type - * variables. - * - * @return an array of {@code TypeVariable} objects that represent - * the type variables declared by this generic declaration - * @throws GenericSignatureFormatError if the generic - * signature of this generic declaration does not conform to - * the format specified in - * The Java™ Virtual Machine Specification + * {@inheritDoc} + * @throws GenericSignatureFormatError {@inheritDoc} * @since 1.5 */ + @Override + @SuppressWarnings({"rawtypes", "unchecked"}) public TypeVariable[] getTypeParameters() { if (getGenericSignature() != null) return (TypeVariable[])getGenericInfo().getTypeParameters(); @@ -241,99 +245,51 @@ public final } else { return getReturnType();} } - /** - * Returns an array of {@code Class} objects that represent the formal - * parameter types, in declaration order, of the method - * represented by this {@code Method} object. Returns an array of length - * 0 if the underlying method takes no parameters. - * - * @return the parameter types for the method this object - * represents + * {@inheritDoc} */ + @Override public Class[] getParameterTypes() { - return (Class[]) parameterTypes.clone(); + return parameterTypes.clone(); } /** - * Returns an array of {@code Type} objects that represent the formal - * parameter types, in declaration order, of the method represented by - * this {@code Method} object. Returns an array of length 0 if the - * underlying method takes no parameters. - * - *

      If a formal parameter type is a parameterized type, - * the {@code Type} object returned for it must accurately reflect - * the actual type parameters used in the source code. - * - *

      If a formal parameter type is a type variable or a parameterized - * type, it is created. Otherwise, it is resolved. - * - * @return an array of Types that represent the formal - * parameter types of the underlying method, in declaration order - * @throws GenericSignatureFormatError - * if the generic method signature does not conform to the format - * specified in - * The Java™ Virtual Machine Specification - * @throws TypeNotPresentException if any of the parameter - * types of the underlying method refers to a non-existent type - * declaration - * @throws MalformedParameterizedTypeException if any of - * the underlying method's parameter types refer to a parameterized - * type that cannot be instantiated for any reason + * {@inheritDoc} + */ + public int getParameterCount() { return parameterTypes.length; } + + + /** + * {@inheritDoc} + * @throws GenericSignatureFormatError {@inheritDoc} + * @throws TypeNotPresentException {@inheritDoc} + * @throws MalformedParameterizedTypeException {@inheritDoc} * @since 1.5 */ + @Override public Type[] getGenericParameterTypes() { - if (getGenericSignature() != null) - return getGenericInfo().getParameterTypes(); - else - return getParameterTypes(); + return super.getGenericParameterTypes(); } - /** - * Returns an array of {@code Class} objects that represent - * the types of the exceptions declared to be thrown - * by the underlying method - * represented by this {@code Method} object. Returns an array of length - * 0 if the method declares no exceptions in its {@code throws} clause. - * - * @return the exception types declared as being thrown by the - * method this object represents + * {@inheritDoc} */ + @Override public Class[] getExceptionTypes() { - return (Class[]) exceptionTypes.clone(); + return exceptionTypes.clone(); } /** - * Returns an array of {@code Type} objects that represent the - * exceptions declared to be thrown by this {@code Method} object. - * Returns an array of length 0 if the underlying method declares - * no exceptions in its {@code throws} clause. - * - *

      If an exception type is a type variable or a parameterized - * type, it is created. Otherwise, it is resolved. - * - * @return an array of Types that represent the exception types - * thrown by the underlying method - * @throws GenericSignatureFormatError - * if the generic method signature does not conform to the format - * specified in - * The Java™ Virtual Machine Specification - * @throws TypeNotPresentException if the underlying method's - * {@code throws} clause refers to a non-existent type declaration - * @throws MalformedParameterizedTypeException if - * the underlying method's {@code throws} clause refers to a - * parameterized type that cannot be instantiated for any reason + * {@inheritDoc} + * @throws GenericSignatureFormatError {@inheritDoc} + * @throws TypeNotPresentException {@inheritDoc} + * @throws MalformedParameterizedTypeException {@inheritDoc} * @since 1.5 */ - public Type[] getGenericExceptionTypes() { - Type[] result; - if (getGenericSignature() != null && - ((result = getGenericInfo().getExceptionTypes()).length > 0)) - return result; - else - return getExceptionTypes(); - } + @Override + public Type[] getGenericExceptionTypes() { + return super.getGenericExceptionTypes(); + } /** * Compares this {@code Method} against the specified object. Returns @@ -348,16 +304,7 @@ public final && (getName() == other.getName())) { if (!returnType.equals(other.getReturnType())) return false; - /* Avoid unnecessary cloning */ - Class[] params1 = parameterTypes; - Class[] params2 = other.parameterTypes; - if (params1.length == params2.length) { - for (int i = 0; i < params1.length; i++) { - if (params1[i] != params2[i]) - return false; - } - return true; - } + return equalParamTypes(parameterTypes, other.parameterTypes); } } return false; @@ -391,39 +338,25 @@ public final * specified by "The Java Language Specification". This is * {@code public}, {@code protected} or {@code private} first, * and then other modifiers in the following order: - * {@code abstract}, {@code static}, {@code final}, + * {@code abstract}, {@code default}, {@code static}, {@code final}, * {@code synchronized}, {@code native}, {@code strictfp}. + * + * @return a string describing this {@code Method} + * + * @jls 8.4.3 Method Modifiers */ public String toString() { - try { - StringBuilder sb = new StringBuilder(); - int mod = getModifiers() & Modifier.methodModifiers(); - if (mod != 0) { - sb.append(Modifier.toString(mod)).append(' '); - } - sb.append(Field.getTypeName(getReturnType())).append(' '); - sb.append(Field.getTypeName(getDeclaringClass())).append('.'); - sb.append(getName()).append('('); - Class[] params = parameterTypes; // avoid clone - for (int j = 0; j < params.length; j++) { - sb.append(Field.getTypeName(params[j])); - if (j < (params.length - 1)) - sb.append(','); - } - sb.append(')'); - Class[] exceptions = exceptionTypes; // avoid clone - if (exceptions.length > 0) { - sb.append(" throws "); - for (int k = 0; k < exceptions.length; k++) { - sb.append(exceptions[k].getName()); - if (k < (exceptions.length - 1)) - sb.append(','); - } - } - return sb.toString(); - } catch (Exception e) { - return "<" + e + ">"; - } + return sharedToString(Modifier.methodModifiers(), + isDefault(), + parameterTypes, + exceptionTypes); + } + + @Override + void specificToStringHeader(StringBuilder sb) { + sb.append(getReturnType().getTypeName()).append(' '); + sb.append(getDeclaringClass().getTypeName()).append('.'); + sb.append(getName()); } /** @@ -449,77 +382,33 @@ public final * class name. If the method is declared to throw exceptions, the * parameter list is followed by a space, followed by the word * throws followed by a comma-separated list of the generic thrown - * exception types. If there are no type parameters, the type - * parameter list is elided. + * exception types. * *

      The access modifiers are placed in canonical order as * specified by "The Java Language Specification". This is * {@code public}, {@code protected} or {@code private} first, * and then other modifiers in the following order: - * {@code abstract}, {@code static}, {@code final}, + * {@code abstract}, {@code default}, {@code static}, {@code final}, * {@code synchronized}, {@code native}, {@code strictfp}. * * @return a string describing this {@code Method}, * include type parameters * * @since 1.5 + * + * @jls 8.4.3 Method Modifiers */ + @Override public String toGenericString() { - try { - StringBuilder sb = new StringBuilder(); - int mod = getModifiers() & Modifier.methodModifiers(); - if (mod != 0) { - sb.append(Modifier.toString(mod)).append(' '); - } - TypeVariable[] typeparms = getTypeParameters(); - if (typeparms.length > 0) { - boolean first = true; - sb.append('<'); - for(TypeVariable typeparm: typeparms) { - if (!first) - sb.append(','); - // Class objects can't occur here; no need to test - // and call Class.getName(). - sb.append(typeparm.toString()); - first = false; - } - sb.append("> "); - } + return sharedToGenericString(Modifier.methodModifiers(), isDefault()); + } - Type genRetType = getGenericReturnType(); - sb.append( ((genRetType instanceof Class)? - Field.getTypeName((Class)genRetType):genRetType.toString())) - .append(' '); - - sb.append(Field.getTypeName(getDeclaringClass())).append('.'); - sb.append(getName()).append('('); - Type[] params = getGenericParameterTypes(); - for (int j = 0; j < params.length; j++) { - String param = (params[j] instanceof Class)? - Field.getTypeName((Class)params[j]): - (params[j].toString()); - if (isVarArgs() && (j == params.length - 1)) // replace T[] with T... - param = param.replaceFirst("\\[\\]$", "..."); - sb.append(param); - if (j < (params.length - 1)) - sb.append(','); - } - sb.append(')'); - Type[] exceptions = getGenericExceptionTypes(); - if (exceptions.length > 0) { - sb.append(" throws "); - for (int k = 0; k < exceptions.length; k++) { - sb.append((exceptions[k] instanceof Class)? - ((Class)exceptions[k]).getName(): - exceptions[k].toString()); - if (k < (exceptions.length - 1)) - sb.append(','); - } - } - return sb.toString(); - } catch (Exception e) { - return "<" + e + ">"; - } + @Override + void specificToGenericStringHeader(StringBuilder sb) { + Type genRetType = getGenericReturnType(); + sb.append(genRetType.getTypeName()).append(' '); + sb.append(getDeclaringClass().getTypeName()).append('.'); + sb.append(getName()); } /** @@ -594,7 +483,7 @@ public final if (ma == null) { ma = acquireMethodAccessor(); } - return ma.invoke(obj, args, CallerID.getCallerID()); + return ma.invoke(obj, args, ikvm.internal.CallerID.getCallerID()); } /** @@ -610,28 +499,41 @@ public final } /** - * Returns {@code true} if this method was declared to take - * a variable number of arguments; returns {@code false} - * otherwise. - * - * @return {@code true} if an only if this method was declared to - * take a variable number of arguments. + * {@inheritDoc} * @since 1.5 */ + @Override public boolean isVarArgs() { - return (getModifiers() & Modifier.VARARGS) != 0; + return super.isVarArgs(); } /** - * Returns {@code true} if this method is a synthetic - * method; returns {@code false} otherwise. - * - * @return true if and only if this method is a synthetic - * method as defined by the Java Language Specification. + * {@inheritDoc} + * @jls 13.1 The Form of a Binary * @since 1.5 */ + @Override public boolean isSynthetic() { - return Modifier.isSynthetic(getModifiers()); + return super.isSynthetic(); + } + + /** + * Returns {@code true} if this method is a default + * method; returns {@code false} otherwise. + * + * A default method is a public non-abstract instance method, that + * is, a non-static method with a body, declared in an interface + * type. + * + * @return true if and only if this method is a default + * method as defined by the Java Language Specification. + * @since 1.8 + */ + public boolean isDefault() { + // Default methods are public non-abstract instance methods + // declared in an interface. + return ((getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == + Modifier.PUBLIC) && getDeclaringClass().isInterface(); } // NOTE that there is no synchronization used here. It is correct @@ -670,37 +572,6 @@ public final } } - /** - * @throws NullPointerException {@inheritDoc} - * @since 1.5 - */ - public T getAnnotation(Class annotationClass) { - if (annotationClass == null) - throw new NullPointerException(); - - return (T) declaredAnnotations().get(annotationClass); - } - - private static final Annotation[] EMPTY_ANNOTATION_ARRAY=new Annotation[0]; - - /** - * @since 1.5 - */ - public Annotation[] getDeclaredAnnotations() { - return declaredAnnotations().values().toArray(EMPTY_ANNOTATION_ARRAY); - } - - private transient Map, Annotation> declaredAnnotations; - - private synchronized Map, Annotation> declaredAnnotations() { - if (declaredAnnotations == null) { - declaredAnnotations = getDeclaredAnnotationsImpl(this); - } - return declaredAnnotations; - } - - static native Map, Annotation> getDeclaredAnnotationsImpl(Object methodOrConstructor); - /** * Returns the default value for the annotation member represented by * this {@code Method} instance. If the member is of a primitive type, @@ -718,32 +589,42 @@ public final public native Object getDefaultValue(); /** - * Returns an array of arrays that represent the annotations on the formal - * parameters, in declaration order, of the method represented by - * this {@code Method} object. (Returns an array of length zero if the - * underlying method is parameterless. If the method has one or more - * parameters, a nested array of length zero is returned for each parameter - * with no annotations.) The annotation objects contained in the returned - * arrays are serializable. The caller of this method is free to modify - * the returned arrays; it will have no effect on the arrays returned to - * other callers. - * - * @return an array of arrays that represent the annotations on the formal - * parameters, in declaration order, of the method represented by this - * Method object + * {@inheritDoc} + * @throws NullPointerException {@inheritDoc} * @since 1.5 */ - public Annotation[][] getParameterAnnotations() { - Annotation[][] result = getParameterAnnotationsImpl(this); - int numParameters = parameterTypes.length; - if (result == null) - return new Annotation[numParameters][0]; - - if (result.length != numParameters) - throw new java.lang.annotation.AnnotationFormatError( - "Parameter annotations don't match number of parameters"); - return result; + public T getAnnotation(Class annotationClass) { + return super.getAnnotation(annotationClass); } - static native Annotation[][] getParameterAnnotationsImpl(Object methodOrConstructor); + /** + * {@inheritDoc} + * @since 1.5 + */ + public Annotation[] getDeclaredAnnotations() { + return super.getDeclaredAnnotations(); + } + + /** + * {@inheritDoc} + * @since 1.5 + */ + @Override + public Annotation[][] getParameterAnnotations() { + return sharedGetParameterAnnotations(parameterTypes); + } + + /** + * {@inheritDoc} + * @since 1.8 + */ + @Override + public AnnotatedType getAnnotatedReturnType() { + return getAnnotatedReturnType0(getGenericReturnType()); + } + + @Override + void handleParameterNumberMismatch(int resultLength, int numParameters) { + throw new AnnotationFormatError("Parameter annotations don't match number of parameters"); + } } diff --git a/external/ikvm/openjdk/java/lang/reflect/Proxy.java b/external/ikvm/openjdk/java/lang/reflect/Proxy.java index 3d9850e032..de7416db1b 100644 --- a/external/ikvm/openjdk/java/lang/reflect/Proxy.java +++ b/external/ikvm/openjdk/java/lang/reflect/Proxy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,17 @@ package java.lang.reflect; -import java.lang.ref.Reference; import java.lang.ref.WeakReference; import java.security.AccessController; -import java.security.Permission; import java.security.PrivilegedAction; import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; +import java.util.IdentityHashMap; import java.util.Map; -import java.util.Set; -import java.util.List; -import java.util.WeakHashMap; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.BiFunction; import sun.misc.ProxyGenerator; +import sun.misc.VM; import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.reflect.misc.ReflectUtil; @@ -52,16 +49,14 @@ import sun.security.util.SecurityConstants; *

      To create a proxy for some interface {@code Foo}: *

        *     InvocationHandler handler = new MyInvocationHandler(...);
      - *     Class proxyClass = Proxy.getProxyClass(
      - *         Foo.class.getClassLoader(), new Class[] { Foo.class });
      - *     Foo f = (Foo) proxyClass.
      - *         getConstructor(new Class[] { InvocationHandler.class }).
      - *         newInstance(new Object[] { handler });
      + *     Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
      + *     Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).
      + *                     newInstance(handler);
        * 
      * or more simply: *
        *     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
      - *                                          new Class[] { Foo.class },
      + *                                          new Class<?>[] { Foo.class },
        *                                          handler);
        * 
      * @@ -90,7 +85,11 @@ import sun.security.util.SecurityConstants; *

      A proxy class has the following properties: * *

        - *
      • Proxy classes are public, final, and not abstract. + *
      • Proxy classes are public, final, and not abstract if + * all proxy interfaces are public.
      • + * + *
      • Proxy classes are non-public, final, and not abstract if + * any of the proxy interfaces is non-public.
      • * *
      • The unqualified name of a proxy class is unspecified. The space * of class names that begin with the string {@code "$Proxy"} @@ -230,27 +229,15 @@ public class Proxy implements java.io.Serializable { private static final long serialVersionUID = -2222568056686623797L; - /** prefix for all proxy class names */ - private final static String proxyClassNamePrefix = "$Proxy"; - /** parameter types of a proxy class constructor */ - private final static Class[] constructorParams = + private static final Class[] constructorParams = { InvocationHandler.class }; - /** maps a class loader to the proxy class cache for that loader */ - private static Map, Object>> loaderToCache - = new WeakHashMap<>(); - - /** marks that a particular proxy class is currently being generated */ - private static Object pendingGenerationMarker = new Object(); - - /** next number to use for generation of unique proxy class names */ - private static long nextUniqueNumber = 0; - private static Object nextUniqueNumberLock = new Object(); - - /** set of all generated proxy classes, for isProxyClass implementation */ - private static Map, Void> proxyClasses = - Collections.synchronizedMap(new WeakHashMap, Void>()); + /** + * a cache of proxy classes + */ + private static final WeakCache[], Class> + proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); /** * the invocation handler for this proxy instance. @@ -269,77 +256,24 @@ public class Proxy implements java.io.Serializable { * (typically, a dynamic proxy class) with the specified value * for its invocation handler. * - * @param h the invocation handler for this proxy instance + * @param h the invocation handler for this proxy instance + * + * @throws NullPointerException if the given invocation handler, {@code h}, + * is {@code null}. */ protected Proxy(InvocationHandler h) { - doNewInstanceCheck(); + Objects.requireNonNull(h); this.h = h; } - private static class ProxyAccessHelper { - // The permission is implementation specific. - static final Permission PROXY_PERMISSION = - new ReflectPermission("proxyConstructorNewInstance"); - // These system properties are defined to provide a short-term - // workaround if customers need to disable the new security checks. - static final boolean allowNewInstance; - static final boolean allowNullLoader; - static { - allowNewInstance = getBooleanProperty("sun.reflect.proxy.allowsNewInstance"); - allowNullLoader = getBooleanProperty("sun.reflect.proxy.allowsNullLoader"); - } - - private static boolean getBooleanProperty(final String key) { - String s = AccessController.doPrivileged(new PrivilegedAction() { - public String run() { - return System.getProperty(key); - } - }); - return Boolean.valueOf(s); - } - - static boolean needsNewInstanceCheck(Class proxyClass) { - if (!Proxy.isProxyClass(proxyClass) || allowNewInstance) { - return false; - } - - if (ReflectUtil.isNonPublicProxyClass(proxyClass)) { - for (Class intf : proxyClass.getInterfaces()) { - if (!Modifier.isPublic(intf.getModifiers())) { - return true; - } - } - } - return false; - } - } - - /* - * Access check on a proxy class that implements any non-public interface. - * - * @throws SecurityException if a security manager exists, and - * the caller does not have the permission. - */ - private void doNewInstanceCheck() { - SecurityManager sm = System.getSecurityManager(); - Class proxyClass = this.getClass(); - if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(proxyClass)) { - try { - sm.checkPermission(ProxyAccessHelper.PROXY_PERMISSION); - } catch (SecurityException e) { - throw new SecurityException("Not allowed to construct a Proxy " - + "instance that implements a non-public interface", e); - } - } - } - /** * Returns the {@code java.lang.Class} object for a proxy class * given a class loader and an array of interfaces. The proxy class * will be defined by the specified class loader and will implement - * all of the supplied interfaces. If a proxy class for the same - * permutation of interfaces has already been defined by the class - * loader, then the existing proxy class will be returned; otherwise, + * all of the supplied interfaces. If any of the given interfaces + * is non-public, the proxy class will be non-public. If a proxy class + * for the same permutation of interfaces has already been defined by the + * class loader, then the existing proxy class will be returned; otherwise, * a proxy class for those interfaces will be generated dynamically * and defined by the class loader. * @@ -404,6 +338,22 @@ public class Proxy implements java.io.Serializable { * @throws IllegalArgumentException if any of the restrictions on the * parameters that may be passed to {@code getProxyClass} * are violated + * @throws SecurityException if a security manager, s, is present + * and any of the following conditions is met: + *
          + *
        • the given {@code loader} is {@code null} and + * the caller's class loader is not {@code null} and the + * invocation of {@link SecurityManager#checkPermission + * s.checkPermission} with + * {@code RuntimePermission("getClassLoader")} permission + * denies access.
        • + *
        • for each proxy interface, {@code intf}, + * the caller's class loader is not the same as or an + * ancestor of the class loader for {@code intf} and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to {@code intf}.
        • + *
        + * @throws NullPointerException if the {@code interfaces} array * argument or any of its elements are {@code null} */ @@ -412,12 +362,13 @@ public class Proxy implements java.io.Serializable { Class... interfaces) throws IllegalArgumentException { - SecurityManager sm = System.getSecurityManager(); + final Class[] intfs = interfaces.clone(); + final SecurityManager sm = System.getSecurityManager(); if (sm != null) { - checkProxyAccess(Reflection.getCallerClass(), loader, interfaces); + checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } - return getProxyClass0(loader, interfaces); + return getProxyClass0(loader, intfs); } /* @@ -445,10 +396,8 @@ public class Proxy implements java.io.Serializable { SecurityManager sm = System.getSecurityManager(); if (sm != null) { ClassLoader ccl = caller.getClassLoader(); - if (loader == null && ccl != null) { - if (!ProxyAccessHelper.allowNullLoader) { - sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); - } + if (VM.isSystemDomainLoader(loader) && !VM.isSystemDomainLoader(ccl)) { + sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); } ReflectUtil.checkProxyPackageAccess(ccl, interfaces); } @@ -464,142 +413,204 @@ public class Proxy implements java.io.Serializable { throw new IllegalArgumentException("interface limit exceeded"); } - Class proxyClass = null; + // If the proxy class defined by the given loader implementing + // the given interfaces exists, this will simply return the cached copy; + // otherwise, it will create the proxy class via the ProxyClassFactory + return proxyClassCache.get(loader, interfaces); + } - /* collect interface names to use as key for proxy class cache */ - String[] interfaceNames = new String[interfaces.length]; + /* + * a key used for proxy class with 0 implemented interfaces + */ + private static final Object key0 = new Object(); - // for detecting duplicates - Set> interfaceSet = new HashSet<>(); + /* + * Key1 and Key2 are optimized for the common use of dynamic proxies + * that implement 1 or 2 interfaces. + */ - for (int i = 0; i < interfaces.length; i++) { - /* - * Verify that the class loader resolves the name of this - * interface to the same Class object. - */ - String interfaceName = interfaces[i].getName(); - Class interfaceClass = null; - try { - interfaceClass = Class.forName(interfaceName, false, loader); - } catch (ClassNotFoundException e) { - } - if (interfaceClass != interfaces[i]) { - throw new IllegalArgumentException( - interfaces[i] + " is not visible from class loader"); - } + /* + * a key used for proxy class with 1 implemented interface + */ + private static final class Key1 extends WeakReference> { + private final int hash; - /* - * Verify that the Class object actually represents an - * interface. - */ - if (!interfaceClass.isInterface()) { - throw new IllegalArgumentException( - interfaceClass.getName() + " is not an interface"); - } - - /* - * Verify that this interface is not a duplicate. - */ - if (interfaceSet.contains(interfaceClass)) { - throw new IllegalArgumentException( - "repeated interface: " + interfaceClass.getName()); - } - interfaceSet.add(interfaceClass); - - interfaceNames[i] = interfaceName; + Key1(Class intf) { + super(intf); + this.hash = intf.hashCode(); } - /* - * Using string representations of the proxy interfaces as - * keys in the proxy class cache (instead of their Class - * objects) is sufficient because we require the proxy - * interfaces to be resolvable by name through the supplied - * class loader, and it has the advantage that using a string - * representation of a class makes for an implicit weak - * reference to the class. - */ - List key = Arrays.asList(interfaceNames); - - /* - * Find or create the proxy class cache for the class loader. - */ - Map, Object> cache; - synchronized (loaderToCache) { - cache = loaderToCache.get(loader); - if (cache == null) { - cache = new HashMap<>(); - loaderToCache.put(loader, cache); - } - /* - * This mapping will remain valid for the duration of this - * method, without further synchronization, because the mapping - * will only be removed if the class loader becomes unreachable. - */ + @Override + public int hashCode() { + return hash; } - /* - * Look up the list of interfaces in the proxy class cache using - * the key. This lookup will result in one of three possible - * kinds of values: - * null, if there is currently no proxy class for the list of - * interfaces in the class loader, - * the pendingGenerationMarker object, if a proxy class for the - * list of interfaces is currently being generated, - * or a weak reference to a Class object, if a proxy class for - * the list of interfaces has already been generated. - */ - synchronized (cache) { - /* - * Note that we need not worry about reaping the cache for - * entries with cleared weak references because if a proxy class - * has been garbage collected, its class loader will have been - * garbage collected as well, so the entire cache will be reaped - * from the loaderToCache map. - */ - do { - Object value = cache.get(key); - if (value instanceof Reference) { - proxyClass = (Class) ((Reference) value).get(); + @Override + public boolean equals(Object obj) { + Class intf; + return this == obj || + obj != null && + obj.getClass() == Key1.class && + (intf = get()) != null && + intf == ((Key1) obj).get(); + } + } + + /* + * a key used for proxy class with 2 implemented interfaces + */ + private static final class Key2 extends WeakReference> { + private final int hash; + private final WeakReference> ref2; + + Key2(Class intf1, Class intf2) { + super(intf1); + hash = 31 * intf1.hashCode() + intf2.hashCode(); + ref2 = new WeakReference>(intf2); + } + + @Override + public int hashCode() { + return hash; + } + + @Override + public boolean equals(Object obj) { + Class intf1, intf2; + return this == obj || + obj != null && + obj.getClass() == Key2.class && + (intf1 = get()) != null && + intf1 == ((Key2) obj).get() && + (intf2 = ref2.get()) != null && + intf2 == ((Key2) obj).ref2.get(); + } + } + + /* + * a key used for proxy class with any number of implemented interfaces + * (used here for 3 or more only) + */ + private static final class KeyX { + private final int hash; + private final WeakReference>[] refs; + + @SuppressWarnings("unchecked") + KeyX(Class[] interfaces) { + hash = Arrays.hashCode(interfaces); + refs = (WeakReference>[])new WeakReference[interfaces.length]; + for (int i = 0; i < interfaces.length; i++) { + refs[i] = new WeakReference<>(interfaces[i]); + } + } + + @Override + public int hashCode() { + return hash; + } + + @Override + public boolean equals(Object obj) { + return this == obj || + obj != null && + obj.getClass() == KeyX.class && + equals(refs, ((KeyX) obj).refs); + } + + private static boolean equals(WeakReference>[] refs1, + WeakReference>[] refs2) { + if (refs1.length != refs2.length) { + return false; + } + for (int i = 0; i < refs1.length; i++) { + Class intf = refs1[i].get(); + if (intf == null || intf != refs2[i].get()) { + return false; } - if (proxyClass != null) { - // proxy class already generated: return it - return proxyClass; - } else if (value == pendingGenerationMarker) { - // proxy class being generated: wait for it - try { - cache.wait(); - } catch (InterruptedException e) { - /* - * The class generation that we are waiting for should - * take a small, bounded time, so we can safely ignore - * thread interrupts here. - */ - } - continue; - } else { - /* - * No proxy class for this list of interfaces has been - * generated or is being generated, so we will go and - * generate it now. Mark it as pending generation. - */ - cache.put(key, pendingGenerationMarker); - break; - } - } while (true); + } + return true; } + } + + /** + * A function that maps an array of interfaces to an optimal key where + * Class objects representing interfaces are weakly referenced. + */ + private static final class KeyFactory + implements BiFunction[], Object> + { + @Override + public Object apply(ClassLoader classLoader, Class[] interfaces) { + switch (interfaces.length) { + case 1: return new Key1(interfaces[0]); // the most frequent + case 2: return new Key2(interfaces[0], interfaces[1]); + case 0: return key0; + default: return new KeyX(interfaces); + } + } + } + + /** + * A factory function that generates, defines and returns the proxy class given + * the ClassLoader and array of interfaces. + */ + private static final class ProxyClassFactory + implements BiFunction[], Class> + { + // prefix for all proxy class names + private static final String proxyClassNamePrefix = "$Proxy"; + + // next number to use for generation of unique proxy class names + private static final AtomicLong nextUniqueNumber = new AtomicLong(); + + @Override + public Class apply(ClassLoader loader, Class[] interfaces) { + + Map, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); + for (Class intf : interfaces) { + /* + * Verify that the class loader resolves the name of this + * interface to the same Class object. + */ + Class interfaceClass = null; + try { + interfaceClass = Class.forName(intf.getName(), false, loader); + } catch (ClassNotFoundException e) { + } + if (interfaceClass != intf) { + throw new IllegalArgumentException( + intf + " is not visible from class loader"); + } + /* + * Verify that the Class object actually represents an + * interface. + */ + if (!interfaceClass.isInterface()) { + throw new IllegalArgumentException( + interfaceClass.getName() + " is not an interface"); + } + /* + * Verify that this interface is not a duplicate. + */ + if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { + throw new IllegalArgumentException( + "repeated interface: " + interfaceClass.getName()); + } + } - try { String proxyPkg = null; // package to define proxy class in + int accessFlags = Modifier.PUBLIC | Modifier.FINAL; /* * Record the package of a non-public proxy interface so that the * proxy class will be defined in the same package. Verify that * all non-public proxy interfaces are in the same package. */ - for (int i = 0; i < interfaces.length; i++) { - int flags = interfaces[i].getModifiers(); + for (Class intf : interfaces) { + int flags = intf.getModifiers(); if (!Modifier.isPublic(flags)) { - String name = interfaces[i].getName(); + accessFlags = Modifier.FINAL; + String name = intf.getName(); int n = name.lastIndexOf('.'); String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); if (proxyPkg == null) { @@ -616,77 +627,42 @@ public class Proxy implements java.io.Serializable { proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } -generate: do - { - /* - * Choose a name for the proxy class to generate. - */ - long num; - synchronized (nextUniqueNumberLock) { - num = nextUniqueNumber++; - } - String proxyName = proxyPkg + proxyClassNamePrefix + num; - /* - * Verify that the class loader hasn't already - * defined a class with the chosen name. - */ - - proxyClass = getPrecompiledProxy(loader, proxyName, interfaces); - if (proxyClass != null) - break generate; - - /* - * Generate the specified proxy class. - */ - byte[] proxyClassFile = ProxyGenerator.generateProxyClass( - proxyName, interfaces); - try { - proxyClass = defineClass0(loader, proxyName, - proxyClassFile, 0, proxyClassFile.length); - } catch (ClassFormatError e) { - /* - * A ClassFormatError here means that (barring bugs in the - * proxy class generation code) there was some other - * invalid aspect of the arguments supplied to the proxy - * class creation (such as virtual machine limitations - * exceeded). - */ - throw new IllegalArgumentException(e.toString()); - } - } - while (false); - // add to set of all generated proxy classes, for isProxyClass - proxyClasses.put(proxyClass, null); - - } finally { /* - * We must clean up the "pending generation" state of the proxy - * class cache entry somehow. If a proxy class was successfully - * generated, store it in the cache (with a weak reference); - * otherwise, remove the reserved entry. In all cases, notify - * all waiters on reserved entries in this cache. + * Choose a name for the proxy class to generate. */ - synchronized (cache) { - if (proxyClass != null) { - cache.put(key, new WeakReference>(proxyClass)); - } else { - cache.remove(key); - } - cache.notifyAll(); + long num = nextUniqueNumber.getAndIncrement(); + String proxyName = proxyPkg + proxyClassNamePrefix + num; + + Class precompiledProxyClass = getPrecompiledProxy(loader, proxyName, interfaces); + if (precompiledProxyClass != null) { + return precompiledProxyClass; + } + + /* + * Generate the specified proxy class. + */ + byte[] proxyClassFile = ProxyGenerator.generateProxyClass( + proxyName, interfaces, accessFlags); + try { + return defineClass0(loader, proxyName, + proxyClassFile, 0, proxyClassFile.length); + } catch (ClassFormatError e) { + /* + * A ClassFormatError here means that (barring bugs in the + * proxy class generation code) there was some other + * invalid aspect of the arguments supplied to the proxy + * class creation (such as virtual machine limitations + * exceeded). + */ + throw new IllegalArgumentException(e.toString()); } } - return proxyClass; } /** * Returns an instance of a proxy class for the specified interfaces * that dispatches method invocations to the specified invocation - * handler. This method is equivalent to: - *
        -     *     Proxy.getProxyClass(loader, interfaces).
        -     *         getConstructor(new Class[] { InvocationHandler.class }).
        -     *         newInstance(new Object[] { handler });
        -     * 
        + * handler. * *

        {@code Proxy.newProxyInstance} throws * {@code IllegalArgumentException} for the same reasons that @@ -702,6 +678,27 @@ generate: do * @throws IllegalArgumentException if any of the restrictions on the * parameters that may be passed to {@code getProxyClass} * are violated + * @throws SecurityException if a security manager, s, is present + * and any of the following conditions is met: + *

          + *
        • the given {@code loader} is {@code null} and + * the caller's class loader is not {@code null} and the + * invocation of {@link SecurityManager#checkPermission + * s.checkPermission} with + * {@code RuntimePermission("getClassLoader")} permission + * denies access;
        • + *
        • for each proxy interface, {@code intf}, + * the caller's class loader is not the same as or an + * ancestor of the class loader for {@code intf} and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to {@code intf};
        • + *
        • any of the given proxy interfaces is non-public and the + * caller class is not in the same {@linkplain Package runtime package} + * as the non-public interface and the invocation of + * {@link SecurityManager#checkPermission s.checkPermission} with + * {@code ReflectPermission("newProxyInPackage.{package name}")} + * permission denies access.
        • + *
        * @throws NullPointerException if the {@code interfaces} array * argument or any of its elements are {@code null}, or * if the invocation handler, {@code h}, is @@ -713,53 +710,70 @@ generate: do InvocationHandler h) throws IllegalArgumentException { - if (h == null) { - throw new NullPointerException(); - } + Objects.requireNonNull(h); + final Class[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { - checkProxyAccess(Reflection.getCallerClass(), loader, interfaces); + checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Look up or generate the designated proxy class. */ - Class cl = getProxyClass0(loader, interfaces); + Class cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { + if (sm != null) { + checkNewProxyPermission(Reflection.getCallerClass(), cl); + } + final Constructor cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; - if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) { - // create proxy instance with doPrivilege as the proxy class may - // implement non-public interfaces that requires a special permission - return AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - return newInstance(cons, ih); + if (!Modifier.isPublic(cl.getModifiers())) { + AccessController.doPrivileged(new PrivilegedAction() { + public Void run() { + cons.setAccessible(true); + return null; } }); - } else { - return newInstance(cons, ih); } - } catch (NoSuchMethodException e) { - throw new InternalError(e.toString()); - } - } - - private static Object newInstance(Constructor cons, InvocationHandler h) { - try { - return cons.newInstance(new Object[] {h} ); - } catch (IllegalAccessException | InstantiationException e) { - throw new InternalError(e.toString()); + return cons.newInstance(new Object[]{h}); + } catch (IllegalAccessException|InstantiationException e) { + throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { - throw new InternalError(t.toString()); + throw new InternalError(t.toString(), t); + } + } catch (NoSuchMethodException e) { + throw new InternalError(e.toString(), e); + } + } + + private static void checkNewProxyPermission(Class caller, Class proxyClass) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + if (ReflectUtil.isNonPublicProxyClass(proxyClass)) { + ClassLoader ccl = caller.getClassLoader(); + ClassLoader pcl = proxyClass.getClassLoader(); + + // do permission check if the caller is in a different runtime package + // of the proxy class + int n = proxyClass.getName().lastIndexOf('.'); + String pkg = (n == -1) ? "" : proxyClass.getName().substring(0, n); + + n = caller.getName().lastIndexOf('.'); + String callerPkg = (n == -1) ? "" : caller.getName().substring(0, n); + + if (pcl != ccl || !pkg.equals(callerPkg)) { + sm.checkPermission(new ReflectPermission("newProxyInPackage." + pkg)); + } } } } @@ -779,11 +793,7 @@ generate: do * @throws NullPointerException if {@code cl} is {@code null} */ public static boolean isProxyClass(Class cl) { - if (cl == null) { - throw new NullPointerException(); - } - - return proxyClasses.containsKey(cl); + return Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl); } /** @@ -793,7 +803,14 @@ generate: do * @return the invocation handler for the proxy instance * @throws IllegalArgumentException if the argument is not a * proxy instance + * @throws SecurityException if a security manager, s, is present + * and the caller's class loader is not the same as or an + * ancestor of the class loader for the invocation handler + * and invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to the invocation + * handler's class. */ + @CallerSensitive public static InvocationHandler getInvocationHandler(Object proxy) throws IllegalArgumentException { @@ -804,12 +821,23 @@ generate: do throw new IllegalArgumentException("not a proxy instance"); } - Proxy p = (Proxy) proxy; - return p.h; + final Proxy p = (Proxy) proxy; + final InvocationHandler ih = p.h; + if (System.getSecurityManager() != null) { + Class ihClass = ih.getClass(); + Class caller = Reflection.getCallerClass(); + if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), + ihClass.getClassLoader())) + { + ReflectUtil.checkPackageAccess(ihClass); + } + } + + return ih; } - private static native Class defineClass0(ClassLoader loader, String name, - byte[] b, int off, int len); + private static native Class defineClass0(ClassLoader loader, String name, + byte[] b, int off, int len); private static native Class getPrecompiledProxy(ClassLoader loader, String proxyName, Class[] interfaces); } diff --git a/external/ikvm/openjdk/java/net/DualStackPlainDatagramSocketImpl_c.java b/external/ikvm/openjdk/java/net/DualStackPlainDatagramSocketImpl_c.java index 1f4ed69bef..98e364d33d 100644 --- a/external/ikvm/openjdk/java/net/DualStackPlainDatagramSocketImpl_c.java +++ b/external/ikvm/openjdk/java/net/DualStackPlainDatagramSocketImpl_c.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -263,15 +263,14 @@ static int socketReceiveOrPeekData packetBuffer = dpObj.buf; packetBufferOffset = dpObj.offset; packetBufferLen = dpObj.bufLength; + /* Note: the buffer needn't be greater than 65,536 (0xFFFF) + * the max size of an IP packet. Anything bigger is truncated anyway. + *-/ + if (packetBufferLen > MAX_PACKET_LEN) { + packetBufferLen = MAX_PACKET_LEN; + } - /* if (packetBufferLen > MAX_BUFFER_LEN) { - /* Note: the buffer needn't be greater than 65,536 (0xFFFF) - * the max size of an IP packet. Anything bigger is truncated anyway. - *-/ - if (packetBufferLen > MAX_PACKET_LEN) { - packetBufferLen = MAX_PACKET_LEN; - } fullPacket = (char *)malloc(packetBufferLen); if (!fullPacket) { JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); @@ -380,8 +379,10 @@ static int socketReceiveOrPeekData int[] tmp = { port }; packetAddress = NET_SockaddrToInetAddress(sa, tmp); port = tmp[0]; - /* stuff the new Inetaddress into the packet */ - dpObj.address = packetAddress; + if (packetAddress != NULL) { + /* stuff the new Inetaddress into the packet */ + dpObj.address = packetAddress; + } } /* populate the packet */ diff --git a/external/ikvm/openjdk/java/net/SocketInputStream.java b/external/ikvm/openjdk/java/net/SocketInputStream.java deleted file mode 100644 index 161947cc5e..0000000000 --- a/external/ikvm/openjdk/java/net/SocketInputStream.java +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.net; - -import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.channels.FileChannel; -import static ikvm.internal.Winsock.*; -import static java.net.net_util_md.*; - -import sun.misc.IoTrace; -import sun.net.ConnectionResetException; - -/** - * This stream extends FileInputStream to implement a - * SocketInputStream. Note that this class should NOT be - * public. - * - * @author Jonathan Payne - * @author Arthur van Hoff - */ -class SocketInputStream extends FileInputStream -{ - - private boolean eof; - private AbstractPlainSocketImpl impl = null; - private byte temp[]; - private Socket socket = null; - - /** - * Creates a new SocketInputStream. Can only be called - * by a Socket. This method needs to hang on to the owner Socket so - * that the fd will not be closed. - * @param impl the implemented socket input stream - */ - SocketInputStream(AbstractPlainSocketImpl impl) throws IOException { - super(impl.getFileDescriptor()); - this.impl = impl; - socket = impl.getSocket(); - } - - /** - * Returns the unique {@link java.nio.channels.FileChannel FileChannel} - * object associated with this file input stream.

        - * - * The getChannel method of SocketInputStream - * returns null since it is a socket based stream.

        - * - * @return the file channel associated with this file input stream - * - * @since 1.4 - * @spec JSR-51 - */ - public final FileChannel getChannel() { - return null; - } - - /** - * Reads into an array of bytes at the specified offset using - * the received socket primitive. - * @param fd the FileDescriptor - * @param b the buffer into which the data is read - * @param off the start offset of the data - * @param len the maximum number of bytes read - * @param timeout the read timeout in ms - * @return the actual number of bytes read, -1 is - * returned when the end of the stream is reached. - * @exception IOException If an I/O error has occurred. - */ - private int socketRead0(FileDescriptor fdObj, byte bufP[], int off, int len, int timeout) throws IOException - { - // [IKVM] this method is a direct port of the native code in openjdk6-b18\jdk\src\windows\native\java\net\SocketInputStream.c - cli.System.Net.Sockets.Socket fd = null; - int nread; - - if (IS_NULL(fdObj)) { - throw new SocketException("socket closed"); - } - fd = fdObj.getSocket(); - if (fd == null) { - throw new SocketException("Socket closed"); - } - - if (timeout != 0) { - if (timeout <= 5000 || !isRcvTimeoutSupported) { - int ret = NET_Timeout (fd, timeout); - - if (ret <= 0) { - if (ret == 0) { - throw new SocketTimeoutException("Read timed out"); - } else { - // [IKVM] the OpenJDK native code is broken and always throws this exception on any failure of NET_Timeout - throw new SocketException("socket closed"); - } - } - - /*check if the socket has been closed while we were in timeout*/ - if (fdObj.getSocket() == null) { - throw new SocketException("Socket Closed"); - } - } - } - - nread = recv(fd, bufP, off, len, 0); - if (nread > 0) { - // ok - } else { - if (nread < 0) { - /* - * Recv failed. - */ - switch (WSAGetLastError()) { - case WSAEINTR: - throw new SocketException("socket closed"); - - case WSAECONNRESET: - case WSAESHUTDOWN: - /* - * Connection has been reset - Windows sometimes reports - * the reset as a shutdown error. - */ - throw new ConnectionResetException(); - - case WSAETIMEDOUT : - throw new SocketTimeoutException("Read timed out"); - - default: - throw NET_ThrowCurrent("recv failed"); - } - } - } - return nread; - } - - /** - * Reads into a byte array data from the socket. - * @param b the buffer into which the data is read - * @return the actual number of bytes read, -1 is - * returned when the end of the stream is reached. - * @exception IOException If an I/O error has occurred. - */ - public int read(byte b[]) throws IOException { - return read(b, 0, b.length); - } - - /** - * Reads into a byte array b at offset off, - * length bytes of data. - * @param b the buffer into which the data is read - * @param off the start offset of the data - * @param len the maximum number of bytes read - * @return the actual number of bytes read, -1 is - * returned when the end of the stream is reached. - * @exception IOException If an I/O error has occurred. - */ - public int read(byte b[], int off, int length) throws IOException { - return read(b, off, length, impl.getTimeout()); - } - - int read(byte b[], int off, int length, int timeout) throws IOException { - int n = 0; - - // EOF already encountered - if (eof) { - return -1; - } - - // connection reset - if (impl.isConnectionReset()) { - throw new SocketException("Connection reset"); - } - - // bounds check - if (length <= 0 || off < 0 || off + length > b.length) { - if (length == 0) { - return 0; - } - throw new ArrayIndexOutOfBoundsException(); - } - - boolean gotReset = false; - - Object traceContext = IoTrace.socketReadBegin(); - // acquire file descriptor and do the read - FileDescriptor fd = impl.acquireFD(); - try { - n = socketRead0(fd, b, off, length, timeout); - if (n > 0) { - return n; - } - } catch (ConnectionResetException rstExc) { - gotReset = true; - } finally { - impl.releaseFD(); - IoTrace.socketReadEnd(traceContext, impl.address, impl.port, - timeout, n > 0 ? n : 0); - } - - /* - * We receive a "connection reset" but there may be bytes still - * buffered on the socket - */ - if (gotReset) { - traceContext = IoTrace.socketReadBegin(); - impl.setConnectionResetPending(); - impl.acquireFD(); - try { - n = socketRead0(fd, b, off, length, timeout); - if (n > 0) { - return n; - } - } catch (ConnectionResetException rstExc) { - } finally { - impl.releaseFD(); - IoTrace.socketReadEnd(traceContext, impl.address, impl.port, - timeout, n > 0 ? n : 0); - } - } - - /* - * If we get here we are at EOF, the socket has been closed, - * or the connection has been reset. - */ - if (impl.isClosedOrPending()) { - throw new SocketException("Socket closed"); - } - if (impl.isConnectionResetPending()) { - impl.setConnectionReset(); - } - if (impl.isConnectionReset()) { - throw new SocketException("Connection reset"); - } - eof = true; - return -1; - } - - /** - * Reads a single byte from the socket. - */ - public int read() throws IOException { - if (eof) { - return -1; - } - temp = new byte[1]; - int n = read(temp, 0, 1); - if (n <= 0) { - return -1; - } - return temp[0] & 0xff; - } - - /** - * Skips n bytes of input. - * @param n the number of bytes to skip - * @return the actual number of bytes skipped. - * @exception IOException If an I/O error has occurred. - */ - public long skip(long numbytes) throws IOException { - if (numbytes <= 0) { - return 0; - } - long n = numbytes; - int buflen = (int) Math.min(1024, n); - byte data[] = new byte[buflen]; - while (n > 0) { - int r = read(data, 0, (int) Math.min((long) buflen, n)); - if (r < 0) { - break; - } - n -= r; - } - return numbytes - n; - } - - /** - * Returns the number of bytes that can be read without blocking. - * @return the number of immediately available bytes - */ - public int available() throws IOException { - return impl.available(); - } - - /** - * Closes the stream. - */ - private boolean closing = false; - public void close() throws IOException { - // Prevent recursion. See BugId 4484411 - if (closing) - return; - closing = true; - if (socket != null) { - if (!socket.isClosed()) - socket.close(); - } else - impl.close(); - closing = false; - } - - void setEOF(boolean eof) { - this.eof = eof; - } - - /** - * Overrides finalize, the fd is closed by the Socket. - */ - protected void finalize() {} -} diff --git a/external/ikvm/openjdk/java/net/SocketOutputStream.java b/external/ikvm/openjdk/java/net/SocketOutputStream.java deleted file mode 100644 index fd6e2c4fb9..0000000000 --- a/external/ikvm/openjdk/java/net/SocketOutputStream.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (c) 1995, 2007, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.net; - -import java.io.FileDescriptor; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.channels.FileChannel; -import static ikvm.internal.Winsock.*; -import static java.net.net_util_md.*; - -import sun.misc.IoTrace; - -/** - * This stream extends FileOutputStream to implement a - * SocketOutputStream. Note that this class should NOT be - * public. - * - * @author Jonathan Payne - * @author Arthur van Hoff - */ -class SocketOutputStream extends FileOutputStream -{ - private AbstractPlainSocketImpl impl = null; - private byte temp[] = new byte[1]; - private Socket socket = null; - - /** - * Creates a new SocketOutputStream. Can only be called - * by a Socket. This method needs to hang on to the owner Socket so - * that the fd will not be closed. - * @param impl the socket output stream inplemented - */ - SocketOutputStream(AbstractPlainSocketImpl impl) throws IOException { - super(impl.getFileDescriptor()); - this.impl = impl; - socket = impl.getSocket(); - } - - /** - * Returns the unique {@link java.nio.channels.FileChannel FileChannel} - * object associated with this file output stream.

        - * - * The getChannel method of SocketOutputStream - * returns null since it is a socket based stream.

        - * - * @return the file channel associated with this file output stream - * - * @since 1.4 - * @spec JSR-51 - */ - public final FileChannel getChannel() { - return null; - } - - /** - * Writes to the socket. - * @param fd the FileDescriptor - * @param b the data to be written - * @param off the start offset in the data - * @param len the number of bytes that are written - * @exception IOException If an I/O error has occurred. - */ - private void socketWrite0(FileDescriptor fdObj, byte[] data, int off, int len) throws IOException - { - // [IKVM] this method is a direct port of the native code in openjdk6-b18\jdk\src\windows\native\java\net\SocketOutputStream.c - final int MAX_BUFFER_LEN = 2048; - cli.System.Net.Sockets.Socket fd; - int buflen = 65536; // MAX_HEAP_BUFFER_LEN - int n; - - if (IS_NULL(fdObj)) { - throw new SocketException("socket closed"); - } else { - fd = fdObj.getSocket(); - } - if (IS_NULL(data)) { - throw new NullPointerException("data argument"); - } - - while(len > 0) { - int loff = 0; - int chunkLen = Math.min(buflen, len); - int llen = chunkLen; - int retry = 0; - - while(llen > 0) { - n = send(fd, data, off + loff, llen, 0); - if (n > 0) { - llen -= n; - loff += n; - continue; - } - - /* - * Due to a bug in Windows Sockets (observed on NT and Windows - * 2000) it may be necessary to retry the send. The issue is that - * on blocking sockets send/WSASend is supposed to block if there - * is insufficient buffer space available. If there are a large - * number of threads blocked on write due to congestion then it's - * possile to hit the NT/2000 bug whereby send returns WSAENOBUFS. - * The workaround we use is to retry the send. If we have a - * large buffer to send (>2k) then we retry with a maximum of - * 2k buffer. If we hit the issue with <=2k buffer then we backoff - * for 1 second and retry again. We repeat this up to a reasonable - * limit before bailing out and throwing an exception. In load - * conditions we've observed that the send will succeed after 2-3 - * attempts but this depends on network buffers associated with - * other sockets draining. - */ - if (WSAGetLastError() == WSAENOBUFS) { - if (llen > MAX_BUFFER_LEN) { - buflen = MAX_BUFFER_LEN; - chunkLen = MAX_BUFFER_LEN; - llen = MAX_BUFFER_LEN; - continue; - } - if (retry >= 30) { - throw new SocketException("No buffer space available - exhausted attempts to queue buffer"); - } - cli.System.Threading.Thread.Sleep(1000); - retry++; - continue; - } - - /* - * Send failed - can be caused by close or write error. - */ - if (WSAGetLastError() == WSAENOTSOCK) { - throw new SocketException("Socket closed"); - } else { - throw NET_ThrowCurrent("socket write error"); - } - } - len -= chunkLen; - off += chunkLen; - } - } - - /** - * Writes to the socket with appropriate locking of the - * FileDescriptor. - * @param b the data to be written - * @param off the start offset in the data - * @param len the number of bytes that are written - * @exception IOException If an I/O error has occurred. - */ - private void socketWrite(byte b[], int off, int len) throws IOException { - - if (len <= 0 || off < 0 || off + len > b.length) { - if (len == 0) { - return; - } - throw new ArrayIndexOutOfBoundsException(); - } - - Object traceContext = IoTrace.socketWriteBegin(); - int bytesWritten = 0; - FileDescriptor fd = impl.acquireFD(); - try { - socketWrite0(fd, b, off, len); - bytesWritten = len; - } catch (SocketException se) { - if (se instanceof sun.net.ConnectionResetException) { - impl.setConnectionResetPending(); - se = new SocketException("Connection reset"); - } - if (impl.isClosedOrPending()) { - throw new SocketException("Socket closed"); - } else { - throw se; - } - } finally { - impl.releaseFD(); - IoTrace.socketWriteEnd(traceContext, impl.address, impl.port, bytesWritten); - } - } - - /** - * Writes a byte to the socket. - * @param b the data to be written - * @exception IOException If an I/O error has occurred. - */ - public void write(int b) throws IOException { - temp[0] = (byte)b; - socketWrite(temp, 0, 1); - } - - /** - * Writes the contents of the buffer b to the socket. - * @param b the data to be written - * @exception SocketException If an I/O error has occurred. - */ - public void write(byte b[]) throws IOException { - socketWrite(b, 0, b.length); - } - - /** - * Writes length bytes from buffer b starting at - * offset len. - * @param b the data to be written - * @param off the start offset in the data - * @param len the number of bytes that are written - * @exception SocketException If an I/O error has occurred. - */ - public void write(byte b[], int off, int len) throws IOException { - socketWrite(b, off, len); - } - - /** - * Closes the stream. - */ - private boolean closing = false; - public void close() throws IOException { - // Prevent recursion. See BugId 4484411 - if (closing) - return; - closing = true; - if (socket != null) { - if (!socket.isClosed()) - socket.close(); - } else - impl.close(); - closing = false; - } - - /** - * Overrides finalize, the fd is closed by the Socket. - */ - protected void finalize() {} -} diff --git a/external/ikvm/openjdk/java/net/TwoStacksPlainDatagramSocketImpl_c.java b/external/ikvm/openjdk/java/net/TwoStacksPlainDatagramSocketImpl_c.java index d84a427b0f..1b44ccec72 100644 --- a/external/ikvm/openjdk/java/net/TwoStacksPlainDatagramSocketImpl_c.java +++ b/external/ikvm/openjdk/java/net/TwoStacksPlainDatagramSocketImpl_c.java @@ -515,6 +515,9 @@ static void bind0(JNIEnv env, TwoStacksPlainDatagramSocketImpl _this, } } } else { + /* NET_BindV6() closes both sockets upon a failure */ + _this.fd = null; + _this.fd1 = null; NET_ThrowCurrent (env, "Cannot bind"); return; } diff --git a/external/ikvm/openjdk/java/net/TwoStacksPlainSocketImpl_c.java b/external/ikvm/openjdk/java/net/TwoStacksPlainSocketImpl_c.java index d86e84d07e..d51845e3ea 100644 --- a/external/ikvm/openjdk/java/net/TwoStacksPlainSocketImpl_c.java +++ b/external/ikvm/openjdk/java/net/TwoStacksPlainSocketImpl_c.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,6 @@ static final int java_net_SocketOptions_SO_LINGER = SocketOptions.SO_LINGER; #include "java_net_SocketOptions.h" #include "java_net_TwoStacksPlainSocketImpl.h" -#include "java_net_SocketImpl.h" #include "java_net_InetAddress.h" #include "java_io_FileDescriptor.h" #include "java_lang_Integer.h" @@ -486,6 +485,10 @@ static void socketBind(JNIEnv env, TwoStacksPlainSocketImpl _this, /* socket was re-created */ fd1Obj.setSocket(fd1); } + } else { + /* NET_BindV6() closes both sockets upon a failure */ + _this.fd = null; + _this.fd1 = null; } } } else { diff --git a/external/ikvm/openjdk/java/net/net_util_md.java b/external/ikvm/openjdk/java/net/net_util_md.java index 724ba4ccf7..03fe929d10 100644 --- a/external/ikvm/openjdk/java/net/net_util_md.java +++ b/external/ikvm/openjdk/java/net/net_util_md.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -318,6 +318,11 @@ final class net_util_md { int rv; + if (level == IPPROTO_IPV6 && optname == IPV6_TCLASS) { + ((int[])optval)[0] = 0; + return 0; + } + rv = getsockopt(s, level, optname, optval); @@ -645,17 +650,17 @@ final class net_util_md * structure for an IPv4 InetAddress. */ static int NET_InetAddressToSockaddr(JNIEnv env, InetAddress iaObj, int port, SOCKETADDRESS him, boolean v4MappedAddress) { - if (iaObj.family == InetAddress.IPv4) { - him.set(new IPEndPoint(new IPAddress(htonl(iaObj.address) & 0xFFFFFFFFL), port)); + if (iaObj.holder().family == InetAddress.IPv4) { + him.set(new IPEndPoint(new IPAddress(htonl(iaObj.holder().address) & 0xFFFFFFFFL), port)); return 0; } else { Inet6Address v6addr = (Inet6Address)iaObj; int scope = v6addr.getScopeId(); if (scope == 0) { - him.set(new IPEndPoint(new IPAddress(v6addr.ipaddress), port)); + him.set(new IPEndPoint(new IPAddress(v6addr.getAddress()), port)); return 0; } else { - him.set(new IPEndPoint(new IPAddress(v6addr.ipaddress, scope & 0xFFFFFFFFL), port)); + him.set(new IPEndPoint(new IPAddress(v6addr.getAddress(), scope & 0xFFFFFFFFL), port)); return 0; } } @@ -725,7 +730,7 @@ final class net_util_md } static boolean NET_SockaddrEqualsInetAddress(SOCKETADDRESS him, InetAddress iaObj) { - int family = iaObj.family == InetAddress.IPv4 ? AF_INET : AF_INET6; + int family = iaObj.holder().family == InetAddress.IPv4 ? AF_INET : AF_INET6; if (him.sa_family == AF_INET6) { byte[] caddrNew = him.him6.sin6_addr; @@ -736,7 +741,7 @@ final class net_util_md return false; } addrNew = NET_IPv4MappedToIPv4(caddrNew); - addrCur = iaObj.address; + addrCur = iaObj.holder().address; if (addrNew == addrCur) { return true; } else { @@ -750,7 +755,7 @@ final class net_util_md return false; } scope = ((Inet6Address)iaObj).getScopeId(); - caddrCur = ((Inet6Address)iaObj).ipaddress; + caddrCur = ((Inet6Address)iaObj).getAddress(); if (NET_IsEqual(caddrNew, caddrCur) && cmpScopeID(scope, him)) { return true; } else { @@ -763,7 +768,7 @@ final class net_util_md return false; } addrNew = ntohl(him.him4.sin_addr.s_addr); - addrCur = iaObj.address; + addrCur = iaObj.holder().address; if (addrNew == addrCur) { return true; } else { @@ -875,10 +880,10 @@ final class net_util_md } static int getInetAddress_addr(JNIEnv env, InetAddress iaObj) { - return iaObj.address; + return iaObj.holder().address; } static int getInetAddress_family(JNIEnv env, InetAddress iaObj) { - return iaObj.family; + return iaObj.holder().family; } } diff --git a/external/ikvm/openjdk/java/util/concurrent/ForkJoinPool.java.REMOVED.git-id b/external/ikvm/openjdk/java/util/concurrent/ForkJoinPool.java.REMOVED.git-id deleted file mode 100644 index 36ff3b60d3..0000000000 --- a/external/ikvm/openjdk/java/util/concurrent/ForkJoinPool.java.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -4b1579622418fcea5533553de4bd441a4303f8e7 \ No newline at end of file diff --git a/external/ikvm/openjdk/map.xml.REMOVED.git-id b/external/ikvm/openjdk/map.xml.REMOVED.git-id index ac27a2608a..fd04a5b0b4 100644 --- a/external/ikvm/openjdk/map.xml.REMOVED.git-id +++ b/external/ikvm/openjdk/map.xml.REMOVED.git-id @@ -1 +1 @@ -21beaab3280677891e9c48e06d9a2bcbd21e7c24 \ No newline at end of file +2ce91edd530b14ec4a26b27fa65026fec0f867e1 \ No newline at end of file diff --git a/external/ikvm/openjdk/openjdk.build b/external/ikvm/openjdk/openjdk.build index 2b3dd1af54..3d7e1892e1 100644 --- a/external/ikvm/openjdk/openjdk.build +++ b/external/ikvm/openjdk/openjdk.build @@ -27,11 +27,11 @@ - + - - + + @@ -192,7 +192,7 @@ - + diff --git a/external/ikvm/openjdk/response.txt.REMOVED.git-id b/external/ikvm/openjdk/response.txt.REMOVED.git-id index 22c0a1089f..616ef235fe 100644 --- a/external/ikvm/openjdk/response.txt.REMOVED.git-id +++ b/external/ikvm/openjdk/response.txt.REMOVED.git-id @@ -1 +1 @@ -409d55c92d6f811ce77f595beba1d76dc74392f2 \ No newline at end of file +9bc69a05416bbd6824ff761bb41aef2e63e5d28b \ No newline at end of file diff --git a/external/ikvm/openjdk/sun/awt/DebugSettings.java b/external/ikvm/openjdk/sun/awt/DebugSettings.java new file mode 100644 index 0000000000..43c3f28210 --- /dev/null +++ b/external/ikvm/openjdk/sun/awt/DebugSettings.java @@ -0,0 +1,30 @@ +/* + Copyright (C) 2015 Jeroen Frijters + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jeroen Frijters + jeroen@frijters.net + +*/ + +package sun.awt; + +final class DebugSettings +{ + static void init() { } +} diff --git a/external/ikvm/openjdk/sun/awt/SunToolkit.java b/external/ikvm/openjdk/sun/awt/SunToolkit.java deleted file mode 100644 index 11612ec1ee..0000000000 --- a/external/ikvm/openjdk/sun/awt/SunToolkit.java +++ /dev/null @@ -1,2010 +0,0 @@ -/* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.awt; - -import java.awt.*; -import static java.awt.RenderingHints.*; -import java.awt.dnd.*; -import java.awt.dnd.peer.DragSourceContextPeer; -import java.awt.peer.*; -import java.awt.event.WindowEvent; -import java.awt.event.KeyEvent; -import java.awt.image.*; -import java.awt.TrayIcon; -import java.awt.SystemTray; -import java.awt.event.InputEvent; -import java.net.URL; -import java.util.*; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -import sun.security.util.SecurityConstants; -import sun.util.logging.PlatformLogger; -import sun.misc.SoftCache; -import sun.font.FontDesignMetrics; -import sun.awt.im.InputContext; -import sun.awt.image.*; -import sun.security.action.GetPropertyAction; -import sun.security.action.GetBooleanAction; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; - -public abstract class SunToolkit extends Toolkit - implements WindowClosingSupport, WindowClosingListener, - ComponentFactory, InputMethodSupport, KeyboardFocusManagerPeerProvider { - - // 8014736: logging has been removed from SunToolkit - - /** - * Special mask for the UngrabEvent events, in addition to the - * public masks defined in AWTEvent. Should be used as the mask - * value for Toolkit.addAWTEventListener. - */ - public static final int GRAB_EVENT_MASK = 0x80000000; - - private static Method wakeupMethod; - /* The key to put()/get() the PostEventQueue into/from the AppContext. - */ - private static final String POST_EVENT_QUEUE_KEY = "PostEventQueue"; - - /** - * Number of buttons. - * By default it's taken from the system. If system value does not - * fit into int type range, use our own MAX_BUTTONS_SUPPORT value. - */ - protected static int numberOfButtons = 0; - - - /* XFree standard mention 24 buttons as maximum: - * http://www.xfree86.org/current/mouse.4.html - * We workaround systems supporting more than 24 buttons. - * Otherwise, we have to use long type values as masks - * which leads to API change. - * InputEvent.BUTTON_DOWN_MASK may contain only 21 masks due to - * the 4-bytes limit for the int type. (CR 6799099) - * One more bit is reserved for FIRST_HIGH_BIT. - */ - public final static int MAX_BUTTONS_SUPPORTED = 20; - - /** - * Creates and initializes EventQueue instance for the specified - * AppContext. - * Note that event queue must be created from createNewAppContext() - * only in order to ensure that EventQueue constructor obtains - * the correct AppContext. - * @param appContext AppContext to associate with the event queue - */ - private static void initEQ(AppContext appContext) { - EventQueue eventQueue; - - String eqName = System.getProperty("AWT.EventQueueClass", - "java.awt.EventQueue"); - - try { - eventQueue = (EventQueue)Class.forName(eqName).newInstance(); - } catch (Exception e) { - e.printStackTrace(); - System.err.println("Failed loading " + eqName + ": " + e); - eventQueue = new EventQueue(); - } - appContext.put(AppContext.EVENT_QUEUE_KEY, eventQueue); - - PostEventQueue postEventQueue = new PostEventQueue(eventQueue); - appContext.put(POST_EVENT_QUEUE_KEY, postEventQueue); - } - - public SunToolkit() { - } - - public boolean useBufferPerWindow() { - return false; - } - - public abstract WindowPeer createWindow(Window target) - throws HeadlessException; - - public abstract FramePeer createFrame(Frame target) - throws HeadlessException; - - public abstract DialogPeer createDialog(Dialog target) - throws HeadlessException; - - public abstract ButtonPeer createButton(Button target) - throws HeadlessException; - - public abstract TextFieldPeer createTextField(TextField target) - throws HeadlessException; - - public abstract ChoicePeer createChoice(Choice target) - throws HeadlessException; - - public abstract LabelPeer createLabel(Label target) - throws HeadlessException; - - public abstract ListPeer createList(java.awt.List target) - throws HeadlessException; - - public abstract CheckboxPeer createCheckbox(Checkbox target) - throws HeadlessException; - - public abstract ScrollbarPeer createScrollbar(Scrollbar target) - throws HeadlessException; - - public abstract ScrollPanePeer createScrollPane(ScrollPane target) - throws HeadlessException; - - public abstract TextAreaPeer createTextArea(TextArea target) - throws HeadlessException; - - public abstract FileDialogPeer createFileDialog(FileDialog target) - throws HeadlessException; - - public abstract MenuBarPeer createMenuBar(MenuBar target) - throws HeadlessException; - - public abstract MenuPeer createMenu(Menu target) - throws HeadlessException; - - public abstract PopupMenuPeer createPopupMenu(PopupMenu target) - throws HeadlessException; - - public abstract MenuItemPeer createMenuItem(MenuItem target) - throws HeadlessException; - - public abstract CheckboxMenuItemPeer createCheckboxMenuItem( - CheckboxMenuItem target) - throws HeadlessException; - - public abstract DragSourceContextPeer createDragSourceContextPeer( - DragGestureEvent dge) - throws InvalidDnDOperationException; - - public abstract TrayIconPeer createTrayIcon(TrayIcon target) - throws HeadlessException, AWTException; - - public abstract SystemTrayPeer createSystemTray(SystemTray target); - - public abstract boolean isTraySupported(); - - public abstract FontPeer getFontPeer(String name, int style); - - public abstract RobotPeer createRobot(Robot target, GraphicsDevice screen) - throws AWTException; - - public abstract KeyboardFocusManagerPeer createKeyboardFocusManagerPeer(KeyboardFocusManager manager) - throws HeadlessException; - - /** - * The AWT lock is typically only used on Unix platforms to synchronize - * access to Xlib, OpenGL, etc. However, these methods are implemented - * in SunToolkit so that they can be called from shared code (e.g. - * from the OGL pipeline) or from the X11 pipeline regardless of whether - * XToolkit or MToolkit is currently in use. There are native macros - * (such as AWT_LOCK) defined in awt.h, so if the implementation of these - * methods is changed, make sure it is compatible with the native macros. - * - * Note: The following methods (awtLock(), awtUnlock(), etc) should be - * used in place of: - * synchronized (getAWTLock()) { - * ... - * } - * - * By factoring these methods out specially, we are able to change the - * implementation of these methods (e.g. use more advanced locking - * mechanisms) without impacting calling code. - * - * Sample usage: - * private void doStuffWithXlib() { - * assert !SunToolkit.isAWTLockHeldByCurrentThread(); - * SunToolkit.awtLock(); - * try { - * ... - * XlibWrapper.XDoStuff(); - * } finally { - * SunToolkit.awtUnlock(); - * } - * } - */ - - private static final ReentrantLock AWT_LOCK = new ReentrantLock(); - private static final Condition AWT_LOCK_COND = AWT_LOCK.newCondition(); - - public static final void awtLock() { - AWT_LOCK.lock(); - } - - public static final boolean awtTryLock() { - return AWT_LOCK.tryLock(); - } - - public static final void awtUnlock() { - AWT_LOCK.unlock(); - } - - public static final void awtLockWait() - throws InterruptedException - { - AWT_LOCK_COND.await(); - } - - public static final void awtLockWait(long timeout) - throws InterruptedException - { - AWT_LOCK_COND.await(timeout, TimeUnit.MILLISECONDS); - } - - public static final void awtLockNotify() { - AWT_LOCK_COND.signal(); - } - - public static final void awtLockNotifyAll() { - AWT_LOCK_COND.signalAll(); - } - - public static final boolean isAWTLockHeldByCurrentThread() { - return AWT_LOCK.isHeldByCurrentThread(); - } - - /* - * Create a new AppContext, along with its EventQueue, for a - * new ThreadGroup. Browser code, for example, would use this - * method to create an AppContext & EventQueue for an Applet. - */ - public static AppContext createNewAppContext() { - ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); - return createNewAppContext(threadGroup); - } - - static final AppContext createNewAppContext(ThreadGroup threadGroup) { - // Create appContext before initialization of EventQueue, so all - // the calls to AppContext.getAppContext() from EventQueue ctor - // return correct values - AppContext appContext = new AppContext(threadGroup); - initEQ(appContext); - - return appContext; - } - - public static Field getField(final Class klass, final String fieldName) { - return AccessController.doPrivileged(new PrivilegedAction() { - public Field run() { - try { - Field field = klass.getDeclaredField(fieldName); - assert (field != null); - field.setAccessible(true); - return field; - } catch (SecurityException e) { - assert false; - } catch (NoSuchFieldException e) { - assert false; - } - return null; - }//run - }); - } - - static void wakeupEventQueue(EventQueue q, boolean isShutdown){ - if (wakeupMethod == null){ - wakeupMethod = (Method)AccessController.doPrivileged(new PrivilegedAction(){ - public Object run(){ - try { - Method method = EventQueue.class.getDeclaredMethod("wakeup",new Class [] {Boolean.TYPE} ); - if (method != null) { - method.setAccessible(true); - } - return method; - } catch (NoSuchMethodException e) { - assert false; - } catch (SecurityException e) { - assert false; - } - return null; - }//run - }); - } - try{ - if (wakeupMethod != null){ - wakeupMethod.invoke(q, new Object[]{Boolean.valueOf(isShutdown)}); - } - } catch (InvocationTargetException e){ - assert false; - } catch (IllegalAccessException e) { - assert false; - } - } - - /* - * Fetch the peer associated with the given target (as specified - * in the peer creation method). This can be used to determine - * things like what the parent peer is. If the target is null - * or the target can't be found (either because the a peer was - * never created for it or the peer was disposed), a null will - * be returned. - */ - protected static Object targetToPeer(Object target) { - if (target != null && !GraphicsEnvironment.isHeadless()) { - return AWTAutoShutdown.getInstance().getPeer(target); - } - return null; - } - - protected static void targetCreatedPeer(Object target, Object peer) { - if (target != null && peer != null && - !GraphicsEnvironment.isHeadless()) - { - AWTAutoShutdown.getInstance().registerPeer(target, peer); - } - } - - protected static void targetDisposedPeer(Object target, Object peer) { - if (target != null && peer != null && - !GraphicsEnvironment.isHeadless()) - { - AWTAutoShutdown.getInstance().unregisterPeer(target, peer); - } - } - - // Maps from non-Component/MenuComponent to AppContext. - // WeakHashMap - private static final Map appContextMap = - Collections.synchronizedMap(new WeakHashMap()); - - /** - * Sets the appContext field of target. If target is not a Component or - * MenuComponent, this returns false. - */ - private static boolean setAppContext(Object target, - AppContext context) { - if (target instanceof Component) { - AWTAccessor.getComponentAccessor(). - setAppContext((Component)target, context); - } else if (target instanceof MenuComponent) { - AWTAccessor.getMenuComponentAccessor(). - setAppContext((MenuComponent)target, context); - } else { - return false; - } - return true; - } - - /** - * Returns the appContext field for target. If target is not a - * Component or MenuComponent this returns null. - */ - private static AppContext getAppContext(Object target) { - if (target instanceof Component) { - return AWTAccessor.getComponentAccessor(). - getAppContext((Component)target); - } else if (target instanceof MenuComponent) { - return AWTAccessor.getMenuComponentAccessor(). - getAppContext((MenuComponent)target); - } else { - return null; - } - } - - /* - * Fetch the AppContext associated with the given target. - * This can be used to determine things like which EventQueue - * to use for posting events to a Component. If the target is - * null or the target can't be found, a null with be returned. - */ - public static AppContext targetToAppContext(Object target) { - if (target == null || GraphicsEnvironment.isHeadless()) { - return null; - } - AppContext context = getAppContext(target); - if (context == null) { - // target is not a Component/MenuComponent, try the - // appContextMap. - context = (AppContext)appContextMap.get(target); - } - return context; - } - - /** - * Sets the synchronous status of focus requests on lightweight - * components in the specified window to the specified value. - * If the boolean parameter is true then the focus - * requests on lightweight components will be performed - * synchronously, if it is false, then asynchronously. - * By default, all windows have their lightweight request status - * set to asynchronous. - *

        - * The application can only set the status of lightweight focus - * requests to synchronous for any of its windows if it doesn't - * perform focus transfers between different heavyweight containers. - * In this case the observable focus behaviour is the same as with - * asynchronous status. - *

        - * If the application performs focus transfer between different - * heavyweight containers and sets the lightweight focus request - * status to synchronous for any of its windows, then further focus - * behaviour is unspecified. - *

        - * @param w window for which the lightweight focus request status - * should be set - * @param status the value of lightweight focus request status - */ - - public static void setLWRequestStatus(Window changed,boolean status){ - AWTAccessor.getWindowAccessor().setLWRequestStatus(changed, status); - }; - - public static void checkAndSetPolicy(Container cont) { - FocusTraversalPolicy defaultPolicy = KeyboardFocusManager. - getCurrentKeyboardFocusManager(). - getDefaultFocusTraversalPolicy(); - - cont.setFocusTraversalPolicy(defaultPolicy); - } - - private static FocusTraversalPolicy createLayoutPolicy() { - FocusTraversalPolicy policy = null; - try { - Class layoutPolicyClass = - Class.forName("javax.swing.LayoutFocusTraversalPolicy"); - policy = (FocusTraversalPolicy) layoutPolicyClass.newInstance(); - } - catch (ClassNotFoundException e) { - assert false; - } - catch (InstantiationException e) { - assert false; - } - catch (IllegalAccessException e) { - assert false; - } - - return policy; - } - - /* - * Insert a mapping from target to AppContext, for later retrieval - * via targetToAppContext() above. - */ - public static void insertTargetMapping(Object target, AppContext appContext) { - if (!GraphicsEnvironment.isHeadless()) { - if (!setAppContext(target, appContext)) { - // Target is not a Component/MenuComponent, use the private Map - // instead. - appContextMap.put(target, appContext); - } - } - } - - /* - * Post an AWTEvent to the Java EventQueue, using the PostEventQueue - * to avoid possibly calling client code (EventQueueSubclass.postEvent()) - * on the toolkit (AWT-Windows/AWT-Motif) thread. This function should - * not be called under another lock since it locks the EventQueue. - * See bugids 4632918, 4526597. - */ - public static void postEvent(AppContext appContext, AWTEvent event) { - if (event == null) { - throw new NullPointerException(); - } - // All events posted via this method are system-generated. - // Placing the following call here reduces considerably the - // number of places throughout the toolkit that would - // otherwise have to be modified to precisely identify - // system-generated events. - setSystemGenerated(event); - PostEventQueue postEventQueue = - (PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY); - if (postEventQueue != null) { - postEventQueue.postEvent(event); - } - } - - /* - * Post AWTEvent of high priority. - */ - public static void postPriorityEvent(final AWTEvent e) { - PeerEvent pe = new PeerEvent(Toolkit.getDefaultToolkit(), new Runnable() { - public void run() { - AWTAccessor.getAWTEventAccessor().setPosted(e); - ((Component)e.getSource()).dispatchEvent(e); - } - }, PeerEvent.ULTIMATE_PRIORITY_EVENT); - postEvent(targetToAppContext(e.getSource()), pe); - } - - protected static final Lock flushLock = new ReentrantLock(); - private static boolean isFlushingPendingEvents = false; - - /* - * Flush any pending events which haven't been posted to the AWT - * EventQueue yet. - */ - public static void flushPendingEvents() { - AppContext appContext = AppContext.getAppContext(); - flushPendingEvents(appContext); - } - - public static void flushPendingEvents(AppContext appContext) { - flushLock.lock(); - try { - // Don't call flushPendingEvents() recursively - if (!isFlushingPendingEvents) { - isFlushingPendingEvents = true; - try { - PostEventQueue postEventQueue = - (PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY); - if (postEventQueue != null) { - postEventQueue.flush(); - } - } - finally { - isFlushingPendingEvents = false; - } - } - } finally { - flushLock.unlock(); - } - } - - public static boolean isPostEventQueueEmpty() { - AppContext appContext = AppContext.getAppContext(); - PostEventQueue postEventQueue = - (PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY); - if (postEventQueue != null) { - return postEventQueue.noEvents(); - } else { - return true; - } - } - - /* - * Execute a chunk of code on the Java event handler thread for the - * given target. Does not wait for the execution to occur before - * returning to the caller. - */ - public static void executeOnEventHandlerThread(Object target, - Runnable runnable) { - executeOnEventHandlerThread(new PeerEvent(target, runnable, PeerEvent.PRIORITY_EVENT)); - } - - /* - * Fixed 5064013: the InvocationEvent time should be equals - * the time of the ActionEvent - */ - public static void executeOnEventHandlerThread(Object target, - Runnable runnable, - final long when) { - executeOnEventHandlerThread(new PeerEvent(target, runnable, PeerEvent.PRIORITY_EVENT){ - public long getWhen(){ - return when; - } - }); - } - - /* - * Execute a chunk of code on the Java event handler thread for the - * given target. Does not wait for the execution to occur before - * returning to the caller. - */ - public static void executeOnEventHandlerThread(PeerEvent peerEvent) { - postEvent(targetToAppContext(peerEvent.getSource()), peerEvent); - } - - /* - * Execute a chunk of code on the Java event handler thread. The - * method takes into account provided AppContext and sets - * SunToolkit.getDefaultToolkit() as a target of the - * event. See 6451487 for detailes. - * Does not wait for the execution to occur before returning to - * the caller. - */ - public static void invokeLaterOnAppContext( - AppContext appContext, Runnable dispatcher) - { - postEvent(appContext, - new PeerEvent(Toolkit.getDefaultToolkit(), dispatcher, - PeerEvent.PRIORITY_EVENT)); - } - - /* - * Execute a chunk of code on the Java event handler thread for the - * given target. Waits for the execution to occur before returning - * to the caller. - */ - public static void executeOnEDTAndWait(Object target, Runnable runnable) - throws InterruptedException, InvocationTargetException - { - if (EventQueue.isDispatchThread()) { - throw new Error("Cannot call executeOnEDTAndWait from any event dispatcher thread"); - } - - class AWTInvocationLock {} - Object lock = new AWTInvocationLock(); - - PeerEvent event = new PeerEvent(target, runnable, lock, true, PeerEvent.PRIORITY_EVENT); - - synchronized (lock) { - executeOnEventHandlerThread(event); - while(!event.isDispatched()) { - lock.wait(); - } - } - - Throwable eventThrowable = event.getThrowable(); - if (eventThrowable != null) { - throw new InvocationTargetException(eventThrowable); - } - } - - /* - * Returns true if the calling thread is the event dispatch thread - * contained within AppContext which associated with the given target. - * Use this call to ensure that a given task is being executed - * (or not being) on the event dispatch thread for the given target. - */ - public static boolean isDispatchThreadForAppContext(Object target) { - AppContext appContext = targetToAppContext(target); - EventQueue eq = (EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY); - - AWTAccessor.EventQueueAccessor accessor = AWTAccessor.getEventQueueAccessor(); - return accessor.isDispatchThreadImpl(eq); - } - - public Dimension getScreenSize() { - return new Dimension(getScreenWidth(), getScreenHeight()); - } - protected abstract int getScreenWidth(); - protected abstract int getScreenHeight(); - - public String[] getFontList() { - String[] hardwiredFontList = { - Font.DIALOG, Font.SANS_SERIF, Font.SERIF, Font.MONOSPACED, - Font.DIALOG_INPUT - - // -- Obsolete font names from 1.0.2. It was decided that - // -- getFontList should not return these old names: - // "Helvetica", "TimesRoman", "Courier", "ZapfDingbats" - }; - return hardwiredFontList; - } - - public PanelPeer createPanel(Panel target) { - return (PanelPeer)createComponent(target); - } - - public CanvasPeer createCanvas(Canvas target) { - return (CanvasPeer)createComponent(target); - } - - /** - * Disables erasing of background on the canvas before painting if - * this is supported by the current toolkit. It is recommended to - * call this method early, before the Canvas becomes displayable, - * because some Toolkit implementations do not support changing - * this property once the Canvas becomes displayable. - */ - public void disableBackgroundErase(Canvas canvas) { - disableBackgroundEraseImpl(canvas); - } - - /** - * Disables the native erasing of the background on the given - * component before painting if this is supported by the current - * toolkit. This only has an effect for certain components such as - * Canvas, Panel and Window. It is recommended to call this method - * early, before the Component becomes displayable, because some - * Toolkit implementations do not support changing this property - * once the Component becomes displayable. - */ - public void disableBackgroundErase(Component component) { - disableBackgroundEraseImpl(component); - } - - private void disableBackgroundEraseImpl(Component component) { - AWTAccessor.getComponentAccessor().setBackgroundEraseDisabled(component, true); - } - - /** - * Returns the value of "sun.awt.noerasebackground" property. Default - * value is {@code false}. - */ - public static boolean getSunAwtNoerasebackground() { - return AccessController.doPrivileged(new GetBooleanAction("sun.awt.noerasebackground")); - } - - /** - * Returns the value of "sun.awt.erasebackgroundonresize" property. Default - * value is {@code false}. - */ - public static boolean getSunAwtErasebackgroundonresize() { - return AccessController.doPrivileged(new GetBooleanAction("sun.awt.erasebackgroundonresize")); - } - - public Image createImage(ImageProducer producer) { - return new ToolkitImage(producer); - } - - public int checkImage(Image img, int w, int h, ImageObserver o) { - if (!(img instanceof ToolkitImage)) { - return ImageObserver.ALLBITS; - } - - ToolkitImage tkimg = (ToolkitImage)img; - int repbits; - if (w == 0 || h == 0) { - repbits = ImageObserver.ALLBITS; - } else { - repbits = tkimg.getImageRep().check(o); - } - return tkimg.check(o) | repbits; - } - - public boolean prepareImage(Image img, int w, int h, ImageObserver o) { - if (w == 0 || h == 0) { - return true; - } - - // Must be a ToolkitImage - if (!(img instanceof ToolkitImage)) { - return true; - } - - ToolkitImage tkimg = (ToolkitImage)img; - if (tkimg.hasError()) { - if (o != null) { - o.imageUpdate(img, ImageObserver.ERROR|ImageObserver.ABORT, - -1, -1, -1, -1); - } - return false; - } - ImageRepresentation ir = tkimg.getImageRep(); - return ir.prepare(o); - } - - /** - * Scans {@code imageList} for best-looking image of specified dimensions. - * Image can be scaled and/or padded with transparency. - */ - public static BufferedImage getScaledIconImage(java.util.List imageList, int width, int height) { - if (width == 0 || height == 0) { - return null; - } - Image bestImage = null; - int bestWidth = 0; - int bestHeight = 0; - double bestSimilarity = 3; //Impossibly high value - double bestScaleFactor = 0; - for (Iterator i = imageList.iterator();i.hasNext();) { - //Iterate imageList looking for best matching image. - //'Similarity' measure is defined as good scale factor and small insets. - //best possible similarity is 0 (no scale, no insets). - //It's found while the experiments that good-looking result is achieved - //with scale factors x1, x3/4, x2/3, xN, x1/N. - Image im = i.next(); - if (im == null) { - continue; - } - if (im instanceof ToolkitImage) { - ImageRepresentation ir = ((ToolkitImage)im).getImageRep(); - ir.reconstruct(ImageObserver.ALLBITS); - } - int iw; - int ih; - try { - iw = im.getWidth(null); - ih = im.getHeight(null); - } catch (Exception e){ - continue; - } - if (iw > 0 && ih > 0) { - //Calc scale factor - double scaleFactor = Math.min((double)width / (double)iw, - (double)height / (double)ih); - //Calculate scaled image dimensions - //adjusting scale factor to nearest "good" value - int adjw = 0; - int adjh = 0; - double scaleMeasure = 1; //0 - best (no) scale, 1 - impossibly bad - if (scaleFactor >= 2) { - //Need to enlarge image more than twice - //Round down scale factor to multiply by integer value - scaleFactor = Math.floor(scaleFactor); - adjw = iw * (int)scaleFactor; - adjh = ih * (int)scaleFactor; - scaleMeasure = 1.0 - 0.5 / scaleFactor; - } else if (scaleFactor >= 1) { - //Don't scale - scaleFactor = 1.0; - adjw = iw; - adjh = ih; - scaleMeasure = 0; - } else if (scaleFactor >= 0.75) { - //Multiply by 3/4 - scaleFactor = 0.75; - adjw = iw * 3 / 4; - adjh = ih * 3 / 4; - scaleMeasure = 0.3; - } else if (scaleFactor >= 0.6666) { - //Multiply by 2/3 - scaleFactor = 0.6666; - adjw = iw * 2 / 3; - adjh = ih * 2 / 3; - scaleMeasure = 0.33; - } else { - //Multiply size by 1/scaleDivider - //where scaleDivider is minimum possible integer - //larger than 1/scaleFactor - double scaleDivider = Math.ceil(1.0 / scaleFactor); - scaleFactor = 1.0 / scaleDivider; - adjw = (int)Math.round((double)iw / scaleDivider); - adjh = (int)Math.round((double)ih / scaleDivider); - scaleMeasure = 1.0 - 1.0 / scaleDivider; - } - double similarity = ((double)width - (double)adjw) / (double)width + - ((double)height - (double)adjh) / (double)height + //Large padding is bad - scaleMeasure; //Large rescale is bad - if (similarity < bestSimilarity) { - bestSimilarity = similarity; - bestScaleFactor = scaleFactor; - bestImage = im; - bestWidth = adjw; - bestHeight = adjh; - } - if (similarity == 0) break; - } - } - if (bestImage == null) { - //No images were found, possibly all are broken - return null; - } - BufferedImage bimage = - new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); - Graphics2D g = bimage.createGraphics(); - g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, - RenderingHints.VALUE_INTERPOLATION_BILINEAR); - try { - int x = (width - bestWidth) / 2; - int y = (height - bestHeight) / 2; - g.drawImage(bestImage, x, y, bestWidth, bestHeight, null); - } finally { - g.dispose(); - } - return bimage; - } - - public static DataBufferInt getScaledIconData(java.util.List imageList, int width, int height) { - BufferedImage bimage = getScaledIconImage(imageList, width, height); - if (bimage == null) { - return null; - } - Raster raster = bimage.getRaster(); - DataBuffer buffer = raster.getDataBuffer(); - return (DataBufferInt)buffer; - } - - protected EventQueue getSystemEventQueueImpl() { - return getSystemEventQueueImplPP(); - } - - // Package private implementation - static EventQueue getSystemEventQueueImplPP() { - return getSystemEventQueueImplPP(AppContext.getAppContext()); - } - - public static EventQueue getSystemEventQueueImplPP(AppContext appContext) { - EventQueue theEventQueue = - (EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY); - return theEventQueue; - } - - /** - * Give native peers the ability to query the native container - * given a native component (eg the direct parent may be lightweight). - */ - public static Container getNativeContainer(Component c) { - return Toolkit.getNativeContainer(c); - } - - /** - * Gives native peers the ability to query the closest HW component. - * If the given component is heavyweight, then it returns this. Otherwise, - * it goes one level up in the hierarchy and tests next component. - */ - public static Component getHeavyweightComponent(Component c) { - while (c != null && AWTAccessor.getComponentAccessor().isLightweight(c)) { - c = AWTAccessor.getComponentAccessor().getParent(c); - } - return c; - } - - /** - * Returns key modifiers used by Swing to set up a focus accelerator key stroke. - */ - public int getFocusAcceleratorKeyMask() { - return InputEvent.ALT_MASK; - } - - /** - * Tests whether specified key modifiers mask can be used to enter a printable - * character. This is a default implementation of this method, which reflects - * the way things work on Windows: here, pressing ctrl + alt allows user to enter - * characters from the extended character set (like euro sign or math symbols) - */ - public boolean isPrintableCharacterModifiersMask(int mods) { - return ((mods & InputEvent.ALT_MASK) == (mods & InputEvent.CTRL_MASK)); - } - - /** - * Returns whether popup is allowed to be shown above the task bar. - * This is a default implementation of this method, which checks - * corresponding security permission. - */ - public boolean canPopupOverlapTaskBar() { - boolean result = true; - try { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission( - SecurityConstants.AWT.SET_WINDOW_ALWAYS_ON_TOP_PERMISSION); - } - } catch (SecurityException se) { - // There is no permission to show popups over the task bar - result = false; - } - return result; - } - - /** - * Returns whether enableInputMethods should be set to true for peered - * TextComponent instances on this platform. False by default. - */ - public boolean enableInputMethodsForTextComponent() { - return false; - } - - private static Locale startupLocale = null; - - /** - * Returns the locale in which the runtime was started. - */ - public static Locale getStartupLocale() { - if (startupLocale == null) { - String language, region, country, variant; - language = (String) AccessController.doPrivileged( - new GetPropertyAction("user.language", "en")); - // for compatibility, check for old user.region property - region = (String) AccessController.doPrivileged( - new GetPropertyAction("user.region")); - if (region != null) { - // region can be of form country, country_variant, or _variant - int i = region.indexOf('_'); - if (i >= 0) { - country = region.substring(0, i); - variant = region.substring(i + 1); - } else { - country = region; - variant = ""; - } - } else { - country = (String) AccessController.doPrivileged( - new GetPropertyAction("user.country", "")); - variant = (String) AccessController.doPrivileged( - new GetPropertyAction("user.variant", "")); - } - startupLocale = new Locale(language, country, variant); - } - return startupLocale; - } - - /** - * Returns the default keyboard locale of the underlying operating system - */ - public Locale getDefaultKeyboardLocale() { - return getStartupLocale(); - } - - private static String dataTransfererClassName = null; - - protected static void setDataTransfererClassName(String className) { - dataTransfererClassName = className; - } - - public static String getDataTransfererClassName() { - if (dataTransfererClassName == null) { - Toolkit.getDefaultToolkit(); // transferer set during toolkit init - } - return dataTransfererClassName; - } - - // Support for window closing event notifications - private transient WindowClosingListener windowClosingListener = null; - /** - * @see sun.awt.WindowClosingSupport#getWindowClosingListener - */ - public WindowClosingListener getWindowClosingListener() { - return windowClosingListener; - } - /** - * @see sun.awt.WindowClosingSupport#setWindowClosingListener - */ - public void setWindowClosingListener(WindowClosingListener wcl) { - windowClosingListener = wcl; - } - - /** - * @see sun.awt.WindowClosingListener#windowClosingNotify - */ - public RuntimeException windowClosingNotify(WindowEvent event) { - if (windowClosingListener != null) { - return windowClosingListener.windowClosingNotify(event); - } else { - return null; - } - } - /** - * @see sun.awt.WindowClosingListener#windowClosingDelivered - */ - public RuntimeException windowClosingDelivered(WindowEvent event) { - if (windowClosingListener != null) { - return windowClosingListener.windowClosingDelivered(event); - } else { - return null; - } - } - - - - /** - * Returns whether default toolkit needs the support of the xembed - * from embedding host(if any). - * @return true, if XEmbed is needed, false otherwise - */ - public static boolean needsXEmbed() { - String noxembed = (String) AccessController. - doPrivileged(new GetPropertyAction("sun.awt.noxembed", "false")); - if ("true".equals(noxembed)) { - return false; - } - - Toolkit tk = Toolkit.getDefaultToolkit(); - if (tk instanceof SunToolkit) { - // SunToolkit descendants should override this method to specify - // concrete behavior - return ((SunToolkit)tk).needsXEmbedImpl(); - } else { - // Non-SunToolkit doubtly might support XEmbed - return false; - } - } - - /** - * Returns whether this toolkit needs the support of the xembed - * from embedding host(if any). - * @return true, if XEmbed is needed, false otherwise - */ - protected boolean needsXEmbedImpl() { - return false; - } - - private static Dialog.ModalExclusionType DEFAULT_MODAL_EXCLUSION_TYPE = null; - - /** - * Returns whether the XEmbed server feature is requested by - * developer. If true, Toolkit should return an - * XEmbed-server-enabled CanvasPeer instead of the ordinary CanvasPeer. - */ - protected final boolean isXEmbedServerRequested() { - return AccessController.doPrivileged(new GetBooleanAction("sun.awt.xembedserver")); - } - - /** - * Returns whether the modal exclusion API is supported by the current toolkit. - * When it isn't supported, calling setModalExcluded has no - * effect, and isModalExcluded returns false for all windows. - * - * @return true if modal exclusion is supported by the toolkit, false otherwise - * - * @see sun.awt.SunToolkit#setModalExcluded(java.awt.Window) - * @see sun.awt.SunToolkit#isModalExcluded(java.awt.Window) - * - * @since 1.5 - */ - public static boolean isModalExcludedSupported() - { - Toolkit tk = Toolkit.getDefaultToolkit(); - return tk.isModalExclusionTypeSupported(DEFAULT_MODAL_EXCLUSION_TYPE); - } - /* - * Default implementation for isModalExcludedSupportedImpl(), returns false. - * - * @see sun.awt.windows.WToolkit#isModalExcludeSupportedImpl - * @see sun.awt.X11.XToolkit#isModalExcludeSupportedImpl - * - * @since 1.5 - */ - protected boolean isModalExcludedSupportedImpl() - { - return false; - } - - /* - * Sets this window to be excluded from being modally blocked. When the - * toolkit supports modal exclusion and this method is called, input - * events, focus transfer and z-order will continue to work for the - * window, it's owned windows and child components, even in the - * presence of a modal dialog. - * For details on which Windows are normally blocked - * by modal dialog, see {@link java.awt.Dialog}. - * Invoking this method when the modal exclusion API is not supported by - * the current toolkit has no effect. - * @param window Window to be marked as not modally blocked - * @see java.awt.Dialog - * @see java.awt.Dialog#setModal(boolean) - * @see sun.awt.SunToolkit#isModalExcludedSupported - * @see sun.awt.SunToolkit#isModalExcluded(java.awt.Window) - */ - public static void setModalExcluded(Window window) - { - if (DEFAULT_MODAL_EXCLUSION_TYPE == null) { - DEFAULT_MODAL_EXCLUSION_TYPE = Dialog.ModalExclusionType.APPLICATION_EXCLUDE; - } - window.setModalExclusionType(DEFAULT_MODAL_EXCLUSION_TYPE); - } - - /* - * Returns whether the specified window is blocked by modal dialogs. - * If the modal exclusion API isn't supported by the current toolkit, - * it returns false for all windows. - * - * @param window Window to test for modal exclusion - * - * @return true if the window is modal excluded, false otherwise. If - * the modal exclusion isn't supported by the current Toolkit, false - * is returned - * - * @see sun.awt.SunToolkit#isModalExcludedSupported - * @see sun.awt.SunToolkit#setModalExcluded(java.awt.Window) - * - * @since 1.5 - */ - public static boolean isModalExcluded(Window window) - { - if (DEFAULT_MODAL_EXCLUSION_TYPE == null) { - DEFAULT_MODAL_EXCLUSION_TYPE = Dialog.ModalExclusionType.APPLICATION_EXCLUDE; - } - return window.getModalExclusionType().compareTo(DEFAULT_MODAL_EXCLUSION_TYPE) >= 0; - } - - /** - * Overridden in XToolkit and WToolkit - */ - public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) { - return (modalityType == Dialog.ModalityType.MODELESS) || - (modalityType == Dialog.ModalityType.APPLICATION_MODAL); - } - - /** - * Overridden in XToolkit and WToolkit - */ - public boolean isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType) { - return (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE); - } - - /////////////////////////////////////////////////////////////////////////// - // - // The following is used by the Java Plug-in to coordinate dialog modality - // between containing applications (browsers, ActiveX containers etc) and - // the AWT. - // - /////////////////////////////////////////////////////////////////////////// - - private ModalityListenerList modalityListeners = new ModalityListenerList(); - - public void addModalityListener(ModalityListener listener) { - modalityListeners.add(listener); - } - - public void removeModalityListener(ModalityListener listener) { - modalityListeners.remove(listener); - } - - public void notifyModalityPushed(Dialog dialog) { - notifyModalityChange(ModalityEvent.MODALITY_PUSHED, dialog); - } - - public void notifyModalityPopped(Dialog dialog) { - notifyModalityChange(ModalityEvent.MODALITY_POPPED, dialog); - } - - final void notifyModalityChange(int id, Dialog source) { - ModalityEvent ev = new ModalityEvent(source, modalityListeners, id); - ev.dispatch(); - } - - static class ModalityListenerList implements ModalityListener { - - Vector listeners = new Vector(); - - void add(ModalityListener listener) { - listeners.addElement(listener); - } - - void remove(ModalityListener listener) { - listeners.removeElement(listener); - } - - public void modalityPushed(ModalityEvent ev) { - Iterator it = listeners.iterator(); - while (it.hasNext()) { - it.next().modalityPushed(ev); - } - } - - public void modalityPopped(ModalityEvent ev) { - Iterator it = listeners.iterator(); - while (it.hasNext()) { - it.next().modalityPopped(ev); - } - } - } // end of class ModalityListenerList - - /////////////////////////////////////////////////////////////////////////// - // End Plug-in code - /////////////////////////////////////////////////////////////////////////// - - public static boolean isLightweightOrUnknown(Component comp) { - if (comp.isLightweight() - || !(getDefaultToolkit() instanceof SunToolkit)) - { - return true; - } - return !(comp instanceof Button - || comp instanceof Canvas - || comp instanceof Checkbox - || comp instanceof Choice - || comp instanceof Label - || comp instanceof java.awt.List - || comp instanceof Panel - || comp instanceof Scrollbar - || comp instanceof ScrollPane - || comp instanceof TextArea - || comp instanceof TextField - || comp instanceof Window); - } - - public static Method getMethod(final Class clz, final String methodName, final Class[] params) { - Method res = null; - try { - res = AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Method run() throws Exception { - Method m = clz.getDeclaredMethod(methodName, params); - m.setAccessible(true); - return m; - } - }); - } catch (PrivilegedActionException ex) { - ex.printStackTrace(); - } - return res; - } - - public static class OperationTimedOut extends RuntimeException { - public OperationTimedOut(String msg) { - super(msg); - } - public OperationTimedOut() { - } - } - public static class InfiniteLoop extends RuntimeException { - } - - public static class IllegalThreadException extends RuntimeException { - public IllegalThreadException(String msg) { - super(msg); - } - public IllegalThreadException() { - } - } - - public static final int DEFAULT_WAIT_TIME = 10000; - private static final int MAX_ITERS = 20; - private static final int MIN_ITERS = 0; - private static final int MINIMAL_EDELAY = 0; - - /** - * Parameterless version of realsync which uses default timout (see DEFAUL_WAIT_TIME). - */ - public void realSync() throws OperationTimedOut, InfiniteLoop { - realSync(DEFAULT_WAIT_TIME); - } - - /** - * Forces toolkit to synchronize with the native windowing - * sub-system, flushing all pending work and waiting for all the - * events to be processed. This method guarantees that after - * return no additional Java events will be generated, unless - * cause by user. Obviously, the method cannot be used on the - * event dispatch thread (EDT). In case it nevertheless gets - * invoked on this thread, the method throws the - * IllegalThreadException runtime exception. - * - *

        This method allows to write tests without explicit timeouts - * or wait for some event. Example: - * - * Frame f = ...; - * f.setVisible(true); - * ((SunToolkit)Toolkit.getDefaultToolkit()).realSync(); - * - * - *

        After realSync, f will be completely visible - * on the screen, its getLocationOnScreen will be returning the - * right result and it will be the focus owner. - * - *

        Another example: - * - * b.requestFocus(); - * ((SunToolkit)Toolkit.getDefaultToolkit()).realSync(); - * - * - *

        After realSync, b will be focus owner. - * - *

        Notice that realSync isn't guaranteed to work if recurring - * actions occur, such as if during processing of some event - * another request which may generate some events occurs. By - * default, sync tries to perform as much as {@value MAX_ITERS} - * cycles of event processing, allowing for roughly {@value - * MAX_ITERS} additional requests. - * - *

        For example, requestFocus() generates native request, which - * generates one or two Java focus events, which then generate a - * serie of paint events, a serie of Java focus events, which then - * generate a serie of paint events which then are processed - - * three cycles, minimum. - * - * @param timeout the maximum time to wait in milliseconds, negative means "forever". - */ - public void realSync(final long timeout) throws OperationTimedOut, InfiniteLoop - { - if (EventQueue.isDispatchThread()) { - throw new IllegalThreadException("The SunToolkit.realSync() method cannot be used on the event dispatch thread (EDT)."); - } - int bigLoop = 0; - do { - // Let's do sync first - sync(); - - // During the wait process, when we were processing incoming - // events, we could have made some new request, which can - // generate new events. Example: MapNotify/XSetInputFocus. - // Therefore, we dispatch them as long as there is something - // to dispatch. - int iters = 0; - while (iters < MIN_ITERS) { - syncNativeQueue(timeout); - iters++; - } - while (syncNativeQueue(timeout) && iters < MAX_ITERS) { - iters++; - } - if (iters >= MAX_ITERS) { - throw new InfiniteLoop(); - } - - // native requests were dispatched by X/Window Manager or Windows - // Moreover, we processed them all on Toolkit thread - // Now wait while EDT processes them. - // - // During processing of some events (focus, for example), - // some other events could have been generated. So, after - // waitForIdle, we may end up with full EventQueue - iters = 0; - while (iters < MIN_ITERS) { - waitForIdle(timeout); - iters++; - } - while (waitForIdle(timeout) && iters < MAX_ITERS) { - iters++; - } - if (iters >= MAX_ITERS) { - throw new InfiniteLoop(); - } - - bigLoop++; - // Again, for Java events, it was simple to check for new Java - // events by checking event queue, but what if Java events - // resulted in native requests? Therefor, check native events again. - } while ((syncNativeQueue(timeout) || waitForIdle(timeout)) && bigLoop < MAX_ITERS); - } - - /** - * Platform toolkits need to implement this method to perform the - * sync of the native queue. The method should wait until native - * requests are processed, all native events are processed and - * corresponding Java events are generated. Should return - * true if some events were processed, - * false otherwise. - */ - protected abstract boolean syncNativeQueue(final long timeout); - - private boolean eventDispatched = false; - private boolean queueEmpty = false; - private final Object waitLock = "Wait Lock"; - - static Method eqNoEvents; - - private boolean isEQEmpty() { - EventQueue queue = getSystemEventQueueImpl(); - synchronized(SunToolkit.class) { - if (eqNoEvents == null) { - eqNoEvents = getMethod(java.awt.EventQueue.class, "noEvents", null); - } - } - try { - return (Boolean)eqNoEvents.invoke(queue); - } catch (Exception e) { - e.printStackTrace(); - return false; - } - } - - /** - * Waits for the Java event queue to empty. Ensures that all - * events are processed (including paint events), and that if - * recursive events were generated, they are also processed. - * Should return true if more processing is - * necessary, false otherwise. - */ - protected final boolean waitForIdle(final long timeout) { - flushPendingEvents(); - boolean queueWasEmpty = isEQEmpty(); - queueEmpty = false; - eventDispatched = false; - synchronized(waitLock) { - postEvent(AppContext.getAppContext(), - new PeerEvent(getSystemEventQueueImpl(), null, PeerEvent.LOW_PRIORITY_EVENT) { - public void dispatch() { - // Here we block EDT. It could have some - // events, it should have dispatched them by - // now. So native requests could have been - // generated. First, dispatch them. Then, - // flush Java events again. - int iters = 0; - while (iters < MIN_ITERS) { - syncNativeQueue(timeout); - iters++; - } - while (syncNativeQueue(timeout) && iters < MAX_ITERS) { - iters++; - } - flushPendingEvents(); - - synchronized(waitLock) { - queueEmpty = isEQEmpty(); - eventDispatched = true; - waitLock.notifyAll(); - } - } - }); - try { - while (!eventDispatched) { - waitLock.wait(); - } - } catch (InterruptedException ie) { - return false; - } - } - - try { - Thread.sleep(MINIMAL_EDELAY); - } catch (InterruptedException ie) { - throw new RuntimeException("Interrupted"); - } - - flushPendingEvents(); - - // Lock to force write-cache flush for queueEmpty. - synchronized (waitLock) { - return !(queueEmpty && isEQEmpty() && queueWasEmpty); - } - } - - /** - * Grabs the mouse input for the given window. The window must be - * visible. The window or its children do not receive any - * additional mouse events besides those targeted to them. All - * other events will be dispatched as before - to the respective - * targets. This Window will receive UngrabEvent when automatic - * ungrab is about to happen. The event can be listened to by - * installing AWTEventListener with WINDOW_EVENT_MASK. See - * UngrabEvent class for the list of conditions when ungrab is - * about to happen. - * @see UngrabEvent - */ - public abstract void grab(Window w); - - /** - * Forces ungrab. No event will be sent. - */ - public abstract void ungrab(Window w); - - - /** - * Locates the splash screen library in a platform dependent way and closes - * the splash screen. Should be invoked on first top-level frame display. - * @see java.awt.SplashScreen - * @since 1.6 - */ - public static native void closeSplashScreen(); - - /* The following methods and variables are to support retrieving - * desktop text anti-aliasing settings - */ - - /* Need an instance method because setDesktopProperty(..) is protected. */ - private void fireDesktopFontPropertyChanges() { - setDesktopProperty(SunToolkit.DESKTOPFONTHINTS, - SunToolkit.getDesktopFontHints()); - } - - private static boolean checkedSystemAAFontSettings; - private static boolean useSystemAAFontSettings; - private static boolean lastExtraCondition = true; - private static RenderingHints desktopFontHints; - - /* Since Swing is the reason for this "extra condition" logic its - * worth documenting it in some detail. - * First, a goal is for Swing and applications to both retrieve and - * use the same desktop property value so that there is complete - * consistency between the settings used by JDK's Swing implementation - * and 3rd party custom Swing components, custom L&Fs and any general - * text rendering that wants to be consistent with these. - * But by default on Solaris & Linux Swing will not use AA text over - * remote X11 display (unless Xrender can be used which is TBD and may not - * always be available anyway) as that is a noticeable performance hit. - * So there needs to be a way to express that extra condition so that - * it is seen by all clients of the desktop property API. - * If this were the only condition it could be handled here as it would - * be the same for any L&F and could reasonably be considered to be - * a static behaviour of those systems. - * But GTK currently has an additional test based on locale which is - * not applied by Metal. So mixing GTK in a few locales with Metal - * would mean the last one wins. - * This could be stored per-app context which would work - * for different applets, but wouldn't help for a single application - * using GTK and some other L&F concurrently. - * But it is expected this will be addressed within GTK and the font - * system so is a temporary and somewhat unlikely harmless corner case. - */ - public static void setAAFontSettingsCondition(boolean extraCondition) { - if (extraCondition != lastExtraCondition) { - lastExtraCondition = extraCondition; - if (checkedSystemAAFontSettings) { - /* Someone already asked for this info, under a different - * condition. - * We'll force re-evaluation instead of replicating the - * logic, then notify any listeners of any change. - */ - checkedSystemAAFontSettings = false; - Toolkit tk = Toolkit.getDefaultToolkit(); - if (tk instanceof SunToolkit) { - ((SunToolkit)tk).fireDesktopFontPropertyChanges(); - } - } - } - } - - /* "false", "off", ""default" aren't explicitly tested, they - * just fall through to produce a null return which all are equated to - * "false". - */ - private static RenderingHints getDesktopAAHintsByName(String hintname) { - Object aaHint = null; - hintname = hintname.toLowerCase(Locale.ENGLISH); - if (hintname.equals("on")) { - aaHint = VALUE_TEXT_ANTIALIAS_ON; - } else if (hintname.equals("gasp")) { - aaHint = VALUE_TEXT_ANTIALIAS_GASP; - } else if (hintname.equals("lcd") || hintname.equals("lcd_hrgb")) { - aaHint = VALUE_TEXT_ANTIALIAS_LCD_HRGB; - } else if (hintname.equals("lcd_hbgr")) { - aaHint = VALUE_TEXT_ANTIALIAS_LCD_HBGR; - } else if (hintname.equals("lcd_vrgb")) { - aaHint = VALUE_TEXT_ANTIALIAS_LCD_VRGB; - } else if (hintname.equals("lcd_vbgr")) { - aaHint = VALUE_TEXT_ANTIALIAS_LCD_VBGR; - } - if (aaHint != null) { - RenderingHints map = new RenderingHints(null); - map.put(KEY_TEXT_ANTIALIASING, aaHint); - return map; - } else { - return null; - } - } - - /* This method determines whether to use the system font settings, - * or ignore them if a L&F has specified they should be ignored, or - * to override both of these with a system property specified value. - * If the toolkit isn't a SunToolkit, (eg may be headless) then that - * system property isn't applied as desktop properties are considered - * to be inapplicable in that case. In that headless case although - * this method will return "true" the toolkit will return a null map. - */ - private static boolean useSystemAAFontSettings() { - if (!checkedSystemAAFontSettings) { - useSystemAAFontSettings = true; /* initially set this true */ - String systemAAFonts = null; - Toolkit tk = Toolkit.getDefaultToolkit(); - if (tk instanceof SunToolkit) { - systemAAFonts = - (String)AccessController.doPrivileged( - new GetPropertyAction("awt.useSystemAAFontSettings")); - } - if (systemAAFonts != null) { - useSystemAAFontSettings = - Boolean.valueOf(systemAAFonts).booleanValue(); - /* If it is anything other than "true", then it may be - * a hint name , or it may be "off, "default", etc. - */ - if (!useSystemAAFontSettings) { - desktopFontHints = getDesktopAAHintsByName(systemAAFonts); - } - } - /* If its still true, apply the extra condition */ - if (useSystemAAFontSettings) { - useSystemAAFontSettings = lastExtraCondition; - } - checkedSystemAAFontSettings = true; - } - return useSystemAAFontSettings; - } - - /* A variable defined for the convenience of JDK code */ - public static final String DESKTOPFONTHINTS = "awt.font.desktophints"; - - /* Overridden by subclasses to return platform/desktop specific values */ - protected RenderingHints getDesktopAAHints() { - return null; - } - - /* Subclass desktop property loading methods call this which - * in turn calls the appropriate subclass implementation of - * getDesktopAAHints() when system settings are being used. - * Its public rather than protected because subclasses may delegate - * to a helper class. - */ - public static RenderingHints getDesktopFontHints() { - if (useSystemAAFontSettings()) { - Toolkit tk = Toolkit.getDefaultToolkit(); - if (tk instanceof SunToolkit) { - Object map = ((SunToolkit)tk).getDesktopAAHints(); - return (RenderingHints)map; - } else { /* Headless Toolkit */ - return null; - } - } else if (desktopFontHints != null) { - /* cloning not necessary as the return value is cloned later, but - * its harmless. - */ - return (RenderingHints)(desktopFontHints.clone()); - } else { - return null; - } - } - - - public abstract boolean isDesktopSupported(); - - /* - * consumeNextKeyTyped() method is not currently used, - * however Swing could use it in the future. - */ - private static Method consumeNextKeyTypedMethod = null; - public static synchronized void consumeNextKeyTyped(KeyEvent keyEvent) { - if (consumeNextKeyTypedMethod == null) { - consumeNextKeyTypedMethod = getMethod(DefaultKeyboardFocusManager.class, - "consumeNextKeyTyped", - new Class[] {KeyEvent.class}); - } - try { - consumeNextKeyTypedMethod.invoke(KeyboardFocusManager.getCurrentKeyboardFocusManager(), - keyEvent); - } catch (IllegalAccessException iae) { - iae.printStackTrace(); - } catch (InvocationTargetException ite) { - ite.printStackTrace(); - } - } - - protected static void dumpPeers(final PlatformLogger aLog) { - AWTAutoShutdown.getInstance().dumpPeers(aLog); - } - - /** - * Returns the Window ancestor of the component comp. - * @return Window ancestor of the component or component by itself if it is Window; - * null, if component is not a part of window hierarchy - */ - public static Window getContainingWindow(Component comp) { - while (comp != null && !(comp instanceof Window)) { - comp = comp.getParent(); - } - return (Window)comp; - } - - private static Boolean sunAwtDisableMixing = null; - - /** - * Returns the value of "sun.awt.disableMixing" property. Default - * value is {@code false}. - */ - public synchronized static boolean getSunAwtDisableMixing() { - if (sunAwtDisableMixing == null) { - sunAwtDisableMixing = AccessController.doPrivileged( - new GetBooleanAction("sun.awt.disableMixing")); - } - return sunAwtDisableMixing.booleanValue(); - } - - /** - * Returns true if the native GTK libraries are available. The - * default implementation returns false, but UNIXToolkit overrides this - * method to provide a more specific answer. - */ - public boolean isNativeGTKAvailable() { - return false; - } - - private static final Object DEACTIVATION_TIMES_MAP_KEY = new Object(); - - public synchronized void setWindowDeactivationTime(Window w, long time) { - AppContext ctx = getAppContext(w); - WeakHashMap map = (WeakHashMap)ctx.get(DEACTIVATION_TIMES_MAP_KEY); - if (map == null) { - map = new WeakHashMap(); - ctx.put(DEACTIVATION_TIMES_MAP_KEY, map); - } - map.put(w, time); - } - - public synchronized long getWindowDeactivationTime(Window w) { - AppContext ctx = getAppContext(w); - WeakHashMap map = (WeakHashMap)ctx.get(DEACTIVATION_TIMES_MAP_KEY); - if (map == null) { - return -1; - } - Long time = map.get(w); - return time == null ? -1 : time; - } - - // Cosntant alpha - public boolean isWindowOpacitySupported() { - return false; - } - - // Shaping - public boolean isWindowShapingSupported() { - return false; - } - - // Per-pixel alpha - public boolean isWindowTranslucencySupported() { - return false; - } - - public boolean isTranslucencyCapable(GraphicsConfiguration gc) { - return false; - } - - /** - * Returns true if swing backbuffer should be translucent. - */ - public boolean isSwingBackbufferTranslucencySupported() { - return false; - } - - /** - * Returns whether or not a containing top level window for the passed - * component is - * {@link GraphicsDevice.WindowTranslucency#PERPIXEL_TRANSLUCENT PERPIXEL_TRANSLUCENT}. - * - * @param c a Component which toplevel's to check - * @return {@code true} if the passed component is not null and has a - * containing toplevel window which is opaque (so per-pixel translucency - * is not enabled), {@code false} otherwise - * @see GraphicsDevice.WindowTranslucency#PERPIXEL_TRANSLUCENT - */ - public static boolean isContainingTopLevelOpaque(Component c) { - Window w = getContainingWindow(c); - return w != null && w.isOpaque(); - } - - /** - * Returns whether or not a containing top level window for the passed - * component is - * {@link GraphicsDevice.WindowTranslucency#TRANSLUCENT TRANSLUCENT}. - * - * @param c a Component which toplevel's to check - * @return {@code true} if the passed component is not null and has a - * containing toplevel window which has opacity less than - * 1.0f (which means that it is translucent), {@code false} otherwise - * @see GraphicsDevice.WindowTranslucency#TRANSLUCENT - */ - public static boolean isContainingTopLevelTranslucent(Component c) { - Window w = getContainingWindow(c); - return w != null && ((Window)w).getOpacity() < 1.0f; - } - - /** - * Returns whether the native system requires using the peer.updateWindow() - * method to update the contents of a non-opaque window, or if usual - * painting procedures are sufficient. The default return value covers - * the X11 systems. On MS Windows this method is overriden in WToolkit - * to return true. - */ - public boolean needUpdateWindow() { - return false; - } - - /** - * Descendants of the SunToolkit should override and put their own logic here. - */ - public int getNumberOfButtons(){ - return 3; - } - - /** - * Checks that the given object implements/extends the given - * interface/class. - * - * Note that using the instanceof operator causes a class to be loaded. - * Using this method doesn't load a class and it can be used instead of - * the instanceof operator for performance reasons. - * - * @param obj Object to be checked - * @param type The name of the interface/class. Must be - * fully-qualified interface/class name. - * @return true, if this object implements/extends the given - * interface/class, false, otherwise, or if obj or type is null - */ - public static boolean isInstanceOf(Object obj, String type) { - if (obj == null) return false; - if (type == null) return false; - - return isInstanceOf(obj.getClass(), type); - } - - private static boolean isInstanceOf(Class cls, String type) { - if (cls == null) return false; - - if (cls.getName().equals(type)) { - return true; - } - - for (Class c : cls.getInterfaces()) { - if (c.getName().equals(type)) { - return true; - } - } - return isInstanceOf(cls.getSuperclass(), type); - } - - /////////////////////////////////////////////////////////////////////////// - // - // The following methods help set and identify whether a particular - // AWTEvent object was produced by the system or by user code. As of this - // writing the only consumer is the Java Plug-In, although this information - // could be useful to more clients and probably should be formalized in - // the public API. - // - /////////////////////////////////////////////////////////////////////////// - - public static void setSystemGenerated(AWTEvent e) { - AWTAccessor.getAWTEventAccessor().setSystemGenerated(e); - } - - public static boolean isSystemGenerated(AWTEvent e) { - return AWTAccessor.getAWTEventAccessor().isSystemGenerated(e); - } - -} // class SunToolkit - - -/* - * PostEventQueue is a Thread that runs in the same AppContext as the - * Java EventQueue. It is a queue of AWTEvents to be posted to the - * Java EventQueue. The toolkit Thread (AWT-Windows/AWT-Motif) posts - * events to this queue, which then calls EventQueue.postEvent(). - * - * We do this because EventQueue.postEvent() may be overridden by client - * code, and we mustn't ever call client code from the toolkit thread. - */ -class PostEventQueue { - private EventQueueItem queueHead = null; - private EventQueueItem queueTail = null; - private final EventQueue eventQueue; - - // For the case when queue is cleared but events are not posted - private volatile boolean isFlushing = false; - - PostEventQueue(EventQueue eq) { - eventQueue = eq; - } - - public synchronized boolean noEvents() { - return queueHead == null && !isFlushing; - } - - /* - * Continually post pending AWTEvents to the Java EventQueue. The method - * is synchronized to ensure the flush is completed before a new event - * can be posted to this queue. - * - * 7177040: The method couldn't be wholly synchronized because of calls - * of EventQueue.postEvent() that uses pushPopLock, otherwise it could - * potentially lead to deadlock - */ - public void flush() { - EventQueueItem tempQueue; - synchronized (this) { - tempQueue = queueHead; - queueHead = queueTail = null; - isFlushing = (tempQueue != null); - } - try { - while (tempQueue != null) { - eventQueue.postEvent(tempQueue.event); - tempQueue = tempQueue.next; - } - } - finally { - isFlushing = false; - } - } - - /* - * Enqueue an AWTEvent to be posted to the Java EventQueue. - */ - void postEvent(AWTEvent event) { - EventQueueItem item = new EventQueueItem(event); - - synchronized (this) { - if (queueHead == null) { - queueHead = queueTail = item; - } else { - queueTail.next = item; - queueTail = item; - } - } - SunToolkit.wakeupEventQueue(eventQueue, event.getSource() == AWTAutoShutdown.getInstance()); - } -} // class PostEventQueue diff --git a/external/ikvm/openjdk/sun/awt/shell/Win32ShellFolder2.java b/external/ikvm/openjdk/sun/awt/shell/Win32ShellFolder2.java index 0f5f6816fe..c7d6ea8614 100644 --- a/external/ikvm/openjdk/sun/awt/shell/Win32ShellFolder2.java +++ b/external/ikvm/openjdk/sun/awt/shell/Win32ShellFolder2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (C) 2009 Volker Berlin (i-net software) * Copyright (C) 2010 Karsten Heinrich (i-net software) * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -596,8 +596,23 @@ final class Win32ShellFolder2 extends ShellFolder { } // Needs to be accessible to Win32ShellFolderManager2 - @cli.System.Security.SecurityCriticalAttribute.Annotation - static native String getFileSystemPath(int csidl) throws IOException, InterruptedException; + static String getFileSystemPath(final int csidl) throws IOException, InterruptedException { + String path = invoke(new Callable() { + public String call() throws IOException { + return getFileSystemPath0(csidl); + } + }, IOException.class); + if (path != null) { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkRead(path); + } + } + return path; + } + + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details + private static native String getFileSystemPath0(int csidl) throws IOException; // Return whether the path is a network root. // Path is assumed to be non-null diff --git a/external/ikvm/openjdk/sun/awt/shell/Win32ShellFolderManager2.java b/external/ikvm/openjdk/sun/awt/shell/Win32ShellFolderManager2.java index d688b6a013..09bbe97f7d 100644 --- a/external/ikvm/openjdk/sun/awt/shell/Win32ShellFolderManager2.java +++ b/external/ikvm/openjdk/sun/awt/shell/Win32ShellFolderManager2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,14 +36,15 @@ import java.security.PrivilegedAction; import java.util.*; import java.util.List; import java.util.concurrent.*; +import java.util.stream.Stream; import cli.System.IntPtr; import cli.System.Drawing.Bitmap; import cli.System.Drawing.SystemIcons; -import sun.security.action.LoadLibraryAction; import static sun.awt.shell.Win32ShellFolder2.*; import sun.awt.OSInfo; +import sun.misc.ThreadGroupUtils; // NOTE: This class supersedes Win32ShellFolderManager, which was removed // from distribution after version 1.4.2. @@ -139,6 +140,8 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { if (desktop == null) { try { desktop = new Win32ShellFolder2(DESKTOP); + } catch (SecurityException e) { + // Ignore error } catch (IOException e) { // Ignore error } catch (InterruptedException e) { @@ -152,6 +155,8 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { if (drives == null) { try { drives = new Win32ShellFolder2(DRIVES); + } catch (SecurityException e) { + // Ignore error } catch (IOException e) { // Ignore error } catch (InterruptedException e) { @@ -169,6 +174,8 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { if (path != null) { recent = createShellFolder(getDesktop(), new File(path)); } + } catch (SecurityException e) { + // Ignore error } catch (InterruptedException e) { // Ignore error } catch (IOException e) { @@ -182,6 +189,8 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { if (network == null) { try { network = new Win32ShellFolder2(NETWORK); + } catch (SecurityException e) { + // Ignore error } catch (IOException e) { // Ignore error } catch (InterruptedException e) { @@ -206,6 +215,8 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { personal.setIsPersonal(); } } + } catch (SecurityException e) { + // Ignore error } catch (InterruptedException e) { // Ignore error } catch (IOException e) { @@ -246,7 +257,7 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { if (file == null) { file = getDesktop(); } - return file; + return checkFile(file); } else if (key.equals("roots")) { // Should be "History" and "Desktop" ? if (roots == null) { @@ -257,11 +268,11 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { roots = (File[])super.get(key); } } - return roots; + return checkFiles(roots); } else if (key.equals("fileChooserComboBoxFolders")) { Win32ShellFolder2 desktop = getDesktop(); - if (desktop != null) { + if (desktop != null && checkFile(desktop) != null) { ArrayList folders = new ArrayList(); Win32ShellFolder2 drives = getDrives(); @@ -272,15 +283,15 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { folders.add(desktop); // Add all second level folders - File[] secondLevelFolders = desktop.listFiles(); + File[] secondLevelFolders = checkFiles(desktop.listFiles()); Arrays.sort(secondLevelFolders); for (File secondLevelFolder : secondLevelFolders) { Win32ShellFolder2 folder = (Win32ShellFolder2) secondLevelFolder; - if (!folder.isFileSystem() || (folder.isDirectory() && !folder.isLink()) ) { + if (!folder.isFileSystem() || (folder.isDirectory() && !folder.isLink())) { folders.add(folder); // Add third level for "My Computer" if (folder.equals(drives)) { - File[] thirdLevelFolders = folder.listFiles(); + File[] thirdLevelFolders = checkFiles(folder.listFiles()); if (thirdLevelFolders != null && thirdLevelFolders.length > 0) { List thirdLevelFoldersList = Arrays.asList(thirdLevelFolders); @@ -290,7 +301,7 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { } } } - return folders.toArray(new File[folders.size()]); + return checkFiles(folders); } else { return super.get(key); } @@ -327,7 +338,7 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { } } } - return folders.toArray(new File[folders.size()]); + return checkFiles(folders); } else if (key.startsWith("fileChooserIcon ")) { String name = key.substring(key.indexOf(" ") + 1); @@ -373,6 +384,41 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { return null; } + private File checkFile(File file) { + SecurityManager sm = System.getSecurityManager(); + return (sm == null || file == null) ? file : checkFile(file, sm); + } + + private File checkFile(File file, SecurityManager sm) { + try { + sm.checkRead(file.getPath()); + return file; + } catch (SecurityException se) { + return null; + } + } + + private File[] checkFiles(File[] files) { + SecurityManager sm = System.getSecurityManager(); + if (sm == null || files == null || files.length == 0) { + return files; + } + return checkFiles(Arrays.stream(files), sm); + } + + private File[] checkFiles(List files) { + SecurityManager sm = System.getSecurityManager(); + if (sm == null || files.isEmpty()) { + return files.toArray(new File[files.size()]); + } + return checkFiles(files.stream(), sm); + } + + private File[] checkFiles(Stream filesStream, SecurityManager sm) { + return filesStream.filter((file) -> checkFile(file, sm) != null) + .toArray(File[]::new); + } + /** * Does dir represent a "computer" such as a node on the network, or * "My Computer" on the desktop. diff --git a/external/ikvm/openjdk/sun/java2d/loops/TransformHelper.java b/external/ikvm/openjdk/sun/java2d/loops/TransformHelper.java new file mode 100644 index 0000000000..29208ff885 --- /dev/null +++ b/external/ikvm/openjdk/sun/java2d/loops/TransformHelper.java @@ -0,0 +1,27 @@ +/* + Copyright (C) 2015 Jeroen Frijters + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jeroen Frijters + jeroen@frijters.net + +*/ +package sun.java2d.loops; + +// only needed at compile time, to satisfy import statement +public class TransformHelper { } diff --git a/external/ikvm/openjdk/sun/misc/VM.java b/external/ikvm/openjdk/sun/misc/VM.java index 6cfa7fbe34..2607d95f99 100644 --- a/external/ikvm/openjdk/sun/misc/VM.java +++ b/external/ikvm/openjdk/sun/misc/VM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,7 @@ public class VM { return suspended; } + @SuppressWarnings("deprecation") public static boolean allowThreadSuspension(ThreadGroup g, boolean b) { return g.allowThreadSuspension(b); } @@ -145,7 +146,9 @@ public class VM { */ // public native static void writeJavaProfilerReport(); + private static volatile boolean booted = false; + private static final Object lock = new Object(); static { // [IKVM] force System properties initialization ("booting") @@ -163,13 +166,27 @@ public class VM { // the booted flag to determine whether it is safe to query the system // properties). public static void booted() { - booted = true; + synchronized (lock) { + booted = true; + lock.notifyAll(); + } } public static boolean isBooted() { return booted; } + // Waits until VM completes initialization + // + // This method is invoked by the Finalizer thread + public static void awaitBooted() throws InterruptedException { + synchronized (lock) { + while (!booted) { + lock.wait(); + } + } + } + // Returns the maximum amount of allocatable direct buffer memory. // The directMemory variable is initialized during system initialization // in the saveAndRemoveProperties method. @@ -216,6 +233,14 @@ public class VM { return allowArraySyntax; } + /** + * Returns true if the given class loader is in the system domain + * in which all permissions are granted. + */ + public static boolean isSystemDomainLoader(ClassLoader loader) { + return loader == null; + } + /** * Returns the system property of the specified key saved at * system initialization time. This method should only be used @@ -282,6 +307,9 @@ public class VM { // used by sun.launcher.LauncherHelper props.remove("sun.java.launcher.diag"); + + // used by sun.misc.URLClassPath + props.remove("sun.cds.enableSharedLookupCache"); } // Initialize any miscellenous operating system settings that need to be @@ -361,6 +389,12 @@ public class VM { private final static int JVMTI_THREAD_STATE_WAITING_INDEFINITELY = 0x0010; private final static int JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT = 0x0020; + /* + * Returns the first non-null class loader up the execution stack, + * or null if only code from the null class loader is on the stack. + */ + public static native ClassLoader latestUserDefinedLoader(); + static { initialize(); } diff --git a/external/ikvm/openjdk/sun/misc/Version.java b/external/ikvm/openjdk/sun/misc/Version.java index 7e0f372421..e11b36719d 100644 --- a/external/ikvm/openjdk/sun/misc/Version.java +++ b/external/ikvm/openjdk/sun/misc/Version.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,13 +33,16 @@ public class Version { "openjdk"; private static final String java_version = - "1.7.0-internal"; + "1.8.0-internal"; private static final String java_runtime_name = - "OpenJDK Runtime Environment"; - + "OpenJDK Runtime Environment"; + + private static final String java_profile_name = + ""; + private static final String java_runtime_version = - "1.7.0-internal-jeroen_2012_05_22_06_05-b00"; + "1.8.0-internal-jeroen_2015_06_02_10_38-b00"; static { init(); @@ -87,23 +90,28 @@ public class Version { boolean isHeadless = false; /* Report that we're running headless if the property is true */ - String headless = System.getProperty("java.awt.headless"); - if ( (headless != null) && (headless.equalsIgnoreCase("true")) ) { + String headless = System.getProperty("java.awt.headless"); + if ( (headless != null) && (headless.equalsIgnoreCase("true")) ) { isHeadless = true; - } + } /* First line: platform version. */ ps.println(launcher_name + " version \"" + java_version + "\""); /* Second line: runtime version (ie, libraries). */ - ps.print(java_runtime_name + " (build " + java_runtime_version); + ps.print(java_runtime_name + " (build " + java_runtime_version); - if (java_runtime_name.indexOf("Embedded") != -1 && isHeadless) { - // embedded builds report headless state - ps.print(", headless"); - } - ps.println(')'); + if (java_profile_name.length() > 0) { + // profile name + ps.print(", profile " + java_profile_name); + } + + if (java_runtime_name.indexOf("Embedded") != -1 && isHeadless) { + // embedded builds report headless state + ps.print(", headless"); + } + ps.println(')'); /* Third line: JVM information. */ String java_vm_name = System.getProperty("java.vm.name"); @@ -328,7 +336,6 @@ public class Version { // Return false if not available which implies an old VM (Tiger or before). private static native boolean getJvmVersionInfo(); private static native void getJdkVersionInfo(); - } // Help Emacs a little because this file doesn't end in .java. diff --git a/external/ikvm/openjdk/sun/nio/ch/DatagramChannelImpl.java b/external/ikvm/openjdk/sun/nio/ch/DatagramChannelImpl.java index 08cc5c95d0..b2c8607b60 100644 --- a/external/ikvm/openjdk/sun/nio/ch/DatagramChannelImpl.java +++ b/external/ikvm/openjdk/sun/nio/ch/DatagramChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ import java.nio.channels.*; import java.nio.channels.spi.*; import java.util.*; import sun.net.ResourceManager; - +import sun.net.ExtendedOptionsImpl; /** * An implementation of DatagramChannels. @@ -169,6 +169,7 @@ class DatagramChannelImpl synchronized (stateLock) { if (!isOpen()) throw new ClosedChannelException(); + // Perform security check before returning address return Net.getRevealedLocalAddress(localAddress); } } @@ -194,15 +195,8 @@ class DatagramChannelImpl synchronized (stateLock) { ensureOpen(); - if (name == StandardSocketOptions.IP_TOS) { - // IPv4 only; no-op for IPv6 - if (family == StandardProtocolFamily.INET) { - Net.setSocketOption(fd, family, name, value); - } - return this; - } - - if (name == StandardSocketOptions.IP_MULTICAST_TTL || + if (name == StandardSocketOptions.IP_TOS || + name == StandardSocketOptions.IP_MULTICAST_TTL || name == StandardSocketOptions.IP_MULTICAST_LOOP) { // options are protocol dependent @@ -255,16 +249,8 @@ class DatagramChannelImpl synchronized (stateLock) { ensureOpen(); - if (name == StandardSocketOptions.IP_TOS) { - // IPv4 only; always return 0 on IPv6 - if (family == StandardProtocolFamily.INET) { - return (T) Net.getSocketOption(fd, family, name); - } else { - return (T) Integer.valueOf(0); - } - } - - if (name == StandardSocketOptions.IP_MULTICAST_TTL || + if (name == StandardSocketOptions.IP_TOS || + name == StandardSocketOptions.IP_MULTICAST_TTL || name == StandardSocketOptions.IP_MULTICAST_LOOP) { return (T) Net.getSocketOption(fd, family, name); @@ -317,6 +303,9 @@ class DatagramChannelImpl set.add(StandardSocketOptions.IP_MULTICAST_IF); set.add(StandardSocketOptions.IP_MULTICAST_TTL); set.add(StandardSocketOptions.IP_MULTICAST_LOOP); + if (ExtendedOptionsImpl.flowSupported()) { + set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA); + } return Collections.unmodifiableSet(set); } } @@ -553,7 +542,7 @@ class DatagramChannelImpl return 0; readerThread = NativeThread.current(); do { - n = IOUtil.read(fd, buf, -1, nd, readLock); + n = IOUtil.read(fd, buf, -1, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { @@ -609,7 +598,7 @@ class DatagramChannelImpl return 0; writerThread = NativeThread.current(); do { - n = IOUtil.write(fd, buf, -1, nd, writeLock); + n = IOUtil.write(fd, buf, -1, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { @@ -747,6 +736,26 @@ class DatagramChannelImpl // set or refresh local address localAddress = Net.localAddress(fd); + + // flush any packets already received. + boolean blocking = false; + synchronized (blockingLock()) { + try { + blocking = isBlocking(); + // remainder of each packet thrown away + ByteBuffer tmpBuf = ByteBuffer.allocate(1); + if (blocking) { + configureBlocking(false); + } + do { + tmpBuf.clear(); + } while (receive(tmpBuf) != null); + } finally { + if (blocking) { + configureBlocking(true); + } + } + } } } } @@ -1032,25 +1041,24 @@ class DatagramChannelImpl int oldOps = sk.nioReadyOps(); int newOps = initialOps; - if ((ops & PollArrayWrapper.POLLNVAL) != 0) { + if ((ops & Net.POLLNVAL) != 0) { // This should only happen if this channel is pre-closed while a // selection operation is in progress // ## Throw an error if this channel has not been pre-closed return false; } - if ((ops & (PollArrayWrapper.POLLERR - | PollArrayWrapper.POLLHUP)) != 0) { + if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) { newOps = intOps; sk.nioReadyOps(newOps); return (newOps & ~oldOps) != 0; } - if (((ops & PollArrayWrapper.POLLIN) != 0) && + if (((ops & Net.POLLIN) != 0) && ((intOps & SelectionKey.OP_READ) != 0)) newOps |= SelectionKey.OP_READ; - if (((ops & PollArrayWrapper.POLLOUT) != 0) && + if (((ops & Net.POLLOUT) != 0) && ((intOps & SelectionKey.OP_WRITE) != 0)) newOps |= SelectionKey.OP_WRITE; @@ -1066,6 +1074,28 @@ class DatagramChannelImpl return translateReadyOps(ops, 0, sk); } + // package-private + int poll(int events, long timeout) throws IOException { + assert Thread.holdsLock(blockingLock()) && !isBlocking(); + + synchronized (readLock) { + int n = 0; + try { + begin(); + synchronized (stateLock) { + if (!isOpen()) + return 0; + readerThread = NativeThread.current(); + } + n = Net.poll(fd, events, timeout); + } finally { + readerThread = 0; + end(n > 0); + } + return n; + } + } + /** * Translates an interest operation set into a native poll event set */ @@ -1073,11 +1103,11 @@ class DatagramChannelImpl int newOps = 0; if ((ops & SelectionKey.OP_READ) != 0) - newOps |= PollArrayWrapper.POLLIN; + newOps |= Net.POLLIN; if ((ops & SelectionKey.OP_WRITE) != 0) - newOps |= PollArrayWrapper.POLLOUT; + newOps |= Net.POLLOUT; if ((ops & SelectionKey.OP_CONNECT) != 0) - newOps |= PollArrayWrapper.POLLIN; + newOps |= Net.POLLIN; sk.selector.putEventOps(sk, newOps); } @@ -1106,7 +1136,7 @@ class DatagramChannelImpl throws IOException; static { - Util.load(); + IOUtil.load(); initIDs(); } diff --git a/external/ikvm/openjdk/sun/nio/ch/DotNetSelectorImpl.java b/external/ikvm/openjdk/sun/nio/ch/DotNetSelectorImpl.java index 897cf9a1f4..5f20394b6e 100644 --- a/external/ikvm/openjdk/sun/nio/ch/DotNetSelectorImpl.java +++ b/external/ikvm/openjdk/sun/nio/ch/DotNetSelectorImpl.java @@ -165,9 +165,9 @@ final class DotNetSelectorImpl extends SelectorImpl private int updateSelectedKeys(ArrayList read, ArrayList write, ArrayList error) { updateCount++; - int keys = processFDSet(updateCount, read, PollArrayWrapper.POLLIN); - keys += processFDSet(updateCount, write, PollArrayWrapper.POLLCONN | PollArrayWrapper.POLLOUT); - keys += processFDSet(updateCount, error, PollArrayWrapper.POLLIN | PollArrayWrapper.POLLCONN | PollArrayWrapper.POLLOUT); + int keys = processFDSet(updateCount, read, Net.POLLIN); + keys += processFDSet(updateCount, write, Net.POLLCONN | Net.POLLOUT); + keys += processFDSet(updateCount, error, Net.POLLIN | Net.POLLCONN | Net.POLLOUT); return keys; } diff --git a/external/ikvm/openjdk/sun/nio/ch/FileChannelImpl.java b/external/ikvm/openjdk/sun/nio/ch/FileChannelImpl.java index 902509bdb6..e0b4f8ba63 100644 --- a/external/ikvm/openjdk/sun/nio/ch/FileChannelImpl.java +++ b/external/ikvm/openjdk/sun/nio/ch/FileChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,12 +33,21 @@ import java.io.FileDescriptor; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; -import java.nio.channels.*; +import java.nio.channels.ClosedByInterruptException; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +import java.nio.channels.FileLockInterruptionException; +import java.nio.channels.NonReadableChannelException; +import java.nio.channels.NonWritableChannelException; +import java.nio.channels.OverlappingFileLockException; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; +import java.security.AccessController; import java.util.ArrayList; import java.util.List; -import java.security.AccessController; + import sun.misc.Cleaner; -import sun.misc.IoTrace; import sun.security.action.GetPropertyAction; public class FileChannelImpl @@ -63,7 +72,8 @@ public class FileChannelImpl // Required to prevent finalization of creating stream (immutable) private final Object parent; - // The path of the referenced file (null if the parent stream is created with a file descriptor) + // The path of the referenced file + // (null if the parent stream is created with a file descriptor) private final String path; // Thread-safe set of IDs of native threads, for signalling @@ -121,7 +131,7 @@ public class FileChannelImpl } } - nd.preClose(fd); + // signal any threads blocked on this channel threads.signalAndWait(); if (parent != null) { @@ -145,19 +155,17 @@ public class FileChannelImpl synchronized (positionLock) { int n = 0; int ti = -1; - Object traceContext = IoTrace.fileReadBegin(path); try { begin(); ti = threads.add(); if (!isOpen()) return 0; do { - n = IOUtil.read(fd, dst, -1, nd, positionLock); + n = IOUtil.read(fd, dst, -1, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { threads.remove(ti); - IoTrace.fileReadEnd(traceContext, n > 0 ? n : 0); end(n > 0); assert IOStatus.check(n); } @@ -175,7 +183,6 @@ public class FileChannelImpl synchronized (positionLock) { long n = 0; int ti = -1; - Object traceContext = IoTrace.fileReadBegin(path); try { begin(); ti = threads.add(); @@ -187,7 +194,6 @@ public class FileChannelImpl return IOStatus.normalize(n); } finally { threads.remove(ti); - IoTrace.fileReadEnd(traceContext, n > 0 ? n : 0); end(n > 0); assert IOStatus.check(n); } @@ -201,20 +207,18 @@ public class FileChannelImpl synchronized (positionLock) { int n = 0; int ti = -1; - Object traceContext = IoTrace.fileWriteBegin(path); try { begin(); ti = threads.add(); if (!isOpen()) return 0; do { - n = IOUtil.write(fd, src, -1, nd, positionLock); + n = IOUtil.write(fd, src, -1, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { threads.remove(ti); end(n > 0); - IoTrace.fileWriteEnd(traceContext, n > 0 ? n : 0); assert IOStatus.check(n); } } @@ -231,7 +235,6 @@ public class FileChannelImpl synchronized (positionLock) { long n = 0; int ti = -1; - Object traceContext = IoTrace.fileWriteBegin(path); try { begin(); ti = threads.add(); @@ -243,7 +246,6 @@ public class FileChannelImpl return IOStatus.normalize(n); } finally { threads.remove(ti); - IoTrace.fileWriteEnd(traceContext, n > 0 ? n : 0); end(n > 0); assert IOStatus.check(n); } @@ -321,12 +323,10 @@ public class FileChannelImpl } } - public FileChannel truncate(long size) throws IOException { + public FileChannel truncate(long newSize) throws IOException { ensureOpen(); - if (size < 0) - throw new IllegalArgumentException(); - if (size > size()) - return this; + if (newSize < 0) + throw new IllegalArgumentException("Negative size"); if (!writable) throw new NonWritableChannelException(); synchronized (positionLock) { @@ -339,6 +339,14 @@ public class FileChannelImpl if (!isOpen()) return null; + // get current size + long size; + do { + size = nd.size(fd); + } while ((size == IOStatus.INTERRUPTED) && isOpen()); + if (!isOpen()) + return null; + // get current position do { p = position0(fd, -1); @@ -347,20 +355,22 @@ public class FileChannelImpl return null; assert p >= 0; - // truncate file - do { - rv = nd.truncate(fd, size); - } while ((rv == IOStatus.INTERRUPTED) && isOpen()); - if (!isOpen()) - return null; + // truncate file if given size is less than the current size + if (newSize < size) { + do { + rv = nd.truncate(fd, newSize); + } while ((rv == IOStatus.INTERRUPTED) && isOpen()); + if (!isOpen()) + return null; + } // [IKVM] in append mode we're not allowed to seek backwards, but the atomic append will honor the new file size if (append) return this; - // set position to size if greater than size - if (p > size) - p = size; + // if position is beyond new size then adjust it + if (p > newSize) + p = newSize; do { rv = (int)position0(fd, p); } while ((rv == IOStatus.INTERRUPTED) && isOpen()); @@ -522,21 +532,30 @@ public class FileChannelImpl if (!readable) throw new NonReadableChannelException(); ensureOpen(); + if (nd.needsPositionLock()) { + synchronized (positionLock) { + return readInternal(dst, position); + } + } else { + return readInternal(dst, position); + } + } + + private int readInternal(ByteBuffer dst, long position) throws IOException { + assert !nd.needsPositionLock() || Thread.holdsLock(positionLock); int n = 0; int ti = -1; - Object traceContext = IoTrace.fileReadBegin(path); try { begin(); ti = threads.add(); if (!isOpen()) return -1; do { - n = IOUtil.read(fd, dst, position, nd, positionLock); + n = IOUtil.read(fd, dst, position, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { threads.remove(ti); - IoTrace.fileReadEnd(traceContext, n > 0 ? n : 0); end(n > 0); assert IOStatus.check(n); } @@ -550,22 +569,31 @@ public class FileChannelImpl if (!writable) throw new NonWritableChannelException(); ensureOpen(); + if (nd.needsPositionLock()) { + synchronized (positionLock) { + return writeInternal(src, position); + } + } else { + return writeInternal(src, position); + } + } + + private int writeInternal(ByteBuffer src, long position) throws IOException { + assert !nd.needsPositionLock() || Thread.holdsLock(positionLock); int n = 0; int ti = -1; - Object traceContext = IoTrace.fileWriteBegin(path); try { begin(); ti = threads.add(); if (!isOpen()) return -1; do { - n = IOUtil.write(fd, src, position, nd, positionLock); + n = IOUtil.write(fd, src, position, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { threads.remove(ti); end(n > 0); - IoTrace.fileWriteEnd(traceContext, n > 0 ? n : 0); assert IOStatus.check(n); } } @@ -642,6 +670,8 @@ public class FileChannelImpl throws IOException { ensureOpen(); + if (mode == null) + throw new NullPointerException("Mode is null"); if (position < 0L) throw new IllegalArgumentException("Negative position"); if (size < 0L) @@ -650,6 +680,7 @@ public class FileChannelImpl throw new IllegalArgumentException("Position + size overflow"); if (size > Integer.MAX_VALUE) throw new IllegalArgumentException("Size exceeds Integer.MAX_VALUE"); + int imode = -1; if (mode == MapMode.READ_ONLY) imode = MAP_RO; @@ -670,7 +701,15 @@ public class FileChannelImpl ti = threads.add(); if (!isOpen()) return null; - if (size() < position + size) { // Extend file size + + long filesize; + do { + filesize = nd.size(fd); + } while ((filesize == IOStatus.INTERRUPTED) && isOpen()); + if (!isOpen()) + return null; + + if (filesize < position + size) { // Extend file size if (!writable) { throw new IOException("Channel not open for writing " + "- cannot extend file to required size"); @@ -679,6 +718,8 @@ public class FileChannelImpl do { rv = nd.truncate(fd, position + size); } while ((rv == IOStatus.INTERRUPTED) && isOpen()); + if (!isOpen()) + return null; } if (size == 0) { addr = 0; diff --git a/external/ikvm/openjdk/sun/nio/ch/Net.java b/external/ikvm/openjdk/sun/nio/ch/Net.java index d9ab0f0fc7..edf52a68be 100644 --- a/external/ikvm/openjdk/sun/nio/ch/Net.java +++ b/external/ikvm/openjdk/sun/nio/ch/Net.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,14 +27,16 @@ package sun.nio.ch; import java.io.*; import java.net.*; +import jdk.net.*; import java.nio.channels.*; import java.util.*; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.PrivilegedExceptionAction; +import sun.net.ExtendedOptionsImpl; -class Net { // package-private +public class Net { private Net() { } @@ -45,12 +47,6 @@ class Net { // package-private } }; - // Value of jdk.net.revealLocalAddress - private static boolean revealLocalAddress; - - // True if jdk.net.revealLocalAddress had been read - private static volatile boolean propRevealLocalAddress; - // set to true if exclusive binding is on for Windows private static final boolean exclusiveBind; @@ -59,8 +55,8 @@ class Net { // package-private if (availLevel >= 0) { String exclBindProp = java.security.AccessController.doPrivileged( - new PrivilegedAction() { - @Override + new PrivilegedAction() { + @Override public String run() { return System.getProperty( "sun.net.useExclusiveBind"); @@ -117,7 +113,7 @@ class Net { // package-private return canJoin6WithIPv4Group0(); } - static InetSocketAddress checkAddress(SocketAddress sa) { + public static InetSocketAddress checkAddress(SocketAddress sa) { if (sa == null) throw new NullPointerException(); if (!(sa instanceof InetSocketAddress)) @@ -197,43 +193,19 @@ class Net { // package-private if (addr == null || sm == null) return addr; - if (!getRevealLocalAddress()) { + try{ + sm.checkConnect(addr.getAddress().getHostAddress(), -1); + // Security check passed + } catch (SecurityException e) { // Return loopback address only if security check fails - try{ - sm.checkConnect(addr.getAddress().getHostAddress(), -1); - //Security check passed - } catch (SecurityException e) { - //Return loopback address - addr = getLoopbackAddress(addr.getPort()); - } + addr = getLoopbackAddress(addr.getPort()); } return addr; } static String getRevealedLocalAddressAsString(InetSocketAddress addr) { - if (!getRevealLocalAddress() && System.getSecurityManager() != null) - addr = getLoopbackAddress(addr.getPort()); - return addr.toString(); - } - - private static boolean getRevealLocalAddress() { - if (!propRevealLocalAddress) { - try { - revealLocalAddress = Boolean.parseBoolean( - AccessController.doPrivileged( - new PrivilegedExceptionAction() { - public String run() { - return System.getProperty( - "jdk.net.revealLocalAddress"); - } - })); - - } catch (Exception e) { - // revealLocalAddress is false - } - propRevealLocalAddress = true; - } - return revealLocalAddress; + return System.getSecurityManager() == null ? addr.toString() : + getLoopbackAddress(addr.getPort()).toString(); } private static InetSocketAddress getLoopbackAddress(int port) { @@ -327,6 +299,16 @@ class Net { // package-private // only simple values supported by this method Class type = name.type(); + + if (type == SocketFlow.class) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new NetworkPermission("setOption.SO_FLOW_SLA")); + } + ExtendedOptionsImpl.setFlowOption(fd, (SocketFlow)value); + return; + } + if (type != Integer.class && type != Boolean.class) throw new AssertionError("Should not reach here"); @@ -370,7 +352,8 @@ class Net { // package-private } boolean mayNeedConversion = (family == UNSPEC); - setIntOption0(fd, mayNeedConversion, key.level(), key.name(), arg); + boolean isIPv6 = (family == StandardProtocolFamily.INET6); + setIntOption0(fd, mayNeedConversion, key.level(), key.name(), arg, isIPv6); } static Object getSocketOption(FileDescriptor fd, ProtocolFamily family, @@ -379,6 +362,16 @@ class Net { // package-private { Class type = name.type(); + if (type == SocketFlow.class) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new NetworkPermission("getOption.SO_FLOW_SLA")); + } + SocketFlow flow = SocketFlow.create(); + ExtendedOptionsImpl.getFlowOption(fd, flow); + return flow; + } + // only simple values supported by this method if (type != Integer.class && type != Boolean.class) throw new AssertionError("Should not reach here"); @@ -430,7 +423,7 @@ class Net { // package-private // Due to oddities SO_REUSEADDR on windows reuse is ignored private static native FileDescriptor socket0(boolean preferIPv6, boolean stream, boolean reuse); - static void bind(FileDescriptor fd, InetAddress addr, int port) + public static void bind(FileDescriptor fd, InetAddress addr, int port) throws IOException { bind(UNSPEC, fd, addr, port); @@ -484,7 +477,7 @@ class Net { // package-private private static native InetAddress localInetAddress(FileDescriptor fd) throws IOException; - static InetSocketAddress localAddress(FileDescriptor fd) + public static InetSocketAddress localAddress(FileDescriptor fd) throws IOException { return new InetSocketAddress(localInetAddress(fd), localPort(fd)); @@ -507,7 +500,10 @@ class Net { // package-private throws IOException; private static native void setIntOption0(FileDescriptor fd, boolean mayNeedConversion, - int level, int opt, int arg) + int level, int opt, int arg, boolean isIPv6) + throws IOException; + + static native int poll(FileDescriptor fd, int events, long timeout) throws IOException; // -- Multicast support -- @@ -606,4 +602,15 @@ class Net { // package-private static native int getInterface6(FileDescriptor fd) throws IOException; + /** + * Event masks for the various poll system calls. + * They will be set platform dependant in the static initializer below. + */ + public static final short POLLIN = 0x0001; + public static final short POLLCONN = 0x0002; + public static final short POLLOUT = 0x0004; + public static final short POLLERR = 0x0008; + public static final short POLLHUP = 0x0010; + public static final short POLLNVAL = 0x0020; + public static final short POLLREMOVE = 0x0800; } diff --git a/external/ikvm/openjdk/sun/nio/ch/PollArrayWrapper.java b/external/ikvm/openjdk/sun/nio/ch/PollArrayWrapper.java deleted file mode 100644 index 72ed9adc22..0000000000 --- a/external/ikvm/openjdk/sun/nio/ch/PollArrayWrapper.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2001, 2002, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.nio.ch; - -class PollArrayWrapper -{ - static final short POLLIN = 0x0001; - static final short POLLCONN = 0x0002; - static final short POLLOUT = 0x0004; - static final short POLLERR = 0x0008; - static final short POLLHUP = 0x0010; - static final short POLLNVAL = 0x0020; - static final short POLLREMOVE = 0x0800; -} diff --git a/external/ikvm/openjdk/sun/nio/ch/SocketOptionRegistry.java b/external/ikvm/openjdk/sun/nio/ch/SocketOptionRegistry.java index 83887fbc34..f8e3306652 100644 --- a/external/ikvm/openjdk/sun/nio/ch/SocketOptionRegistry.java +++ b/external/ikvm/openjdk/sun/nio/ch/SocketOptionRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -24,7 +24,7 @@ * questions. * */ - +// AUTOMATICALLY GENERATED FILE - DO NOT EDIT package sun.nio.ch; import java.net.SocketOption; import java.net.StandardSocketOptions; @@ -34,7 +34,6 @@ import java.util.Map; import java.util.HashMap; import cli.System.Net.Sockets.SocketOptionLevel; import cli.System.Net.Sockets.SocketOptionName; - class SocketOptionRegistry { private SocketOptionRegistry() { } private static class RegistryKey { @@ -72,6 +71,7 @@ class SocketOptionRegistry { map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_IF, StandardProtocolFamily.INET), new OptionKey(SocketOptionLevel.IP, SocketOptionName.MulticastInterface)); map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_TTL, StandardProtocolFamily.INET), new OptionKey(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive)); map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_LOOP, StandardProtocolFamily.INET), new OptionKey(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback)); + map.put(new RegistryKey(StandardSocketOptions.IP_TOS, StandardProtocolFamily.INET6), new OptionKey(SocketOptionLevel.IPv6, ikvm.internal.Winsock.IPV6_TCLASS)); map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_IF, StandardProtocolFamily.INET6), new OptionKey(SocketOptionLevel.IPv6, SocketOptionName.MulticastInterface)); map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_TTL, StandardProtocolFamily.INET6), new OptionKey(SocketOptionLevel.IPv6, SocketOptionName.IpTimeToLive)); map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_LOOP, StandardProtocolFamily.INET6), new OptionKey(SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback)); diff --git a/external/ikvm/openjdk/sun/nio/fs/NetFileSystemProvider.java b/external/ikvm/openjdk/sun/nio/fs/NetFileSystemProvider.java index 1f112199e1..b49c6cd651 100644 --- a/external/ikvm/openjdk/sun/nio/fs/NetFileSystemProvider.java +++ b/external/ikvm/openjdk/sun/nio/fs/NetFileSystemProvider.java @@ -36,6 +36,8 @@ import cli.System.IO.FileMode; import cli.System.IO.FileShare; import cli.System.IO.FileStream; import cli.System.IO.FileOptions; +import cli.System.Runtime.InteropServices.DllImportAttribute; +import cli.System.Runtime.InteropServices.Marshal; import cli.System.Security.AccessControl.FileSystemRights; import com.sun.nio.file.ExtendedOpenOption; import java.io.FileDescriptor; @@ -338,7 +340,7 @@ final class NetFileSystemProvider extends AbstractFileSystemProvider } } - return FileChannelImpl.open(open(npath.path, mode, rights, share, options), read, write, append, null); + return FileChannelImpl.open(open(npath.path, mode, rights, share, options), npath.path, read, write, append, null); } private static FileDescriptor open(String path, int mode, int rights, int share, int options) throws IOException @@ -628,6 +630,7 @@ final class NetFileSystemProvider extends AbstractFileSystemProvider NetPath nsource = NetPath.from(source); NetPath ntarget = NetPath.from(target); boolean overwrite = false; + boolean atomicMove = false; for (CopyOption opt : options) { if (opt == StandardCopyOption.REPLACE_EXISTING) @@ -636,7 +639,14 @@ final class NetFileSystemProvider extends AbstractFileSystemProvider } else if (opt == StandardCopyOption.ATOMIC_MOVE) { - throw new AtomicMoveNotSupportedException(nsource.path, ntarget.path, "Unsupported copy option"); + if (WINDOWS) + { + atomicMove = true; + } + else + { + throw new AtomicMoveNotSupportedException(nsource.path, ntarget.path, "Unsupported copy option"); + } } else { @@ -651,6 +661,36 @@ final class NetFileSystemProvider extends AbstractFileSystemProvider sm.checkRead(nsource.path); sm.checkWrite(ntarget.path); } + if (atomicMove) + { + int MOVEFILE_REPLACE_EXISTING = 1; + if (MoveFileEx(nsource.path, ntarget.path, MOVEFILE_REPLACE_EXISTING) == 0) + { + final int ERROR_FILE_NOT_FOUND = 2; + final int ERROR_PATH_NOT_FOUND = 3; + final int ERROR_ACCESS_DENIED = 5; + final int ERROR_NOT_SAME_DEVICE = 17; + final int ERROR_FILE_EXISTS = 80; + final int ERROR_ALREADY_EXISTS = 183; + int lastError = Marshal.GetLastWin32Error(); + switch (lastError) + { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + throw new NoSuchFileException(nsource.path, ntarget.path, null); + case ERROR_ACCESS_DENIED: + throw new AccessDeniedException(nsource.path, ntarget.path, null); + case ERROR_NOT_SAME_DEVICE: + throw new AtomicMoveNotSupportedException(nsource.path, ntarget.path, "Unsupported copy option"); + case ERROR_FILE_EXISTS: + case ERROR_ALREADY_EXISTS: + throw new FileAlreadyExistsException(nsource.path, ntarget.path, null); + default: + throw new FileSystemException(nsource.path, ntarget.path, "Error " + lastError); + } + } + return; + } try { if (false) throw new cli.System.ArgumentException(); @@ -711,6 +751,9 @@ final class NetFileSystemProvider extends AbstractFileSystemProvider } } + @DllImportAttribute.Annotation(value="kernel32", SetLastError=true) + private static native int MoveFileEx(String lpExistingFileName, String lpNewFileName, int dwFlags); + public boolean isSameFile(Path path, Path path2) throws IOException { if (path.equals(path2)) diff --git a/external/ikvm/openjdk/sun/reflect/Reflection.java b/external/ikvm/openjdk/sun/reflect/Reflection.java index 6cff5746d4..2df2e2d463 100644 --- a/external/ikvm/openjdk/sun/reflect/Reflection.java +++ b/external/ikvm/openjdk/sun/reflect/Reflection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,6 @@ package sun.reflect; import java.lang.reflect.*; -import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -47,17 +46,18 @@ public class Reflection { view, where they are sensitive or they may contain VM-internal objects. These Maps are updated very rarely. Rather than synchronize on each access, we use copy-on-write */ - private static volatile Map fieldFilterMap; - private static volatile Map methodFilterMap; + private static volatile Map,String[]> fieldFilterMap; + private static volatile Map,String[]> methodFilterMap; static { - Map map = new HashMap(); + Map,String[]> map = new HashMap,String[]>(); map.put(Reflection.class, new String[] {"fieldFilterMap", "methodFilterMap"}); map.put(System.class, new String[] {"security"}); + map.put(Class.class, new String[] {"classLoader"}); fieldFilterMap = map; - methodFilterMap = new HashMap(); + methodFilterMap = new HashMap<>(); // [IKVM] to avoid initialization order issues, we actually add // Unsafe.getUnsafe() here, instead of in Unsafe's class initializer methodFilterMap.put(sun.misc.Unsafe.class, new String[] {"getUnsafe"}); @@ -67,21 +67,15 @@ public class Reflection { ignoring frames associated with java.lang.reflect.Method.invoke() and its implementation. */ @CallerSensitive - public static Class getCallerClass() { - return getCallerClass(2); - } + public static native Class getCallerClass(); - /** Returns the class of the method realFramesToSkip - frames up the stack (zero-based), ignoring frames associated - with java.lang.reflect.Method.invoke() and its implementation. - The first frame is that associated with this method, so - getCallerClass(0) returns the Class object for - sun.reflect.Reflection. Frames associated with - java.lang.reflect.Method.invoke() and its implementation are - completely ignored and do not count toward the number of "real" - frames skipped. */ - @CallerSensitive - public static native Class getCallerClass(int realFramesToSkip); + /** + * @deprecated This method will be removed in JDK 9. + * This method is a private JDK API and retained temporarily for + * existing code to run until a replacement API is defined. + */ + @Deprecated + public static native Class getCallerClass(int depth); /** Retrieves the access flags written to the class file. For inner classes these flags may differ from those returned by @@ -91,18 +85,18 @@ public class Reflection { to compatibility reasons; see 4471811. Only the values of the low 13 bits (i.e., a mask of 0x1FFF) are guaranteed to be valid. */ - private static native int getClassAccessFlags(Class c); + public static native int getClassAccessFlags(Class c); /** A quick "fast-path" check to try to avoid getCallerClass() calls. */ - public static boolean quickCheckMemberAccess(Class memberClass, + public static boolean quickCheckMemberAccess(Class memberClass, int modifiers) { return Modifier.isPublic(getClassAccessFlags(memberClass) & modifiers); } - public static void ensureMemberAccess(Class currentClass, - Class memberClass, + public static void ensureMemberAccess(Class currentClass, + Class memberClass, Object target, int modifiers) throws IllegalAccessException @@ -124,13 +118,13 @@ public class Reflection { /*IKVM*/ private static native boolean checkInternalAccess(Class currentClass, Class memberClass); - public static boolean verifyMemberAccess(Class currentClass, + public static boolean verifyMemberAccess(Class currentClass, // Declaring class of field // or method - Class memberClass, + Class memberClass, // May be NULL in case of statics - Object target, - int modifiers) + Object target, + int modifiers) { // Verify that currentClass can access a field, method, or // constructor of memberClass, where that member's access bits are @@ -192,7 +186,7 @@ public class Reflection { if (Modifier.isProtected(modifiers)) { // Additional test for protected members: JLS 6.6.2 - Class targetClass = (target == null ? memberClass : target.getClass()); + Class targetClass = (target == null ? memberClass : target.getClass()); if (targetClass != currentClass) { if (!gotIsSameClassPackage) { isSameClassPackage = isSameClassPackage(currentClass, memberClass); @@ -209,7 +203,7 @@ public class Reflection { return true; } - private static boolean isSameClassPackage(Class c1, Class c2) { + private static boolean isSameClassPackage(Class c1, Class c2) { return isSameClassPackage(c1.getClassLoader(), c1.getName(), c2.getClassLoader(), c2.getName()); } @@ -264,8 +258,8 @@ public class Reflection { } } - static boolean isSubclassOf(Class queryClass, - Class ofClass) + static boolean isSubclassOf(Class queryClass, + Class ofClass) { while (queryClass != null) { if (queryClass == ofClass) { @@ -277,31 +271,31 @@ public class Reflection { } // fieldNames must contain only interned Strings - public static synchronized void registerFieldsToFilter(Class containingClass, + public static synchronized void registerFieldsToFilter(Class containingClass, String ... fieldNames) { fieldFilterMap = registerFilter(fieldFilterMap, containingClass, fieldNames); } // methodNames must contain only interned Strings - public static synchronized void registerMethodsToFilter(Class containingClass, + public static synchronized void registerMethodsToFilter(Class containingClass, String ... methodNames) { methodFilterMap = registerFilter(methodFilterMap, containingClass, methodNames); } - private static Map registerFilter(Map map, - Class containingClass, String ... names) { + private static Map,String[]> registerFilter(Map,String[]> map, + Class containingClass, String ... names) { if (map.get(containingClass) != null) { throw new IllegalArgumentException ("Filter already registered: " + containingClass); } - map = new HashMap(map); + map = new HashMap,String[]>(map); map.put(containingClass, names); return map; } - public static Field[] filterFields(Class containingClass, + public static Field[] filterFields(Class containingClass, Field[] fields) { if (fieldFilterMap == null) { // Bootstrapping @@ -310,7 +304,7 @@ public class Reflection { return (Field[])filter(fields, fieldFilterMap.get(containingClass)); } - public static Method[] filterMethods(Class containingClass, Method[] methods) { + public static Method[] filterMethods(Class containingClass, Method[] methods) { if (methodFilterMap == null) { // Bootstrapping return methods; @@ -352,4 +346,27 @@ public class Reflection { } return newMembers; } + + /** + * Tests if the given method is caller-sensitive and the declaring class + * is defined by either the bootstrap class loader or extension class loader. + */ + public static boolean isCallerSensitive(Method m) { + final ClassLoader loader = m.getDeclaringClass().getClassLoader(); + if (sun.misc.VM.isSystemDomainLoader(loader) || isExtClassLoader(loader)) { + return m.isAnnotationPresent(CallerSensitive.class); + } + return false; + } + + private static boolean isExtClassLoader(ClassLoader loader) { + ClassLoader cl = ClassLoader.getSystemClassLoader(); + while (cl != null) { + if (cl.getParent() == null && cl == loader) { + return true; + } + cl = cl.getParent(); + } + return false; + } } diff --git a/external/ikvm/openjdk/sun/reflect/ReflectionFactory.java b/external/ikvm/openjdk/sun/reflect/ReflectionFactory.java index 5a3a848e9d..35cae84cc3 100644 --- a/external/ikvm/openjdk/sun/reflect/ReflectionFactory.java +++ b/external/ikvm/openjdk/sun/reflect/ReflectionFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,12 +32,14 @@ package sun.reflect; import java.lang.reflect.Field; +import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; import java.security.AccessController; import java.security.Permission; import java.security.PrivilegedAction; +import sun.reflect.misc.ReflectUtil; /**

        The master factory for all reflective objects, both those in java.lang.reflect (Fields, Methods, Constructors) as well as their @@ -53,9 +55,9 @@ import java.security.PrivilegedAction; public class ReflectionFactory { - private static Permission reflectionFactoryAccessPerm + private static final Permission reflectionFactoryAccessPerm = new RuntimePermission("reflectionFactoryAccess"); - private static ReflectionFactory soleInstance = new ReflectionFactory(); + private static final ReflectionFactory soleInstance = new ReflectionFactory(); // Provides access to package-private mechanisms in java.lang.reflect private static volatile LangReflectAccess langReflectAccess; @@ -129,7 +131,7 @@ public class ReflectionFactory { private native ConstructorAccessor newConstructorAccessor0(Constructor c); - public ConstructorAccessor newConstructorAccessor(Constructor c) { + public ConstructorAccessor newConstructorAccessor(Constructor c) { Class declaringClass = c.getDeclaringClass(); if (Modifier.isAbstract(declaringClass.getModifiers())) { return new InstantiationExceptionConstructorAccessorImpl(null); @@ -195,14 +197,14 @@ public class ReflectionFactory { /** Creates a new java.lang.reflect.Constructor. Access checks as per java.lang.reflect.AccessibleObject are not overridden. */ - public Constructor newConstructor(Class declaringClass, - Class[] parameterTypes, - Class[] checkedExceptions, - int modifiers, - int slot, - String signature, - byte[] annotations, - byte[] parameterAnnotations) + public Constructor newConstructor(Class declaringClass, + Class[] parameterTypes, + Class[] checkedExceptions, + int modifiers, + int slot, + String signature, + byte[] annotations, + byte[] parameterAnnotations) { return langReflectAccess().newConstructor(declaringClass, parameterTypes, @@ -226,13 +228,13 @@ public class ReflectionFactory { /** Gets the ConstructorAccessor object for a java.lang.reflect.Constructor */ - public ConstructorAccessor getConstructorAccessor(Constructor c) { + public ConstructorAccessor getConstructorAccessor(Constructor c) { return langReflectAccess().getConstructorAccessor(c); } /** Sets the ConstructorAccessor object for a java.lang.reflect.Constructor */ - public void setConstructorAccessor(Constructor c, + public void setConstructorAccessor(Constructor c, ConstructorAccessor accessor) { langReflectAccess().setConstructorAccessor(c, accessor); @@ -259,6 +261,12 @@ public class ReflectionFactory { return langReflectAccess().copyConstructor(arg); } + /** Gets the byte[] that encodes TypeAnnotations on an executable. + */ + public byte[] getExecutableTypeAnnotationBytes(Executable ex) { + return langReflectAccess().getExecutableTypeAnnotationBytes(ex); + } + //-------------------------------------------------------------------------- // // Routines used by serialization @@ -267,8 +275,8 @@ public class ReflectionFactory { private static native ConstructorAccessor newConstructorAccessorForSerialization(Class classToInstantiate, Constructor constructorToCall); - public Constructor newConstructorForSerialization - (Class classToInstantiate, Constructor constructorToCall) + public Constructor newConstructorForSerialization + (Class classToInstantiate, Constructor constructorToCall) { // Fast path if (constructorToCall.getDeclaringClass() == classToInstantiate) { @@ -276,18 +284,18 @@ public class ReflectionFactory { } ConstructorAccessor acc = newConstructorAccessorForSerialization(classToInstantiate, constructorToCall); - Constructor c = newConstructor(constructorToCall.getDeclaringClass(), - constructorToCall.getParameterTypes(), - constructorToCall.getExceptionTypes(), - constructorToCall.getModifiers(), - langReflectAccess(). - getConstructorSlot(constructorToCall), - langReflectAccess(). - getConstructorSignature(constructorToCall), - langReflectAccess(). - getConstructorAnnotations(constructorToCall), - langReflectAccess(). - getConstructorParameterAnnotations(constructorToCall)); + Constructor c = newConstructor(constructorToCall.getDeclaringClass(), + constructorToCall.getParameterTypes(), + constructorToCall.getExceptionTypes(), + constructorToCall.getModifiers(), + langReflectAccess(). + getConstructorSlot(constructorToCall), + langReflectAccess(). + getConstructorSignature(constructorToCall), + langReflectAccess(). + getConstructorAnnotations(constructorToCall), + langReflectAccess(). + getConstructorParameterAnnotations(constructorToCall)); setConstructorAccessor(c, acc); return c; } diff --git a/external/ikvm/reflect/Emit/ModuleBuilder.cs b/external/ikvm/reflect/Emit/ModuleBuilder.cs index 8ceea42cd6..571f8e2409 100644 --- a/external/ikvm/reflect/Emit/ModuleBuilder.cs +++ b/external/ikvm/reflect/Emit/ModuleBuilder.cs @@ -1133,7 +1133,7 @@ namespace IKVM.Reflection.Emit } } - internal void WriteMetadata(MetadataWriter mw, out int guidHeapOffset) + internal void WriteMetadata(MetadataWriter mw, out uint guidHeapOffset) { mw.Write(0x424A5342); // Signature ("BSJB") mw.Write((ushort)1); // MajorVersion diff --git a/external/ikvm/reflect/Emit/TypeBuilder.cs b/external/ikvm/reflect/Emit/TypeBuilder.cs index 7a4c262bad..9916ee6edf 100644 --- a/external/ikvm/reflect/Emit/TypeBuilder.cs +++ b/external/ikvm/reflect/Emit/TypeBuilder.cs @@ -142,6 +142,11 @@ namespace IKVM.Reflection.Emit throw new NotImplementedException(); } + public override CustomModifiers[] __GetGenericParameterConstraintCustomModifiers() + { + throw new NotImplementedException(); + } + public override GenericParameterAttributes GenericParameterAttributes { get diff --git a/external/ikvm/reflect/Reader/GenericTypeParameter.cs b/external/ikvm/reflect/Reader/GenericTypeParameter.cs index f583fca3a6..e030566904 100644 --- a/external/ikvm/reflect/Reader/GenericTypeParameter.cs +++ b/external/ikvm/reflect/Reader/GenericTypeParameter.cs @@ -239,6 +239,11 @@ namespace IKVM.Reflection.Reader throw new InvalidOperationException(); } + public override CustomModifiers[] __GetGenericParameterConstraintCustomModifiers() + { + throw new InvalidOperationException(); + } + public override GenericParameterAttributes GenericParameterAttributes { get { throw new InvalidOperationException(); } @@ -331,6 +336,24 @@ namespace IKVM.Reflection.Reader return list.ToArray(); } + public override CustomModifiers[] __GetGenericParameterConstraintCustomModifiers() + { + IGenericContext context = (this.DeclaringMethod as IGenericContext) ?? this.DeclaringType; + List list = new List(); + foreach (int i in module.GenericParamConstraint.Filter(this.MetadataToken)) + { + CustomModifiers mods = new CustomModifiers(); + int metadataToken = module.GenericParamConstraint.records[i].Constraint; + if ((metadataToken >> 24) == TypeSpecTable.Index) + { + int index = (metadataToken & 0xFFFFFF) - 1; + mods = CustomModifiers.Read(module, module.GetBlob(module.TypeSpec.records[index]), context); + } + list.Add(mods); + } + return list.ToArray(); + } + public override GenericParameterAttributes GenericParameterAttributes { get { return (GenericParameterAttributes)module.GenericParam.records[index].Flags; } diff --git a/external/ikvm/reflect/Signature.cs b/external/ikvm/reflect/Signature.cs index cb2d9f0406..7d02b1c776 100644 --- a/external/ikvm/reflect/Signature.cs +++ b/external/ikvm/reflect/Signature.cs @@ -150,6 +150,7 @@ namespace IKVM.Reflection Type[] args = new Type[br.ReadCompressedUInt()]; for (int i = 0; i < args.Length; i++) { + CustomModifiers.Skip(br); args[i] = ReadType(module, br, context); } return args; diff --git a/external/ikvm/reflect/Type.cs b/external/ikvm/reflect/Type.cs index a87478fa9e..1550b02b94 100644 --- a/external/ikvm/reflect/Type.cs +++ b/external/ikvm/reflect/Type.cs @@ -459,6 +459,11 @@ namespace IKVM.Reflection throw new InvalidOperationException(); } + public virtual CustomModifiers[] __GetGenericParameterConstraintCustomModifiers() + { + throw new InvalidOperationException(); + } + public virtual GenericParameterAttributes GenericParameterAttributes { get { throw new InvalidOperationException(); } diff --git a/external/ikvm/reflect/Writer/Heaps.cs b/external/ikvm/reflect/Writer/Heaps.cs index 54beaa4a52..9da3903e99 100644 --- a/external/ikvm/reflect/Writer/Heaps.cs +++ b/external/ikvm/reflect/Writer/Heaps.cs @@ -36,7 +36,7 @@ namespace IKVM.Reflection.Writer internal void Write(MetadataWriter mw) { - int pos = mw.Position; + uint pos = mw.Position; WriteImpl(mw); Debug.Assert(mw.Position == pos + unalignedlength); int align = Length - unalignedlength; @@ -136,7 +136,7 @@ namespace IKVM.Reflection.Writer { if (table != null && table.RowCount > 0) { - int pos = mw.Position; + uint pos = mw.Position; table.Write(mw); Debug.Assert(mw.Position - pos == table.GetLength(mw)); } diff --git a/external/ikvm/reflect/Writer/MetadataWriter.cs b/external/ikvm/reflect/Writer/MetadataWriter.cs index 9f20571a17..11a6d19c2d 100644 --- a/external/ikvm/reflect/Writer/MetadataWriter.cs +++ b/external/ikvm/reflect/Writer/MetadataWriter.cs @@ -48,9 +48,9 @@ namespace IKVM.Reflection.Writer get { return moduleBuilder; } } - internal int Position + internal uint Position { - get { return (int)stream.Position; } + get { return (uint)stream.Position; } } internal void Write(ByteBuffer bb) diff --git a/external/ikvm/reflect/Writer/ModuleWriter.cs b/external/ikvm/reflect/Writer/ModuleWriter.cs index 7ef9c6d673..1e880d58c6 100644 --- a/external/ikvm/reflect/Writer/ModuleWriter.cs +++ b/external/ikvm/reflect/Writer/ModuleWriter.cs @@ -313,7 +313,7 @@ namespace IKVM.Reflection.Writer } stream.Seek(text.PointerToRawData, SeekOrigin.Begin); - int guidHeapOffset; + uint guidHeapOffset; code.Write(mw, sdata.VirtualAddress, out guidHeapOffset); if (sdata.SizeOfRawData != 0) diff --git a/external/ikvm/reflect/Writer/TextSection.cs b/external/ikvm/reflect/Writer/TextSection.cs index fceedcf6f5..e71e8acdb6 100644 --- a/external/ikvm/reflect/Writer/TextSection.cs +++ b/external/ikvm/reflect/Writer/TextSection.cs @@ -275,7 +275,7 @@ namespace IKVM.Reflection.Writer } } - internal void Write(MetadataWriter mw, uint sdataRVA, out int guidHeapOffset) + internal void Write(MetadataWriter mw, uint sdataRVA, out uint guidHeapOffset) { // Now that we're ready to start writing, we need to do some fix ups moduleBuilder.TypeRef.Fixup(moduleBuilder); diff --git a/external/ikvm/runtime/ClassFile.cs b/external/ikvm/runtime/ClassFile.cs deleted file mode 100644 index 9dfa170f08..0000000000 --- a/external/ikvm/runtime/ClassFile.cs +++ /dev/null @@ -1,3895 +0,0 @@ -/* - Copyright (C) 2002-2015 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ -using System; -using System.IO; -using System.Collections.Generic; -using IKVM.Attributes; - -namespace IKVM.Internal -{ - enum HardError : short - { - NoClassDefFoundError, - IllegalAccessError, - InstantiationError, - IncompatibleClassChangeError, - NoSuchFieldError, - AbstractMethodError, - NoSuchMethodError, - LinkageError, - // "exceptions" that are wrapped in an IncompatibleClassChangeError - IllegalAccessException, - // if an error is added here, it must also be added to MethodAnalyzer.SetHardError() - } - - [Flags] - enum ClassFileParseOptions - { - None = 0, - LocalVariableTable = 1, - LineNumberTable = 2, - RelaxedClassNameValidation = 4, - TrustedAnnotations = 8, - } - - sealed class ClassFile - { - private ConstantPoolItem[] constantpool; - // Modifiers is a ushort, so the next four fields combine into two 32 bit slots - private Modifiers access_flags; - private ushort this_class; - private ushort super_class; - private ushort flags; - private const ushort FLAG_MASK_MAJORVERSION = 0xFF; - private const ushort FLAG_MASK_DEPRECATED = 0x100; - private const ushort FLAG_MASK_INTERNAL = 0x200; - private const ushort FLAG_CALLERSENSITIVE = 0x400; - private const ushort FLAG_LAMBDAFORM_COMPILED = 0x800; - private const ushort FLAG_LAMBDAFORM_HIDDEN = 0x1000; - private const ushort FLAG_FORCEINLINE = 0x2000; - private ConstantPoolItemClass[] interfaces; - private Field[] fields; - private Method[] methods; - private string sourceFile; -#if STATIC_COMPILER - private string sourcePath; -#endif - private string ikvmAssembly; - private InnerClass[] innerClasses; - private object[] annotations; - private string signature; - private string[] enclosingMethod; - private BootstrapMethod[] bootstrapMethods; - private byte[] runtimeVisibleTypeAnnotations; - - private static class SupportedVersions - { - internal static readonly int Minimum = 45; - internal static readonly int Maximum = Experimental.JDK_9 ? 53 : 52; - } - -#if STATIC_COMPILER - // This method parses just enough of the class file to obtain its name and - // determine if the class is a possible ikvmstub generated stub, it doesn't - // validate the class file structure, but it may throw a ClassFormatError if it - // encounters bogus data - internal static string GetClassName(byte[] buf, int offset, int length, out bool isstub) - { - isstub = false; - BigEndianBinaryReader br = new BigEndianBinaryReader(buf, offset, length); - if(br.ReadUInt32() != 0xCAFEBABE) - { - throw new ClassFormatError("Bad magic number"); - } - int minorVersion = br.ReadUInt16(); - int majorVersion = br.ReadUInt16(); - if((majorVersion & FLAG_MASK_MAJORVERSION) != majorVersion - || majorVersion < SupportedVersions.Minimum - || majorVersion > SupportedVersions.Maximum - || (majorVersion == SupportedVersions.Minimum && minorVersion < 3) - || (majorVersion == SupportedVersions.Maximum && minorVersion != 0)) - { - throw new UnsupportedClassVersionError(majorVersion + "." + minorVersion); - } - int constantpoolcount = br.ReadUInt16(); - int[] cpclass = new int[constantpoolcount]; - string[] utf8_cp = new string[constantpoolcount]; - for(int i = 1; i < constantpoolcount; i++) - { - Constant tag = (Constant)br.ReadByte(); - switch(tag) - { - case Constant.Class: - cpclass[i] = br.ReadUInt16(); - break; - case Constant.Double: - case Constant.Long: - br.Skip(8); - i++; - break; - case Constant.Fieldref: - case Constant.InterfaceMethodref: - case Constant.Methodref: - case Constant.InvokeDynamic: - case Constant.NameAndType: - case Constant.Float: - case Constant.Integer: - br.Skip(4); - break; - case Constant.MethodHandle: - br.Skip(3); - break; - case Constant.String: - case Constant.MethodType: - br.Skip(2); - break; - case Constant.Utf8: - isstub |= (utf8_cp[i] = br.ReadString(null, majorVersion)) == "IKVM.NET.Assembly"; - break; - default: - throw new ClassFormatError("Illegal constant pool type 0x{0:X}", tag); - } - } - br.ReadUInt16(); // access_flags - try - { - return String.Intern(utf8_cp[cpclass[br.ReadUInt16()]].Replace('/', '.')); - } - catch(Exception x) - { - throw new ClassFormatError("{0}: {1}", x.GetType().Name, x.Message); - } - } -#endif // STATIC_COMPILER - - internal ClassFile(byte[] buf, int offset, int length, string inputClassName, ClassFileParseOptions options, object[] constantPoolPatches) - { - try - { - BigEndianBinaryReader br = new BigEndianBinaryReader(buf, offset, length); - if(br.ReadUInt32() != 0xCAFEBABE) - { - throw new ClassFormatError("{0} (Bad magic number)", inputClassName); - } - ushort minorVersion = br.ReadUInt16(); - ushort majorVersion = br.ReadUInt16(); - if((majorVersion & FLAG_MASK_MAJORVERSION) != majorVersion - || majorVersion < SupportedVersions.Minimum - || majorVersion > SupportedVersions.Maximum - || (majorVersion == SupportedVersions.Minimum && minorVersion < 3) - || (majorVersion == SupportedVersions.Maximum && minorVersion != 0)) - { - throw new UnsupportedClassVersionError(inputClassName + " (" + majorVersion + "." + minorVersion + ")"); - } - flags = majorVersion; - int constantpoolcount = br.ReadUInt16(); - constantpool = new ConstantPoolItem[constantpoolcount]; - string[] utf8_cp = new string[constantpoolcount]; - for(int i = 1; i < constantpoolcount; i++) - { - Constant tag = (Constant)br.ReadByte(); - switch(tag) - { - case Constant.Class: - constantpool[i] = new ConstantPoolItemClass(br); - break; - case Constant.Double: - constantpool[i] = new ConstantPoolItemDouble(br); - i++; - break; - case Constant.Fieldref: - constantpool[i] = new ConstantPoolItemFieldref(br); - break; - case Constant.Float: - constantpool[i] = new ConstantPoolItemFloat(br); - break; - case Constant.Integer: - constantpool[i] = new ConstantPoolItemInteger(br); - break; - case Constant.InterfaceMethodref: - constantpool[i] = new ConstantPoolItemInterfaceMethodref(br); - break; - case Constant.Long: - constantpool[i] = new ConstantPoolItemLong(br); - i++; - break; - case Constant.Methodref: - constantpool[i] = new ConstantPoolItemMethodref(br); - break; - case Constant.NameAndType: - constantpool[i] = new ConstantPoolItemNameAndType(br); - break; - case Constant.MethodHandle: - if (majorVersion < 51) - goto default; - constantpool[i] = new ConstantPoolItemMethodHandle(br); - break; - case Constant.MethodType: - if (majorVersion < 51) - goto default; - constantpool[i] = new ConstantPoolItemMethodType(br); - break; - case Constant.InvokeDynamic: - if (majorVersion < 51) - goto default; - constantpool[i] = new ConstantPoolItemInvokeDynamic(br); - break; - case Constant.String: - constantpool[i] = new ConstantPoolItemString(br); - break; - case Constant.Utf8: - utf8_cp[i] = br.ReadString(inputClassName, majorVersion); - break; - default: - throw new ClassFormatError("{0} (Illegal constant pool type 0x{1:X})", inputClassName, tag); - } - } - if (constantPoolPatches != null) - { - PatchConstantPool(constantPoolPatches, utf8_cp, inputClassName); - } - for(int i = 1; i < constantpoolcount; i++) - { - if(constantpool[i] != null) - { - try - { - constantpool[i].Resolve(this, utf8_cp, options); - } - catch(ClassFormatError x) - { - // HACK at this point we don't yet have the class name, so any exceptions throw - // are missing the class name - throw new ClassFormatError("{0} ({1})", inputClassName, x.Message); - } - catch(IndexOutOfRangeException) - { - throw new ClassFormatError("{0} (Invalid constant pool item #{1})", inputClassName, i); - } - catch(InvalidCastException) - { - throw new ClassFormatError("{0} (Invalid constant pool item #{1})", inputClassName, i); - } - } - } - access_flags = (Modifiers)br.ReadUInt16(); - // NOTE although the vmspec says (in 4.1) that interfaces must be marked abstract, earlier versions of - // javac (JDK 1.1) didn't do this, so the VM doesn't enforce this rule for older class files. - // NOTE although the vmspec implies (in 4.1) that ACC_SUPER is illegal on interfaces, it doesn't enforce this - // for older class files. - // (See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6320322) - if((IsInterface && IsFinal) - || (IsAbstract && IsFinal) - || (majorVersion >= 49 && IsAnnotation && !IsInterface) - || (majorVersion >= 49 && IsInterface && (!IsAbstract || IsSuper || IsEnum))) - { - throw new ClassFormatError("{0} (Illegal class modifiers 0x{1:X})", inputClassName, access_flags); - } - this_class = br.ReadUInt16(); - ValidateConstantPoolItemClass(inputClassName, this_class); - super_class = br.ReadUInt16(); - ValidateConstantPoolItemClass(inputClassName, super_class); - if(IsInterface && (super_class == 0 || this.SuperClass.Name != "java.lang.Object")) - { - throw new ClassFormatError("{0} (Interfaces must have java.lang.Object as superclass)", Name); - } - // most checks are already done by ConstantPoolItemClass.Resolve, but since it allows - // array types, we do need to check for that - if(this.Name[0] == '[') - { - throw new ClassFormatError("Bad name"); - } - int interfaces_count = br.ReadUInt16(); - interfaces = new ConstantPoolItemClass[interfaces_count]; - for(int i = 0; i < interfaces.Length; i++) - { - int index = br.ReadUInt16(); - if(index == 0 || index >= constantpool.Length) - { - throw new ClassFormatError("{0} (Illegal constant pool index)", Name); - } - ConstantPoolItemClass cpi = constantpool[index] as ConstantPoolItemClass; - if(cpi == null) - { - throw new ClassFormatError("{0} (Interface name has bad constant type)", Name); - } - interfaces[i] = cpi; - } - CheckDuplicates(interfaces, "Repetitive interface name"); - int fields_count = br.ReadUInt16(); - fields = new Field[fields_count]; - for(int i = 0; i < fields_count; i++) - { - fields[i] = new Field(this, utf8_cp, br); - string name = fields[i].Name; - if(!IsValidFieldName(name, majorVersion)) - { - throw new ClassFormatError("{0} (Illegal field name \"{1}\")", Name, name); - } - } - CheckDuplicates(fields, "Repetitive field name/signature"); - int methods_count = br.ReadUInt16(); - methods = new Method[methods_count]; - for(int i = 0; i < methods_count; i++) - { - methods[i] = new Method(this, utf8_cp, options, br); - string name = methods[i].Name; - string sig = methods[i].Signature; - if(!IsValidMethodName(name, majorVersion)) - { - if(!ReferenceEquals(name, StringConstants.INIT) && !ReferenceEquals(name, StringConstants.CLINIT)) - { - throw new ClassFormatError("{0} (Illegal method name \"{1}\")", Name, name); - } - if(!sig.EndsWith("V")) - { - throw new ClassFormatError("{0} (Method \"{1}\" has illegal signature \"{2}\")", Name, name, sig); - } - } - } - CheckDuplicates(methods, "Repetitive method name/signature"); - int attributes_count = br.ReadUInt16(); - for(int i = 0; i < attributes_count; i++) - { - switch(GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16())) - { - case "Deprecated": - if(br.ReadUInt32() != 0) - { - throw new ClassFormatError("Invalid Deprecated attribute length"); - } - flags |= FLAG_MASK_DEPRECATED; - break; - case "SourceFile": - if(br.ReadUInt32() != 2) - { - throw new ClassFormatError("SourceFile attribute has incorrect length"); - } - sourceFile = GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16()); - break; - case "InnerClasses": - { - BigEndianBinaryReader rdr = br; - uint attribute_length = br.ReadUInt32(); - ushort count = rdr.ReadUInt16(); - if(this.MajorVersion >= 49 && attribute_length != 2 + count * (2 + 2 + 2 + 2)) - { - throw new ClassFormatError("{0} (InnerClasses attribute has incorrect length)", this.Name); - } - innerClasses = new InnerClass[count]; - for(int j = 0; j < innerClasses.Length; j++) - { - innerClasses[j].innerClass = rdr.ReadUInt16(); - innerClasses[j].outerClass = rdr.ReadUInt16(); - innerClasses[j].name = rdr.ReadUInt16(); - innerClasses[j].accessFlags = (Modifiers)rdr.ReadUInt16(); - if(innerClasses[j].innerClass != 0 && !(GetConstantPoolItem(innerClasses[j].innerClass) is ConstantPoolItemClass)) - { - throw new ClassFormatError("{0} (inner_class_info_index has bad constant pool index)", this.Name); - } - if(innerClasses[j].outerClass != 0 && !(GetConstantPoolItem(innerClasses[j].outerClass) is ConstantPoolItemClass)) - { - throw new ClassFormatError("{0} (outer_class_info_index has bad constant pool index)", this.Name); - } - if(innerClasses[j].name != 0 && utf8_cp[innerClasses[j].name] == null) - { - throw new ClassFormatError("{0} (inner class name has bad constant pool index)", this.Name); - } - if(innerClasses[j].innerClass == innerClasses[j].outerClass) - { - throw new ClassFormatError("{0} (Class is both inner and outer class)", this.Name); - } - if(innerClasses[j].innerClass != 0 && innerClasses[j].outerClass != 0) - { - MarkLinkRequiredConstantPoolItem(innerClasses[j].innerClass); - MarkLinkRequiredConstantPoolItem(innerClasses[j].outerClass); - } - } - break; - } - case "Signature": - if(majorVersion < 49) - { - goto default; - } - if(br.ReadUInt32() != 2) - { - throw new ClassFormatError("Signature attribute has incorrect length"); - } - signature = GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16()); - break; - case "EnclosingMethod": - if(majorVersion < 49) - { - goto default; - } - if(br.ReadUInt32() != 4) - { - throw new ClassFormatError("EnclosingMethod attribute has incorrect length"); - } - else - { - ushort class_index = br.ReadUInt16(); - ushort method_index = br.ReadUInt16(); - ValidateConstantPoolItemClass(inputClassName, class_index); - if(method_index == 0) - { - enclosingMethod = new string[] { - GetConstantPoolClass(class_index), - null, - null - }; - } - else - { - ConstantPoolItemNameAndType m = GetConstantPoolItem(method_index) as ConstantPoolItemNameAndType; - if(m == null) - { - throw new ClassFormatError("{0} (Bad constant pool index #{1})", inputClassName, method_index); - } - enclosingMethod = new string[] { - GetConstantPoolClass(class_index), - GetConstantPoolUtf8String(utf8_cp, m.name_index), - GetConstantPoolUtf8String(utf8_cp, m.descriptor_index).Replace('/', '.') - }; - } - } - break; - case "RuntimeVisibleAnnotations": - if(majorVersion < 49) - { - goto default; - } - annotations = ReadAnnotations(br, this, utf8_cp); - break; -#if STATIC_COMPILER - case "RuntimeInvisibleAnnotations": - if(majorVersion < 49) - { - goto default; - } - foreach(object[] annot in ReadAnnotations(br, this, utf8_cp)) - { - if(annot[1].Equals("Likvm/lang/Internal;")) - { - this.access_flags &= ~Modifiers.AccessMask; - flags |= FLAG_MASK_INTERNAL; - } - } - break; -#endif - case "BootstrapMethods": - if(majorVersion < 51) - { - goto default; - } - bootstrapMethods = ReadBootstrapMethods(br, this); - break; - case "RuntimeVisibleTypeAnnotations": - if(majorVersion < 52) - { - goto default; - } - CreateUtf8ConstantPoolItems(utf8_cp); - runtimeVisibleTypeAnnotations = br.Section(br.ReadUInt32()).ToArray(); - break; - case "IKVM.NET.Assembly": - if(br.ReadUInt32() != 2) - { - throw new ClassFormatError("IKVM.NET.Assembly attribute has incorrect length"); - } - ikvmAssembly = GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16()); - break; - default: - br.Skip(br.ReadUInt32()); - break; - } - } - // validate the invokedynamic entries to point into the bootstrapMethods array - for(int i = 1; i < constantpoolcount; i++) - { - ConstantPoolItemInvokeDynamic cpi; - if(constantpool[i] != null - && (cpi = constantpool[i] as ConstantPoolItemInvokeDynamic) != null) - { - if(bootstrapMethods == null || cpi.BootstrapMethod >= bootstrapMethods.Length) - { - throw new ClassFormatError("Short length on BootstrapMethods in class file"); - } - } - } - if(br.Position != offset + length) - { - throw new ClassFormatError("Extra bytes at the end of the class file"); - } - } - catch(OverflowException) - { - throw new ClassFormatError("Truncated class file (or section)"); - } - catch(IndexOutOfRangeException) - { - // TODO we should throw more specific errors - throw new ClassFormatError("Unspecified class file format error"); - } - // catch(Exception x) - // { - // Console.WriteLine(x); - // FileStream fs = File.Create(inputClassName + ".broken"); - // fs.Write(buf, offset, length); - // fs.Close(); - // throw; - // } - } - - private void CreateUtf8ConstantPoolItems(string[] utf8_cp) - { - for (int i = 0; i < constantpool.Length; i++) - { - if (constantpool[i] == null && utf8_cp[i] != null) - { - constantpool[i] = new ConstantPoolItemUtf8(utf8_cp[i]); - } - } - } - - private void CheckDuplicates(T[] members, string msg) - where T : IEquatable - { - if (members.Length < 100) - { - for (int i = 0; i < members.Length; i++) - { - for (int j = 0; j < i; j++) - { - if (members[i].Equals(members[j])) - { - throw new ClassFormatError("{0} ({1})", Name, msg); - } - } - } - } - else - { - Dictionary dict = new Dictionary(); - for (int i = 0; i < members.Length; i++) - { - if (dict.ContainsKey(members[i])) - { - throw new ClassFormatError("{0} ({1})", Name, msg); - } - dict.Add(members[i], null); - } - } - } - - private void PatchConstantPool(object[] constantPoolPatches, string[] utf8_cp, string inputClassName) - { -#if !STATIC_COMPILER && !FIRST_PASS - for (int i = 0; i < constantPoolPatches.Length; i++) - { - if (constantPoolPatches[i] != null) - { - if (utf8_cp[i] != null) - { - if (!(constantPoolPatches[i] is string)) - { - throw new ClassFormatError("Illegal utf8 patch at {0} in class file {1}", i, inputClassName); - } - utf8_cp[i] = (string)constantPoolPatches[i]; - } - else if (constantpool[i] != null) - { - switch (constantpool[i].GetConstantType()) - { - case ConstantType.String: - constantpool[i] = new ConstantPoolItemLiveObject(constantPoolPatches[i]); - break; - case ConstantType.Class: - java.lang.Class clazz; - string name; - if ((clazz = constantPoolPatches[i] as java.lang.Class) != null) - { - TypeWrapper tw = TypeWrapper.FromClass(clazz); - constantpool[i] = new ConstantPoolItemClass(tw.Name, tw); - } - else if ((name = constantPoolPatches[i] as string) != null) - { - constantpool[i] = new ConstantPoolItemClass(String.Intern(name.Replace('/', '.')), null); - } - else - { - throw new ClassFormatError("Illegal class patch at {0} in class file {1}", i, inputClassName); - } - break; - case ConstantType.Integer: - ((ConstantPoolItemInteger)constantpool[i]).v = ((java.lang.Integer)constantPoolPatches[i]).intValue(); - break; - case ConstantType.Long: - ((ConstantPoolItemLong)constantpool[i]).l = ((java.lang.Long)constantPoolPatches[i]).longValue(); - break; - case ConstantType.Float: - ((ConstantPoolItemFloat)constantpool[i]).v = ((java.lang.Float)constantPoolPatches[i]).floatValue(); - break; - case ConstantType.Double: - ((ConstantPoolItemDouble)constantpool[i]).d = ((java.lang.Double)constantPoolPatches[i]).doubleValue(); - break; - default: - throw new NotImplementedException("ConstantPoolPatch: " + constantPoolPatches[i]); - } - } - } - } -#endif - } - - private void MarkLinkRequiredConstantPoolItem(int index) - { - if (index > 0 && index < constantpool.Length && constantpool[index] != null) - { - constantpool[index].MarkLinkRequired(); - } - } - - private static BootstrapMethod[] ReadBootstrapMethods(BigEndianBinaryReader br, ClassFile classFile) - { - BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); - ushort count = rdr.ReadUInt16(); - BootstrapMethod[] bsm = new BootstrapMethod[count]; - for(int i = 0; i < bsm.Length; i++) - { - ushort bsm_index = rdr.ReadUInt16(); - if(bsm_index >= classFile.constantpool.Length || !(classFile.constantpool[bsm_index] is ConstantPoolItemMethodHandle)) - { - throw new ClassFormatError("bootstrap_method_index {0} has bad constant type in class file {1}", bsm_index, classFile.Name); - } - classFile.MarkLinkRequiredConstantPoolItem(bsm_index); - ushort argument_count = rdr.ReadUInt16(); - ushort[] args = new ushort[argument_count]; - for(int j = 0; j < args.Length; j++) - { - ushort argument_index = rdr.ReadUInt16(); - if(!classFile.IsValidConstant(argument_index)) - { - throw new ClassFormatError("argument_index {0} has bad constant type in class file {1}", argument_index, classFile.Name); - } - classFile.MarkLinkRequiredConstantPoolItem(argument_index); - args[j] = argument_index; - } - bsm[i] = new BootstrapMethod(bsm_index, args); - } - if(!rdr.IsAtEnd) - { - throw new ClassFormatError("Bad length on BootstrapMethods in class file {0}", classFile.Name); - } - return bsm; - } - - private bool IsValidConstant(ushort index) - { - if(index < constantpool.Length && constantpool[index] != null) - { - try - { - constantpool[index].GetConstantType(); - return true; - } - catch (InvalidOperationException) { } - } - return false; - } - - private static object[] ReadAnnotations(BigEndianBinaryReader br, ClassFile classFile, string[] utf8_cp) - { - BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); - ushort num_annotations = rdr.ReadUInt16(); - object[] annotations = new object[num_annotations]; - for(int i = 0; i < annotations.Length; i++) - { - annotations[i] = ReadAnnotation(rdr, classFile, utf8_cp); - } - if(!rdr.IsAtEnd) - { - throw new ClassFormatError("{0} (RuntimeVisibleAnnotations attribute has wrong length)", classFile.Name); - } - return annotations; - } - - private static object ReadAnnotation(BigEndianBinaryReader rdr, ClassFile classFile, string[] utf8_cp) - { - string type = classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()); - ushort num_element_value_pairs = rdr.ReadUInt16(); - object[] annot = new object[2 + num_element_value_pairs * 2]; - annot[0] = AnnotationDefaultAttribute.TAG_ANNOTATION; - annot[1] = type; - for(int i = 0; i < num_element_value_pairs; i++) - { - annot[2 + i * 2 + 0] = classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()); - annot[2 + i * 2 + 1] = ReadAnnotationElementValue(rdr, classFile, utf8_cp); - } - return annot; - } - - private static object ReadAnnotationElementValue(BigEndianBinaryReader rdr, ClassFile classFile, string[] utf8_cp) - { - try - { - byte tag = rdr.ReadByte(); - switch (tag) - { - case (byte)'Z': - return classFile.GetConstantPoolConstantInteger(rdr.ReadUInt16()) != 0; - case (byte)'B': - return (byte)classFile.GetConstantPoolConstantInteger(rdr.ReadUInt16()); - case (byte)'C': - return (char)classFile.GetConstantPoolConstantInteger(rdr.ReadUInt16()); - case (byte)'S': - return (short)classFile.GetConstantPoolConstantInteger(rdr.ReadUInt16()); - case (byte)'I': - return classFile.GetConstantPoolConstantInteger(rdr.ReadUInt16()); - case (byte)'F': - return classFile.GetConstantPoolConstantFloat(rdr.ReadUInt16()); - case (byte)'J': - return classFile.GetConstantPoolConstantLong(rdr.ReadUInt16()); - case (byte)'D': - return classFile.GetConstantPoolConstantDouble(rdr.ReadUInt16()); - case (byte)'s': - return classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()); - case (byte)'e': - { - ushort type_name_index = rdr.ReadUInt16(); - ushort const_name_index = rdr.ReadUInt16(); - return new object[] { - AnnotationDefaultAttribute.TAG_ENUM, - classFile.GetConstantPoolUtf8String(utf8_cp, type_name_index), - classFile.GetConstantPoolUtf8String(utf8_cp, const_name_index) - }; - } - case (byte)'c': - return new object[] { - AnnotationDefaultAttribute.TAG_CLASS, - classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()) - }; - case (byte)'@': - return ReadAnnotation(rdr, classFile, utf8_cp); - case (byte)'[': - { - ushort num_values = rdr.ReadUInt16(); - object[] array = new object[num_values + 1]; - array[0] = AnnotationDefaultAttribute.TAG_ARRAY; - for (int i = 0; i < num_values; i++) - { - array[i + 1] = ReadAnnotationElementValue(rdr, classFile, utf8_cp); - } - return array; - } - default: - throw new ClassFormatError("Invalid tag {0} in annotation element_value", tag); - } - } - catch (NullReferenceException) - { - } - catch (InvalidCastException) - { - } - catch (IndexOutOfRangeException) - { - } - return new object[] { AnnotationDefaultAttribute.TAG_ERROR, "java.lang.IllegalArgumentException", "Wrong type at constant pool index" }; - } - - private void ValidateConstantPoolItemClass(string classFile, ushort index) - { - if(index >= constantpool.Length || !(constantpool[index] is ConstantPoolItemClass)) - { - throw new ClassFormatError("{0} (Bad constant pool index #{1})", classFile, index); - } - } - - private static bool IsValidMethodName(string name, int majorVersion) - { - if(name.Length == 0) - { - return false; - } - for(int i = 0; i < name.Length; i++) - { - if(".;[/<>".IndexOf(name[i]) != -1) - { - return false; - } - } - return majorVersion >= 49 || IsValidPre49Identifier(name); - } - - private static bool IsValidFieldName(string name, int majorVersion) - { - if(name.Length == 0) - { - return false; - } - for(int i = 0; i < name.Length; i++) - { - if(".;[/".IndexOf(name[i]) != -1) - { - return false; - } - } - return majorVersion >= 49 || IsValidPre49Identifier(name); - } - - private static bool IsValidPre49Identifier(string name) - { - if(!Char.IsLetter(name[0]) && "$_".IndexOf(name[0]) == -1) - { - return false; - } - for(int i = 1; i < name.Length; i++) - { - if(!Char.IsLetterOrDigit(name[i]) && "$_".IndexOf(name[i]) == -1) - { - return false; - } - } - return true; - } - - internal static bool IsValidFieldSig(string sig) - { - return IsValidFieldSigImpl(sig, 0, sig.Length); - } - - private static bool IsValidFieldSigImpl(string sig, int start, int end) - { - if(start >= end) - { - return false; - } - switch(sig[start]) - { - case 'L': - return sig.IndexOf(';', start + 1) == end - 1; - case '[': - while(sig[start] == '[') - { - start++; - if(start == end) - { - return false; - } - } - return IsValidFieldSigImpl(sig, start, end); - case 'B': - case 'Z': - case 'C': - case 'S': - case 'I': - case 'J': - case 'F': - case 'D': - return start == end - 1; - default: - return false; - } - } - - internal static bool IsValidMethodSig(string sig) - { - if(sig.Length < 3 || sig[0] != '(') - { - return false; - } - int end = sig.IndexOf(')'); - if(end == -1) - { - return false; - } - if(!sig.EndsWith(")V") && !IsValidFieldSigImpl(sig, end + 1, sig.Length)) - { - return false; - } - for(int i = 1; i < end; i++) - { - switch(sig[i]) - { - case 'B': - case 'Z': - case 'C': - case 'S': - case 'I': - case 'J': - case 'F': - case 'D': - break; - case 'L': - i = sig.IndexOf(';', i); - break; - case '[': - while(sig[i] == '[') - { - i++; - } - if("BZCSIJFDL".IndexOf(sig[i]) == -1) - { - return false; - } - if(sig[i] == 'L') - { - i = sig.IndexOf(';', i); - } - break; - default: - return false; - } - if(i == -1 || i >= end) - { - return false; - } - } - return true; - } - - internal int MajorVersion - { - get - { - return flags & FLAG_MASK_MAJORVERSION; - } - } - - internal void Link(TypeWrapper thisType, LoadMode mode) - { - // this is not just an optimization, it's required for anonymous classes to be able to refer to themselves - ((ConstantPoolItemClass)constantpool[this_class]).LinkSelf(thisType); - for(int i = 1; i < constantpool.Length; i++) - { - if(constantpool[i] != null) - { - constantpool[i].Link(thisType, mode); - } - } - } - - internal Modifiers Modifiers - { - get - { - return access_flags; - } - } - - internal bool IsAbstract - { - get - { - // interfaces are implicitly abstract - return (access_flags & (Modifiers.Abstract | Modifiers.Interface)) != 0; - } - } - - internal bool IsFinal - { - get - { - return (access_flags & Modifiers.Final) != 0; - } - } - - internal bool IsPublic - { - get - { - return (access_flags & Modifiers.Public) != 0; - } - } - - internal bool IsInterface - { - get - { - return (access_flags & Modifiers.Interface) != 0; - } - } - - internal bool IsEnum - { - get - { - return (access_flags & Modifiers.Enum) != 0; - } - } - - internal bool IsAnnotation - { - get - { - return (access_flags & Modifiers.Annotation) != 0; - } - } - - internal bool IsSuper - { - get - { - return (access_flags & Modifiers.Super) != 0; - } - } - - internal void RemoveUnusedFields() - { - List list = new List(); - foreach(Field f in fields) - { - if(f.IsPrivate && f.IsStatic && f.Name != "serialVersionUID" && !IsReferenced(f)) - { - // unused, so we skip it - Tracer.Info(Tracer.Compiler, "Unused field {0}::{1}", this.Name, f.Name); - } - else - { - list.Add(f); - } - } - fields = list.ToArray(); - } - - private bool IsReferenced(Field fld) - { - foreach(ConstantPoolItem cpi in constantpool) - { - ConstantPoolItemFieldref fieldref = cpi as ConstantPoolItemFieldref; - if(fieldref != null && - fieldref.Class == this.Name && - fieldref.Name == fld.Name && - fieldref.Signature == fld.Signature) - { - return true; - } - } - return false; - } - - internal ConstantPoolItemFieldref GetFieldref(int index) - { - return (ConstantPoolItemFieldref)constantpool[index]; - } - - // this won't throw an exception if index is invalid - // (used by IsSideEffectFreeStaticInitializer) - internal ConstantPoolItemFieldref SafeGetFieldref(int index) - { - if(index > 0 && index < constantpool.Length) - { - return constantpool[index] as ConstantPoolItemFieldref; - } - return null; - } - - // NOTE this returns an MI, because it used for both normal methods and interface methods - internal ConstantPoolItemMI GetMethodref(int index) - { - return (ConstantPoolItemMI)constantpool[index]; - } - - // this won't throw an exception if index is invalid - // (used by IsAccessBridge) - internal ConstantPoolItemMI SafeGetMethodref(int index) - { - if (index > 0 && index < constantpool.Length) - { - return constantpool[index] as ConstantPoolItemMI; - } - return null; - } - - internal ConstantPoolItemInvokeDynamic GetInvokeDynamic(int index) - { - return (ConstantPoolItemInvokeDynamic)constantpool[index]; - } - - private ConstantPoolItem GetConstantPoolItem(int index) - { - return constantpool[index]; - } - - internal string GetConstantPoolClass(int index) - { - return ((ConstantPoolItemClass)constantpool[index]).Name; - } - - private bool SafeIsConstantPoolClass(int index) - { - if(index > 0 && index < constantpool.Length) - { - return constantpool[index] as ConstantPoolItemClass != null; - } - return false; - } - - internal TypeWrapper GetConstantPoolClassType(int index) - { - return ((ConstantPoolItemClass)constantpool[index]).GetClassType(); - } - - private string GetConstantPoolUtf8String(string[] utf8_cp, int index) - { - string s = utf8_cp[index]; - if(s == null) - { - if(this_class == 0) - { - throw new ClassFormatError("Bad constant pool index #{0}", index); - } - else - { - throw new ClassFormatError("{0} (Bad constant pool index #{1})", this.Name, index); - } - } - return s; - } - - internal ConstantType GetConstantPoolConstantType(int index) - { - return constantpool[index].GetConstantType(); - } - - internal double GetConstantPoolConstantDouble(int index) - { - return ((ConstantPoolItemDouble)constantpool[index]).Value; - } - - internal float GetConstantPoolConstantFloat(int index) - { - return ((ConstantPoolItemFloat)constantpool[index]).Value; - } - - internal int GetConstantPoolConstantInteger(int index) - { - return ((ConstantPoolItemInteger)constantpool[index]).Value; - } - - internal long GetConstantPoolConstantLong(int index) - { - return ((ConstantPoolItemLong)constantpool[index]).Value; - } - - internal string GetConstantPoolConstantString(int index) - { - return ((ConstantPoolItemString)constantpool[index]).Value; - } - - internal ConstantPoolItemMethodHandle GetConstantPoolConstantMethodHandle(int index) - { - return (ConstantPoolItemMethodHandle)constantpool[index]; - } - - internal ConstantPoolItemMethodType GetConstantPoolConstantMethodType(int index) - { - return (ConstantPoolItemMethodType)constantpool[index]; - } - - internal object GetConstantPoolConstantLiveObject(int index) - { - return ((ConstantPoolItemLiveObject)constantpool[index]).Value; - } - - internal string Name - { - get - { - return GetConstantPoolClass(this_class); - } - } - - internal ConstantPoolItemClass SuperClass - { - get - { - return (ConstantPoolItemClass)constantpool[super_class]; - } - } - - internal Field[] Fields - { - get - { - return fields; - } - } - - internal Method[] Methods - { - get - { - return methods; - } - } - - internal ConstantPoolItemClass[] Interfaces - { - get - { - return interfaces; - } - } - - internal string SourceFileAttribute - { - get - { - return sourceFile; - } - } - - internal string SourcePath - { -#if STATIC_COMPILER - get { return sourcePath; } - set { sourcePath = value; } -#else - get { return sourceFile; } -#endif - } - - internal object[] Annotations - { - get - { - return annotations; - } - } - - internal string GenericSignature - { - get - { - return signature; - } - } - - internal string[] EnclosingMethod - { - get - { - return enclosingMethod; - } - } - - internal byte[] RuntimeVisibleTypeAnnotations - { - get - { - return runtimeVisibleTypeAnnotations; - } - } - - internal object[] GetConstantPool() - { - object[] cp = new object[constantpool.Length]; - for (int i = 1; i < cp.Length; i++) - { - if (constantpool[i] != null) - { - cp[i] = constantpool[i].GetRuntimeValue(); - } - } - return cp; - } - - internal string IKVMAssemblyAttribute - { - get - { - return ikvmAssembly; - } - } - - internal bool DeprecatedAttribute - { - get - { - return (flags & FLAG_MASK_DEPRECATED) != 0; - } - } - - internal bool IsInternal - { - get - { - return (flags & FLAG_MASK_INTERNAL) != 0; - } - } - - // for use by ikvmc (to implement the -privatepackage option) - internal void SetInternal() - { - access_flags &= ~Modifiers.AccessMask; - flags |= FLAG_MASK_INTERNAL; - } - - internal bool HasInitializedFields - { - get - { - foreach (Field f in fields) - { - if (f.IsStatic && !f.IsFinal && f.ConstantValue != null) - { - return true; - } - } - return false; - } - } - - internal BootstrapMethod GetBootstrapMethod(int index) - { - return bootstrapMethods[index]; - } - - internal struct BootstrapMethod - { - private ushort bsm_index; - private ushort[] args; - - internal BootstrapMethod(ushort bsm_index, ushort[] args) - { - this.bsm_index = bsm_index; - this.args = args; - } - - internal int BootstrapMethodIndex - { - get { return bsm_index; } - } - - internal int ArgumentCount - { - get { return args.Length; } - } - - internal int GetArgument(int index) - { - return args[index]; - } - } - - internal struct InnerClass - { - internal ushort innerClass; // ConstantPoolItemClass - internal ushort outerClass; // ConstantPoolItemClass - internal ushort name; // ConstantPoolItemUtf8 - internal Modifiers accessFlags; - } - - internal InnerClass[] InnerClasses - { - get - { - return innerClasses; - } - } - - internal enum RefKind - { - getField = 1, - getStatic = 2, - putField = 3, - putStatic = 4, - invokeVirtual = 5, - invokeStatic = 6, - invokeSpecial = 7, - newInvokeSpecial = 8, - invokeInterface = 9 - } - - internal enum ConstantType - { - Integer, - Long, - Float, - Double, - String, - Class, - MethodHandle, - MethodType, - LiveObject, // used by anonymous class constant pool patching - } - - internal abstract class ConstantPoolItem - { - internal virtual void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) - { - } - - internal virtual void Link(TypeWrapper thisType, LoadMode mode) - { - } - - internal virtual ConstantType GetConstantType() - { - throw new InvalidOperationException(); - } - - internal virtual void MarkLinkRequired() - { - } - - // this is used for sun.reflect.ConstantPool - // it returns a boxed System.Int32, System.Int64, System.Float, System.Double or a string - internal virtual object GetRuntimeValue() - { - return null; - } - } - - internal sealed class ConstantPoolItemClass : ConstantPoolItem, IEquatable - { - private ushort name_index; - private string name; - private TypeWrapper typeWrapper; - private static char[] invalidJava15Characters = { '.', ';', '[', ']' }; - - internal ConstantPoolItemClass(BigEndianBinaryReader br) - { - name_index = br.ReadUInt16(); - } - - internal ConstantPoolItemClass(string name, TypeWrapper typeWrapper) - { - this.name = name; - this.typeWrapper = typeWrapper; - } - - internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) - { - // if the item was patched, we already have a name - if(name != null) - { - return; - } - name = classFile.GetConstantPoolUtf8String(utf8_cp, name_index); - if(name.Length > 0) - { - // We don't enforce the strict class name rules in the static compiler, since HotSpot doesn't enforce *any* rules on - // class names for the system (and boot) class loader. We still need to enforce the 1.5 restrictions, because we - // rely on those invariants. -#if !STATIC_COMPILER - if(classFile.MajorVersion < 49 && (options & ClassFileParseOptions.RelaxedClassNameValidation) == 0) - { - char prev = name[0]; - if(Char.IsLetter(prev) || prev == '$' || prev == '_' || prev == '[' || prev == '/') - { - int skip = 1; - int end = name.Length; - if(prev == '[') - { - if(!IsValidFieldSig(name)) - { - goto barf; - } - while(name[skip] == '[') - { - skip++; - } - if(name.EndsWith(";")) - { - end--; - } - } - for(int i = skip; i < end; i++) - { - char c = name[i]; - if(!Char.IsLetterOrDigit(c) && c != '$' && c != '_' && (c != '/' || prev == '/')) - { - goto barf; - } - prev = c; - } - name = String.Intern(name.Replace('/', '.')); - return; - } - } - else -#endif - { - // since 1.5 the restrictions on class names have been greatly reduced - int start = 0; - int end = name.Length; - if(name[0] == '[') - { - if(!IsValidFieldSig(name)) - { - goto barf; - } - // the semicolon is only allowed at the end and IsValidFieldSig enforces this, - // but since invalidJava15Characters contains the semicolon, we decrement end - // to make the following check against invalidJava15Characters ignore the - // trailing semicolon. - if(name[end - 1] == ';') - { - end--; - } - while(name[start] == '[') - { - start++; - } - } - if(name.IndexOfAny(invalidJava15Characters, start, end - start) >= 0) - { - goto barf; - } - name = String.Intern(name.Replace('/', '.')); - return; - } - } - barf: - throw new ClassFormatError("Invalid class name \"{0}\"", name); - } - - internal override void MarkLinkRequired() - { - if(typeWrapper == null) - { - typeWrapper = VerifierTypeWrapper.Null; - } - } - - internal void LinkSelf(TypeWrapper thisType) - { - this.typeWrapper = thisType; - } - - internal override void Link(TypeWrapper thisType, LoadMode mode) - { - if(typeWrapper == VerifierTypeWrapper.Null) - { - TypeWrapper tw = thisType.GetClassLoader().LoadClass(name, mode | LoadMode.WarnClassNotFound); -#if !STATIC_COMPILER && !FIRST_PASS - if(!tw.IsUnloadable) - { - try - { - thisType.GetClassLoader().CheckPackageAccess(tw, thisType.ClassObject.pd); - } - catch(java.lang.SecurityException) - { - tw = new UnloadableTypeWrapper(name); - } - } -#endif - typeWrapper = tw; - } - } - - internal string Name - { - get - { - return name; - } - } - - internal TypeWrapper GetClassType() - { - return typeWrapper; - } - - internal override ConstantType GetConstantType() - { - return ConstantType.Class; - } - - public sealed override int GetHashCode() - { - return name.GetHashCode(); - } - - public bool Equals(ConstantPoolItemClass other) - { - return ReferenceEquals(name, other.name); - } - } - - private sealed class ConstantPoolItemDouble : ConstantPoolItem - { - internal double d; - - internal ConstantPoolItemDouble(BigEndianBinaryReader br) - { - d = br.ReadDouble(); - } - - internal override ConstantType GetConstantType() - { - return ConstantType.Double; - } - - internal double Value - { - get - { - return d; - } - } - - internal override object GetRuntimeValue() - { - return d; - } - } - - internal abstract class ConstantPoolItemFMI : ConstantPoolItem - { - private ushort class_index; - private ushort name_and_type_index; - private ConstantPoolItemClass clazz; - private string name; - private string descriptor; - - internal ConstantPoolItemFMI(BigEndianBinaryReader br) - { - class_index = br.ReadUInt16(); - name_and_type_index = br.ReadUInt16(); - } - - internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) - { - ConstantPoolItemNameAndType name_and_type = (ConstantPoolItemNameAndType)classFile.GetConstantPoolItem(name_and_type_index); - clazz = (ConstantPoolItemClass)classFile.GetConstantPoolItem(class_index); - // if the constant pool items referred to were strings, GetConstantPoolItem returns null - if(name_and_type == null || clazz == null) - { - throw new ClassFormatError("Bad index in constant pool"); - } - name = String.Intern(classFile.GetConstantPoolUtf8String(utf8_cp, name_and_type.name_index)); - descriptor = classFile.GetConstantPoolUtf8String(utf8_cp, name_and_type.descriptor_index); - Validate(name, descriptor, classFile.MajorVersion); - descriptor = String.Intern(descriptor.Replace('/', '.')); - } - - protected abstract void Validate(string name, string descriptor, int majorVersion); - - internal override void MarkLinkRequired() - { - clazz.MarkLinkRequired(); - } - - internal override void Link(TypeWrapper thisType, LoadMode mode) - { - clazz.Link(thisType, mode); - } - - internal string Name - { - get - { - return name; - } - } - - internal string Signature - { - get - { - return descriptor; - } - } - - internal string Class - { - get - { - return clazz.Name; - } - } - - internal TypeWrapper GetClassType() - { - return clazz.GetClassType(); - } - - internal abstract MemberWrapper GetMember(); - } - - internal sealed class ConstantPoolItemFieldref : ConstantPoolItemFMI - { - private FieldWrapper field; - private TypeWrapper fieldTypeWrapper; - - internal ConstantPoolItemFieldref(BigEndianBinaryReader br) : base(br) - { - } - - protected override void Validate(string name, string descriptor, int majorVersion) - { - if(!IsValidFieldSig(descriptor)) - { - throw new ClassFormatError("Invalid field signature \"{0}\"", descriptor); - } - if(!IsValidFieldName(name, majorVersion)) - { - throw new ClassFormatError("Invalid field name \"{0}\"", name); - } - } - - internal TypeWrapper GetFieldType() - { - return fieldTypeWrapper; - } - - internal override void Link(TypeWrapper thisType, LoadMode mode) - { - base.Link(thisType, mode); - lock(this) - { - if(fieldTypeWrapper != null) - { - return; - } - } - FieldWrapper fw = null; - TypeWrapper wrapper = GetClassType(); - if(wrapper == null) - { - return; - } - if(!wrapper.IsUnloadable) - { - fw = wrapper.GetFieldWrapper(Name, Signature); - if(fw != null) - { - fw.Link(mode); - } - } - ClassLoaderWrapper classLoader = thisType.GetClassLoader(); - TypeWrapper fld = classLoader.FieldTypeWrapperFromSig(this.Signature, mode); - lock(this) - { - if(fieldTypeWrapper == null) - { - fieldTypeWrapper = fld; - field = fw; - } - } - } - - internal FieldWrapper GetField() - { - return field; - } - - internal override MemberWrapper GetMember() - { - return field; - } - } - - internal class ConstantPoolItemMI : ConstantPoolItemFMI - { - private TypeWrapper[] argTypeWrappers; - private TypeWrapper retTypeWrapper; - protected MethodWrapper method; - protected MethodWrapper invokespecialMethod; - - internal ConstantPoolItemMI(BigEndianBinaryReader br) : base(br) - { - } - - protected override void Validate(string name, string descriptor, int majorVersion) - { - if(!IsValidMethodSig(descriptor)) - { - throw new ClassFormatError("Method {0} has invalid signature {1}", name, descriptor); - } - if(!IsValidMethodName(name, majorVersion)) - { - if(!ReferenceEquals(name, StringConstants.INIT)) - { - throw new ClassFormatError("Invalid method name \"{0}\"", name); - } - if(!descriptor.EndsWith("V")) - { - throw new ClassFormatError("Method {0} has invalid signature {1}", name, descriptor); - } - } - } - - internal override void Link(TypeWrapper thisType, LoadMode mode) - { - base.Link(thisType, mode); - lock(this) - { - if(argTypeWrappers != null) - { - return; - } - } - ClassLoaderWrapper classLoader = thisType.GetClassLoader(); - TypeWrapper[] args = classLoader.ArgTypeWrapperListFromSig(this.Signature, mode); - TypeWrapper ret = classLoader.RetTypeWrapperFromSig(this.Signature, mode); - lock(this) - { - if(argTypeWrappers == null) - { - argTypeWrappers = args; - retTypeWrapper = ret; - } - } - } - - internal TypeWrapper[] GetArgTypes() - { - return argTypeWrappers; - } - - internal TypeWrapper GetRetType() - { - return retTypeWrapper; - } - - internal MethodWrapper GetMethod() - { - return method; - } - - internal MethodWrapper GetMethodForInvokespecial() - { - return invokespecialMethod != null ? invokespecialMethod : method; - } - - internal override MemberWrapper GetMember() - { - return method; - } - } - - internal sealed class ConstantPoolItemMethodref : ConstantPoolItemMI - { - internal ConstantPoolItemMethodref(BigEndianBinaryReader br) : base(br) - { - } - - internal override void Link(TypeWrapper thisType, LoadMode mode) - { - base.Link(thisType, mode); - TypeWrapper wrapper = GetClassType(); - if(wrapper != null && !wrapper.IsUnloadable) - { - method = wrapper.GetMethodWrapper(Name, Signature, !ReferenceEquals(Name, StringConstants.INIT)); - if(method != null) - { - method.Link(mode); - } - if(Name != StringConstants.INIT - && !thisType.IsInterface - && (!JVM.AllowNonVirtualCalls || (thisType.Modifiers & Modifiers.Super) == Modifiers.Super) - && thisType != wrapper - && thisType.IsSubTypeOf(wrapper)) - { - invokespecialMethod = thisType.BaseTypeWrapper.GetMethodWrapper(Name, Signature, true); - if(invokespecialMethod != null) - { - invokespecialMethod.Link(mode); - } - } - } - } - } - - internal sealed class ConstantPoolItemInterfaceMethodref : ConstantPoolItemMI - { - internal ConstantPoolItemInterfaceMethodref(BigEndianBinaryReader br) : base(br) - { - } - - internal override void Link(TypeWrapper thisType, LoadMode mode) - { - base.Link(thisType, mode); - TypeWrapper wrapper = GetClassType(); - if(wrapper != null) - { - if(!wrapper.IsUnloadable) - { - method = wrapper.GetInterfaceMethod(Name, Signature); - } - if(method == null) - { - // NOTE vmspec 5.4.3.4 clearly states that an interfacemethod may also refer to a method in Object - method = CoreClasses.java.lang.Object.Wrapper.GetMethodWrapper(Name, Signature, false); - } - if(method != null) - { - method.Link(mode); - } - } - } - } - - private sealed class ConstantPoolItemFloat : ConstantPoolItem - { - internal float v; - - internal ConstantPoolItemFloat(BigEndianBinaryReader br) - { - v = br.ReadSingle(); - } - - internal override ConstantType GetConstantType() - { - return ConstantType.Float; - } - - internal float Value - { - get - { - return v; - } - } - - internal override object GetRuntimeValue() - { - return v; - } - } - - private sealed class ConstantPoolItemInteger : ConstantPoolItem - { - internal int v; - - internal ConstantPoolItemInteger(BigEndianBinaryReader br) - { - v = br.ReadInt32(); - } - - internal override ConstantType GetConstantType() - { - return ConstantType.Integer; - } - - internal int Value - { - get - { - return v; - } - } - - internal override object GetRuntimeValue() - { - return v; - } - } - - private sealed class ConstantPoolItemLong : ConstantPoolItem - { - internal long l; - - internal ConstantPoolItemLong(BigEndianBinaryReader br) - { - l = br.ReadInt64(); - } - - internal override ConstantType GetConstantType() - { - return ConstantType.Long; - } - - internal long Value - { - get - { - return l; - } - } - - internal override object GetRuntimeValue() - { - return l; - } - } - - private sealed class ConstantPoolItemNameAndType : ConstantPoolItem - { - internal ushort name_index; - internal ushort descriptor_index; - - internal ConstantPoolItemNameAndType(BigEndianBinaryReader br) - { - name_index = br.ReadUInt16(); - descriptor_index = br.ReadUInt16(); - } - - internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) - { - if(classFile.GetConstantPoolUtf8String(utf8_cp, name_index) == null - || classFile.GetConstantPoolUtf8String(utf8_cp, descriptor_index) == null) - { - throw new ClassFormatError("Illegal constant pool index"); - } - } - } - - internal sealed class ConstantPoolItemMethodHandle : ConstantPoolItem - { - private byte ref_kind; - private ushort method_index; - private ConstantPoolItemFMI cpi; - - internal ConstantPoolItemMethodHandle(BigEndianBinaryReader br) - { - ref_kind = br.ReadByte(); - method_index = br.ReadUInt16(); - } - - internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) - { - switch ((RefKind)ref_kind) - { - case RefKind.getField: - case RefKind.getStatic: - case RefKind.putField: - case RefKind.putStatic: - cpi = classFile.GetConstantPoolItem(method_index) as ConstantPoolItemFieldref; - break; - case RefKind.invokeSpecial: - case RefKind.invokeVirtual: - case RefKind.invokeStatic: - case RefKind.newInvokeSpecial: - cpi = classFile.GetConstantPoolItem(method_index) as ConstantPoolItemMethodref; - if (cpi == null && classFile.MajorVersion >= 52 && ((RefKind)ref_kind == RefKind.invokeStatic || (RefKind)ref_kind == RefKind.invokeSpecial)) - goto case RefKind.invokeInterface; - break; - case RefKind.invokeInterface: - cpi = classFile.GetConstantPoolItem(method_index) as ConstantPoolItemInterfaceMethodref; - break; - } - if (cpi == null) - { - throw new ClassFormatError("Invalid constant pool item MethodHandle"); - } - if (ReferenceEquals(cpi.Name, StringConstants.INIT) && Kind != RefKind.newInvokeSpecial) - { - throw new ClassFormatError("Bad method name"); - } - } - - internal override void MarkLinkRequired() - { - cpi.MarkLinkRequired(); - } - - internal string Class - { - get { return cpi.Class; } - } - - internal string Name - { - get { return cpi.Name; } - } - - internal string Signature - { - get { return cpi.Signature; } - } - - internal ConstantPoolItemFMI MemberConstantPoolItem - { - get { return cpi; } - } - - internal RefKind Kind - { - get { return (RefKind)ref_kind; } - } - - internal MemberWrapper Member - { - get { return cpi.GetMember(); } - } - - internal TypeWrapper GetClassType() - { - return cpi.GetClassType(); - } - - internal override void Link(TypeWrapper thisType, LoadMode mode) - { - cpi.Link(thisType, mode); - } - - internal override ConstantType GetConstantType() - { - return ConstantType.MethodHandle; - } - } - - internal sealed class ConstantPoolItemMethodType : ConstantPoolItem - { - private ushort signature_index; - private string descriptor; - private TypeWrapper[] argTypeWrappers; - private TypeWrapper retTypeWrapper; - - internal ConstantPoolItemMethodType(BigEndianBinaryReader br) - { - signature_index = br.ReadUInt16(); - } - - internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) - { - string descriptor = classFile.GetConstantPoolUtf8String(utf8_cp, signature_index); - if (descriptor == null || !IsValidMethodSig(descriptor)) - { - throw new ClassFormatError("Invalid MethodType signature"); - } - this.descriptor = String.Intern(descriptor.Replace('/', '.')); - } - - internal override void Link(TypeWrapper thisType, LoadMode mode) - { - lock (this) - { - if (argTypeWrappers != null) - { - return; - } - } - ClassLoaderWrapper classLoader = thisType.GetClassLoader(); - TypeWrapper[] args = classLoader.ArgTypeWrapperListFromSig(descriptor, mode); - TypeWrapper ret = classLoader.RetTypeWrapperFromSig(descriptor, mode); - lock (this) - { - if (argTypeWrappers == null) - { - argTypeWrappers = args; - retTypeWrapper = ret; - } - } - } - - internal string Signature - { - get { return descriptor; } - } - - internal TypeWrapper[] GetArgTypes() - { - return argTypeWrappers; - } - - internal TypeWrapper GetRetType() - { - return retTypeWrapper; - } - - internal override ConstantType GetConstantType() - { - return ConstantType.MethodType; - } - } - - internal sealed class ConstantPoolItemInvokeDynamic : ConstantPoolItem - { - private ushort bootstrap_specifier_index; - private ushort name_and_type_index; - private string name; - private string descriptor; - private TypeWrapper[] argTypeWrappers; - private TypeWrapper retTypeWrapper; - - internal ConstantPoolItemInvokeDynamic(BigEndianBinaryReader br) - { - bootstrap_specifier_index = br.ReadUInt16(); - name_and_type_index = br.ReadUInt16(); - } - - internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) - { - ConstantPoolItemNameAndType name_and_type = (ConstantPoolItemNameAndType)classFile.GetConstantPoolItem(name_and_type_index); - // if the constant pool items referred to were strings, GetConstantPoolItem returns null - if (name_and_type == null) - { - throw new ClassFormatError("Bad index in constant pool"); - } - name = String.Intern(classFile.GetConstantPoolUtf8String(utf8_cp, name_and_type.name_index)); - descriptor = String.Intern(classFile.GetConstantPoolUtf8String(utf8_cp, name_and_type.descriptor_index).Replace('/', '.')); - } - - internal override void Link(TypeWrapper thisType, LoadMode mode) - { - lock (this) - { - if (argTypeWrappers != null) - { - return; - } - } - ClassLoaderWrapper classLoader = thisType.GetClassLoader(); - TypeWrapper[] args = classLoader.ArgTypeWrapperListFromSig(descriptor, mode); - TypeWrapper ret = classLoader.RetTypeWrapperFromSig(descriptor, mode); - lock (this) - { - if (argTypeWrappers == null) - { - argTypeWrappers = args; - retTypeWrapper = ret; - } - } - } - - internal TypeWrapper[] GetArgTypes() - { - return argTypeWrappers; - } - - internal TypeWrapper GetRetType() - { - return retTypeWrapper; - } - - internal string Name - { - get { return name; } - } - - internal string Signature - { - get { return descriptor; } - } - - internal ushort BootstrapMethod - { - get { return bootstrap_specifier_index; } - } - } - - private sealed class ConstantPoolItemString : ConstantPoolItem - { - private ushort string_index; - private string s; - - internal ConstantPoolItemString(BigEndianBinaryReader br) - { - string_index = br.ReadUInt16(); - } - - internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) - { - s = classFile.GetConstantPoolUtf8String(utf8_cp, string_index); - } - - internal override ConstantType GetConstantType() - { - return ConstantType.String; - } - - internal string Value - { - get - { - return s; - } - } - } - - // this is only used to copy strings into "constantpool" when we see a RuntimeVisibleTypeAnnotations attribute, - // because we need a consistent way of exposing constant pool items to the runtime and that case - private sealed class ConstantPoolItemUtf8 : ConstantPoolItem - { - private readonly string str; - - internal ConstantPoolItemUtf8(string str) - { - this.str = str; - } - - internal override object GetRuntimeValue() - { - return str; - } - } - - private sealed class ConstantPoolItemLiveObject : ConstantPoolItem - { - internal readonly object Value; - - internal ConstantPoolItemLiveObject(object value) - { - this.Value = value; - } - - internal override ConstantType GetConstantType() - { - return ConstantType.LiveObject; - } - } - - internal enum Constant - { - Utf8 = 1, - Integer = 3, - Float = 4, - Long = 5, - Double = 6, - Class = 7, - String = 8, - Fieldref = 9, - Methodref = 10, - InterfaceMethodref = 11, - NameAndType = 12, - MethodHandle = 15, - MethodType = 16, - InvokeDynamic = 18, - } - - internal abstract class FieldOrMethod : IEquatable - { - // Note that Modifiers is a ushort, so it combines nicely with the following ushort field - protected Modifiers access_flags; - protected ushort flags; - private string name; - private string descriptor; - protected string signature; - protected object[] annotations; - protected byte[] runtimeVisibleTypeAnnotations; - - internal FieldOrMethod(ClassFile classFile, string[] utf8_cp, BigEndianBinaryReader br) - { - access_flags = (Modifiers)br.ReadUInt16(); - name = String.Intern(classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16())); - descriptor = classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16()); - ValidateSig(classFile, descriptor); - descriptor = String.Intern(descriptor.Replace('/', '.')); - } - - protected abstract void ValidateSig(ClassFile classFile, string descriptor); - - internal string Name - { - get - { - return name; - } - } - - internal string Signature - { - get - { - return descriptor; - } - } - - internal object[] Annotations - { - get - { - return annotations; - } - } - - internal string GenericSignature - { - get - { - return signature; - } - } - - internal Modifiers Modifiers - { - get - { - return (Modifiers)access_flags; - } - } - - internal bool IsAbstract - { - get - { - return (access_flags & Modifiers.Abstract) != 0; - } - } - - internal bool IsFinal - { - get - { - return (access_flags & Modifiers.Final) != 0; - } - } - - internal bool IsPublic - { - get - { - return (access_flags & Modifiers.Public) != 0; - } - } - - internal bool IsPrivate - { - get - { - return (access_flags & Modifiers.Private) != 0; - } - } - - internal bool IsProtected - { - get - { - return (access_flags & Modifiers.Protected) != 0; - } - } - - internal bool IsStatic - { - get - { - return (access_flags & Modifiers.Static) != 0; - } - } - - internal bool IsSynchronized - { - get - { - return (access_flags & Modifiers.Synchronized) != 0; - } - } - - internal bool IsVolatile - { - get - { - return (access_flags & Modifiers.Volatile) != 0; - } - } - - internal bool IsTransient - { - get - { - return (access_flags & Modifiers.Transient) != 0; - } - } - - internal bool IsNative - { - get - { - return (access_flags & Modifiers.Native) != 0; - } - } - - internal bool IsEnum - { - get - { - return (access_flags & Modifiers.Enum) != 0; - } - } - - internal bool DeprecatedAttribute - { - get - { - return (flags & FLAG_MASK_DEPRECATED) != 0; - } - } - - internal bool IsInternal - { - get - { - return (flags & FLAG_MASK_INTERNAL) != 0; - } - } - - internal byte[] RuntimeVisibleTypeAnnotations - { - get - { - return runtimeVisibleTypeAnnotations; - } - } - - public sealed override int GetHashCode() - { - return name.GetHashCode() ^ descriptor.GetHashCode(); - } - - public bool Equals(FieldOrMethod other) - { - return ReferenceEquals(name, other.name) && ReferenceEquals(descriptor, other.descriptor); - } - } - - internal sealed class Field : FieldOrMethod - { - private object constantValue; - private string[] propertyGetterSetter; - - internal Field(ClassFile classFile, string[] utf8_cp, BigEndianBinaryReader br) : base(classFile, utf8_cp, br) - { - if((IsPrivate && IsPublic) || (IsPrivate && IsProtected) || (IsPublic && IsProtected) - || (IsFinal && IsVolatile) - || (classFile.IsInterface && (!IsPublic || !IsStatic || !IsFinal || IsTransient))) - { - throw new ClassFormatError("{0} (Illegal field modifiers: 0x{1:X})", classFile.Name, access_flags); - } - int attributes_count = br.ReadUInt16(); - for(int i = 0; i < attributes_count; i++) - { - switch(classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16())) - { - case "Deprecated": - if(br.ReadUInt32() != 0) - { - throw new ClassFormatError("Invalid Deprecated attribute length"); - } - flags |= FLAG_MASK_DEPRECATED; - break; - case "ConstantValue": - { - if(br.ReadUInt32() != 2) - { - throw new ClassFormatError("Invalid ConstantValue attribute length"); - } - ushort index = br.ReadUInt16(); - try - { - switch(Signature) - { - case "I": - constantValue = classFile.GetConstantPoolConstantInteger(index); - break; - case "S": - constantValue = (short)classFile.GetConstantPoolConstantInteger(index); - break; - case "B": - constantValue = (byte)classFile.GetConstantPoolConstantInteger(index); - break; - case "C": - constantValue = (char)classFile.GetConstantPoolConstantInteger(index); - break; - case "Z": - constantValue = classFile.GetConstantPoolConstantInteger(index) != 0; - break; - case "J": - constantValue = classFile.GetConstantPoolConstantLong(index); - break; - case "F": - constantValue = classFile.GetConstantPoolConstantFloat(index); - break; - case "D": - constantValue = classFile.GetConstantPoolConstantDouble(index); - break; - case "Ljava.lang.String;": - constantValue = classFile.GetConstantPoolConstantString(index); - break; - default: - throw new ClassFormatError("{0} (Invalid signature for constant)", classFile.Name); - } - } - catch(InvalidCastException) - { - throw new ClassFormatError("{0} (Bad index into constant pool)", classFile.Name); - } - catch(IndexOutOfRangeException) - { - throw new ClassFormatError("{0} (Bad index into constant pool)", classFile.Name); - } - catch(InvalidOperationException) - { - throw new ClassFormatError("{0} (Bad index into constant pool)", classFile.Name); - } - catch(NullReferenceException) - { - throw new ClassFormatError("{0} (Bad index into constant pool)", classFile.Name); - } - break; - } - case "Signature": - if(classFile.MajorVersion < 49) - { - goto default; - } - if(br.ReadUInt32() != 2) - { - throw new ClassFormatError("Signature attribute has incorrect length"); - } - signature = classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16()); - break; - case "RuntimeVisibleAnnotations": - if(classFile.MajorVersion < 49) - { - goto default; - } - annotations = ReadAnnotations(br, classFile, utf8_cp); - break; - case "RuntimeInvisibleAnnotations": - if(classFile.MajorVersion < 49) - { - goto default; - } - foreach(object[] annot in ReadAnnotations(br, classFile, utf8_cp)) - { - if(annot[1].Equals("Likvm/lang/Property;")) - { - DecodePropertyAnnotation(classFile, annot); - } -#if STATIC_COMPILER - else if(annot[1].Equals("Likvm/lang/Internal;")) - { - this.access_flags &= ~Modifiers.AccessMask; - flags |= FLAG_MASK_INTERNAL; - } -#endif - } - break; - case "RuntimeVisibleTypeAnnotations": - if (classFile.MajorVersion < 52) - { - goto default; - } - classFile.CreateUtf8ConstantPoolItems(utf8_cp); - runtimeVisibleTypeAnnotations = br.Section(br.ReadUInt32()).ToArray(); - break; - default: - br.Skip(br.ReadUInt32()); - break; - } - } - } - - private void DecodePropertyAnnotation(ClassFile classFile, object[] annot) - { - if(propertyGetterSetter != null) - { - Tracer.Error(Tracer.ClassLoading, "Ignoring duplicate ikvm.lang.Property annotation on {0}.{1}", classFile.Name, this.Name); - return; - } - propertyGetterSetter = new string[2]; - for(int i = 2; i < annot.Length - 1; i += 2) - { - string value = annot[i + 1] as string; - if(value == null) - { - propertyGetterSetter = null; - break; - } - if(annot[i].Equals("get") && propertyGetterSetter[0] == null) - { - propertyGetterSetter[0] = value; - } - else if(annot[i].Equals("set") && propertyGetterSetter[1] == null) - { - propertyGetterSetter[1] = value; - } - else - { - propertyGetterSetter = null; - break; - } - } - if(propertyGetterSetter == null || propertyGetterSetter[0] == null) - { - propertyGetterSetter = null; - Tracer.Error(Tracer.ClassLoading, "Ignoring malformed ikvm.lang.Property annotation on {0}.{1}", classFile.Name, this.Name); - return; - } - } - - protected override void ValidateSig(ClassFile classFile, string descriptor) - { - if(!IsValidFieldSig(descriptor)) - { - throw new ClassFormatError("{0} (Field \"{1}\" has invalid signature \"{2}\")", classFile.Name, this.Name, descriptor); - } - } - - internal object ConstantValue - { - get - { - return constantValue; - } - } - - internal bool IsStaticFinalConstant - { - get { return (access_flags & (Modifiers.Final | Modifiers.Static)) == (Modifiers.Final | Modifiers.Static) && constantValue != null; } - } - - internal bool IsProperty - { - get - { - return propertyGetterSetter != null; - } - } - - internal string PropertyGetter - { - get - { - return propertyGetterSetter[0]; - } - } - - internal string PropertySetter - { - get - { - return propertyGetterSetter[1]; - } - } - } - - internal sealed class Method : FieldOrMethod - { - private Code code; - private string[] exceptions; - private LowFreqData low; - private MethodParametersEntry[] parameters; - - sealed class LowFreqData - { - internal object annotationDefault; - internal object[][] parameterAnnotations; -#if STATIC_COMPILER - internal string DllExportName; - internal int DllExportOrdinal; - internal string InterlockedCompareAndSetField; -#endif - } - - internal Method(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options, BigEndianBinaryReader br) : base(classFile, utf8_cp, br) - { - // vmspec 4.6 says that all flags, except ACC_STRICT are ignored on - // however, since Java 7 it does need to be marked static - if(ReferenceEquals(Name, StringConstants.CLINIT) && ReferenceEquals(Signature, StringConstants.SIG_VOID) && (classFile.MajorVersion < 51 || IsStatic)) - { - access_flags &= Modifiers.Strictfp; - access_flags |= (Modifiers.Static | Modifiers.Private); - } - else - { - // LAMESPEC: vmspec 4.6 says that abstract methods can not be strictfp (and this makes sense), but - // javac (pre 1.5) is broken and marks abstract methods as strictfp (if you put the strictfp on the class) - if((ReferenceEquals(Name, StringConstants.INIT) && (IsStatic || IsSynchronized || IsFinal || IsAbstract || IsNative)) - || (IsPrivate && IsPublic) || (IsPrivate && IsProtected) || (IsPublic && IsProtected) - || (IsAbstract && (IsFinal || IsNative || IsPrivate || IsStatic || IsSynchronized)) - || (classFile.IsInterface && classFile.MajorVersion <= 51 && (!IsPublic || IsFinal || IsNative || IsSynchronized || !IsAbstract)) - || (classFile.IsInterface && classFile.MajorVersion >= 52 && (!(IsPublic || IsPrivate) || IsFinal || IsNative || IsSynchronized))) - { - throw new ClassFormatError("Method {0} in class {1} has illegal modifiers: 0x{2:X}", Name, classFile.Name, (int)access_flags); - } - } - int attributes_count = br.ReadUInt16(); - for(int i = 0; i < attributes_count; i++) - { - switch(classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16())) - { - case "Deprecated": - if(br.ReadUInt32() != 0) - { - throw new ClassFormatError("Invalid Deprecated attribute length"); - } - flags |= FLAG_MASK_DEPRECATED; - break; - case "Code": - { - if(!code.IsEmpty) - { - throw new ClassFormatError("{0} (Duplicate Code attribute)", classFile.Name); - } - BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); - code.Read(classFile, utf8_cp, this, rdr, options); - if(!rdr.IsAtEnd) - { - throw new ClassFormatError("{0} (Code attribute has wrong length)", classFile.Name); - } - break; - } - case "Exceptions": - { - if(exceptions != null) - { - throw new ClassFormatError("{0} (Duplicate Exceptions attribute)", classFile.Name); - } - BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); - ushort count = rdr.ReadUInt16(); - exceptions = new string[count]; - for(int j = 0; j < count; j++) - { - exceptions[j] = classFile.GetConstantPoolClass(rdr.ReadUInt16()); - } - if(!rdr.IsAtEnd) - { - throw new ClassFormatError("{0} (Exceptions attribute has wrong length)", classFile.Name); - } - break; - } - case "Signature": - if(classFile.MajorVersion < 49) - { - goto default; - } - if(br.ReadUInt32() != 2) - { - throw new ClassFormatError("Signature attribute has incorrect length"); - } - signature = classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16()); - break; - case "RuntimeVisibleAnnotations": - if(classFile.MajorVersion < 49) - { - goto default; - } - annotations = ReadAnnotations(br, classFile, utf8_cp); - if ((options & ClassFileParseOptions.TrustedAnnotations) != 0) - { - foreach(object[] annot in annotations) - { - switch((string)annot[1]) - { -#if STATIC_COMPILER - case "Lsun/reflect/CallerSensitive;": - flags |= FLAG_CALLERSENSITIVE; - break; -#endif - case "Ljava/lang/invoke/LambdaForm$Compiled;": - flags |= FLAG_LAMBDAFORM_COMPILED; - break; - case "Ljava/lang/invoke/LambdaForm$Hidden;": - flags |= FLAG_LAMBDAFORM_HIDDEN; - break; - case "Ljava/lang/invoke/ForceInline;": - flags |= FLAG_FORCEINLINE; - break; - } - } - } - break; - case "RuntimeVisibleParameterAnnotations": - { - if(classFile.MajorVersion < 49) - { - goto default; - } - if(low == null) - { - low = new LowFreqData(); - } - BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); - byte num_parameters = rdr.ReadByte(); - low.parameterAnnotations = new object[num_parameters][]; - for(int j = 0; j < num_parameters; j++) - { - ushort num_annotations = rdr.ReadUInt16(); - low.parameterAnnotations[j] = new object[num_annotations]; - for(int k = 0; k < num_annotations; k++) - { - low.parameterAnnotations[j][k] = ReadAnnotation(rdr, classFile, utf8_cp); - } - } - if(!rdr.IsAtEnd) - { - throw new ClassFormatError("{0} (RuntimeVisibleParameterAnnotations attribute has wrong length)", classFile.Name); - } - break; - } - case "AnnotationDefault": - { - if(classFile.MajorVersion < 49) - { - goto default; - } - if(low == null) - { - low = new LowFreqData(); - } - BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); - low.annotationDefault = ReadAnnotationElementValue(rdr, classFile, utf8_cp); - if(!rdr.IsAtEnd) - { - throw new ClassFormatError("{0} (AnnotationDefault attribute has wrong length)", classFile.Name); - } - break; - } -#if STATIC_COMPILER - case "RuntimeInvisibleAnnotations": - if(classFile.MajorVersion < 49) - { - goto default; - } - foreach(object[] annot in ReadAnnotations(br, classFile, utf8_cp)) - { - if(annot[1].Equals("Likvm/lang/Internal;")) - { - if (classFile.IsInterface) - { - StaticCompiler.IssueMessage(Message.InterfaceMethodCantBeInternal, classFile.Name, this.Name, this.Signature); - } - else - { - this.access_flags &= ~Modifiers.AccessMask; - flags |= FLAG_MASK_INTERNAL; - } - } - if(annot[1].Equals("Likvm/lang/DllExport;")) - { - string name = null; - int? ordinal = null; - for (int j = 2; j < annot.Length; j += 2) - { - if (annot[j].Equals("name") && annot[j + 1] is string) - { - name = (string)annot[j + 1]; - } - else if (annot[j].Equals("ordinal") && annot[j + 1] is int) - { - ordinal = (int)annot[j + 1]; - } - } - if (name != null && ordinal != null) - { - if (!IsStatic) - { - StaticCompiler.IssueMessage(Message.DllExportMustBeStaticMethod, classFile.Name, this.Name, this.Signature); - } - else - { - if (low == null) - { - low = new LowFreqData(); - } - low.DllExportName = name; - low.DllExportOrdinal = ordinal.Value; - } - } - } - if(annot[1].Equals("Likvm/internal/InterlockedCompareAndSet;")) - { - string field = null; - for (int j = 2; j < annot.Length; j += 2) - { - if (annot[j].Equals("value") && annot[j + 1] is string) - { - field = (string)annot[j + 1]; - } - } - if (field != null) - { - if (low == null) - { - low = new LowFreqData(); - } - low.InterlockedCompareAndSetField = field; - } - } - } - break; -#endif - case "MethodParameters": - { - if(classFile.MajorVersion < 52) - { - goto default; - } - if(parameters != null) - { - throw new ClassFormatError("{0} (Duplicate MethodParameters attribute)", classFile.Name); - } - parameters = ReadMethodParameters(br, utf8_cp); - break; - } - case "RuntimeVisibleTypeAnnotations": - if (classFile.MajorVersion < 52) - { - goto default; - } - classFile.CreateUtf8ConstantPoolItems(utf8_cp); - runtimeVisibleTypeAnnotations = br.Section(br.ReadUInt32()).ToArray(); - break; - default: - br.Skip(br.ReadUInt32()); - break; - } - } - if(IsAbstract || IsNative) - { - if(!code.IsEmpty) - { - throw new ClassFormatError("Code attribute in native or abstract methods in class file " + classFile.Name); - } - } - else - { - if(code.IsEmpty) - { - if(ReferenceEquals(this.Name, StringConstants.CLINIT)) - { - code.verifyError = string.Format("Class {0}, method {1} signature {2}: No Code attribute", classFile.Name, this.Name, this.Signature); - return; - } - throw new ClassFormatError("Absent Code attribute in method that is not native or abstract in class file " + classFile.Name); - } - } - } - - private static MethodParametersEntry[] ReadMethodParameters(BigEndianBinaryReader br, string[] utf8_cp) - { - uint length = br.ReadUInt32(); - if(length > 0) - { - BigEndianBinaryReader rdr = br.Section(length); - byte parameters_count = rdr.ReadByte(); - if(length == 1 + parameters_count * 4) - { - MethodParametersEntry[] parameters = new MethodParametersEntry[parameters_count]; - for(int j = 0; j < parameters_count; j++) - { - ushort name = rdr.ReadUInt16(); - if(name >= utf8_cp.Length || (name != 0 && utf8_cp[name] == null)) - { - return MethodParametersEntry.Malformed; - } - parameters[j].name = utf8_cp[name]; - parameters[j].flags = rdr.ReadUInt16(); - } - return parameters; - } - } - throw new ClassFormatError("Invalid MethodParameters method attribute length " + length + " in class file"); - } - - protected override void ValidateSig(ClassFile classFile, string descriptor) - { - if(!IsValidMethodSig(descriptor)) - { - throw new ClassFormatError("{0} (Method \"{1}\" has invalid signature \"{2}\")", classFile.Name, this.Name, descriptor); - } - } - - internal bool IsStrictfp - { - get - { - return (access_flags & Modifiers.Strictfp) != 0; - } - } - - internal bool IsVirtual - { - get - { - return (access_flags & (Modifiers.Static | Modifiers.Private)) == 0 - && !IsConstructor; - } - } - - // Is this the ()V method? - internal bool IsClassInitializer - { - get - { - return ReferenceEquals(Name, StringConstants.CLINIT) && ReferenceEquals(Signature, StringConstants.SIG_VOID) && IsStatic; - } - } - - internal bool IsConstructor - { - get - { - return ReferenceEquals(Name, StringConstants.INIT); - } - } - -#if STATIC_COMPILER - internal bool IsCallerSensitive - { - get - { - return (flags & FLAG_CALLERSENSITIVE) != 0; - } - } -#endif - - internal bool IsLambdaFormCompiled - { - get - { - return (flags & FLAG_LAMBDAFORM_COMPILED) != 0; - } - } - - internal bool IsLambdaFormHidden - { - get - { - return (flags & FLAG_LAMBDAFORM_HIDDEN) != 0; - } - } - - internal bool IsForceInline - { - get - { - return (flags & FLAG_FORCEINLINE) != 0; - } - } - - internal string[] ExceptionsAttribute - { - get - { - return exceptions; - } - } - - internal object[][] ParameterAnnotations - { - get - { - return low == null ? null : low.parameterAnnotations; - } - } - - internal object AnnotationDefault - { - get - { - return low == null ? null : low.annotationDefault; - } - } - -#if STATIC_COMPILER - internal string DllExportName - { - get - { - return low == null ? null : low.DllExportName; - } - } - - internal int DllExportOrdinal - { - get - { - return low == null ? -1 : low.DllExportOrdinal; - } - } - - internal string InterlockedCompareAndSetField - { - get - { - return low == null ? null : low.InterlockedCompareAndSetField; - } - } -#endif - - internal string VerifyError - { - get - { - return code.verifyError; - } - } - - // maps argument 'slot' (as encoded in the xload/xstore instructions) into the ordinal - internal int[] ArgMap - { - get - { - return code.argmap; - } - } - - internal int MaxStack - { - get - { - return code.max_stack; - } - } - - internal int MaxLocals - { - get - { - return code.max_locals; - } - } - - internal Instruction[] Instructions - { - get - { - return code.instructions; - } - set - { - code.instructions = value; - } - } - - internal ExceptionTableEntry[] ExceptionTable - { - get - { - return code.exception_table; - } - set - { - code.exception_table = value; - } - } - - internal LineNumberTableEntry[] LineNumberTableAttribute - { - get - { - return code.lineNumberTable; - } - } - - internal LocalVariableTableEntry[] LocalVariableTableAttribute - { - get - { - return code.localVariableTable; - } - } - - internal MethodParametersEntry[] MethodParameters - { - get - { - return parameters; - } - } - - internal bool MalformedMethodParameters - { - get - { - return parameters == MethodParametersEntry.Malformed; - } - } - - internal bool HasJsr - { - get - { - return code.hasJsr; - } - } - - private struct Code - { - internal bool hasJsr; - internal string verifyError; - internal ushort max_stack; - internal ushort max_locals; - internal Instruction[] instructions; - internal ExceptionTableEntry[] exception_table; - internal int[] argmap; - internal LineNumberTableEntry[] lineNumberTable; - internal LocalVariableTableEntry[] localVariableTable; - - internal void Read(ClassFile classFile, string[] utf8_cp, Method method, BigEndianBinaryReader br, ClassFileParseOptions options) - { - max_stack = br.ReadUInt16(); - max_locals = br.ReadUInt16(); - uint code_length = br.ReadUInt32(); - if(code_length == 0 || code_length > 65535) - { - throw new ClassFormatError("Invalid method Code length {1} in class file {0}", classFile.Name, code_length); - } - Instruction[] instructions = new Instruction[code_length + 1]; - int basePosition = br.Position; - int instructionIndex = 0; - try - { - BigEndianBinaryReader rdr = br.Section(code_length); - while(!rdr.IsAtEnd) - { - instructions[instructionIndex].Read((ushort)(rdr.Position - basePosition), rdr, classFile); - hasJsr |= instructions[instructionIndex].NormalizedOpCode == NormalizedByteCode.__jsr; - instructionIndex++; - } - // we add an additional nop instruction to make it easier for consumers of the code array - instructions[instructionIndex++].SetTermNop((ushort)(rdr.Position - basePosition)); - } - catch(ClassFormatError x) - { - // any class format errors in the code block are actually verify errors - verifyError = x.Message; - } - this.instructions = new Instruction[instructionIndex]; - Array.Copy(instructions, 0, this.instructions, 0, instructionIndex); - // build the pcIndexMap - int[] pcIndexMap = new int[this.instructions[instructionIndex - 1].PC + 1]; - for(int i = 0; i < pcIndexMap.Length; i++) - { - pcIndexMap[i] = -1; - } - for(int i = 0; i < instructionIndex - 1; i++) - { - pcIndexMap[this.instructions[i].PC] = i; - } - // convert branch offsets to indexes - for(int i = 0; i < instructionIndex - 1; i++) - { - switch(this.instructions[i].NormalizedOpCode) - { - case NormalizedByteCode.__ifeq: - case NormalizedByteCode.__ifne: - case NormalizedByteCode.__iflt: - case NormalizedByteCode.__ifge: - case NormalizedByteCode.__ifgt: - case NormalizedByteCode.__ifle: - case NormalizedByteCode.__if_icmpeq: - case NormalizedByteCode.__if_icmpne: - case NormalizedByteCode.__if_icmplt: - case NormalizedByteCode.__if_icmpge: - case NormalizedByteCode.__if_icmpgt: - case NormalizedByteCode.__if_icmple: - case NormalizedByteCode.__if_acmpeq: - case NormalizedByteCode.__if_acmpne: - case NormalizedByteCode.__ifnull: - case NormalizedByteCode.__ifnonnull: - case NormalizedByteCode.__goto: - case NormalizedByteCode.__jsr: - this.instructions[i].SetTargetIndex(pcIndexMap[this.instructions[i].Arg1 + this.instructions[i].PC]); - break; - case NormalizedByteCode.__tableswitch: - case NormalizedByteCode.__lookupswitch: - this.instructions[i].MapSwitchTargets(pcIndexMap); - break; - } - } - // read exception table - ushort exception_table_length = br.ReadUInt16(); - exception_table = new ExceptionTableEntry[exception_table_length]; - for(int i = 0; i < exception_table_length; i++) - { - ushort start_pc = br.ReadUInt16(); - ushort end_pc = br.ReadUInt16(); - ushort handler_pc = br.ReadUInt16(); - ushort catch_type = br.ReadUInt16(); - if(start_pc >= end_pc - || end_pc > code_length - || handler_pc >= code_length - || (catch_type != 0 && !classFile.SafeIsConstantPoolClass(catch_type))) - { - throw new ClassFormatError("Illegal exception table: {0}.{1}{2}", classFile.Name, method.Name, method.Signature); - } - classFile.MarkLinkRequiredConstantPoolItem(catch_type); - // if start_pc, end_pc or handler_pc is invalid (i.e. doesn't point to the start of an instruction), - // the index will be -1 and this will be handled by the verifier - int startIndex = pcIndexMap[start_pc]; - int endIndex; - if (end_pc == code_length) - { - // it is legal for end_pc to point to just after the last instruction, - // but since there isn't an entry in our pcIndexMap for that, we have - // a special case for this - endIndex = instructionIndex - 1; - } - else - { - endIndex = pcIndexMap[end_pc]; - } - int handlerIndex = pcIndexMap[handler_pc]; - exception_table[i] = new ExceptionTableEntry(startIndex, endIndex, handlerIndex, catch_type, i); - } - ushort attributes_count = br.ReadUInt16(); - for(int i = 0; i < attributes_count; i++) - { - switch(classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16())) - { - case "LineNumberTable": - if((options & ClassFileParseOptions.LineNumberTable) != 0) - { - BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); - int count = rdr.ReadUInt16(); - lineNumberTable = new LineNumberTableEntry[count]; - for(int j = 0; j < count; j++) - { - lineNumberTable[j].start_pc = rdr.ReadUInt16(); - lineNumberTable[j].line_number = rdr.ReadUInt16(); - if(lineNumberTable[j].start_pc >= code_length) - { - throw new ClassFormatError("{0} (LineNumberTable has invalid pc)", classFile.Name); - } - } - if(!rdr.IsAtEnd) - { - throw new ClassFormatError("{0} (LineNumberTable attribute has wrong length)", classFile.Name); - } - } - else - { - br.Skip(br.ReadUInt32()); - } - break; - case "LocalVariableTable": - if((options & ClassFileParseOptions.LocalVariableTable) != 0) - { - BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); - int count = rdr.ReadUInt16(); - localVariableTable = new LocalVariableTableEntry[count]; - for(int j = 0; j < count; j++) - { - localVariableTable[j].start_pc = rdr.ReadUInt16(); - localVariableTable[j].length = rdr.ReadUInt16(); - localVariableTable[j].name = classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()); - localVariableTable[j].descriptor = classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()).Replace('/', '.'); - localVariableTable[j].index = rdr.ReadUInt16(); - } - // NOTE we're intentionally not checking that we're at the end of the section - // (optional attributes shouldn't cause ClassFormatError) - } - else - { - br.Skip(br.ReadUInt32()); - } - break; - default: - br.Skip(br.ReadUInt32()); - break; - } - } - // build the argmap - string sig = method.Signature; - List args = new List(); - int pos = 0; - if(!method.IsStatic) - { - args.Add(pos++); - } - for(int i = 1; sig[i] != ')'; i++) - { - args.Add(pos++); - switch(sig[i]) - { - case 'L': - i = sig.IndexOf(';', i); - break; - case 'D': - case 'J': - args.Add(-1); - break; - case '[': - { - while(sig[i] == '[') - { - i++; - } - if(sig[i] == 'L') - { - i = sig.IndexOf(';', i); - } - break; - } - } - } - argmap = args.ToArray(); - if(args.Count > max_locals) - { - throw new ClassFormatError("{0} (Arguments can't fit into locals)", classFile.Name); - } - } - - internal bool IsEmpty - { - get - { - return instructions == null; - } - } - } - - internal sealed class ExceptionTableEntry - { - internal readonly int startIndex; - internal readonly int endIndex; - internal readonly int handlerIndex; - internal readonly ushort catch_type; - internal readonly int ordinal; - internal readonly bool isFinally; - - internal ExceptionTableEntry(int startIndex, int endIndex, int handlerIndex, ushort catch_type, int ordinal) - : this(startIndex, endIndex, handlerIndex, catch_type, ordinal, false) - { - } - - internal ExceptionTableEntry(int startIndex, int endIndex, int handlerIndex, ushort catch_type, int ordinal, bool isFinally) - { - this.startIndex = startIndex; - this.endIndex = endIndex; - this.handlerIndex = handlerIndex; - this.catch_type = catch_type; - this.ordinal = ordinal; - this.isFinally = isFinally; - } - } - - [Flags] - internal enum InstructionFlags : byte - { - Reachable = 1, - Processed = 2, - BranchTarget = 4, - } - - internal struct Instruction - { - private ushort pc; - private NormalizedByteCode normopcode; - private int arg1; - private short arg2; - private SwitchEntry[] switch_entries; - - struct SwitchEntry - { - internal int value; - internal int target; - } - - internal void SetHardError(HardError error, int messageId) - { - normopcode = NormalizedByteCode.__static_error; - arg2 = (short)error; - arg1 = messageId; - } - - internal HardError HardError - { - get - { - return (HardError)arg2; - } - } - - internal int HandlerIndex - { - get { return (ushort)arg2; } - } - - internal int HardErrorMessageId - { - get - { - return arg1; - } - } - - internal void PatchOpCode(NormalizedByteCode bc) - { - this.normopcode = bc; - } - - internal void PatchOpCode(NormalizedByteCode bc, int arg1) - { - this.normopcode = bc; - this.arg1 = arg1; - } - - internal void PatchOpCode(NormalizedByteCode bc, int arg1, short arg2) - { - this.normopcode = bc; - this.arg1 = arg1; - this.arg2 = arg2; - } - - internal void SetPC(int pc) - { - this.pc = (ushort)pc; - } - - internal void SetTargetIndex(int targetIndex) - { - this.arg1 = targetIndex; - } - - internal void SetTermNop(ushort pc) - { - // TODO what happens if we already have exactly the maximum number of instructions? - this.pc = pc; - this.normopcode = NormalizedByteCode.__nop; - } - - internal void MapSwitchTargets(int[] pcIndexMap) - { - arg1 = pcIndexMap[arg1 + pc]; - for (int i = 0; i < switch_entries.Length; i++) - { - switch_entries[i].target = pcIndexMap[switch_entries[i].target + pc]; - } - } - - internal void Read(ushort pc, BigEndianBinaryReader br, ClassFile classFile) - { - this.pc = pc; - ByteCode bc = (ByteCode)br.ReadByte(); - switch(ByteCodeMetaData.GetMode(bc)) - { - case ByteCodeMode.Simple: - break; - case ByteCodeMode.Constant_1: - arg1 = br.ReadByte(); - classFile.MarkLinkRequiredConstantPoolItem(arg1); - break; - case ByteCodeMode.Local_1: - arg1 = br.ReadByte(); - break; - case ByteCodeMode.Constant_2: - arg1 = br.ReadUInt16(); - classFile.MarkLinkRequiredConstantPoolItem(arg1); - break; - case ByteCodeMode.Branch_2: - arg1 = br.ReadInt16(); - break; - case ByteCodeMode.Branch_4: - arg1 = br.ReadInt32(); - break; - case ByteCodeMode.Constant_2_1_1: - arg1 = br.ReadUInt16(); - classFile.MarkLinkRequiredConstantPoolItem(arg1); - arg2 = br.ReadByte(); - if(br.ReadByte() != 0) - { - throw new ClassFormatError("invokeinterface filler must be zero"); - } - break; - case ByteCodeMode.Immediate_1: - arg1 = br.ReadSByte(); - break; - case ByteCodeMode.Immediate_2: - arg1 = br.ReadInt16(); - break; - case ByteCodeMode.Local_1_Immediate_1: - arg1 = br.ReadByte(); - arg2 = br.ReadSByte(); - break; - case ByteCodeMode.Constant_2_Immediate_1: - arg1 = br.ReadUInt16(); - classFile.MarkLinkRequiredConstantPoolItem(arg1); - arg2 = br.ReadSByte(); - break; - case ByteCodeMode.Tableswitch: - { - // skip the padding - uint p = pc + 1u; - uint align = ((p + 3) & 0x7ffffffc) - p; - br.Skip(align); - int default_offset = br.ReadInt32(); - this.arg1 = default_offset; - int low = br.ReadInt32(); - int high = br.ReadInt32(); - if(low > high || high > 16384L + low) - { - throw new ClassFormatError("Incorrect tableswitch"); - } - SwitchEntry[] entries = new SwitchEntry[high - low + 1]; - for(int i = low; i < high; i++) - { - entries[i - low].value = i; - entries[i - low].target = br.ReadInt32(); - } - // do the last entry outside the loop, to avoid overflowing "i", if high == int.MaxValue - entries[high - low].value = high; - entries[high - low].target = br.ReadInt32(); - this.switch_entries = entries; - break; - } - case ByteCodeMode.Lookupswitch: - { - // skip the padding - uint p = pc + 1u; - uint align = ((p + 3) & 0x7ffffffc) - p; - br.Skip(align); - int default_offset = br.ReadInt32(); - this.arg1 = default_offset; - int count = br.ReadInt32(); - if(count < 0 || count > 16384) - { - throw new ClassFormatError("Incorrect lookupswitch"); - } - SwitchEntry[] entries = new SwitchEntry[count]; - for(int i = 0; i < count; i++) - { - entries[i].value = br.ReadInt32(); - entries[i].target = br.ReadInt32(); - } - this.switch_entries = entries; - break; - } - case ByteCodeMode.WidePrefix: - bc = (ByteCode)br.ReadByte(); - // NOTE the PC of a wide instruction is actually the PC of the - // wide prefix, not the following instruction (vmspec 4.9.2) - switch(ByteCodeMetaData.GetWideMode(bc)) - { - case ByteCodeModeWide.Local_2: - arg1 = br.ReadUInt16(); - break; - case ByteCodeModeWide.Local_2_Immediate_2: - arg1 = br.ReadUInt16(); - arg2 = br.ReadInt16(); - break; - default: - throw new ClassFormatError("Invalid wide prefix on opcode: {0}", bc); - } - break; - default: - throw new ClassFormatError("Invalid opcode: {0}", bc); - } - this.normopcode = ByteCodeMetaData.GetNormalizedByteCode(bc); - arg1 = ByteCodeMetaData.GetArg(bc, arg1); - } - - internal int PC - { - get - { - return pc; - } - } - - internal NormalizedByteCode NormalizedOpCode - { - get - { - return normopcode; - } - } - - internal int Arg1 - { - get - { - return arg1; - } - } - - internal int TargetIndex - { - get - { - return arg1; - } - set - { - arg1 = value; - } - } - - internal int Arg2 - { - get - { - return arg2; - } - } - - internal int NormalizedArg1 - { - get - { - return arg1; - } - } - - internal int DefaultTarget - { - get - { - return arg1; - } - set - { - arg1 = value; - } - } - - internal int SwitchEntryCount - { - get - { - return switch_entries.Length; - } - } - - internal int GetSwitchValue(int i) - { - return switch_entries[i].value; - } - - internal int GetSwitchTargetIndex(int i) - { - return switch_entries[i].target; - } - - internal void SetSwitchTargets(int[] targets) - { - SwitchEntry[] newEntries = (SwitchEntry[])switch_entries.Clone(); - for (int i = 0; i < newEntries.Length; i++) - { - newEntries[i].target = targets[i]; - } - switch_entries = newEntries; - } - } - - internal struct LineNumberTableEntry - { - internal ushort start_pc; - internal ushort line_number; - } - - internal struct LocalVariableTableEntry - { - internal ushort start_pc; - internal ushort length; - internal string name; - internal string descriptor; - internal ushort index; - } - } - - internal Field GetField(string name, string sig) - { - for (int i = 0; i < fields.Length; i++) - { - if (fields[i].Name == name && fields[i].Signature == sig) - { - return fields[i]; - } - } - return null; - } - - internal bool HasSerialVersionUID - { - get - { - Field field = GetField("serialVersionUID", "J"); - return field != null && field.IsStatic && field.IsFinal; - } - } - } -} diff --git a/external/ikvm/runtime/ClassFile.cs.REMOVED.git-id b/external/ikvm/runtime/ClassFile.cs.REMOVED.git-id new file mode 100644 index 0000000000..d2c9344c93 --- /dev/null +++ b/external/ikvm/runtime/ClassFile.cs.REMOVED.git-id @@ -0,0 +1 @@ +9752fe830196d3033a76e68effb74af89c700164 \ No newline at end of file diff --git a/external/ikvm/runtime/ClassLoaderWrapper.cs b/external/ikvm/runtime/ClassLoaderWrapper.cs index a7907db2f5..d04d05dd47 100644 --- a/external/ikvm/runtime/ClassLoaderWrapper.cs +++ b/external/ikvm/runtime/ClassLoaderWrapper.cs @@ -53,6 +53,7 @@ namespace IKVM.Internal NoAutomagicSerialization = 32, DisableDynamicBinding = 64, NoRefEmitHelpers = 128, + RemoveUnusedFields = 256, } [Flags] @@ -329,6 +330,14 @@ namespace IKVM.Internal } } + internal bool RemoveUnusedFields + { + get + { + return (codegenoptions & CodeGenOptions.RemoveUnusedFields) != 0; + } + } + internal bool WorkaroundAbstractMethodWidening { get @@ -1486,6 +1495,10 @@ namespace IKVM.Internal { cfp |= ClassFileParseOptions.TrustedAnnotations; } + if (RemoveAsserts) + { + cfp |= ClassFileParseOptions.RemoveAssertions; + } return cfp; #else ClassFileParseOptions cfp = ClassFileParseOptions.LineNumberTable; diff --git a/external/ikvm/runtime/CodeEmitter.cs b/external/ikvm/runtime/CodeEmitter.cs index 72bab5a1c6..253de2524e 100644 --- a/external/ikvm/runtime/CodeEmitter.cs +++ b/external/ikvm/runtime/CodeEmitter.cs @@ -2376,11 +2376,15 @@ namespace IKVM.Internal { Console.Write(" label" + labelIndexes[code[i].Label]); } - else if (code[i].opcode == OpCodes.Ldarg) + else if (code[i].opcode == OpCodes.Ldarg_S || code[i].opcode == OpCodes.Ldarga_S) + { + Console.Write(" " + code[i].ValueByte); + } + else if (code[i].opcode == OpCodes.Ldarg || code[i].opcode == OpCodes.Ldarga) { Console.Write(" " + code[i].ValueInt16); } - else if (code[i].opcode == OpCodes.Isinst) + else if (code[i].opcode == OpCodes.Isinst || code[i].opcode == OpCodes.Castclass || code[i].opcode == OpCodes.Box || code[i].opcode == OpCodes.Unbox || code[i].opcode == OpCodes.Ldobj || code[i].opcode == OpCodes.Newarr) { Console.Write(" " + code[i].Type); } @@ -2388,12 +2392,28 @@ namespace IKVM.Internal { Console.Write(" " + code[i].MethodBase); } + else if (code[i].opcode == OpCodes.Ldfld || code[i].opcode == OpCodes.Ldsfld || code[i].opcode == OpCodes.Stfld || code[i].opcode == OpCodes.Stsfld) + { + Console.Write(" " + code[i].FieldInfo); + } + else if (code[i].opcode == OpCodes.Ldc_I4) + { + Console.Write(" " + code[i].ValueInt32); + } + else if (code[i].opcode == OpCodes.Ldloc || code[i].opcode == OpCodes.Stloc) + { + Console.Write(" " + code[i].Local.__LocalIndex); + } Console.WriteLine(); } else if (code[i].pseudo == CodeType.Label) { Console.WriteLine("label{0}: // temp = {1}", i, code[i].Label.Temp); } + else if (code[i].pseudo == CodeType.DeclareLocal) + { + Console.WriteLine("local #{0} = {1}", code[i].Local.__LocalIndex, code[i].Local.LocalType); + } else { Console.WriteLine(code[i]); diff --git a/external/ikvm/runtime/DotNetTypeWrapper.cs b/external/ikvm/runtime/DotNetTypeWrapper.cs index efcce0488d..a180901620 100644 --- a/external/ikvm/runtime/DotNetTypeWrapper.cs +++ b/external/ikvm/runtime/DotNetTypeWrapper.cs @@ -57,7 +57,6 @@ namespace IKVM.Internal private volatile TypeWrapper[] innerClasses; private TypeWrapper outerClass; private volatile TypeWrapper[] interfaces; - private volatile bool finished; private static Modifiers GetModifiers(Type type) { @@ -313,30 +312,11 @@ namespace IKVM.Internal get { return type.IsInterface ? null : CoreClasses.java.lang.Object.Wrapper; } } - internal override TypeWrapper DeclaringTypeWrapper - { - get { return null; } - } - - internal override TypeWrapper[] InnerClasses - { - get { return TypeWrapper.EmptyArray; } - } - - internal override TypeWrapper[] Interfaces - { - get { return TypeWrapper.EmptyArray; } - } - internal override Type TypeAsTBD { get { return type; } } - internal override void Finish() - { - } - internal override ClassLoaderWrapper GetClassLoader() { return AssemblyClassLoader.FromAssembly(type.Assembly); @@ -418,31 +398,11 @@ namespace IKVM.Internal } } - internal override void Finish() - { - } - internal override ClassLoaderWrapper GetClassLoader() { return DeclaringTypeWrapper.GetClassLoader(); } - internal override TypeWrapper[] InnerClasses - { - get - { - return TypeWrapper.EmptyArray; - } - } - - internal override TypeWrapper[] Interfaces - { - get - { - return TypeWrapper.EmptyArray; - } - } - internal override Type TypeAsTBD { get @@ -655,31 +615,11 @@ namespace IKVM.Internal } } - internal override void Finish() - { - } - internal override ClassLoaderWrapper GetClassLoader() { return DeclaringTypeWrapper.GetClassLoader(); } - internal override TypeWrapper[] InnerClasses - { - get - { - return TypeWrapper.EmptyArray; - } - } - - internal override TypeWrapper[] Interfaces - { - get - { - return TypeWrapper.EmptyArray; - } - } - internal override Type TypeAsTBD { get @@ -701,10 +641,6 @@ namespace IKVM.Internal { } - internal sealed override void Finish() - { - } - internal sealed override ClassLoaderWrapper GetClassLoader() { return DeclaringTypeWrapper.GetClassLoader(); @@ -1089,14 +1025,6 @@ namespace IKVM.Internal } } - internal override TypeWrapper[] InnerClasses - { - get - { - return TypeWrapper.EmptyArray; - } - } - internal override Type TypeAsTBD { get @@ -1233,14 +1161,6 @@ namespace IKVM.Internal } } - internal override TypeWrapper[] InnerClasses - { - get - { - return TypeWrapper.EmptyArray; - } - } - internal override Type TypeAsTBD { get @@ -2782,32 +2702,6 @@ namespace IKVM.Internal } #endif // EMITTERS - internal override void Finish() - { - // we don't need locking, because Finish and Link are idempotent - if (finished) - { - return; - } - if (BaseTypeWrapper != null) - { - BaseTypeWrapper.Finish(); - } - foreach (TypeWrapper tw in this.Interfaces) - { - tw.Finish(); - } - foreach (MethodWrapper mw in GetMethods()) - { - mw.Link(); - } - foreach (FieldWrapper fw in GetFields()) - { - fw.Link(); - } - finished = true; - } - internal override MethodParametersEntry[] GetMethodParameters(MethodWrapper mw) { MethodBase mb = mw.GetMethod(); diff --git a/external/ikvm/runtime/Dummy.OpenJDK.Core.cs b/external/ikvm/runtime/Dummy.OpenJDK.Core.cs index e9968b28c7..eac75180e5 100644 --- a/external/ikvm/runtime/Dummy.OpenJDK.Core.cs +++ b/external/ikvm/runtime/Dummy.OpenJDK.Core.cs @@ -1,5 +1,5 @@ /* - Copyright (C) 2010 Jeroen Frijters + Copyright (C) 2010-2014 Jeroen Frijters This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -53,10 +53,9 @@ namespace java namespace invoke { - public class MemberName { } - public class AdapterMethodHandle { } - public class BoundMethodHandle { } public class DirectMethodHandle { } + public class LambdaForm { } + public class MemberName { } public class MethodType { } public class MethodHandle { } public class CallSite { } @@ -64,8 +63,10 @@ namespace java namespace reflect { - public class Constructor { } - public class Method { } + public class Constructor : Executable { } + public class Executable { } + public class Field { } + public class Method : Executable { } } } @@ -92,3 +93,10 @@ namespace java public class Vector { } } } + +namespace sun.reflect +{ + public interface ConstructorAccessor { } + public interface FieldAccessor { } + public interface MethodAccessor { } +} diff --git a/external/ikvm/runtime/DynamicTypeWrapper.cs.REMOVED.git-id b/external/ikvm/runtime/DynamicTypeWrapper.cs.REMOVED.git-id index 5c8ea32860..832e38c2cf 100644 --- a/external/ikvm/runtime/DynamicTypeWrapper.cs.REMOVED.git-id +++ b/external/ikvm/runtime/DynamicTypeWrapper.cs.REMOVED.git-id @@ -1 +1 @@ -1aa34b686a8e309033b7934a16238a455a6696f5 \ No newline at end of file +72685c14a95305ab5cef323c82245442b4620449 \ No newline at end of file diff --git a/external/ikvm/runtime/IKVM.Runtime.8.csproj b/external/ikvm/runtime/IKVM.Runtime.8.csproj index 0418b8ed1e..adee8e30e5 100644 --- a/external/ikvm/runtime/IKVM.Runtime.8.csproj +++ b/external/ikvm/runtime/IKVM.Runtime.8.csproj @@ -155,11 +155,13 @@ + + diff --git a/external/ikvm/runtime/MemberWrapper.cs b/external/ikvm/runtime/MemberWrapper.cs index 27e4bdc87d..58f0411071 100644 --- a/external/ikvm/runtime/MemberWrapper.cs +++ b/external/ikvm/runtime/MemberWrapper.cs @@ -53,6 +53,7 @@ namespace IKVM.Internal NonPublicTypeInSignature = 512, // this flag is only available after linking and is not set for access stubs DelegateInvokeWithByRefParameter = 1024, Type2FinalField = 2048, + NoOp = 4096, // empty static initializer } abstract class MemberWrapper @@ -296,6 +297,11 @@ namespace IKVM.Internal get { return (flags & MemberFlags.DelegateInvokeWithByRefParameter) != 0; } } + internal bool IsNoOp + { + get { return (flags & MemberFlags.NoOp) != 0; } + } + internal Modifiers Modifiers { get @@ -853,6 +859,11 @@ namespace IKVM.Internal get { return (object)Name == (object)StringConstants.INIT; } } + internal bool IsClassInitializer + { + get { return (object)Name == (object)StringConstants.CLINIT; } + } + internal bool IsVirtual { get @@ -873,22 +884,6 @@ namespace IKVM.Internal } } - // placeholder for method that exist in ClassFile but not in TypeWrapper - // (because it is optimized away) - sealed class DummyMethodWrapper : MethodWrapper - { - internal DummyMethodWrapper(TypeWrapper tw) - : base(tw, StringConstants.CLINIT, StringConstants.SIG_VOID, null, PrimitiveTypeWrapper.VOID, TypeWrapper.EmptyArray, Modifiers.Static, MemberFlags.None) - { - } - - protected override void DoLinkMethod() - { - // we're pre-linked (because we pass the signature types to the base constructor) - throw new InvalidOperationException(); - } - } - abstract class SmartMethodWrapper : MethodWrapper { internal SmartMethodWrapper(TypeWrapper declaringType, string name, string sig, MethodBase method, TypeWrapper returnType, TypeWrapper[] parameterTypes, Modifiers modifiers, MemberFlags flags) @@ -1526,6 +1521,21 @@ namespace IKVM.Internal } } + internal bool IsSerialVersionUID + { + get + { + // a serialVersionUID field must be static and final to be recognized (see ObjectStreamClass.getDeclaredSUID()) + return (Modifiers & (Modifiers.Static | Modifiers.Final)) == (Modifiers.Static | Modifiers.Final) + && Name == "serialVersionUID" + && (FieldTypeWrapper == PrimitiveTypeWrapper.LONG + || FieldTypeWrapper == PrimitiveTypeWrapper.INT + || FieldTypeWrapper == PrimitiveTypeWrapper.CHAR + || FieldTypeWrapper == PrimitiveTypeWrapper.SHORT + || FieldTypeWrapper == PrimitiveTypeWrapper.BYTE); + } + } + internal static FieldWrapper Create(TypeWrapper declaringType, TypeWrapper fieldType, FieldInfo fi, string name, string sig, ExModifiers modifiers) { // volatile long & double field accesses must be made atomic @@ -1799,7 +1809,7 @@ namespace IKVM.Internal { if(getter == null) { - EmitThrowNoSuchMethodErrorForGetter(ilgen, this.FieldTypeWrapper, this.IsStatic); + EmitThrowNoSuchMethodErrorForGetter(ilgen, this.FieldTypeWrapper, this); } else if(getter.IsStatic) { @@ -1811,15 +1821,18 @@ namespace IKVM.Internal } } - internal static void EmitThrowNoSuchMethodErrorForGetter(CodeEmitter ilgen, TypeWrapper type, bool isStatic) + internal static void EmitThrowNoSuchMethodErrorForGetter(CodeEmitter ilgen, TypeWrapper type, MemberWrapper member) { +#if STATIC_COMPILER + StaticCompiler.IssueMessage(Message.EmittedNoSuchMethodError, "", member.DeclaringType.Name + "." + member.Name + member.Signature); +#endif // HACK the branch around the throw is to keep the verifier happy CodeEmitterLabel label = ilgen.DefineLabel(); ilgen.Emit(OpCodes.Ldc_I4_0); ilgen.EmitBrtrue(label); ilgen.EmitThrow("java.lang.NoSuchMethodError"); ilgen.MarkLabel(label); - if (!isStatic) + if (!member.IsStatic) { ilgen.Emit(OpCodes.Pop); } @@ -1840,7 +1853,7 @@ namespace IKVM.Internal } else { - EmitThrowNoSuchMethodErrorForSetter(ilgen, this.IsStatic); + EmitThrowNoSuchMethodErrorForSetter(ilgen, this); } } else if(setter.IsStatic) @@ -1853,8 +1866,11 @@ namespace IKVM.Internal } } - internal static void EmitThrowNoSuchMethodErrorForSetter(CodeEmitter ilgen, bool isStatic) + internal static void EmitThrowNoSuchMethodErrorForSetter(CodeEmitter ilgen, MemberWrapper member) { +#if STATIC_COMPILER + StaticCompiler.IssueMessage(Message.EmittedNoSuchMethodError, "", member.DeclaringType.Name + "." + member.Name + member.Signature); +#endif // HACK the branch around the throw is to keep the verifier happy CodeEmitterLabel label = ilgen.DefineLabel(); ilgen.Emit(OpCodes.Ldc_I4_0); @@ -1862,7 +1878,7 @@ namespace IKVM.Internal ilgen.EmitThrow("java.lang.NoSuchMethodError"); ilgen.MarkLabel(label); ilgen.Emit(OpCodes.Pop); - if (!isStatic) + if (!member.IsStatic) { ilgen.Emit(OpCodes.Pop); } @@ -1908,7 +1924,7 @@ namespace IKVM.Internal MethodInfo getter = property.GetGetMethod(true); if(getter == null) { - DynamicPropertyFieldWrapper.EmitThrowNoSuchMethodErrorForGetter(ilgen, this.FieldTypeWrapper, this.IsStatic); + DynamicPropertyFieldWrapper.EmitThrowNoSuchMethodErrorForGetter(ilgen, this.FieldTypeWrapper, this); } else if(getter.IsStatic) { @@ -1935,7 +1951,7 @@ namespace IKVM.Internal } else { - DynamicPropertyFieldWrapper.EmitThrowNoSuchMethodErrorForSetter(ilgen, this.IsStatic); + DynamicPropertyFieldWrapper.EmitThrowNoSuchMethodErrorForSetter(ilgen, this); } } else if(setter.IsStatic) diff --git a/external/ikvm/runtime/TypeWrapper.cs.REMOVED.git-id b/external/ikvm/runtime/TypeWrapper.cs.REMOVED.git-id index c59760be77..82491b69a5 100644 --- a/external/ikvm/runtime/TypeWrapper.cs.REMOVED.git-id +++ b/external/ikvm/runtime/TypeWrapper.cs.REMOVED.git-id @@ -1 +1 @@ -31d3db8cd9de088ded6bcee11ef1d8e9d7e6d546 \ No newline at end of file +1afb52fe351bf417f16ab65bbad26a8f7fbd19b8 \ No newline at end of file diff --git a/external/ikvm/runtime/common.cs b/external/ikvm/runtime/common.cs index 94cad5878c..74db684866 100644 --- a/external/ikvm/runtime/common.cs +++ b/external/ikvm/runtime/common.cs @@ -1,5 +1,5 @@ /* - Copyright (C) 2002-2014 Jeroen Frijters + Copyright (C) 2002-2015 Jeroen Frijters This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -23,6 +23,7 @@ */ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.InteropServices; @@ -131,6 +132,24 @@ namespace IKVM.NativeCode.java.lang return IsWindowsConsole(false) ? GetConsoleEncoding() : null; } + public static FileVersionInfo getKernel32FileVersionInfo() + { + try + { + foreach (ProcessModule module in Process.GetCurrentProcess().Modules) + { + if (string.Compare(module.ModuleName, "kernel32.dll", StringComparison.OrdinalIgnoreCase) == 0) + { + return module.FileVersionInfo; + } + } + } + catch + { + } + return null; + } + private static bool IsWindowsConsole(bool stdout) { if (Environment.OSVersion.Platform != PlatformID.Win32NT) diff --git a/external/ikvm/runtime/compiler.cs.REMOVED.git-id b/external/ikvm/runtime/compiler.cs.REMOVED.git-id index 8e8a40b9ea..73ea4cb01a 100644 --- a/external/ikvm/runtime/compiler.cs.REMOVED.git-id +++ b/external/ikvm/runtime/compiler.cs.REMOVED.git-id @@ -1 +1 @@ -69bf1f5c084614078ccfa239cff97cb90cb122b2 \ No newline at end of file +08c2bc38900a0011bb0d7efcdfb52672f225f95a \ No newline at end of file diff --git a/external/ikvm/runtime/intrinsics.cs b/external/ikvm/runtime/intrinsics.cs index f058c4c9c5..c8ed3701ee 100644 --- a/external/ikvm/runtime/intrinsics.cs +++ b/external/ikvm/runtime/intrinsics.cs @@ -616,7 +616,7 @@ namespace IKVM.Internal { // it is only valid to replace a ThreadLocal instantiation by our ThreadStatic based version, if we can prove that the instantiation only happens once // (which is the case when we're in and there aren't any branches that lead to the current position) - if (eic.Caller.Name != StringConstants.CLINIT) + if (!eic.Caller.IsClassInitializer) { return false; } diff --git a/external/ikvm/runtime/openjdk/NativeInvokerBytecodeGenerator.cs b/external/ikvm/runtime/openjdk/NativeInvokerBytecodeGenerator.cs new file mode 100644 index 0000000000..c38a010f8b --- /dev/null +++ b/external/ikvm/runtime/openjdk/NativeInvokerBytecodeGenerator.cs @@ -0,0 +1,1029 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// [IKVM] Based on original from OpenJDK, but heavily modified to directly generate a DynamicMethod, +// instead of Java bytecode. +// Copyright (C) 2015 Jeroen Frijters + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.CompilerServices; +using IKVM.Attributes; +using IKVM.Internal; +using java.lang.invoke; +#if !FIRST_PASS +using BasicType = java.lang.invoke.LambdaForm.BasicType; +using Class = java.lang.Class; +using Name = java.lang.invoke.LambdaForm.Name; +using Opcodes = jdk.@internal.org.objectweb.asm.Opcodes.__Fields; +using VerifyType = sun.invoke.util.VerifyType; +using Wrapper = sun.invoke.util.Wrapper; +#endif + +sealed class NativeInvokerBytecodeGenerator +{ +#if FIRST_PASS + public static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) + { + return null; + } +#else + private readonly LambdaForm lambdaForm; + private readonly MethodType invokerType; + private readonly Type delegateType; + private readonly DynamicMethod dm; + private readonly CodeEmitter ilgen; + private readonly int packedArgPos; + private readonly Type packedArgType; + private readonly CodeEmitterLocal[] locals; + private readonly List constants = new List(); + + private enum Bailout + { + NotBasicType, + UnsupportedIntrinsic, + UnsupportedArrayType, + UnsupportedRefKind, + UnsupportedConstant, + NotStaticallyInvocable, + PreconditionViolated, + } + + private sealed class BailoutException : Exception + { + internal BailoutException(Bailout reason, object data) + : base("BAILOUT " + reason + ": " + data) + { + } + } + + private NativeInvokerBytecodeGenerator(LambdaForm lambdaForm, MethodType invokerType) + { + if (invokerType != invokerType.basicType()) + { + throw new BailoutException(Bailout.NotBasicType, invokerType); + } + this.lambdaForm = lambdaForm; + this.invokerType = invokerType; + this.delegateType = MethodHandleUtil.GetMemberWrapperDelegateType(invokerType); + MethodInfo mi = MethodHandleUtil.GetDelegateInvokeMethod(delegateType); + Type[] paramTypes = MethodHandleUtil.GetParameterTypes(typeof(object[]), mi); + // HACK the code we generate is not verifiable (known issue: locals aren't typed correctly), so we stick the DynamicMethod into mscorlib (a security critical assembly) + this.dm = new DynamicMethod(lambdaForm.debugName, mi.ReturnType, paramTypes, typeof(object).Module, true); + this.ilgen = CodeEmitter.Create(this.dm); + if (invokerType.parameterCount() > MethodHandleUtil.MaxArity) + { + this.packedArgType = paramTypes[paramTypes.Length - 1]; + this.packedArgPos = paramTypes.Length - 1; + } + else + { + this.packedArgPos = Int32.MaxValue; + } + + locals = new CodeEmitterLocal[lambdaForm.names.Length]; + for (int i = lambdaForm._arity(); i < lambdaForm.names.Length; i++) + { + Name name = lambdaForm.names[i]; + if (name.index() != i) + { + throw new BailoutException(Bailout.PreconditionViolated, "name.index() != i"); + } + switch (name.typeChar()) + { + case 'L': + locals[i] = ilgen.DeclareLocal(Types.Object); + break; + case 'I': + locals[i] = ilgen.DeclareLocal(Types.Int32); + break; + case 'J': + locals[i] = ilgen.DeclareLocal(Types.Int64); + break; + case 'F': + locals[i] = ilgen.DeclareLocal(Types.Single); + break; + case 'D': + locals[i] = ilgen.DeclareLocal(Types.Double); + break; + case 'V': + break; + default: + throw new BailoutException(Bailout.PreconditionViolated, "Unsupported typeChar(): " + name.typeChar()); + } + } + } + + /* + * Low-level emit helpers. + */ + private void emitConst(object con) { + if (con == null) { + ilgen.Emit(OpCodes.Ldnull); + } else if (con is string) { + ilgen.Emit(OpCodes.Ldstr, (string)con); + } else if (con is java.lang.Integer) { + ilgen.EmitLdc_I4(((java.lang.Integer)con).intValue()); + } else if (con is java.lang.Long) { + ilgen.EmitLdc_I8(((java.lang.Long)con).longValue()); + } else if (con is java.lang.Float) { + ilgen.EmitLdc_R4(((java.lang.Float)con).floatValue()); + } else if (con is java.lang.Double) { + ilgen.EmitLdc_R8(((java.lang.Double)con).doubleValue()); + } else if (con is java.lang.Boolean) { + ilgen.EmitLdc_I4(((java.lang.Boolean)con).booleanValue() ? 1 : 0); + } else { + throw new BailoutException(Bailout.UnsupportedConstant, con); + } + } + + private void emitIconstInsn(int i) { + ilgen.EmitLdc_I4(i); + } + + /* + * NOTE: These load/store methods use the localsMap to find the correct index! + */ + private void emitLoadInsn(BasicType type, int index) { + // [IKVM] we don't need the localsMap (it is used to correct for long/double taking two slots) + if (locals[index] == null) { + MethodHandleUtil.LoadPackedArg(ilgen, index, 1, packedArgPos, packedArgType); + } else { + ilgen.Emit(OpCodes.Ldloc, locals[index]); + } + } + + private void emitStoreInsn(BasicType type, int index) { + ilgen.Emit(OpCodes.Stloc, locals[index]); + } + + private void emitAstoreInsn(int index) { + emitStoreInsn(BasicType.L_TYPE, index); + } + + private byte arrayTypeCode(Wrapper elementType) { + switch (elementType.name()) { + case "BOOLEAN": return Opcodes.T_BOOLEAN; + case "BYTE": return Opcodes.T_BYTE; + case "CHAR": return Opcodes.T_CHAR; + case "SHORT": return Opcodes.T_SHORT; + case "INT": return Opcodes.T_INT; + case "LONG": return Opcodes.T_LONG; + case "FLOAT": return Opcodes.T_FLOAT; + case "DOUBLE": return Opcodes.T_DOUBLE; + case "OBJECT": return 0; // in place of Opcodes.T_OBJECT + default: throw new BailoutException(Bailout.PreconditionViolated, "elemendType = " + elementType); + } + } + + private OpCode arrayInsnOpcode(byte tcode) + { + switch (tcode) + { + case Opcodes.T_BOOLEAN: + case Opcodes.T_BYTE: + return OpCodes.Stelem_I1; + case Opcodes.T_CHAR: + case Opcodes.T_SHORT: + return OpCodes.Stelem_I2; + case Opcodes.T_INT: + return OpCodes.Stelem_I4; + case Opcodes.T_LONG: + return OpCodes.Stelem_I8; + case Opcodes.T_FLOAT: + return OpCodes.Stelem_R4; + case Opcodes.T_DOUBLE: + return OpCodes.Stelem_R8; + case 0: + return OpCodes.Stelem_Ref; + default: + throw new BailoutException(Bailout.PreconditionViolated, "tcode = " + tcode); + } + } + + /** + * Emit an implicit conversion for an argument which must be of the given pclass. + * This is usually a no-op, except when pclass is a subword type or a reference other than Object or an interface. + * + * @param ptype type of value present on stack + * @param pclass type of value required on stack + * @param arg compile-time representation of value on stack (Node, constant) or null if none + */ + private void emitImplicitConversion(BasicType ptype, Class pclass, object arg) { + //assert(basicType(pclass) == ptype); // boxing/unboxing handled by caller + if (pclass == ptype.basicTypeClass() && ptype != BasicType.L_TYPE) + return; // nothing to do + switch (ptype.name()) { + case "L_TYPE": + if (VerifyType.isNullConversion(CoreClasses.java.lang.Object.Wrapper.ClassObject, pclass, false)) { + //if (PROFILE_LEVEL > 0) + // emitReferenceCast(Object.class, arg); + return; + } + emitReferenceCast(pclass, arg); + return; + case "I_TYPE": + if (!VerifyType.isNullConversion(java.lang.Integer.TYPE, pclass, false)) + emitPrimCast(ptype.basicTypeWrapper(), Wrapper.forPrimitiveType(pclass)); + return; + } + throw new BailoutException(Bailout.PreconditionViolated, "bad implicit conversion: tc=" + ptype + ": " + pclass); + } + + /** Update localClasses type map. Return true if the information is already present. */ + private void assertStaticType(Class cls, Name n) { + // [IKVM] not implemented + } + + private void emitReferenceCast(Class cls, object arg) { + // [IKVM] handle the type system hole that is caused by arrays being both derived from cli.System.Array and directly from java.lang.Object + if (cls != CoreClasses.cli.System.Object.Wrapper.ClassObject) + { + TypeWrapper.FromClass(cls).EmitCheckcast(ilgen); + } + } + + private sealed class AnonymousClass : TypeWrapper + { + internal static readonly Class Instance = new AnonymousClass().ClassObject; + + private AnonymousClass() + : base(TypeFlags.Anonymous, Modifiers.Super | Modifiers.Final, "java.lang.invoke.LambdaForm$MH") + { + } + + internal override ClassLoaderWrapper GetClassLoader() + { + return ClassLoaderWrapper.GetBootstrapClassLoader(); + } + + internal override Type TypeAsTBD + { + get { throw new InvalidOperationException(); } + } + + internal override TypeWrapper BaseTypeWrapper + { + get { return CoreClasses.java.lang.Object.Wrapper; } + } + } + + /** + * Generate customized bytecode for a given LambdaForm. + */ + public static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) + { + try + { + MemberName memberName = new MemberName(); + memberName._clazz(AnonymousClass.Instance); + memberName._name(form.debugName); + memberName._type(invokerType); + memberName._flags(MethodHandleNatives.Constants.MN_IS_METHOD | MethodHandleNatives.Constants.ACC_STATIC | (MethodHandleNatives.Constants.REF_invokeStatic << MethodHandleNatives.Constants.MN_REFERENCE_KIND_SHIFT)); + memberName.vmtarget = new NativeInvokerBytecodeGenerator(form, invokerType).generateCustomizedCodeBytes(); + return memberName; + } +#if DEBUG + catch (BailoutException x) + { + Console.WriteLine(x.Message); + Console.WriteLine("generateCustomizedCode: " + form + ", " + invokerType); + } +#else + catch (BailoutException) + { + } +#endif + return InvokerBytecodeGenerator.generateCustomizedCode(form, invokerType); + } + + /** + * Generate an invoker method for the passed {@link LambdaForm}. + */ + private Delegate generateCustomizedCodeBytes() { + // iterate over the form's names, generating bytecode instructions for each + // start iterating at the first name following the arguments + Name onStack = null; + for (int i = lambdaForm._arity(); i < lambdaForm.names.Length; i++) { + Name name = lambdaForm.names[i]; + + emitStoreResult(onStack); + onStack = name; // unless otherwise modified below + MethodHandleImpl.Intrinsic intr = name.function.intrinsicName(); + switch (intr.name()) { + case "SELECT_ALTERNATIVE": + //assert isSelectAlternative(i); + onStack = emitSelectAlternative(name, lambdaForm.names[i+1]); + i++; // skip MH.invokeBasic of the selectAlternative result + continue; + case "GUARD_WITH_CATCH": + //assert isGuardWithCatch(i); + onStack = emitGuardWithCatch(i); + i = i+2; // Jump to the end of GWC idiom + continue; + case "NEW_ARRAY": + Class rtype = name.function.methodType().returnType(); + if (InvokerBytecodeGenerator.isStaticallyNameable(rtype)) { + emitNewArray(name); + continue; + } + break; + case "ARRAY_LOAD": + emitArrayLoad(name); + continue; + case "IDENTITY": + //assert(name.arguments.length == 1); + emitPushArguments(name); + continue; + case "NONE": + // no intrinsic associated + break; + // [IKVM] ARRAY_STORE and ZERO appear to be unused + default: + throw new BailoutException(Bailout.UnsupportedIntrinsic, "Unknown intrinsic: "+intr); + } + + MemberName member = name.function._member(); + if (isStaticallyInvocable(member)) { + emitStaticInvoke(member, name); + } else { + emitInvoke(name); + } + } + + // return statement + emitReturn(onStack); + + ilgen.DoEmit(); + return dm.CreateDelegate(delegateType, constants.ToArray()); + } + + void emitArrayLoad(Name name) { + OpCode arrayOpcode = OpCodes.Ldelem_Ref; + Class elementType = name.function.methodType().parameterType(0).getComponentType(); + emitPushArguments(name); + if (elementType.isPrimitive()) { + Wrapper w = Wrapper.forPrimitiveType(elementType); + arrayOpcode = arrayLoadOpcode(arrayTypeCode(w)); + } + ilgen.Emit(arrayOpcode); + } + + /** + * Emit an invoke for the given name. + */ + void emitInvoke(Name name) { + //assert(!isLinkerMethodInvoke(name)); // should use the static path for these + if (true) { + // push receiver + MethodHandle target = name.function._resolvedHandle(); + //assert(target != null) : name.exprString(); + //mv.visitLdcInsn(constantPlaceholder(target)); + EmitConstant(target); + emitReferenceCast(CoreClasses.java.lang.invoke.MethodHandle.Wrapper.ClassObject, target); + } else { + // load receiver + //emitAloadInsn(0); + //emitReferenceCast(MethodHandle.class, null); + //mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", LF_SIG); + //mv.visitFieldInsn(Opcodes.GETFIELD, LF, "names", LFN_SIG); + // TODO more to come + } + + // push arguments + emitPushArguments(name); + + // invocation + MethodType type = name.function.methodType(); + //mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString(), false); + EmitInvokeBasic(type.basicType()); + } + + static bool isStaticallyInvocable(MemberName member) { + if (member == null) return false; + if (member.isConstructor()) return false; + Class cls = member.getDeclaringClass(); + if (cls.isArray() || cls.isPrimitive()) + return false; // FIXME + /* + if (cls.isAnonymousClass() || cls.isLocalClass()) + return false; // inner class of some sort + if (cls.getClassLoader() != MethodHandle.class.getClassLoader()) + return false; // not on BCP + if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: switch to supported API once it is added + return false; + MethodType mtype = member.getMethodOrFieldType(); + if (!isStaticallyNameable(mtype.returnType())) + return false; + for (Class ptype : mtype.parameterArray()) + if (!isStaticallyNameable(ptype)) + return false; + if (!member.isPrivate() && VerifyAccess.isSamePackage(MethodHandle.class, cls)) + return true; // in java.lang.invoke package + if (member.isPublic() && isStaticallyNameable(cls)) + return true; + */ + if (member.isMethod()) { + // [IKVM] If we can't call the method directly, invoke it via the invokeBasic infrastructure. + return IsMethodHandleLinkTo(member) + || IsMethodHandleInvokeBasic(member) + || IsStaticallyInvocable(GetMethodWrapper(member)); + } + if (member.isField()) { + // [IKVM] If we can't access the field directly, use the invokeBasic infrastructure. + return IsStaticallyInvocable(GetFieldWrapper(member)); + } + return false; + } + + /* + static boolean isStaticallyNameable(Class cls) { + if (cls == Object.class) + return true; + while (cls.isArray()) + cls = cls.getComponentType(); + if (cls.isPrimitive()) + return true; // int[].class, for example + if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: switch to supported API once it is added + return false; + // could use VerifyAccess.isClassAccessible but the following is a safe approximation + if (cls.getClassLoader() != Object.class.getClassLoader()) + return false; + if (VerifyAccess.isSamePackage(MethodHandle.class, cls)) + return true; + if (!Modifier.isPublic(cls.getModifiers())) + return false; + for (Class pkgcls : STATICALLY_INVOCABLE_PACKAGES) { + if (VerifyAccess.isSamePackage(pkgcls, cls)) + return true; + } + return false; + } + */ + + void emitStaticInvoke(Name name) { + emitStaticInvoke(name.function._member(), name); + } + + /** + * Emit an invoke for the given name, using the MemberName directly. + */ + void emitStaticInvoke(MemberName member, Name name) { + // push arguments + emitPushArguments(name); + + // invocation + if (member.isMethod()) { + if (IsMethodHandleLinkTo(member)) { + MethodType mt = member.getMethodType(); + TypeWrapper[] args = new TypeWrapper[mt.parameterCount()]; + for (int j = 0; j < args.Length; j++) { + args[j] = TypeWrapper.FromClass(mt.parameterType(j)); + args[j].Finish(); + } + TypeWrapper ret = TypeWrapper.FromClass(mt.returnType()); + ret.Finish(); + Compiler.MethodHandleMethodWrapper.EmitLinkToCall(ilgen, args, ret); + ret.EmitConvSignatureTypeToStackType(ilgen); + } else if (IsMethodHandleInvokeBasic(member)) { + EmitInvokeBasic(member.getMethodType()); + } else { + switch (member.getReferenceKind()) { + case MethodHandleNatives.Constants.REF_invokeInterface: + case MethodHandleNatives.Constants.REF_invokeSpecial: + case MethodHandleNatives.Constants.REF_invokeStatic: + case MethodHandleNatives.Constants.REF_invokeVirtual: + break; + default: + throw new BailoutException(Bailout.UnsupportedRefKind, member); + } + MethodWrapper mw = GetMethodWrapper(member); + if (!IsStaticallyInvocable(mw)) { + throw new BailoutException(Bailout.NotStaticallyInvocable, member); + } + mw.Link(); + mw.DeclaringType.Finish(); + mw.ResolveMethod(); + if (mw.HasCallerID) { + EmitConstant(DynamicCallerIDProvider.Instance); + ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.DynamicCallerID); + } + if (mw.IsStatic || member.getReferenceKind() == MethodHandleNatives.Constants.REF_invokeSpecial) { + mw.EmitCall(ilgen); + } else { + mw.EmitCallvirt(ilgen); + } + mw.ReturnType.EmitConvSignatureTypeToStackType(ilgen); + } + } else if (member.isField()) { + FieldWrapper fw = GetFieldWrapper(member); + if (!IsStaticallyInvocable(fw)) { + throw new BailoutException(Bailout.NotStaticallyInvocable, member); + } + fw.Link(); + fw.DeclaringType.Finish(); + fw.ResolveField(); + switch (member.getReferenceKind()) { + case MethodHandleNatives.Constants.REF_getField: + case MethodHandleNatives.Constants.REF_getStatic: + fw.EmitGet(ilgen); + fw.FieldTypeWrapper.EmitConvSignatureTypeToStackType(ilgen); + break; + case MethodHandleNatives.Constants.REF_putField: + case MethodHandleNatives.Constants.REF_putStatic: + fw.EmitSet(ilgen); + break; + default: + throw new BailoutException(Bailout.UnsupportedRefKind, member); + } + } else { + throw new BailoutException(Bailout.NotStaticallyInvocable, member); + } + } + + void emitNewArray(Name name) { + Class rtype = name.function.methodType().returnType(); + if (name.arguments.Length == 0) { + // The array will be a constant. + object emptyArray; + try { + emptyArray = name.function._resolvedHandle().invoke(); + } catch (Exception ex) { + throw new java.lang.InternalError(ex); + } + //assert(java.lang.reflect.Array.getLength(emptyArray) == 0); + //assert(emptyArray.getClass() == rtype); // exact typing + //mv.visitLdcInsn(constantPlaceholder(emptyArray)); + EmitConstant(emptyArray); + emitReferenceCast(rtype, emptyArray); + return; + } + Class arrayElementType = rtype.getComponentType(); + //assert(arrayElementType != null); + emitIconstInsn(name.arguments.Length); + OpCode xas = OpCodes.Stelem_Ref; + if (!arrayElementType.isPrimitive()) { + TypeWrapper tw = TypeWrapper.FromClass(arrayElementType); + if (tw.IsUnloadable || tw.IsGhost || tw.IsGhostArray || tw.IsNonPrimitiveValueType) { + throw new BailoutException(Bailout.UnsupportedArrayType, tw); + } + ilgen.Emit(OpCodes.Newarr, tw.TypeAsArrayType); + } else { + byte tc = arrayTypeCode(Wrapper.forPrimitiveType(arrayElementType)); + xas = arrayInsnOpcode(tc); + //mv.visitIntInsn(Opcodes.NEWARRAY, tc); + ilgen.Emit(OpCodes.Newarr, TypeWrapper.FromClass(arrayElementType).TypeAsArrayType); + } + // store arguments + for (int i = 0; i < name.arguments.Length; i++) { + //mv.visitInsn(Opcodes.DUP); + ilgen.Emit(OpCodes.Dup); + emitIconstInsn(i); + emitPushArgument(name, i); + //mv.visitInsn(xas); + ilgen.Emit(xas); + } + // the array is left on the stack + assertStaticType(rtype, name); + } + + /** + * Emit bytecode for the selectAlternative idiom. + * + * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithTest): + *
        {@code
        +     *   Lambda(a0:L,a1:I)=>{
        +     *     t2:I=foo.test(a1:I);
        +     *     t3:L=MethodHandleImpl.selectAlternative(t2:I,(MethodHandle(int)int),(MethodHandle(int)int));
        +     *     t4:I=MethodHandle.invokeBasic(t3:L,a1:I);t4:I}
        +     * }
        + */ + private Name emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) { + //assert isStaticallyInvocable(invokeBasicName); + + Name receiver = (Name) invokeBasicName.arguments[0]; + + CodeEmitterLabel L_fallback = ilgen.DefineLabel(); + CodeEmitterLabel L_done = ilgen.DefineLabel(); + + // load test result + emitPushArgument(selectAlternativeName, 0); + + // if_icmpne L_fallback + ilgen.EmitBrfalse(L_fallback); + + // invoke selectAlternativeName.arguments[1] + //Class[] preForkClasses = localClasses.clone(); + emitPushArgument(selectAlternativeName, 1); // get 2nd argument of selectAlternative + emitAstoreInsn(receiver.index()); // store the MH in the receiver slot + emitStaticInvoke(invokeBasicName); + + // goto L_done + ilgen.EmitBr(L_done); + + // L_fallback: + ilgen.MarkLabel(L_fallback); + + // invoke selectAlternativeName.arguments[2] + //System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length); + emitPushArgument(selectAlternativeName, 2); // get 3rd argument of selectAlternative + emitAstoreInsn(receiver.index()); // store the MH in the receiver slot + emitStaticInvoke(invokeBasicName); + + // L_done: + ilgen.MarkLabel(L_done); + // for now do not bother to merge typestate; just reset to the dominator state + //System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length); + + return invokeBasicName; // return what's on stack + } + + /** + * Emit bytecode for the guardWithCatch idiom. + * + * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithCatch): + *
        {@code
        +      *  guardWithCatch=Lambda(a0:L,a1:L,a2:L,a3:L,a4:L,a5:L,a6:L,a7:L)=>{
        +      *    t8:L=MethodHandle.invokeBasic(a4:L,a6:L,a7:L);
        +      *    t9:L=MethodHandleImpl.guardWithCatch(a1:L,a2:L,a3:L,t8:L);
        +      *   t10:I=MethodHandle.invokeBasic(a5:L,t9:L);t10:I}
        +      * }
        + * + * It is compiled into bytecode equivalent of the following code: + *
        {@code
        +      *  try {
        +      *      return a1.invokeBasic(a6, a7);
        +      *  } catch (Throwable e) {
        +      *      if (!a2.isInstance(e)) throw e;
        +      *      return a3.invokeBasic(ex, a6, a7);
        +      *  }}
        +      */
        +    private Name emitGuardWithCatch(int pos) {
        +        Name args    = lambdaForm.names[pos];
        +        Name invoker = lambdaForm.names[pos+1];
        +        Name result  = lambdaForm.names[pos+2];
        +
        +        CodeEmitterLabel L_handler = ilgen.DefineLabel();
        +        CodeEmitterLabel L_done = ilgen.DefineLabel();
        +
        +        Class returnType = result.function._resolvedHandle().type().returnType();
        +        MethodType type = args.function._resolvedHandle().type()
        +                              .dropParameterTypes(0,1)
        +                              .changeReturnType(returnType);
        +
        +        // Normal case
        +        ilgen.BeginExceptionBlock();
        +        // load target
        +        emitPushArgument(invoker, 0);
        +        emitPushArguments(args, 1); // skip 1st argument: method handle
        +        EmitInvokeBasic(type.basicType());
        +        CodeEmitterLocal returnValue = null;
        +        if (returnType != java.lang.Void.TYPE) {
        +            returnValue = ilgen.DeclareLocal(TypeWrapper.FromClass(returnType).TypeAsLocalOrStackType);
        +            ilgen.Emit(OpCodes.Stloc, returnValue);
        +        }
        +        ilgen.EmitLeave(L_done);
        +
        +        // Exceptional case
        +        ilgen.BeginCatchBlock(typeof(Exception));
        +
        +        // [IKVM] map the exception and store it in a local and exit the handler
        +        ilgen.EmitLdc_I4(0);
        +        ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.mapException.MakeGenericMethod(typeof(Exception)));
        +        CodeEmitterLocal exception = ilgen.DeclareLocal(typeof(Exception));
        +        ilgen.Emit(OpCodes.Stloc, exception);
        +        ilgen.EmitLeave(L_handler);
        +        ilgen.EndExceptionBlock();
        +
        +        // Check exception's type
        +        ilgen.MarkLabel(L_handler);
        +        // load exception class
        +        emitPushArgument(invoker, 1);
        +        ilgen.Emit(OpCodes.Ldloc, exception);
        +        CoreClasses.java.lang.Class.Wrapper.GetMethodWrapper("isInstance", "(Ljava.lang.Object;)Z", false).EmitCall(ilgen);
        +        CodeEmitterLabel L_rethrow = ilgen.DefineLabel();
        +        ilgen.EmitBrfalse(L_rethrow);
        +
        +        // Invoke catcher
        +        // load catcher
        +        emitPushArgument(invoker, 2);
        +        ilgen.Emit(OpCodes.Ldloc, exception);
        +        emitPushArguments(args, 1); // skip 1st argument: method handle
        +        MethodType catcherType = type.insertParameterTypes(0, CoreClasses.java.lang.Throwable.Wrapper.ClassObject);
        +        EmitInvokeBasic(catcherType.basicType());
        +        if (returnValue != null) {
        +            ilgen.Emit(OpCodes.Stloc, returnValue);
        +        }
        +        ilgen.EmitBr(L_done);
        +
        +        ilgen.MarkLabel(L_rethrow);
        +        ilgen.Emit(OpCodes.Ldloc, exception);
        +        ilgen.Emit(OpCodes.Call, Compiler.unmapExceptionMethod);
        +        ilgen.Emit(OpCodes.Throw);
        +
        +        ilgen.MarkLabel(L_done);
        +        if (returnValue != null) {
        +            ilgen.Emit(OpCodes.Ldloc, returnValue);
        +        }
        +
        +        return result;
        +    }
        +
        +    private void emitPushArguments(Name args) {
        +        emitPushArguments(args, 0);
        +    }
        +
        +    private void emitPushArguments(Name args, int start) {
        +        for (int i = start; i < args.arguments.Length; i++) {
        +            emitPushArgument(args, i);
        +        }
        +    }
        +
        +    private void emitPushArgument(Name name, int paramIndex) {
        +        object arg = name.arguments[paramIndex];
        +        Class ptype = name.function.methodType().parameterType(paramIndex);
        +        emitPushArgument(ptype, arg);
        +    }
        +
        +    private void emitPushArgument(Class ptype, object arg) {
        +        BasicType bptype = BasicType.basicType(ptype);
        +        if (arg is Name) {
        +            Name n = (Name)arg;
        +            emitLoadInsn(n._type(), n.index());
        +            emitImplicitConversion(n._type(), ptype, n);
        +        } else if ((arg == null || arg is string) && bptype == BasicType.L_TYPE) {
        +            emitConst(arg);
        +        } else {
        +            if (Wrapper.isWrapperType(ikvm.extensions.ExtensionMethods.getClass(arg)) && bptype != BasicType.L_TYPE) {
        +                emitConst(arg);
        +            } else {
        +                EmitConstant(arg);
        +                emitImplicitConversion(BasicType.L_TYPE, ptype, arg);
        +            }
        +        }
        +    }
        +
        +    /**
        +     * Store the name to its local, if necessary.
        +     */
        +    private void emitStoreResult(Name name) {
        +        if (name != null && name._type() != BasicType.V_TYPE) {
        +            // non-void: actually assign
        +            emitStoreInsn(name._type(), name.index());
        +        }
        +    }
        +
        +    /**
        +     * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type.
        +     */
        +    private void emitReturn(Name onStack) {
        +        // return statement
        +        Class rclass = invokerType.returnType();
        +        BasicType rtype = lambdaForm.returnType();
        +        //assert(rtype == basicType(rclass));  // must agree
        +        if (rtype == BasicType.V_TYPE) {
        +            // [IKVM] unlike the JVM, the CLR doesn't like left over values on the stack
        +            if (onStack != null && onStack._type() != BasicType.V_TYPE) {
        +                ilgen.Emit(OpCodes.Pop);
        +            }
        +        } else {
        +            LambdaForm.Name rn = lambdaForm.names[lambdaForm.result];
        +
        +            // put return value on the stack if it is not already there
        +            if (rn != onStack) {
        +                emitLoadInsn(rtype, lambdaForm.result);
        +            }
        +
        +            emitImplicitConversion(rtype, rclass, rn);
        +        }
        +        ilgen.Emit(OpCodes.Ret);
        +    }
        +
        +    /**
        +     * Emit a type conversion bytecode casting from "from" to "to".
        +     */
        +    private void emitPrimCast(Wrapper from, Wrapper to) {
        +        // Here's how.
        +        // -   indicates forbidden
        +        // <-> indicates implicit
        +        //      to ----> boolean  byte     short    char     int      long     float    double
        +        // from boolean    <->        -        -        -        -        -        -        -
        +        //      byte        -       <->       i2s      i2c      <->      i2l      i2f      i2d
        +        //      short       -       i2b       <->      i2c      <->      i2l      i2f      i2d
        +        //      char        -       i2b       i2s      <->      <->      i2l      i2f      i2d
        +        //      int         -       i2b       i2s      i2c      <->      i2l      i2f      i2d
        +        //      long        -     l2i,i2b   l2i,i2s  l2i,i2c    l2i      <->      l2f      l2d
        +        //      float       -     f2i,i2b   f2i,i2s  f2i,i2c    f2i      f2l      <->      f2d
        +        //      double      -     d2i,i2b   d2i,i2s  d2i,i2c    d2i      d2l      d2f      <->
        +        if (from == to) {
        +            // no cast required, should be dead code anyway
        +            return;
        +        }
        +        if (from.isSubwordOrInt()) {
        +            // cast from {byte,short,char,int} to anything
        +            emitI2X(to);
        +        } else {
        +            // cast from {long,float,double} to anything
        +            if (to.isSubwordOrInt()) {
        +                // cast to {byte,short,char,int}
        +                emitX2I(from);
        +                if (to.bitWidth() < 32) {
        +                    // targets other than int require another conversion
        +                    emitI2X(to);
        +                }
        +            } else {
        +                // cast to {long,float,double} - this is verbose
        +                bool error = false;
        +                switch (from.name()) {
        +                case "LONG":
        +                    switch (to.name()) {
        +                    case "FLOAT":   ilgen.Emit(OpCodes.Conv_R4);  break;
        +                    case "DOUBLE":  ilgen.Emit(OpCodes.Conv_R8);  break;
        +                    default:        error = true;                 break;
        +                    }
        +                    break;
        +                case "FLOAT":
        +                    switch (to.name()) {
        +                    case "LONG":    ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.f2l); break;
        +                    case "DOUBLE":  ilgen.Emit(OpCodes.Conv_R8);  break;
        +                    default:        error = true;                 break;
        +                    }
        +                    break;
        +                case "DOUBLE":
        +                    switch (to.name()) {
        +                    case "LONG" :   ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.d2l); break;
        +                    case "FLOAT":   ilgen.Emit(OpCodes.Conv_R4);  break;
        +                    default:        error = true;                 break;
        +                    }
        +                    break;
        +                default:
        +                    error = true;
        +                    break;
        +                }
        +                if (error) {
        +                    throw new BailoutException(Bailout.PreconditionViolated, "unhandled prim cast: " + from + "2" + to);
        +                }
        +            }
        +        }
        +    }
        +
        +    private void emitI2X(Wrapper type) {
        +        switch (type.name()) {
        +        case "BYTE":    ilgen.Emit(OpCodes.Conv_I1);  break;
        +        case "SHORT":   ilgen.Emit(OpCodes.Conv_I2);  break;
        +        case "CHAR":    ilgen.Emit(OpCodes.Conv_U2);  break;
        +        case "INT":     /* naught */                  break;
        +        case "LONG":    ilgen.Emit(OpCodes.Conv_I8);  break;
        +        case "FLOAT":   ilgen.Emit(OpCodes.Conv_R4);  break;
        +        case "DOUBLE":  ilgen.Emit(OpCodes.Conv_R8);  break;
        +        case "BOOLEAN":
        +            // For compatibility with ValueConversions and explicitCastArguments:
        +            ilgen.EmitLdc_I4(1);
        +            ilgen.Emit(OpCodes.And);
        +            break;
        +        default:   throw new BailoutException(Bailout.PreconditionViolated, "unknown type: " + type);
        +        }
        +    }
        +
        +    private void emitX2I(Wrapper type) {
        +        switch (type.name()) {
        +        case "LONG":    ilgen.Emit(OpCodes.Conv_I4);  break;
        +        case "FLOAT":   ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.f2i);  break;
        +        case "DOUBLE":  ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.d2i);  break;
        +        default:        throw new BailoutException(Bailout.PreconditionViolated, "unknown type: " + type);
        +        }
        +    }
        +
        +    private void EmitConstant(object obj)
        +    {
        +        if (obj == null)
        +        {
        +            ilgen.Emit(OpCodes.Ldnull);
        +            return;
        +        }
        +        int index = constants.IndexOf(obj);
        +        if (index == -1)
        +        {
        +            index = constants.Count;
        +            constants.Add(obj);
        +        }
        +        ilgen.EmitLdarg(0);	// we want the bound value, not the real first parameter
        +        ilgen.EmitLdc_I4(index);
        +        ilgen.Emit(OpCodes.Ldelem_Ref);
        +    }
        +
        +    private void EmitInvokeBasic(MethodType mt)
        +    {
        +        TypeWrapper[] args = new TypeWrapper[mt.parameterCount()];
        +        for (int i = 0; i < args.Length; i++)
        +        {
        +            args[i] = TypeWrapper.FromClass(mt.parameterType(i));
        +            args[i].Finish();
        +        }
        +        TypeWrapper ret = TypeWrapper.FromClass(mt.returnType());
        +        ret.Finish();
        +        Compiler.MethodHandleMethodWrapper.EmitInvokeBasic(ilgen, args, ret, false);
        +    }
        +
        +    private OpCode arrayLoadOpcode(byte tcode)
        +    {
        +        switch (tcode)
        +        {
        +            case Opcodes.T_BOOLEAN:
        +            case Opcodes.T_BYTE:
        +                return OpCodes.Ldelem_I1;
        +            case Opcodes.T_CHAR:
        +                return OpCodes.Ldelem_U2;
        +            case Opcodes.T_SHORT:
        +                return OpCodes.Ldelem_I2;
        +            case Opcodes.T_INT:
        +                return OpCodes.Ldelem_I4;
        +            case Opcodes.T_LONG:
        +                return OpCodes.Ldelem_I8;
        +            case Opcodes.T_FLOAT:
        +                return OpCodes.Ldelem_R4;
        +            case Opcodes.T_DOUBLE:
        +                return OpCodes.Ldelem_R8;
        +            case 0:
        +                return OpCodes.Ldelem_Ref;
        +            default:
        +                throw new BailoutException(Bailout.PreconditionViolated, "tcode = " + tcode);
        +        }
        +    }
        +
        +    private static bool IsMethodHandleLinkTo(MemberName member)
        +    {
        +        return member.getDeclaringClass() == CoreClasses.java.lang.invoke.MethodHandle.Wrapper.ClassObject
        +            && member.getName().StartsWith("linkTo", StringComparison.Ordinal);
        +    }
        +
        +    private static bool IsMethodHandleInvokeBasic(MemberName member)
        +    {
        +        return member.getDeclaringClass() == CoreClasses.java.lang.invoke.MethodHandle.Wrapper.ClassObject
        +            && member.getName() == "invokeBasic";
        +    }
        +
        +    private static MethodWrapper GetMethodWrapper(MemberName member)
        +    {
        +        return TypeWrapper.FromClass(member.getDeclaringClass()).GetMethodWrapper(member.getName(), member.getSignature().Replace('/', '.'), true);
        +    }
        +
        +    private static bool IsStaticallyInvocable(MethodWrapper mw)
        +    {
        +        if (mw == null || mw.DeclaringType.IsUnloadable || mw.DeclaringType.IsGhost || mw.DeclaringType.IsNonPrimitiveValueType || mw.IsFinalizeOrClone || mw.IsDynamicOnly)
        +        {
        +            return false;
        +        }
        +        if (mw.ReturnType.IsUnloadable || mw.ReturnType.IsGhost || mw.ReturnType.IsNonPrimitiveValueType)
        +        {
        +            return false;
        +        }
        +        foreach (TypeWrapper tw in mw.GetParameters())
        +        {
        +            if (tw.IsUnloadable || tw.IsGhost || tw.IsNonPrimitiveValueType)
        +            {
        +                return false;
        +            }
        +        }
        +        return true;
        +    }
        +
        +    private static FieldWrapper GetFieldWrapper(MemberName member)
        +    {
        +        return TypeWrapper.FromClass(member.getDeclaringClass()).GetFieldWrapper(member.getName(), member.getSignature().Replace('/', '.'));
        +    }
        +
        +    private static bool IsStaticallyInvocable(FieldWrapper fw)
        +    {
        +        return fw != null
        +            && !fw.FieldTypeWrapper.IsUnloadable
        +            && !fw.FieldTypeWrapper.IsGhost
        +            && !fw.FieldTypeWrapper.IsNonPrimitiveValueType;
        +    }
        +#endif
        +}
        diff --git a/external/ikvm/runtime/openjdk/java.io.cs b/external/ikvm/runtime/openjdk/java.io.cs
        index f161fa7b37..78b51cb11e 100644
        --- a/external/ikvm/runtime/openjdk/java.io.cs
        +++ b/external/ikvm/runtime/openjdk/java.io.cs
        @@ -185,6 +185,105 @@ static class Java_java_io_FileDescriptor
         	}
         }
         
        +static class Java_java_io_FileInputStream
        +{
        +	public static void open0(object _this, string name, [In] java.io.FileDescriptor fd)
        +	{
        +#if !FIRST_PASS
        +		fd.openReadOnly(name);
        +#endif
        +	}
        +
        +	public static int read0(object _this, [In] java.io.FileDescriptor fd)
        +	{
        +#if FIRST_PASS
        +		return 0;
        +#else
        +		return fd.read();
        +#endif
        +	}
        +
        +	public static int readBytes(object _this, byte[] b, int off, int len, [In] java.io.FileDescriptor fd)
        +	{
        +#if FIRST_PASS
        +		return 0;
        +#else
        +		return fd.readBytes(b, off, len);
        +#endif
        +	}
        +
        +	public static long skip(object _this, long n, [In] java.io.FileDescriptor fd)
        +	{
        +#if FIRST_PASS
        +		return 0;
        +#else
        +		return fd.skip(n);
        +#endif
        +	}
        +
        +	public static int available(object _this, [In] java.io.FileDescriptor fd)
        +	{
        +#if FIRST_PASS
        +		return 0;
        +#else
        +		return fd.available();
        +#endif
        +	}
        +
        +	public static void close0(object _this, [In] java.io.FileDescriptor fd)
        +	{
        +#if !FIRST_PASS
        +		fd.close();
        +#endif
        +	}
        +
        +	public static void initIDs()
        +	{
        +	}
        +}
        +
        +static class Java_java_io_FileOutputStream
        +{
        +	public static void open0(object _this, string name, bool append, [In] java.io.FileDescriptor fd)
        +	{
        +#if !FIRST_PASS
        +		if (append)
        +		{
        +			fd.openAppend(name);
        +		}
        +		else
        +		{
        +			fd.openWriteOnly(name);
        +		}
        +#endif
        +	}
        +
        +	public static void write(object _this, int b, bool append, [In] java.io.FileDescriptor fd)
        +	{
        +#if !FIRST_PASS
        +		fd.write(b);
        +#endif
        +	}
        +
        +	public static void writeBytes(object _this, byte[] b, int off, int len, bool append, [In] java.io.FileDescriptor fd)
        +	{
        +#if !FIRST_PASS
        +		fd.writeBytes(b, off, len);
        +#endif
        +	}
        +
        +	public static void close0(object _this, [In] java.io.FileDescriptor fd)
        +	{
        +#if !FIRST_PASS
        +		fd.close();
        +#endif
        +	}
        +
        +	public static void initIDs()
        +	{
        +	}
        +}
        +
         static class Java_java_io_ObjectInputStream
         {
         	public static void bytesToFloats(byte[] src, int srcpos, float[] dst, int dstpos, int nfloats)
        @@ -667,6 +766,98 @@ static class Java_java_io_ObjectStreamClass
         	}
         }
         
        +static class Java_java_io_RandomAccessFile
        +{
        +	public static void open0(object _this, string name, int mode, [In] java.io.FileDescriptor fd, [In] int O_RDWR)
        +	{
        +#if !FIRST_PASS
        +		if ((mode & O_RDWR) == O_RDWR)
        +		{
        +			fd.openReadWrite(name);
        +		}
        +		else
        +		{
        +			fd.openReadOnly(name);
        +		}
        +#endif
        +	}
        +
        +	public static int read0(object _this, [In] java.io.FileDescriptor fd)
        +	{
        +#if FIRST_PASS
        +		return 0;
        +#else
        +		return fd.read();
        +#endif
        +	}
        +
        +	public static int readBytes(object _this, byte[] b, int off, int len, [In] java.io.FileDescriptor fd)
        +	{
        +#if FIRST_PASS
        +		return 0;
        +#else
        +		return fd.readBytes(b, off, len);
        +#endif
        +	}
        +
        +	public static void write0(object _this, int b, [In] java.io.FileDescriptor fd)
        +	{
        +#if !FIRST_PASS
        +		fd.write(b);
        +#endif
        +	}
        +
        +	public static void writeBytes(object _this, byte[] b, int off, int len, [In] java.io.FileDescriptor fd)
        +	{
        +#if !FIRST_PASS
        +		fd.writeBytes(b, off, len);
        +#endif
        +	}
        +
        +	public static long getFilePointer(object _this, [In] java.io.FileDescriptor fd)
        +	{
        +#if FIRST_PASS
        +		return 0;
        +#else
        +		return fd.getFilePointer();
        +#endif
        +	}
        +
        +	public static void seek0(object _this, long pos, [In] java.io.FileDescriptor fd)
        +	{
        +#if !FIRST_PASS
        +		fd.seek(pos);
        +#endif
        +	}
        +
        +	public static long length(object _this, [In] java.io.FileDescriptor fd)
        +	{
        +#if FIRST_PASS
        +		return 0;
        +#else
        +		return fd.length();
        +#endif
        +	}
        +
        +	public static void setLength(object _this, long newLength, [In] java.io.FileDescriptor fd)
        +	{
        +#if !FIRST_PASS
        +		fd.setLength(newLength);
        +#endif
        +	}
        +
        +	public static void close0(object _this, [In] java.io.FileDescriptor fd)
        +	{
        +#if !FIRST_PASS
        +		fd.close();
        +#endif
        +	}
        +
        +	public static void initIDs()
        +	{
        +	}
        +}
        +
         static class Java_java_io_WinNTFileSystem
         {
         	internal const int ACCESS_READ = 0x04;
        diff --git a/external/ikvm/runtime/openjdk/java.lang.cs b/external/ikvm/runtime/openjdk/java.lang.cs
        index 4cb85bed2a..1879c1bd6c 100644
        --- a/external/ikvm/runtime/openjdk/java.lang.cs
        +++ b/external/ikvm/runtime/openjdk/java.lang.cs
        @@ -34,7 +34,7 @@ using IKVM.Internal;
         
         static class Java_java_lang_Class
         {
        -	public static java.lang.Class forName0(string name, bool initialize, java.lang.ClassLoader loader)
        +	public static java.lang.Class forName0(string name, bool initialize, java.lang.ClassLoader loader, java.lang.Class caller)
         	{
         #if FIRST_PASS
         		return null;
        @@ -80,6 +80,11 @@ static class Java_java_lang_Class
         				throw x.ToJava();
         			}
         		}
        +		java.security.ProtectionDomain pd;
        +		if (loader != null && caller != null && (pd = getProtectionDomain0(caller)) != null)
        +		{
        +			loader.checkPackageAccess(tw.ClassObject, pd);
        +		}
         		if (initialize && !tw.IsArray)
         		{
         			try
        @@ -538,13 +543,14 @@ static class Java_java_lang_Class
         				throw new ClassFormatError(wrapper.Name);
         			}
         			MethodWrapper[] methods = wrapper.GetMethods();
        -			List list = new List();
        +			List list = new List(methods.Length);
         			for (int i = 0; i < methods.Length; i++)
         			{
         				// we don't want to expose "hideFromReflection" methods (one reason is that it would
         				// mess up the serialVersionUID computation)
         				if (!methods[i].IsHideFromReflection
        -					&& methods[i].Name != "" && methods[i].Name != ""
        +					&& !methods[i].IsConstructor
        +					&& !methods[i].IsClassInitializer
         					&& (!publicOnly || methods[i].IsPublic))
         				{
         					list.Add((java.lang.reflect.Method)methods[i].ToMethodOrConstructor(false));
        @@ -590,7 +596,7 @@ static class Java_java_lang_Class
         				// we don't want to expose "hideFromReflection" methods (one reason is that it would
         				// mess up the serialVersionUID computation)
         				if (!methods[i].IsHideFromReflection
        -					&& methods[i].Name == ""
        +					&& methods[i].IsConstructor
         					&& (!publicOnly || methods[i].IsPublic))
         				{
         					list.Add((java.lang.reflect.Constructor)methods[i].ToMethodOrConstructor(false));
        @@ -1168,6 +1174,65 @@ static class Java_java_lang_StrictMath
         
         static class Java_java_lang_System
         {
        +	public static void registerNatives()
        +	{
        +	}
        +
        +	public static void setIn0(object @in)
        +	{
        +#if !FIRST_PASS
        +		java.lang.StdIO.@in = (java.io.InputStream)@in;
        +#endif
        +	}
        +
        +	public static void setOut0(object @out)
        +	{
        +#if !FIRST_PASS
        +		java.lang.StdIO.@out = (java.io.PrintStream)@out;
        +#endif
        +	}
        +
        +	public static void setErr0(object err)
        +	{
        +#if !FIRST_PASS
        +		java.lang.StdIO.err = (java.io.PrintStream)err;
        +#endif
        +	}
        +
        +	public static object initProperties(object props)
        +	{
        +#if FIRST_PASS
        +		return null;
        +#else
        +		java.lang.VMSystemProperties.initProperties((java.util.Properties)props);
        +		return props;
        +#endif
        +	}
        +
        +	public static string mapLibraryName(string libname)
        +	{
        +#if FIRST_PASS
        +		return null;
        +#else
        +		if (libname == null)
        +		{
        +			throw new java.lang.NullPointerException();
        +		}
        +		if (ikvm.@internal.Util.WINDOWS)
        +		{
        +			return libname + ".dll";
        +		}
        +		else if (ikvm.@internal.Util.MACOSX)
        +		{
        +			return "lib" + libname + ".jnilib";
        +		}
        +		else
        +		{
        +			return "lib" + libname + ".so";
        +		}
        +#endif
        +	}
        +
         	public static void arraycopy(object src, int srcPos, object dest, int destPos, int length)
         	{
         		IKVM.Runtime.ByteCodeHelper.arraycopy(src, srcPos, dest, destPos, length);
        diff --git a/external/ikvm/runtime/openjdk/java.lang.invoke.cs b/external/ikvm/runtime/openjdk/java.lang.invoke.cs
        index e038a8093f..2f6a3187f7 100644
        --- a/external/ikvm/runtime/openjdk/java.lang.invoke.cs
        +++ b/external/ikvm/runtime/openjdk/java.lang.invoke.cs
        @@ -22,6 +22,7 @@
           
         */
         using System;
        +using System.Collections.Generic;
         using System.Diagnostics;
         using System.Reflection;
         using System.Reflection.Emit;
        @@ -30,6 +31,26 @@ using IKVM.Internal;
         using java.lang.invoke;
         using jlClass = java.lang.Class;
         
        +static class Java_java_lang_invoke_DirectMethodHandle
        +{
        +	// this is called from DirectMethodHandle.makeAllocator() via a map.xml prologue patch
        +	public static DirectMethodHandle makeStringAllocator(MemberName member)
        +	{
        +#if FIRST_PASS
        +		return null;
        +#else
        +		// we cannot construct strings via the standard two-pass approach (allocateObject followed by constructor invocation),
        +		// so we special case string construction here (to call our static factory method instead)
        +		if (member.getDeclaringClass() == CoreClasses.java.lang.String.Wrapper.ClassObject)
        +		{
        +			MethodType mt = member.getMethodType().changeReturnType(CoreClasses.java.lang.String.Wrapper.ClassObject);
        +			return new DirectMethodHandle(mt, DirectMethodHandle._preparedLambdaForm(mt, MethodTypeForm.LF_INVSTATIC), member, null);
        +		}
        +		return null;
        +#endif
        +	}
        +}
        +
         static class Java_java_lang_invoke_MethodHandle
         {
         	public static object invokeExact(MethodHandle thisObject, object[] args)
        @@ -76,36 +97,64 @@ static class Java_java_lang_invoke_MethodHandle
         	}
         }
         
        -static class Java_java_lang_invoke_MethodHandleNatives
        +static class Java_java_lang_invoke_MethodHandleImpl
         {
        -	// called from Lookup.revealDirect() (instead of MethodHandle.internalMemberName()) via map.xml replace-method-call
        -	public static MemberName internalMemberName(MethodHandle mh)
        +	// hooked up via map.xml (as a replacement for makePairwiseConvertByEditor)
        +	public static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, bool strict, bool monobox)
         	{
         #if FIRST_PASS
         		return null;
         #else
        -		MemberName mn = mh.internalMemberName();
        -		if (mn.isStatic() && mn.getName() == "")
        +		object[] convSpecs = MethodHandleImpl.computeValueConversions(srcType, target.type(), strict, monobox);
        +		List names = new List();
        +		names.Add(new LambdaForm.Name(0, LambdaForm.BasicType.L_TYPE));
        +		for (int i = 0; i < srcType.parameterCount(); i++)
         		{
        -			// HACK since we convert String constructors into static methods, we have to undo that here
        -			// Note that the MemberName we return is only used for a security check and by InfoFromMemberName (a MethodHandleInfo implementation),
        -			// so we don't need to make it actually invokable.
        -			MemberName alt = new MemberName();
        -			typeof(MemberName).GetField("clazz", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(alt, mn.getDeclaringClass());
        -			typeof(MemberName).GetField("name", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(alt, mn.getName());
        -			typeof(MemberName).GetField("type", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(alt, mn.getMethodType().changeReturnType(typeof(void)));
        -			int flags = mn._flags();
        -			flags -= MethodHandleNatives.Constants.MN_IS_METHOD;
        -			flags += MethodHandleNatives.Constants.MN_IS_CONSTRUCTOR;
        -			flags &= ~(MethodHandleNatives.Constants.MN_REFERENCE_KIND_MASK << MethodHandleNatives.Constants.MN_REFERENCE_KIND_SHIFT);
        -			flags |= MethodHandleNatives.Constants.REF_newInvokeSpecial << MethodHandleNatives.Constants.MN_REFERENCE_KIND_SHIFT;
        -			flags &= ~MethodHandleNatives.Constants.ACC_STATIC;
        -			alt._flags(flags);
        -			return alt;
        +			names.Add(new LambdaForm.Name(i + 1, LambdaForm.BasicType.basicType(srcType.parameterType(i))));
         		}
        -		return mn;
        +		LambdaForm.Name[] invokeArgs = new LambdaForm.Name[srcType.parameterCount()];
        +		for (int i = 0; i < invokeArgs.Length; i++)
        +		{
        +			object convSpec = convSpecs[i];
        +			if (convSpec == null)
        +			{
        +				invokeArgs[i] = names[i + 1];
        +			}
        +			else
        +			{
        +				LambdaForm.Name temp = new LambdaForm.Name(convSpec as MethodHandle ?? MethodHandleImpl.Lazy.MH_castReference.bindTo(convSpec), names[i + 1]);
        +				names.Add(temp);
        +				invokeArgs[i] = temp;
        +			}
        +		}
        +		names.Add(new LambdaForm.Name(target, invokeArgs));
        +		if (convSpecs[convSpecs.Length - 1] != null)
        +		{
        +			object convSpec = convSpecs[convSpecs.Length - 1];
        +			if (convSpec != java.lang.Void.TYPE)
        +			{
        +				names.Add(new LambdaForm.Name(convSpec as MethodHandle ?? MethodHandleImpl.Lazy.MH_castReference.bindTo(convSpec), names[names.Count - 1]));
        +			}
        +		}
        +		if (target.type().returnType() == java.lang.Void.TYPE && srcType.returnType() != java.lang.Void.TYPE)
        +		{
        +			names.Add(new LambdaForm.Name(LambdaForm.constantZero(LambdaForm.BasicType.basicType(srcType.returnType()))));
        +		}
        +		LambdaForm form = new LambdaForm("PairwiseConvert", srcType.parameterCount() + 1, names.ToArray(), srcType.returnType() == java.lang.Void.TYPE ? LambdaForm.VOID_RESULT : LambdaForm.LAST_RESULT, false);
        +		return new LightWeightMethodHandle(srcType, form);
         #endif
         	}
        +}
        +
        +static class Java_java_lang_invoke_MethodHandleNatives
        +{
        +	// called from map.xml as a replacement for Class.isInstance() in java.lang.invoke.MethodHandleImpl.castReference()
        +	public static bool Class_isInstance(java.lang.Class clazz, object obj)
        +	{
        +		TypeWrapper tw = TypeWrapper.FromClass(clazz);
        +		// handle the type system hole that is caused by arrays being both derived from cli.System.Array and directly from java.lang.Object
        +		return tw.IsInstance(obj) || (tw == CoreClasses.cli.System.Object.Wrapper && obj is Array);
        +	}
         
         	public static void init(MemberName self, object refObj)
         	{
        @@ -151,6 +200,10 @@ static class Java_java_lang_invoke_MethodHandleNatives
         		{
         			flags |= MethodHandleNatives.Constants.REF_invokeStatic << MethodHandleNatives.Constants.MN_REFERENCE_KIND_SHIFT;
         		}
        +		else if (mw.IsConstructor && !wantSpecial)
        +		{
        +			flags |= MethodHandleNatives.Constants.REF_newInvokeSpecial << MethodHandleNatives.Constants.MN_REFERENCE_KIND_SHIFT;
        +		}
         		else if (mw.IsPrivate || mw.IsFinal || mw.IsConstructor || wantSpecial)
         		{
         			flags |= MethodHandleNatives.Constants.REF_invokeSpecial << MethodHandleNatives.Constants.MN_REFERENCE_KIND_SHIFT;
        @@ -174,16 +227,11 @@ static class Java_java_lang_invoke_MethodHandleNatives
         			{
         				parameters1[i] = mw.GetParameters()[i].ClassObject;
         			}
        -			MethodType mt = MethodType.methodType(typeof(string), parameters1);
        -			typeof(MemberName).GetField("type", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(self, mt);
        -			self.vmtarget = CreateMemberNameDelegate(mw, null, false, mt);
        -			flags -= MethodHandleNatives.Constants.REF_invokeSpecial << MethodHandleNatives.Constants.MN_REFERENCE_KIND_SHIFT;
        -			flags += MethodHandleNatives.Constants.REF_invokeStatic << MethodHandleNatives.Constants.MN_REFERENCE_KIND_SHIFT;
        -			flags -= MethodHandleNatives.Constants.MN_IS_CONSTRUCTOR;
        -			flags += MethodHandleNatives.Constants.MN_IS_METHOD;
        -			flags += MethodHandleNatives.Constants.ACC_STATIC;
        +			MethodType mt = MethodType.methodType(PrimitiveTypeWrapper.VOID.ClassObject, parameters1);
        +			self._type(mt);
         			self._flags(flags);
         			self._clazz(mw.DeclaringType.ClassObject);
        +			self.vmtarget = CreateMemberNameDelegate(mw, null, false, self.getMethodType().changeReturnType(CoreClasses.java.lang.String.Wrapper.ClassObject));
         			return;
         		}
         		self._flags(flags);
        @@ -311,8 +359,7 @@ static class Java_java_lang_invoke_MethodHandleNatives
         		}
         		if (mw.IsConstructor && mw.DeclaringType == CoreClasses.java.lang.String.Wrapper)
         		{
        -			typeof(MemberName).GetField("type", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(self, self.getMethodType().changeReturnType(typeof(string)));
        -			self.vmtarget = CreateMemberNameDelegate(mw, caller, false, self.getMethodType());
        +			self.vmtarget = CreateMemberNameDelegate(mw, caller, false, self.getMethodType().changeReturnType(CoreClasses.java.lang.String.Wrapper.ClassObject));
         		}
         		else if (!mw.IsConstructor || invokeSpecial || newInvokeSpecial)
         		{
        @@ -340,16 +387,6 @@ static class Java_java_lang_invoke_MethodHandleNatives
         		{
         			self._flags(self._flags() | MemberName.CALLER_SENSITIVE);
         		}
        -		if (mw.IsConstructor && mw.DeclaringType == CoreClasses.java.lang.String.Wrapper)
        -		{
        -			int flags = self._flags();
        -			flags -= MethodHandleNatives.Constants.REF_invokeSpecial << MethodHandleNatives.Constants.MN_REFERENCE_KIND_SHIFT;
        -			flags += MethodHandleNatives.Constants.REF_invokeStatic << MethodHandleNatives.Constants.MN_REFERENCE_KIND_SHIFT;
        -			flags -= MethodHandleNatives.Constants.MN_IS_CONSTRUCTOR;
        -			flags += MethodHandleNatives.Constants.MN_IS_METHOD;
        -			flags += MethodHandleNatives.Constants.ACC_STATIC;
        -			self._flags(flags);
        -		}
         	}
         
         	private static void ResolveField(MemberName self)
        @@ -470,7 +507,7 @@ static class Java_java_lang_invoke_MethodHandleNatives
         		MethodWrapper[] methods = TypeWrapper.FromClass(defc).GetMethods();
         		for (int i = skip, len = Math.Min(results.Length, methods.Length - skip); i < len; i++)
         		{
        -			if (!methods[i].IsConstructor && methods[i].Name != StringConstants.CLINIT)
        +			if (!methods[i].IsConstructor && !methods[i].IsClassInitializer)
         			{
         				results[i - skip] = new MemberName((java.lang.reflect.Method)methods[i].ToMethodOrConstructor(true), false);
         			}
        @@ -608,7 +645,7 @@ static partial class MethodHandleUtil
         		return args;
         	}
         
        -	private static Type[] GetParameterTypes(Type thisType, MethodBase mb)
        +	internal static Type[] GetParameterTypes(Type thisType, MethodBase mb)
         	{
         		ParameterInfo[] pi = mb.GetParameters();
         		Type[] args = new Type[pi.Length + 1];
        @@ -1027,25 +1064,7 @@ static partial class MethodHandleUtil
         
         		internal void Ldarg(int i)
         		{
        -			i += firstArg;
        -			if (i >= packedArgPos)
        -			{
        -				ilgen.EmitLdarga(packedArgPos);
        -				int fieldPos = i - packedArgPos;
        -				Type type = packedArgType;
        -				while (fieldPos >= MaxArity || (fieldPos == MaxArity - 1 && IsPackedArgsContainer(type.GetField("t8").FieldType)))
        -				{
        -					FieldInfo field = type.GetField("t8");
        -					type = field.FieldType;
        -					ilgen.Emit(OpCodes.Ldflda, field);
        -					fieldPos -= MaxArity - 1;
        -				}
        -				ilgen.Emit(OpCodes.Ldfld, type.GetField("t" + (1 + fieldPos)));
        -			}
        -			else
        -			{
        -				ilgen.EmitLdarg(i);
        -			}
        +			LoadPackedArg(ilgen, i, firstArg, packedArgPos, packedArgType);
         		}
         
         		internal void LoadCallerID()
        @@ -1232,5 +1251,28 @@ static partial class MethodHandleUtil
         		}
         		return type.voidAdapter;
         	}
        +
        +	internal static void LoadPackedArg(CodeEmitter ilgen, int index, int firstArg, int packedArgPos, Type packedArgType)
        +	{
        +		index += firstArg;
        +		if (index >= packedArgPos)
        +		{
        +			ilgen.EmitLdarga(packedArgPos);
        +			int fieldPos = index - packedArgPos;
        +			Type type = packedArgType;
        +			while (fieldPos >= MaxArity || (fieldPos == MaxArity - 1 && IsPackedArgsContainer(type.GetField("t8").FieldType)))
        +			{
        +				FieldInfo field = type.GetField("t8");
        +				type = field.FieldType;
        +				ilgen.Emit(OpCodes.Ldflda, field);
        +				fieldPos -= MaxArity - 1;
        +			}
        +			ilgen.Emit(OpCodes.Ldfld, type.GetField("t" + (1 + fieldPos)));
        +		}
        +		else
        +		{
        +			ilgen.EmitLdarg(index);
        +		}
        +	}
         #endif
         }
        diff --git a/external/ikvm/runtime/openjdk/java.net.SocketInputStream.cs b/external/ikvm/runtime/openjdk/java.net.SocketInputStream.cs
        new file mode 100644
        index 0000000000..800eb4f09a
        --- /dev/null
        +++ b/external/ikvm/runtime/openjdk/java.net.SocketInputStream.cs
        @@ -0,0 +1,216 @@
        +/*
        + * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
        + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        + *
        + * This code is free software; you can redistribute it and/or modify it
        + * under the terms of the GNU General Public License version 2 only, as
        + * published by the Free Software Foundation.  Oracle designates this
        + * particular file as subject to the "Classpath" exception as provided
        + * by Oracle in the LICENSE file that accompanied this code.
        + *
        + * This code is distributed in the hope that it will be useful, but WITHOUT
        + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
        + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        + * version 2 for more details (a copy is included in the LICENSE file that
        + * accompanied this code).
        + *
        + * You should have received a copy of the GNU General Public License version
        + * 2 along with this work; if not, write to the Free Software Foundation,
        + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
        + *
        + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
        + * or visit www.oracle.com if you need additional information or have any
        + * questions.
        + */
        +#if !FIRST_PASS
        +using Winsock = ikvm.@internal.Winsock;
        +using java.net;
        +#endif
        +
        +static class Java_java_net_SocketInputStream
        +{
        +	public static int socketRead0(object _this, java.io.FileDescriptor fd, byte[] b, int off, int len, int timeout)
        +	{
        +#if FIRST_PASS
        +		return 0;
        +#else
        +		// [IKVM] this method is a direct port of the native code in openjdk6-b18\jdk\src\windows\native\java\net\SocketInputStream.c
        +		System.Net.Sockets.Socket socket = null;
        +		int nread;
        +
        +		if (fd == null)
        +		{
        +			throw new SocketException("socket closed");
        +		}
        +		socket = fd.getSocket();
        +		if (socket == null)
        +		{
        +			throw new SocketException("Socket closed");
        +		}
        +
        +		if (timeout != 0)
        +		{
        +			if (timeout <= 5000 || !net_util_md.isRcvTimeoutSupported)
        +			{
        +				int ret = net_util_md.NET_Timeout(socket, timeout);
        +
        +				if (ret <= 0)
        +				{
        +					if (ret == 0)
        +					{
        +						throw new SocketTimeoutException("Read timed out");
        +					}
        +					else
        +					{
        +						// [IKVM] the OpenJDK native code is broken and always throws this exception on any failure of NET_Timeout
        +						throw new SocketException("socket closed");
        +					}
        +				}
        +
        +				/*check if the socket has been closed while we were in timeout*/
        +				if (fd.getSocket() == null)
        +				{
        +					throw new SocketException("Socket Closed");
        +				}
        +			}
        +		}
        +
        +		nread = Winsock.recv(socket, b, off, len, 0);
        +		if (nread > 0)
        +		{
        +			// ok
        +		}
        +		else
        +		{
        +			if (nread < 0)
        +			{
        +				/*
        +				 * Recv failed.
        +				 */
        +				switch (Winsock.WSAGetLastError())
        +				{
        +					case Winsock.WSAEINTR:
        +						throw new SocketException("socket closed");
        +
        +					case Winsock.WSAECONNRESET:
        +					case Winsock.WSAESHUTDOWN:
        +						/*
        +						 * Connection has been reset - Windows sometimes reports
        +						 * the reset as a shutdown error.
        +						 */
        +						throw new sun.net.ConnectionResetException();
        +
        +					case Winsock.WSAETIMEDOUT:
        +						throw new SocketTimeoutException("Read timed out");
        +
        +					default:
        +						throw net_util_md.NET_ThrowCurrent("recv failed");
        +				}
        +			}
        +		}
        +		return nread;
        +#endif
        +	}
        +
        +	public static void init()
        +	{
        +	}
        +}
        +
        +static class Java_java_net_SocketOutputStream
        +{
        +	public static void socketWrite0(object _this, java.io.FileDescriptor fd, byte[] data, int off, int len)
        +	{
        +#if !FIRST_PASS
        +		// [IKVM] this method is a direct port of the native code in openjdk6-b18\jdk\src\windows\native\java\net\SocketOutputStream.c
        +		const int MAX_BUFFER_LEN = 2048;
        +		System.Net.Sockets.Socket socket;
        +		int buflen = 65536; // MAX_HEAP_BUFFER_LEN
        +		int n;
        +
        +		if (fd == null)
        +		{
        +			throw new SocketException("socket closed");
        +		}
        +		else
        +		{
        +			socket = fd.getSocket();
        +		}
        +		if (data == null)
        +		{
        +			throw new java.lang.NullPointerException("data argument");
        +		}
        +
        +		while (len > 0)
        +		{
        +			int loff = 0;
        +			int chunkLen = java.lang.Math.min(buflen, len);
        +			int llen = chunkLen;
        +			int retry = 0;
        +
        +			while (llen > 0)
        +			{
        +				n = Winsock.send(socket, data, off + loff, llen, 0);
        +				if (n > 0)
        +				{
        +					llen -= n;
        +					loff += n;
        +					continue;
        +				}
        +
        +				/*
        +				 * Due to a bug in Windows Sockets (observed on NT and Windows
        +				 * 2000) it may be necessary to retry the send. The issue is that
        +				 * on blocking sockets send/WSASend is supposed to block if there
        +				 * is insufficient buffer space available. If there are a large
        +				 * number of threads blocked on write due to congestion then it's
        +				 * possile to hit the NT/2000 bug whereby send returns WSAENOBUFS.
        +				 * The workaround we use is to retry the send. If we have a
        +				 * large buffer to send (>2k) then we retry with a maximum of
        +				 * 2k buffer. If we hit the issue with <=2k buffer then we backoff
        +				 * for 1 second and retry again. We repeat this up to a reasonable
        +				 * limit before bailing out and throwing an exception. In load
        +				 * conditions we've observed that the send will succeed after 2-3
        +				 * attempts but this depends on network buffers associated with
        +				 * other sockets draining.
        +				 */
        +				if (Winsock.WSAGetLastError() == Winsock.WSAENOBUFS)
        +				{
        +					if (llen > MAX_BUFFER_LEN)
        +					{
        +						buflen = MAX_BUFFER_LEN;
        +						chunkLen = MAX_BUFFER_LEN;
        +						llen = MAX_BUFFER_LEN;
        +						continue;
        +					}
        +					if (retry >= 30)
        +					{
        +						throw new SocketException("No buffer space available - exhausted attempts to queue buffer");
        +					}
        +					System.Threading.Thread.Sleep(1000);
        +					retry++;
        +					continue;
        +				}
        +
        +				/*
        +				 * Send failed - can be caused by close or write error.
        +				 */
        +				if (Winsock.WSAGetLastError() == Winsock.WSAENOTSOCK)
        +				{
        +					throw new SocketException("Socket closed");
        +				}
        +				else
        +				{
        +					throw net_util_md.NET_ThrowCurrent("socket write error");
        +				}
        +			}
        +			len -= chunkLen;
        +			off += chunkLen;
        +		}
        +#endif
        +	}
        +
        +	public static void init()
        +	{
        +	}
        +}
        diff --git a/external/ikvm/runtime/openjdk/java.net.cs b/external/ikvm/runtime/openjdk/java.net.cs
        index f84cbf8127..ea81ef224e 100644
        --- a/external/ikvm/runtime/openjdk/java.net.cs
        +++ b/external/ikvm/runtime/openjdk/java.net.cs
        @@ -1,5 +1,5 @@
         /*
        -  Copyright (C) 2007-2013 Jeroen Frijters
        +  Copyright (C) 2007-2015 Jeroen Frijters
         
           This software is provided 'as-is', without any express or implied
           warranty.  In no event will the authors be held liable for any damages
        @@ -28,6 +28,36 @@ using System.Net.NetworkInformation;
         using System.Net.Sockets;
         using System.Security;
         
        +static class Java_java_net_AbstractPlainDatagramSocketImpl
        +{
        +	public static void init()
        +	{
        +	}
        +
        +	public static int dataAvailable(object _this)
        +	{
        +#if FIRST_PASS
        +		return 0;
        +#else
        +		try
        +		{
        +			java.net.AbstractPlainDatagramSocketImpl obj = (java.net.AbstractPlainDatagramSocketImpl)_this;
        +			if (obj.fd != null)
        +			{
        +				return obj.fd.getSocket().Available;
        +			}
        +		}
        +		catch (ObjectDisposedException)
        +		{
        +		}
        +		catch (SocketException)
        +		{
        +		}
        +		throw new java.net.SocketException("Socket closed");
        +#endif
        +	}
        +}
        +
         static class Java_java_net_DatagramPacket
         {
         	public static void init()
        @@ -436,6 +466,7 @@ static class Java_java_net_NetworkInterface
         		int lo = 0;
         		int ppp = 0;
         		int sl = 0;
        +		int wlan = 0;
         		int net = 0;
         		for (int i = 0; i < ifaces.Length; i++)
         		{
        @@ -465,6 +496,9 @@ static class Java_java_net_NetworkInterface
         				case NetworkInterfaceType.Slip:
         					name = "sl" + sl++;
         					break;
        +				case NetworkInterfaceType.Wireless80211:
        +					name = "wlan" + wlan++;
        +					break;
         				default:
         					name = "net" + net++;
         					break;
        @@ -480,6 +514,13 @@ static class Java_java_net_NetworkInterface
         				IPAddress addr = uipaic[j].Address;
         				if (addr.AddressFamily == AddressFamily.InterNetwork)
         				{
        +					if (ifaces[i].OperationalStatus != OperationalStatus.Up)
        +					{
        +						// HACK on Windows, OpenJDK seems to only return IPv4 addresses for interfaces that are up.
        +						// This is possibly the result of their usage of the (legacy) Win32 API GetIpAddrTable.
        +						// Not doing this filtering causes some OpenJDK tests to fail.
        +						continue;
        +					}
         					java.net.Inet4Address address = new java.net.Inet4Address(null, addr.GetAddressBytes());
         					java.net.InterfaceAddress binding = new java.net.InterfaceAddress();
         					short mask = 32;
        diff --git a/external/ikvm/runtime/openjdk/java.util.cs b/external/ikvm/runtime/openjdk/java.util.cs
        new file mode 100644
        index 0000000000..c0d3b82ebd
        --- /dev/null
        +++ b/external/ikvm/runtime/openjdk/java.util.cs
        @@ -0,0 +1,339 @@
        +/*
        +  Copyright (C) 2007-2013 Jeroen Frijters
        +
        +  This software is provided 'as-is', without any express or implied
        +  warranty.  In no event will the authors be held liable for any damages
        +  arising from the use of this software.
        +
        +  Permission is granted to anyone to use this software for any purpose,
        +  including commercial applications, and to alter it and redistribute it
        +  freely, subject to the following restrictions:
        +
        +  1. The origin of this software must not be misrepresented; you must not
        +     claim that you wrote the original software. If you use this software
        +     in a product, an acknowledgment in the product documentation would be
        +     appreciated but is not required.
        +  2. Altered source versions must be plainly marked as such, and must not be
        +     misrepresented as being the original software.
        +  3. This notice may not be removed or altered from any source distribution.
        +
        +  Jeroen Frijters
        +  jeroen@frijters.net
        +  
        +*/
        +using System;
        +
        +static class Java_java_util_TimeZone
        +{
        +	private static string GetCurrentTimeZoneID()
        +	{
        +#if NET_4_0
        +		return TimeZoneInfo.Local.Id;
        +#else
        +		// we don't want a static dependency on System.Core (to be able to run on .NET 2.0)
        +		Type typeofTimeZoneInfo = Type.GetType("System.TimeZoneInfo, System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
        +		if (typeofTimeZoneInfo != null)
        +		{
        +			try
        +			{
        +				return (string)typeofTimeZoneInfo.GetProperty("Id").GetValue(typeofTimeZoneInfo.GetProperty("Local").GetValue(null, null), null);
        +			}
        +			catch (Exception x)
        +			{
        +				// older Mono versions did not wrap the exception in a TargetInvocationExcception,
        +				// so we check both x and x.InnerException
        +				if (typeofTimeZoneInfo.Assembly.GetType("System.TimeZoneNotFoundException").IsInstanceOfType(x)
        +					|| typeofTimeZoneInfo.Assembly.GetType("System.TimeZoneNotFoundException").IsInstanceOfType(x.InnerException))
        +				{
        +					// MONOBUG Mono's TimeZoneInfo.Local property throws a TimeZoneNotFoundException on Windows
        +					// (https://bugzilla.novell.com/show_bug.cgi?id=622524)
        +					return TimeZone.CurrentTimeZone.StandardName;
        +				}
        +				else
        +				{
        +					throw;
        +				}
        +			}
        +		}
        +		else
        +		{
        +			// HACK this is very lame and probably won't work on localized windows versions
        +			return TimeZone.CurrentTimeZone.StandardName;
        +		}
        +#endif
        +	}
        +
        +	public static string getSystemTimeZoneID(string javaHome)
        +	{
        +		// (the switch was generated from the contents of $JAVA_HOME/lib/tzmappings)
        +		switch (GetCurrentTimeZoneID())
        +		{
        +			case "Romance":
        +			case "Romance Standard Time":
        +				return "Europe/Paris";
        +			case "Warsaw":
        +				return "Europe/Warsaw";
        +			case "Central Europe":
        +			case "Central Europe Standard Time":
        +			case "Prague Bratislava":
        +				return "Europe/Prague";
        +			case "W. Central Africa Standard Time":
        +				return "Africa/Luanda";
        +			case "FLE":
        +			case "FLE Standard Time":
        +				return "Europe/Helsinki";
        +			case "GFT":
        +			case "GFT Standard Time":
        +			case "GTB":
        +			case "GTB Standard Time":
        +				return "Europe/Athens";
        +			case "Israel":
        +			case "Israel Standard Time":
        +				return "Asia/Jerusalem";
        +			case "Arab":
        +			case "Arab Standard Time":
        +				return "Asia/Riyadh";
        +			case "Arabic Standard Time":
        +				return "Asia/Baghdad";
        +			case "E. Africa":
        +			case "E. Africa Standard Time":
        +				return "Africa/Nairobi";
        +			case "Saudi Arabia":
        +			case "Saudi Arabia Standard Time":
        +				return "Asia/Riyadh";
        +			case "Iran":
        +			case "Iran Standard Time":
        +				return "Asia/Tehran";
        +			case "Afghanistan":
        +			case "Afghanistan Standard Time":
        +				return "Asia/Kabul";
        +			case "India":
        +			case "India Standard Time":
        +				return "Asia/Calcutta";
        +			case "Myanmar Standard Time":
        +				return "Asia/Rangoon";
        +			case "Nepal Standard Time":
        +				return "Asia/Katmandu";
        +			case "Sri Lanka":
        +			case "Sri Lanka Standard Time":
        +				return "Asia/Colombo";
        +			case "Beijing":
        +			case "China":
        +			case "China Standard Time":
        +				return "Asia/Shanghai";
        +			case "AUS Central":
        +			case "AUS Central Standard Time":
        +				return "Australia/Darwin";
        +			case "Cen. Australia":
        +			case "Cen. Australia Standard Time":
        +				return "Australia/Adelaide";
        +			case "Vladivostok":
        +			case "Vladivostok Standard Time":
        +				return "Asia/Vladivostok";
        +			case "West Pacific":
        +			case "West Pacific Standard Time":
        +				return "Pacific/Guam";
        +			case "E. South America":
        +			case "E. South America Standard Time":
        +				return "America/Sao_Paulo";
        +			case "Greenland Standard Time":
        +				return "America/Godthab";
        +			case "Newfoundland":
        +			case "Newfoundland Standard Time":
        +				return "America/St_Johns";
        +			case "Pacific SA":
        +			case "Pacific SA Standard Time":
        +				return "America/Santiago";
        +			case "SA Western":
        +			case "SA Western Standard Time":
        +				return "America/Caracas";
        +			case "SA Pacific":
        +			case "SA Pacific Standard Time":
        +				return "America/Bogota";
        +			case "US Eastern":
        +			case "US Eastern Standard Time":
        +				return "America/Indianapolis";
        +			case "Central America Standard Time":
        +				return "America/Regina";
        +			case "Mexico":
        +			case "Mexico Standard Time":
        +				return "America/Mexico_City";
        +			case "Canada Central":
        +			case "Canada Central Standard Time":
        +				return "America/Regina";
        +			case "US Mountain":
        +			case "US Mountain Standard Time":
        +				return "America/Phoenix";
        +			case "GMT":
        +			case "GMT Standard Time":
        +				return "Europe/London";
        +			case "Ekaterinburg":
        +			case "Ekaterinburg Standard Time":
        +				return "Asia/Yekaterinburg";
        +			case "West Asia":
        +			case "West Asia Standard Time":
        +				return "Asia/Karachi";
        +			case "Central Asia":
        +			case "Central Asia Standard Time":
        +				return "Asia/Dhaka";
        +			case "N. Central Asia Standard Time":
        +				return "Asia/Novosibirsk";
        +			case "Bangkok":
        +			case "Bangkok Standard Time":
        +				return "Asia/Bangkok";
        +			case "North Asia Standard Time":
        +				return "Asia/Krasnoyarsk";
        +			case "SE Asia":
        +			case "SE Asia Standard Time":
        +				return "Asia/Bangkok";
        +			case "North Asia East Standard Time":
        +				return "Asia/Ulaanbaatar";
        +			case "Singapore":
        +			case "Singapore Standard Time":
        +				return "Asia/Singapore";
        +			case "Taipei":
        +			case "Taipei Standard Time":
        +				return "Asia/Taipei";
        +			case "W. Australia":
        +			case "W. Australia Standard Time":
        +				return "Australia/Perth";
        +			case "Korea":
        +			case "Korea Standard Time":
        +				return "Asia/Seoul";
        +			case "Tokyo":
        +			case "Tokyo Standard Time":
        +				return "Asia/Tokyo";
        +			case "Yakutsk":
        +			case "Yakutsk Standard Time":
        +				return "Asia/Yakutsk";
        +			case "Central European":
        +			case "Central European Standard Time":
        +				return "Europe/Belgrade";
        +			case "W. Europe":
        +			case "W. Europe Standard Time":
        +				return "Europe/Berlin";
        +			case "Tasmania":
        +			case "Tasmania Standard Time":
        +				return "Australia/Hobart";
        +			case "AUS Eastern":
        +			case "AUS Eastern Standard Time":
        +				return "Australia/Sydney";
        +			case "E. Australia":
        +			case "E. Australia Standard Time":
        +				return "Australia/Brisbane";
        +			case "Sydney Standard Time":
        +				return "Australia/Sydney";
        +			case "Central Pacific":
        +			case "Central Pacific Standard Time":
        +				return "Pacific/Guadalcanal";
        +			case "Dateline":
        +			case "Dateline Standard Time":
        +				return "GMT-1200";
        +			case "Fiji":
        +			case "Fiji Standard Time":
        +				return "Pacific/Fiji";
        +			case "Samoa":
        +			case "Samoa Standard Time":
        +				return "Pacific/Apia";
        +			case "Hawaiian":
        +			case "Hawaiian Standard Time":
        +				return "Pacific/Honolulu";
        +			case "Alaskan":
        +			case "Alaskan Standard Time":
        +				return "America/Anchorage";
        +			case "Pacific":
        +			case "Pacific Standard Time":
        +				return "America/Los_Angeles";
        +			case "Mexico Standard Time 2":
        +				return "America/Chihuahua";
        +			case "Mountain":
        +			case "Mountain Standard Time":
        +				return "America/Denver";
        +			case "Central":
        +			case "Central Standard Time":
        +				return "America/Chicago";
        +			case "Eastern":
        +			case "Eastern Standard Time":
        +				return "America/New_York";
        +			case "E. Europe":
        +			case "E. Europe Standard Time":
        +				return "Europe/Minsk";
        +			case "Egypt":
        +			case "Egypt Standard Time":
        +				return "Africa/Cairo";
        +			case "South Africa":
        +			case "South Africa Standard Time":
        +				return "Africa/Harare";
        +			case "Atlantic":
        +			case "Atlantic Standard Time":
        +				return "America/Halifax";
        +			case "SA Eastern":
        +			case "SA Eastern Standard Time":
        +				return "America/Buenos_Aires";
        +			case "Mid-Atlantic":
        +			case "Mid-Atlantic Standard Time":
        +				return "Atlantic/South_Georgia";
        +			case "Azores":
        +			case "Azores Standard Time":
        +				return "Atlantic/Azores";
        +			case "Cape Verde Standard Time":
        +				return "Atlantic/Cape_Verde";
        +			case "Russian":
        +			case "Russian Standard Time":
        +				return "Europe/Moscow";
        +			case "New Zealand":
        +			case "New Zealand Standard Time":
        +				return "Pacific/Auckland";
        +			case "Tonga Standard Time":
        +				return "Pacific/Tongatapu";
        +			case "Arabian":
        +			case "Arabian Standard Time":
        +				return "Asia/Muscat";
        +			case "Caucasus":
        +			case "Caucasus Standard Time":
        +				return "Asia/Yerevan";
        +			case "Greenwich":
        +			case "Greenwich Standard Time":
        +				return "GMT";
        +			case "Central Brazilian Standard Time":
        +				return "America/Manaus";
        +			case "Central Standard Time (Mexico)":
        +				return "America/Mexico_City";
        +			case "Georgian Standard Time":
        +				return "Asia/Tbilisi";
        +			case "Mountain Standard Time (Mexico)":
        +				return "America/Chihuahua";
        +			case "Namibia Standard Time":
        +				return "Africa/Windhoek";
        +			case "Pacific Standard Time (Mexico)":
        +				return "America/Tijuana";
        +			case "Western Brazilian Standard Time":
        +				return "America/Rio_Branco";
        +			case "Azerbaijan Standard Time":
        +				return "Asia/Baku";
        +			case "Jordan Standard Time":
        +				return "Asia/Amman";
        +			case "Middle East Standard Time":
        +				return "Asia/Beirut";
        +			default:
        +				// this means fall back to GMT offset
        +				return getSystemGMTOffsetID();
        +		}
        +	}
        +
        +	public static string getSystemGMTOffsetID()
        +	{
        +		TimeSpan sp = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now);
        +		int hours = sp.Hours;
        +		int mins = sp.Minutes;
        +		if (hours >= 0 && mins >= 0)
        +		{
        +			return String.Format("GMT+{0:D2}:{1:D2}", hours, mins);
        +		}
        +		else
        +		{
        +			return String.Format("GMT-{0:D2}:{1:D2}", -hours, -mins);
        +		}
        +	}
        +}
        +
        diff --git a/external/ikvm/runtime/openjdk/java.util.prefs.cs b/external/ikvm/runtime/openjdk/java.util.prefs.cs
        new file mode 100644
        index 0000000000..0166e37006
        --- /dev/null
        +++ b/external/ikvm/runtime/openjdk/java.util.prefs.cs
        @@ -0,0 +1,359 @@
        +/*
        +  Copyright (C) 2007-2013 Jeroen Frijters
        +  Copyright (C) 2009 Volker Berlin (i-net software)
        +
        +  This software is provided 'as-is', without any express or implied
        +  warranty.  In no event will the authors be held liable for any damages
        +  arising from the use of this software.
        +
        +  Permission is granted to anyone to use this software for any purpose,
        +  including commercial applications, and to alter it and redistribute it
        +  freely, subject to the following restrictions:
        +
        +  1. The origin of this software must not be misrepresented; you must not
        +     claim that you wrote the original software. If you use this software
        +     in a product, an acknowledgment in the product documentation would be
        +     appreciated but is not required.
        +  2. Altered source versions must be plainly marked as such, and must not be
        +     misrepresented as being the original software.
        +  3. This notice may not be removed or altered from any source distribution.
        +
        +  Jeroen Frijters
        +  jeroen@frijters.net
        +  
        +*/
        +using System;
        +using System.Runtime.InteropServices;
        +using System.Security;
        +using System.Security.Principal;
        +using System.Text;
        +
        +static class Java_java_util_prefs_FileSystemPreferences
        +{
        +	public static int chmod(string filename, int permission)
        +	{
        +		// TODO
        +		return 0;
        +	}
        +
        +	public static int[] lockFile0(string filename, int permission, bool shared)
        +	{
        +		// TODO
        +		return new int[] { 1, 0 };
        +	}
        +
        +	public static int unlockFile0(int fd)
        +	{
        +		// TODO
        +		return 0;
        +	}
        +}
        +
        +static class Java_java_util_prefs_WindowsPreferences
        +{
        +	// HACK we currently support only 16 handles at a time
        +	private static readonly Microsoft.Win32.RegistryKey[] keys = new Microsoft.Win32.RegistryKey[16];
        +
        +	private static Microsoft.Win32.RegistryKey MapKey(int hKey)
        +	{
        +		switch (hKey)
        +		{
        +			case unchecked((int)0x80000001):
        +				return Microsoft.Win32.Registry.CurrentUser;
        +			case unchecked((int)0x80000002):
        +				return Microsoft.Win32.Registry.LocalMachine;
        +			default:
        +				return keys[hKey - 1];
        +		}
        +	}
        +
        +	private static int AllocHandle(Microsoft.Win32.RegistryKey key)
        +	{
        +		lock (keys)
        +		{
        +			if (key != null)
        +			{
        +				for (int i = 0; i < keys.Length; i++)
        +				{
        +					if (keys[i] == null)
        +					{
        +						keys[i] = key;
        +						return i + 1;
        +					}
        +				}
        +			}
        +			return 0;
        +		}
        +	}
        +
        +	private static string BytesToString(byte[] bytes)
        +	{
        +		int len = bytes.Length;
        +		if (bytes[len - 1] == 0)
        +		{
        +			len--;
        +		}
        +		return Encoding.ASCII.GetString(bytes, 0, len);
        +	}
        +
        +	private static byte[] StringToBytes(string str)
        +	{
        +		if (str.Length == 0 || str[str.Length - 1] != 0)
        +		{
        +			str += '\u0000';
        +		}
        +		return Encoding.ASCII.GetBytes(str);
        +	}
        +
        +	public static int[] WindowsRegOpenKey(int hKey, byte[] subKey, int securityMask)
        +	{
        +		// writeable = DELETE == 0x10000 || KEY_SET_VALUE == 2 || KEY_CREATE_SUB_KEY == 4 || KEY_WRITE = 0x20006;
        +		// !writeable : KEY_ENUMERATE_SUB_KEYS == 8 || KEY_READ == 0x20019 || KEY_QUERY_VALUE == 1
        +		bool writable = (securityMask & 0x10006) != 0;
        +		Microsoft.Win32.RegistryKey resultKey = null;
        +		int error = 0;
        +		try
        +		{
        +			Microsoft.Win32.RegistryKey parent = MapKey(hKey);
        +			// HACK we check if we can write in the system preferences 
        +			// we want not user registry virtualization for compatibility
        +			if (writable && parent.Name.StartsWith("HKEY_LOCAL_MACHINE", StringComparison.Ordinal) && UACVirtualization.Enabled)
        +			{
        +				resultKey = parent.OpenSubKey(BytesToString(subKey), false);
        +				if (resultKey != null)
        +				{
        +					// error only if key exists
        +					resultKey.Close();
        +					error = 5;
        +					resultKey = null;
        +				}
        +			}
        +			else
        +			{
        +				resultKey = parent.OpenSubKey(BytesToString(subKey), writable);
        +			}
        +		}
        +		catch (SecurityException)
        +		{
        +			error = 5;
        +		}
        +		catch (UnauthorizedAccessException)
        +		{
        +			error = 5;
        +		}
        +		return new int[] { AllocHandle(resultKey), error };
        +	}
        +
        +	public static int WindowsRegCloseKey(int hKey)
        +	{
        +		keys[hKey - 1].Close();
        +		lock (keys)
        +		{
        +			keys[hKey - 1] = null;
        +		}
        +		return 0;
        +	}
        +
        +	public static int[] WindowsRegCreateKeyEx(int hKey, byte[] subKey)
        +	{
        +		Microsoft.Win32.RegistryKey resultKey = null;
        +		int error = 0;
        +		int disposition = -1;
        +		try
        +		{
        +			Microsoft.Win32.RegistryKey key = MapKey(hKey);
        +			string name = BytesToString(subKey);
        +			resultKey = key.OpenSubKey(name);
        +			disposition = 2;
        +			if (resultKey == null)
        +			{
        +				resultKey = key.CreateSubKey(name);
        +				disposition = 1;
        +			}
        +		}
        +		catch (SecurityException)
        +		{
        +			error = 5;
        +		}
        +		catch (UnauthorizedAccessException)
        +		{
        +			error = 5;
        +		}
        +		return new int[] { AllocHandle(resultKey), error, disposition };
        +	}
        +
        +	public static int WindowsRegDeleteKey(int hKey, byte[] subKey)
        +	{
        +		try
        +		{
        +			MapKey(hKey).DeleteSubKey(BytesToString(subKey), false);
        +			return 0;
        +		}
        +		catch (SecurityException)
        +		{
        +			return 5;
        +		}
        +	}
        +
        +	public static int WindowsRegFlushKey(int hKey)
        +	{
        +		MapKey(hKey).Flush();
        +		return 0;
        +	}
        +
        +	public static byte[] WindowsRegQueryValueEx(int hKey, byte[] valueName)
        +	{
        +		try
        +		{
        +			string value = MapKey(hKey).GetValue(BytesToString(valueName)) as string;
        +			if (value == null)
        +			{
        +				return null;
        +			}
        +			return StringToBytes(value);
        +		}
        +		catch (SecurityException)
        +		{
        +			return null;
        +		}
        +		catch (UnauthorizedAccessException)
        +		{
        +			return null;
        +		}
        +	}
        +
        +	public static int WindowsRegSetValueEx(int hKey, byte[] valueName, byte[] data)
        +	{
        +		if (valueName == null || data == null)
        +		{
        +			return -1;
        +		}
        +		try
        +		{
        +			MapKey(hKey).SetValue(BytesToString(valueName), BytesToString(data));
        +			return 0;
        +		}
        +		catch (SecurityException)
        +		{
        +			return 5;
        +		}
        +		catch (UnauthorizedAccessException)
        +		{
        +			return 5;
        +		}
        +	}
        +
        +	public static int WindowsRegDeleteValue(int hKey, byte[] valueName)
        +	{
        +		try
        +		{
        +			MapKey(hKey).DeleteValue(BytesToString(valueName));
        +			return 0;
        +		}
        +		catch (System.ArgumentException)
        +		{
        +			return 2; //ERROR_FILE_NOT_FOUND
        +		}
        +		catch (SecurityException)
        +		{
        +			return 5; //ERROR_ACCESS_DENIED
        +		}
        +		catch (UnauthorizedAccessException)
        +		{
        +			return 5; //ERROR_ACCESS_DENIED
        +		}
        +	}
        +
        +	public static int[] WindowsRegQueryInfoKey(int hKey)
        +	{
        +		int[] result = new int[5] { -1, -1, -1, -1, -1 };
        +		try
        +		{
        +			Microsoft.Win32.RegistryKey key = MapKey(hKey);
        +			result[0] = key.SubKeyCount;
        +			result[1] = 0;
        +			result[2] = key.ValueCount;
        +			foreach (string s in key.GetSubKeyNames())
        +			{
        +				result[3] = Math.Max(result[3], s.Length);
        +			}
        +			foreach (string s in key.GetValueNames())
        +			{
        +				result[4] = Math.Max(result[4], s.Length);
        +			}
        +		}
        +		catch (SecurityException)
        +		{
        +			result[1] = 5;
        +		}
        +		catch (UnauthorizedAccessException)
        +		{
        +			result[1] = 5;
        +		}
        +		return result;
        +	}
        +
        +	public static byte[] WindowsRegEnumKeyEx(int hKey, int subKeyIndex, int maxKeyLength)
        +	{
        +		try
        +		{
        +			return StringToBytes(MapKey(hKey).GetSubKeyNames()[subKeyIndex]);
        +		}
        +		catch (SecurityException)
        +		{
        +			return null;
        +		}
        +		catch (UnauthorizedAccessException)
        +		{
        +			return null;
        +		}
        +	}
        +
        +	public static byte[] WindowsRegEnumValue(int hKey, int valueIndex, int maxValueNameLength)
        +	{
        +		try
        +		{
        +			return StringToBytes(MapKey(hKey).GetValueNames()[valueIndex]);
        +		}
        +		catch (SecurityException)
        +		{
        +			return null;
        +		}
        +		catch (UnauthorizedAccessException)
        +		{
        +			return null;
        +		}
        +	}
        +}
        +
        +static class UACVirtualization
        +{
        +	private enum TOKEN_INFORMATION_CLASS
        +	{
        +		TokenVirtualizationEnabled = 24
        +	}
        +
        +	[DllImport("advapi32.dll")]
        +	private static extern int GetTokenInformation(
        +		IntPtr TokenHandle,
        +		TOKEN_INFORMATION_CLASS TokenInformationClass,
        +		out int TokenInformation,
        +		int TokenInformationLength,
        +		out int ReturnLength);
        +
        +	internal static bool Enabled
        +	{
        +		[SecuritySafeCritical]
        +		get
        +		{
        +			OperatingSystem os = Environment.OSVersion;
        +			if (os.Platform != PlatformID.Win32NT || os.Version.Major < 6)
        +			{
        +				return false;
        +			}
        +			int enabled, length;
        +			return GetTokenInformation(WindowsIdentity.GetCurrent().Token, TOKEN_INFORMATION_CLASS.TokenVirtualizationEnabled, out enabled, 4, out length) != 0
        +				&& enabled != 0;
        +		}
        +	}
        +}
        diff --git a/external/ikvm/runtime/openjdk/misc.cs b/external/ikvm/runtime/openjdk/misc.cs
        index 368c22de53..396f641319 100644
        --- a/external/ikvm/runtime/openjdk/misc.cs
        +++ b/external/ikvm/runtime/openjdk/misc.cs
        @@ -197,17 +197,6 @@ static class Java_sun_invoke_anon_AnonymousClassLoader
         	}
         }
         
        -static class Java_sun_invoke_util_ValueConversions
        -{
        -	// called from map.xml as a replacement for Class.isInstance() in sun.invoke.util.ValueConversions.castReference()
        -	public static bool Class_isInstance(java.lang.Class clazz, object obj)
        -	{
        -		TypeWrapper tw = TypeWrapper.FromClass(clazz);
        -		// handle the type system hole that is caused by arrays being both derived from cli.System.Array and directly from java.lang.Object
        -		return tw.IsInstance(obj) || (tw == CoreClasses.cli.System.Object.Wrapper && obj is Array);
        -	}
        -}
        -
         static class Java_sun_invoke_util_VerifyAccess
         {
         	// called from map.xml as a replacement for Class.getClassLoader() in sun.invoke.util.VerifyAccess.isTypeVisible()
        @@ -311,6 +300,9 @@ static class Java_sun_security_provider_NativeSeedGenerator
         		{
         			RNGCryptoServiceProvider csp = new RNGCryptoServiceProvider();
         			csp.GetBytes(result);
        +#if NET_4_0
        +			csp.Dispose();
        +#endif
         			return true;
         		}
         		catch (CryptographicException)
        @@ -359,27 +351,22 @@ static class Java_com_sun_java_util_jar_pack_NativeUnpack
         
         static class Java_com_sun_security_auth_module_NTSystem
         {
        -	public static void getCurrent(object thisObj, bool debug)
        +	public static void getCurrent(object thisObj, bool debug, ref string userName, ref string domain, ref string domainSID, ref string userSID, ref string[] groupIDs, ref string primaryGroupID)
         	{
         		WindowsIdentity id = WindowsIdentity.GetCurrent();
         		string[] name = id.Name.Split('\\');
        -		SetField(thisObj, "userName", name[1]);
        -		SetField(thisObj, "domain", name[0]);
        -		SetField(thisObj, "domainSID", id.User.AccountDomainSid.Value);
        -		SetField(thisObj, "userSID", id.User.Value);
        +		userName = name[1];
        +		domain = name[0];
        +		domainSID = id.User.AccountDomainSid.Value;
        +		userSID = id.User.Value;
         		string[] groups = new string[id.Groups.Count];
         		for (int i = 0; i < groups.Length; i++)
         		{
         			groups[i] = id.Groups[i].Value;
         		}
        -		SetField(thisObj, "groupIDs", groups);
        +		groupIDs = groups;
         		// HACK it turns out that Groups[0] is the primary group, but AFAIK this is not documented anywhere
        -		SetField(thisObj, "primaryGroupID", groups[0]);
        -	}
        -
        -	private static void SetField(object thisObj, string field, object value)
        -	{
        -		thisObj.GetType().GetField(field, BindingFlags.NonPublic | BindingFlags.Instance).SetValue(thisObj, value);
        +		primaryGroupID = groups[0];
         	}
         
         	public static long getImpersonationToken0(object thisObj)
        @@ -547,6 +534,7 @@ static class Java_java_awt_SplashScreen
         	public static String _getImageFileName(long splashPtr) { return null; }
         	public static String _getImageJarName(long splashPtr) { return null; }
         	public static bool _setImageData(long splashPtr, byte[] data) { return false; }
        +	public static float _getScaleFactor(long SplashPtr) { return 1; }
         }
         
         static class Java_java_awt_TextArea
        @@ -618,3 +606,30 @@ static class Java_java_awt_image_SampleModel
         {
         	public static void initIDs() { }
         }
        +
        +static class Java_sun_net_ExtendedOptionsImpl
        +{
        +	public static void init()
        +	{
        +	}
        +
        +	public static void setFlowOption(java.io.FileDescriptor fd, object f)
        +	{
        +#if !FIRST_PASS
        +		throw new java.lang.UnsupportedOperationException();
        +#endif
        +	}
        +
        +	public static void getFlowOption(java.io.FileDescriptor fd, object f)
        +	{
        +#if !FIRST_PASS
        +		throw new java.lang.UnsupportedOperationException();
        +#endif
        +	}
        +
        +	public static bool flowSupported()
        +	{
        +		// We don't support this. Solaris only functionality.
        +		return false;
        +	}
        +}
        diff --git a/external/ikvm/runtime/openjdk/sun.misc.cs b/external/ikvm/runtime/openjdk/sun.misc.cs
        index 446da7e7a2..45939f10d3 100644
        --- a/external/ikvm/runtime/openjdk/sun.misc.cs
        +++ b/external/ikvm/runtime/openjdk/sun.misc.cs
        @@ -733,6 +733,24 @@ static class Java_sun_misc_Unsafe
         	}
         }
         
        +static class Java_sun_misc_URLClassPath
        +{
        +	public static java.net.URL[] getLookupCacheURLs(java.lang.ClassLoader loader)
        +	{
        +		return null;
        +	}
        +
        +	public static int[] getLookupCacheForClassLoader(java.lang.ClassLoader loader, string name)
        +	{
        +		return null;
        +	}
        +
        +	public static bool knownToNotExist0(java.lang.ClassLoader loader, string className)
        +	{
        +		return false;
        +	}
        +}
        +
         static class Java_sun_misc_Version
         {
         	public static string getJvmSpecialVersion()
        @@ -803,4 +821,9 @@ static class Java_sun_misc_VMSupport
         	{
         		return props;
         	}
        +
        +	public static string getVMTemporaryDirectory()
        +	{
        +		return System.IO.Path.GetTempPath();
        +	}
         }
        diff --git a/external/ikvm/runtime/openjdk/sun.nio.ch.cs b/external/ikvm/runtime/openjdk/sun.nio.ch.cs
        index 7b5258fa99..06a63da48b 100644
        --- a/external/ikvm/runtime/openjdk/sun.nio.ch.cs
        +++ b/external/ikvm/runtime/openjdk/sun.nio.ch.cs
        @@ -646,6 +646,10 @@ namespace IKVM.NativeCode.sun.nio.ch
         #if FIRST_PASS
         			return 0;
         #else
        +			if (level == global::ikvm.@internal.Winsock.IPPROTO_IPV6 && opt == global::ikvm.@internal.Winsock.IPV6_TCLASS)
        +			{
        +				return 0;
        +			}
         			System.Net.Sockets.SocketOptionLevel sol = (System.Net.Sockets.SocketOptionLevel)level;
         			System.Net.Sockets.SocketOptionName son = (System.Net.Sockets.SocketOptionName)opt;
         			try
        @@ -678,9 +682,13 @@ namespace IKVM.NativeCode.sun.nio.ch
         #endif
         		}
         
        -		public static void setIntOption0(FileDescriptor fd, bool mayNeedConversion, int level, int opt, int arg)
        +		public static void setIntOption0(FileDescriptor fd, bool mayNeedConversion, int level, int opt, int arg, bool isIPv6)
         		{
         #if !FIRST_PASS
        +			if (level == global::ikvm.@internal.Winsock.IPPROTO_IPV6 && opt == global::ikvm.@internal.Winsock.IPV6_TCLASS)
        +			{
        +				return;
        +			}
         			System.Net.Sockets.SocketOptionLevel sol = (System.Net.Sockets.SocketOptionLevel)level;
         			System.Net.Sockets.SocketOptionName son = (System.Net.Sockets.SocketOptionName)opt;
         			if (mayNeedConversion)
        @@ -998,8 +1006,7 @@ namespace IKVM.NativeCode.sun.nio.ch
         			{
         				if (useExclBind)
         				{
        -					// TODO enable this after we merge OpenJDK 7u40
        -					//global::java.net.net_util_md.setExclusiveBind(fd.getSocket());
        +					global::java.net.net_util_md.setExclusiveBind(fd.getSocket());
         				}
         				fd.getSocket().Bind(new System.Net.IPEndPoint(global::java.net.SocketUtil.getAddressFromInetAddress(addr, preferIPv6), port));
         			}
        @@ -1076,6 +1083,44 @@ namespace IKVM.NativeCode.sun.nio.ch
         			{
         				throw new global::java.net.SocketException("Socket is closed");
         			}
        +#endif
        +		}
        +
        +		public static int poll(FileDescriptor fd, int events, long timeout)
        +		{
        +#if FIRST_PASS
        +			return 0;
        +#else
        +			System.Net.Sockets.SelectMode selectMode;
        +			switch (events)
        +			{
        +				case global::sun.nio.ch.Net.POLLCONN:
        +				case global::sun.nio.ch.Net.POLLOUT:
        +					selectMode = System.Net.Sockets.SelectMode.SelectWrite;
        +					break;
        +				case global::sun.nio.ch.Net.POLLIN:
        +					selectMode = System.Net.Sockets.SelectMode.SelectRead;
        +					break;
        +				default:
        +					throw new NotSupportedException();
        +			}
        +			int microSeconds = timeout >= Int32.MaxValue / 1000 ? Int32.MaxValue : (int)(timeout * 1000);
        +			try
        +			{
        +				if (fd.getSocket().Poll(microSeconds, selectMode))
        +				{
        +					return events;
        +				}
        +			}
        +			catch (System.Net.Sockets.SocketException x)
        +			{
        +				throw new global::java.net.SocketException(x.Message);
        +			}
        +			catch (System.ObjectDisposedException)
        +			{
        +				throw new global::java.net.SocketException("Socket is closed");
        +			}
        +			return 0;
         #endif
         		}
         	}
        diff --git a/external/ikvm/runtime/runtime.build b/external/ikvm/runtime/runtime.build
        index 808f06f16a..19efa7470e 100644
        --- a/external/ikvm/runtime/runtime.build
        +++ b/external/ikvm/runtime/runtime.build
        @@ -1,6 +1,6 @@