diff options
author | Miguel de Icaza <miguel@gnome.org> | 2016-02-27 23:38:24 +0300 |
---|---|---|
committer | Miguel de Icaza <miguel@gnome.org> | 2016-02-27 23:38:24 +0300 |
commit | 94d4a298ad560f8674d746dea2d51e26e0a97f2a (patch) | |
tree | ae303637d83843abf98938b07eb9808880cea9fa /openjdk/java | |
parent | c9edfe788667d5777e97e3f2fd195080d06dd32c (diff) |
Remove unused filesmaster-signed
Diffstat (limited to 'openjdk/java')
91 files changed, 0 insertions, 66651 deletions
diff --git a/openjdk/java/awt/Font.java b/openjdk/java/awt/Font.java deleted file mode 100644 index d99c6757..00000000 --- a/openjdk/java/awt/Font.java +++ /dev/null @@ -1,2640 +0,0 @@ -/* - * 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. - */ - -package java.awt; - -import java.awt.font.FontRenderContext; -import java.awt.font.GlyphVector; -import java.awt.font.LineMetrics; -import java.awt.font.TextAttribute; -import java.awt.font.TextLayout; -import java.awt.geom.AffineTransform; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.peer.FontPeer; -import java.io.*; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.SoftReference; -import java.lang.ref.WeakReference; -import java.nio.file.Files; -import java.nio.file.StandardCopyOption; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.text.AttributedCharacterIterator.Attribute; -import java.text.CharacterIterator; -import java.text.StringCharacterIterator; -import java.util.Collections; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import sun.font.StandardGlyphVector; - -import cli.System.IntPtr; -import cli.System.Drawing.FontFamily; -import cli.System.Drawing.GraphicsUnit; -import cli.System.Drawing.Text.PrivateFontCollection; -import cli.System.Runtime.InteropServices.DllImportAttribute; - -import sun.font.AttributeMap; -import sun.font.AttributeValues; -import sun.font.CompositeFont; -import sun.font.CreatedFontTracker; -import sun.font.Font2D; -import sun.font.Font2DHandle; -import sun.font.FontAccess; -import sun.font.FontManager; -import sun.font.FontManagerFactory; -import sun.font.FontUtilities; -import sun.font.GlyphLayout; -import sun.font.FontLineMetrics; -import sun.font.CoreMetrics; -import sun.font.SunFontManager; - -import static sun.font.EAttribute.*; - -/** - * The <code>Font</code> class represents fonts, which are used to - * render text in a visible way. - * A font provides the information needed to map sequences of - * <em>characters</em> to sequences of <em>glyphs</em> - * and to render sequences of glyphs on <code>Graphics</code> and - * <code>Component</code> objects. - * - * <h3>Characters and Glyphs</h3> - * - * A <em>character</em> is a symbol that represents an item such as a letter, - * a digit, or punctuation in an abstract way. For example, <code>'g'</code>, - * LATIN SMALL LETTER G, is a character. - * <p> - * A <em>glyph</em> is a shape used to render a character or a sequence of - * characters. In simple writing systems, such as Latin, typically one glyph - * represents one character. In general, however, characters and glyphs do not - * have one-to-one correspondence. For example, the character 'á' - * LATIN SMALL LETTER A WITH ACUTE, can be represented by - * two glyphs: one for 'a' and one for '´'. On the other hand, the - * two-character string "fi" can be represented by a single glyph, an - * "fi" ligature. In complex writing systems, such as Arabic or the South - * and South-East Asian writing systems, the relationship between characters - * and glyphs can be more complicated and involve context-dependent selection - * of glyphs as well as glyph reordering. - * - * A font encapsulates the collection of glyphs needed to render a selected set - * of characters as well as the tables needed to map sequences of characters to - * corresponding sequences of glyphs. - * - * <h3>Physical and Logical Fonts</h3> - * - * The Java Platform distinguishes between two kinds of fonts: - * <em>physical</em> fonts and <em>logical</em> fonts. - * <p> - * <em>Physical</em> fonts are the actual font libraries containing glyph data - * and tables to map from character sequences to glyph sequences, using a font - * technology such as TrueType or PostScript Type 1. - * All implementations of the Java Platform must support TrueType fonts; - * support for other font technologies is implementation dependent. - * Physical fonts may use names such as Helvetica, Palatino, HonMincho, or - * any number of other font names. - * Typically, each physical font supports only a limited set of writing - * systems, for example, only Latin characters or only Japanese and Basic - * Latin. - * The set of available physical fonts varies between configurations. - * Applications that require specific fonts can bundle them and instantiate - * them using the {@link #createFont createFont} method. - * <p> - * <em>Logical</em> fonts are the five font families defined by the Java - * platform which must be supported by any Java runtime environment: - * Serif, SansSerif, Monospaced, Dialog, and DialogInput. - * These logical fonts are not actual font libraries. Instead, the logical - * font names are mapped to physical fonts by the Java runtime environment. - * The mapping is implementation and usually locale dependent, so the look - * and the metrics provided by them vary. - * Typically, each logical font name maps to several physical fonts in order to - * cover a large range of characters. - * <p> - * Peered AWT components, such as {@link Label Label} and - * {@link TextField TextField}, can only use logical fonts. - * <p> - * For a discussion of the relative advantages and disadvantages of using - * physical or logical fonts, see the - * <a href="http://www.oracle.com/technetwork/java/javase/tech/faq-jsp-138165.html">Internationalization FAQ</a> - * document. - * - * <h3>Font Faces and Names</h3> - * - * A <code>Font</code> - * can have many faces, such as heavy, medium, oblique, gothic and - * regular. All of these faces have similar typographic design. - * <p> - * There are three different names that you can get from a - * <code>Font</code> object. The <em>logical font name</em> is simply the - * name that was used to construct the font. - * The <em>font face name</em>, or just <em>font name</em> for - * short, is the name of a particular font face, like Helvetica Bold. The - * <em>family name</em> is the name of the font family that determines the - * typographic design across several faces, like Helvetica. - * <p> - * The <code>Font</code> class represents an instance of a font face from - * a collection of font faces that are present in the system resources - * of the host system. As examples, Arial Bold and Courier Bold Italic - * are font faces. There can be several <code>Font</code> objects - * associated with a font face, each differing in size, style, transform - * and font features. - * <p> - * The {@link GraphicsEnvironment#getAllFonts() getAllFonts} method - * of the <code>GraphicsEnvironment</code> class returns an - * array of all font faces available in the system. These font faces are - * returned as <code>Font</code> objects with a size of 1, identity - * transform and default font features. These - * base fonts can then be used to derive new <code>Font</code> objects - * with varying sizes, styles, transforms and font features via the - * <code>deriveFont</code> methods in this class. - * - * <h3>Font and TextAttribute</h3> - * - * <p><code>Font</code> supports most - * <code>TextAttribute</code>s. This makes some operations, such as - * rendering underlined text, convenient since it is not - * necessary to explicitly construct a <code>TextLayout</code> object. - * Attributes can be set on a Font by constructing or deriving it - * using a <code>Map</code> of <code>TextAttribute</code> values. - * - * <p>The values of some <code>TextAttributes</code> are not - * serializable, and therefore attempting to serialize an instance of - * <code>Font</code> that has such values will not serialize them. - * This means a Font deserialized from such a stream will not compare - * equal to the original Font that contained the non-serializable - * attributes. This should very rarely pose a problem - * since these attributes are typically used only in special - * circumstances and are unlikely to be serialized. - * - * <ul> - * <li><code>FOREGROUND</code> and <code>BACKGROUND</code> use - * <code>Paint</code> values. The subclass <code>Color</code> is - * serializable, while <code>GradientPaint</code> and - * <code>TexturePaint</code> are not.</li> - * <li><code>CHAR_REPLACEMENT</code> uses - * <code>GraphicAttribute</code> values. The subclasses - * <code>ShapeGraphicAttribute</code> and - * <code>ImageGraphicAttribute</code> are not serializable.</li> - * <li><code>INPUT_METHOD_HIGHLIGHT</code> uses - * <code>InputMethodHighlight</code> values, which are - * not serializable. See {@link java.awt.im.InputMethodHighlight}.</li> - * </ul> - * - * <p>Clients who create custom subclasses of <code>Paint</code> and - * <code>GraphicAttribute</code> can make them serializable and - * avoid this problem. Clients who use input method highlights can - * convert these to the platform-specific attributes for that - * highlight on the current platform and set them on the Font as - * a workaround. - * - * <p>The <code>Map</code>-based constructor and - * <code>deriveFont</code> APIs ignore the FONT attribute, and it is - * not retained by the Font; the static {@link #getFont} method should - * be used if the FONT attribute might be present. See {@link - * java.awt.font.TextAttribute#FONT} for more information.</p> - * - * <p>Several attributes will cause additional rendering overhead - * and potentially invoke layout. If a <code>Font</code> has such - * attributes, the <code>{@link #hasLayoutAttributes()}</code> method - * will return true.</p> - * - * <p>Note: Font rotations can cause text baselines to be rotated. In - * order to account for this (rare) possibility, font APIs are - * specified to return metrics and take parameters 'in - * baseline-relative coordinates'. This maps the 'x' coordinate to - * the advance along the baseline, (positive x is forward along the - * baseline), and the 'y' coordinate to a distance along the - * perpendicular to the baseline at 'x' (positive y is 90 degrees - * clockwise from the baseline vector). APIs for which this is - * especially important are called out as having 'baseline-relative - * coordinates.' - */ -public class Font implements java.io.Serializable -{ - private static class FontAccessImpl extends FontAccess { - public Font2D getFont2D(Font font) { - return font.getFont2D(); - } - - public void setFont2D(Font font, Font2DHandle handle) { - font.font2DHandle = handle; - } - - public void setCreatedFont(Font font) { - font.createdFont = true; - } - - public boolean isCreatedFont(Font font) { - return font.createdFont; - } - } - - static { - FontAccess.setFontAccess(new FontAccessImpl()); - } - - /** - * This is now only used during serialization. Typically - * it is null. - * - * @serial - * @see #getAttributes() - */ - private Hashtable<Object, Object> fRequestedAttributes; - - /* - * Constants to be used for logical font family names. - */ - - /** - * A String constant for the canonical family name of the - * logical font "Dialog". It is useful in Font construction - * to provide compile-time verification of the name. - * @since 1.6 - */ - public static final String DIALOG = "Dialog"; - - /** - * A String constant for the canonical family name of the - * logical font "DialogInput". It is useful in Font construction - * to provide compile-time verification of the name. - * @since 1.6 - */ - public static final String DIALOG_INPUT = "DialogInput"; - - /** - * A String constant for the canonical family name of the - * logical font "SansSerif". It is useful in Font construction - * to provide compile-time verification of the name. - * @since 1.6 - */ - public static final String SANS_SERIF = "SansSerif"; - - /** - * A String constant for the canonical family name of the - * logical font "Serif". It is useful in Font construction - * to provide compile-time verification of the name. - * @since 1.6 - */ - public static final String SERIF = "Serif"; - - /** - * A String constant for the canonical family name of the - * logical font "Monospaced". It is useful in Font construction - * to provide compile-time verification of the name. - * @since 1.6 - */ - public static final String MONOSPACED = "Monospaced"; - - /* - * Constants to be used for styles. Can be combined to mix - * styles. - */ - - /** - * The plain style constant. - */ - public static final int PLAIN = 0; - - /** - * The bold style constant. This can be combined with the other style - * constants (except PLAIN) for mixed styles. - */ - public static final int BOLD = 1; - - /** - * The italicized style constant. This can be combined with the other - * style constants (except PLAIN) for mixed styles. - */ - public static final int ITALIC = 2; - - /** - * The baseline used in most Roman scripts when laying out text. - */ - public static final int ROMAN_BASELINE = 0; - - /** - * The baseline used in ideographic scripts like Chinese, Japanese, - * and Korean when laying out text. - */ - public static final int CENTER_BASELINE = 1; - - /** - * The baseline used in Devanigiri and similar scripts when laying - * out text. - */ - public static final int HANGING_BASELINE = 2; - - /** - * Identify a font resource of type TRUETYPE. - * Used to specify a TrueType font resource to the - * {@link #createFont} method. - * The TrueType format was extended to become the OpenType - * format, which adds support for fonts with Postscript outlines, - * this tag therefore references these fonts, as well as those - * with TrueType outlines. - * @since 1.3 - */ - - public static final int TRUETYPE_FONT = 0; - - /** - * Identify a font resource of type TYPE1. - * Used to specify a Type1 font resource to the - * {@link #createFont} method. - * @since 1.5 - */ - public static final int TYPE1_FONT = 1; - - /** - * The logical name of this <code>Font</code>, as passed to the - * constructor. - * @since JDK1.0 - * - * @serial - * @see #getName - */ - protected String name; - - /** - * The style of this <code>Font</code>, as passed to the constructor. - * This style can be PLAIN, BOLD, ITALIC, or BOLD+ITALIC. - * @since JDK1.0 - * - * @serial - * @see #getStyle() - */ - protected int style; - - /** - * The point size of this <code>Font</code>, rounded to integer. - * @since JDK1.0 - * - * @serial - * @see #getSize() - */ - protected int size; - - /** - * The point size of this <code>Font</code> in <code>float</code>. - * - * @serial - * @see #getSize() - * @see #getSize2D() - */ - protected float pointSize; - - /** - * The platform specific font information. - */ - private transient FontPeer peer; - private transient cli.System.Drawing.Font netFont; - private transient Font2DHandle font2DHandle; - - private transient AttributeValues values; - private transient boolean hasLayoutAttributes; - - /* - * If the origin of a Font is a created font then this attribute - * must be set on all derived fonts too. - */ - private transient boolean createdFont = false; - - /* - * This is true if the font transform is not identity. It - * is used to avoid unnecessary instantiation of an AffineTransform. - */ - private transient boolean nonIdentityTx; - - /* - * A cached value used when a transform is required for internal - * use. This must not be exposed to callers since AffineTransform - * is mutable. - */ - private static final AffineTransform identityTx = new AffineTransform(); - - /* - * JDK 1.1 serialVersionUID - */ - private static final long serialVersionUID = -4206021311591459213L; - - /** - * Gets the peer of this <code>Font</code>. - * @return the peer of the <code>Font</code>. - * @since JDK1.1 - * @deprecated Font rendering is now platform independent. - */ - @Deprecated - public FontPeer getPeer(){ - return getPeer_NoClientCode(); - } - // NOTE: This method is called by privileged threads. - // We implement this functionality in a package-private method - // to insure that it cannot be overridden by client subclasses. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - @SuppressWarnings("deprecation") - final FontPeer getPeer_NoClientCode() { - if(peer == null) { - Toolkit tk = Toolkit.getDefaultToolkit(); - this.peer = tk.getFontPeer(name, style); - } - return peer; - } - - /** - * Return the AttributeValues object associated with this - * font. Most of the time, the internal object is null. - * If required, it will be created from the 'standard' - * state on the font. Only non-default values will be - * set in the AttributeValues object. - * - * <p>Since the AttributeValues object is mutable, and it - * is cached in the font, care must be taken to ensure that - * it is not mutated. - */ - private AttributeValues getAttributeValues() { - if (values == null) { - AttributeValues valuesTmp = new AttributeValues(); - valuesTmp.setFamily(name); - valuesTmp.setSize(pointSize); // expects the float value. - - if ((style & BOLD) != 0) { - valuesTmp.setWeight(2); // WEIGHT_BOLD - } - - if ((style & ITALIC) != 0) { - valuesTmp.setPosture(.2f); // POSTURE_OBLIQUE - } - valuesTmp.defineAll(PRIMARY_MASK); // for streaming compatibility - values = valuesTmp; - } - - return values; - } - - private Font2D getFont2D() { - FontManager fm = FontManagerFactory.getInstance(); - if (fm.usingPerAppContextComposites() && - font2DHandle != null && - font2DHandle.font2D instanceof CompositeFont && - ((CompositeFont)(font2DHandle.font2D)).isStdComposite()) { - return fm.findFont2D(name, style, - FontManager.LOGICAL_FALLBACK); - } else if (font2DHandle == null) { - font2DHandle = - fm.findFont2D(name, style, - FontManager.LOGICAL_FALLBACK).handle; - } - /* Do not cache the de-referenced font2D. It must be explicitly - * de-referenced to pick up a valid font in the event that the - * original one is marked invalid - */ - return font2DHandle.font2D; - } - - @cli.IKVM.Attributes.HideFromJavaAttribute.Annotation - public cli.System.Drawing.Font getNetFont(){ - if(netFont == null){ - netFont = getFont2D().createNetFont(this); - } - return netFont; - } - /** - * Creates a new <code>Font</code> from the specified name, style and - * point size. - * <p> - * The font name can be a font face name or a font family name. - * It is used together with the style to find an appropriate font face. - * When a font family name is specified, the style argument is used to - * select the most appropriate face from the family. When a font face - * name is specified, the face's style and the style argument are - * merged to locate the best matching font from the same family. - * For example if face name "Arial Bold" is specified with style - * <code>Font.ITALIC</code>, the font system looks for a face in the - * "Arial" family that is bold and italic, and may associate the font - * instance with the physical font face "Arial Bold Italic". - * The style argument is merged with the specified face's style, not - * added or subtracted. - * This means, specifying a bold face and a bold style does not - * double-embolden the font, and specifying a bold face and a plain - * style does not lighten the font. - * <p> - * If no face for the requested style can be found, the font system - * may apply algorithmic styling to achieve the desired style. - * For example, if <code>ITALIC</code> is requested, but no italic - * face is available, glyphs from the plain face may be algorithmically - * obliqued (slanted). - * <p> - * Font name lookup is case insensitive, using the case folding - * rules of the US locale. - * <p> - * If the <code>name</code> parameter represents something other than a - * logical font, i.e. is interpreted as a physical font face or family, and - * this cannot be mapped by the implementation to a physical font or a - * compatible alternative, then the font system will map the Font - * instance to "Dialog", such that for example, the family as reported - * by {@link #getFamily() getFamily} will be "Dialog". - * <p> - * - * @param name the font name. This can be a font face name or a font - * family name, and may represent either a logical font or a physical - * font found in this {@code GraphicsEnvironment}. - * The family names for logical fonts are: Dialog, DialogInput, - * Monospaced, Serif, or SansSerif. Pre-defined String constants exist - * for all of these names, for example, {@code DIALOG}. If {@code name} is - * {@code null}, the <em>logical font name</em> of the new - * {@code Font} as returned by {@code getName()} is set to - * the name "Default". - * @param style the style constant for the {@code Font} - * The style argument is an integer bitmask that may - * be {@code PLAIN}, or a bitwise union of {@code BOLD} and/or - * {@code ITALIC} (for example, {@code ITALIC} or {@code BOLD|ITALIC}). - * If the style argument does not conform to one of the expected - * integer bitmasks then the style is set to {@code PLAIN}. - * @param size the point size of the {@code Font} - * @see GraphicsEnvironment#getAllFonts - * @see GraphicsEnvironment#getAvailableFontFamilyNames - * @since JDK1.0 - */ - public Font(String name, int style, int size) { - this.name = (name != null) ? name : "Default"; - this.style = (style & ~0x03) == 0 ? style : 0; - this.size = size; - this.pointSize = size; - } - - private Font(String name, int style, float sizePts) { - this.name = (name != null) ? name : "Default"; - this.style = (style & ~0x03) == 0 ? style : 0; - this.size = (int)(sizePts + 0.5); - this.pointSize = sizePts; - } - - /* This constructor is used by deriveFont when attributes is null */ - private Font(String name, int style, float sizePts, - boolean created, Font2DHandle handle) { - this(name, style, sizePts); - this.createdFont = created; - /* Fonts created from a stream will use the same font2D instance - * as the parent. - * One exception is that if the derived font is requested to be - * in a different style, then also check if its a CompositeFont - * and if so build a new CompositeFont from components of that style. - * CompositeFonts can only be marked as "created" if they are used - * to add fall backs to a physical font. And non-composites are - * always from "Font.createFont()" and shouldn't get this treatment. - */ - if (created) { - if (handle.font2D instanceof CompositeFont && - handle.font2D.getStyle() != style) { - FontManager fm = FontManagerFactory.getInstance(); - this.font2DHandle = fm.getNewComposite(null, style, handle); - } else { - this.font2DHandle = handle; - } - } - } - - /* This constructor is used when one font is derived from another. - * Fonts created from a stream will use the same font2D instance as the - * parent. They can be distinguished because the "created" argument - * will be "true". Since there is no way to recreate these fonts they - * need to have the handle to the underlying font2D passed in. - * "created" is also true when a special composite is referenced by the - * handle for essentially the same reasons. - * But when deriving a font in these cases two particular attributes - * need special attention: family/face and style. - * The "composites" in these cases need to be recreated with optimal - * fonts for the new values of family and style. - * For fonts created with createFont() these are treated differently. - * JDK can often synthesise a different style (bold from plain - * for example). For fonts created with "createFont" this is a reasonable - * solution but its also possible (although rare) to derive a font with a - * different family attribute. In this case JDK needs - * to break the tie with the original Font2D and find a new Font. - * The oldName and oldStyle are supplied so they can be compared with - * what the Font2D and the values. To speed things along : - * oldName == null will be interpreted as the name is unchanged. - * oldStyle = -1 will be interpreted as the style is unchanged. - * In these cases there is no need to interrogate "values". - */ - private Font(AttributeValues values, String oldName, int oldStyle, - boolean created, Font2DHandle handle) { - - this.createdFont = created; - if (created) { - this.font2DHandle = handle; - - String newName = null; - if (oldName != null) { - newName = values.getFamily(); - if (oldName.equals(newName)) newName = null; - } - int newStyle = 0; - if (oldStyle == -1) { - newStyle = -1; - } else { - if (values.getWeight() >= 2f) newStyle = BOLD; - if (values.getPosture() >= .2f) newStyle |= ITALIC; - if (oldStyle == newStyle) newStyle = -1; - } - if (handle.font2D instanceof CompositeFont) { - if (newStyle != -1 || newName != null) { - FontManager fm = FontManagerFactory.getInstance(); - this.font2DHandle = - fm.getNewComposite(newName, newStyle, handle); - } - } else if (newName != null) { - this.createdFont = false; - this.font2DHandle = null; - } - } - initFromValues(values); - } - - /** - * Creates a new <code>Font</code> with the specified attributes. - * Only keys defined in {@link java.awt.font.TextAttribute TextAttribute} - * are recognized. In addition the FONT attribute is - * not recognized by this constructor - * (see {@link #getAvailableAttributes}). Only attributes that have - * values of valid types will affect the new <code>Font</code>. - * <p> - * If <code>attributes</code> is <code>null</code>, a new - * <code>Font</code> is initialized with default values. - * @see java.awt.font.TextAttribute - * @param attributes the attributes to assign to the new - * <code>Font</code>, or <code>null</code> - */ - public Font(Map<? extends Attribute, ?> attributes) { - initFromValues(AttributeValues.fromMap(attributes, RECOGNIZED_MASK)); - } - - /** - * Creates a new <code>Font</code> from the specified <code>font</code>. - * This constructor is intended for use by subclasses. - * @param font from which to create this <code>Font</code>. - * @throws NullPointerException if <code>font</code> is null - * @since 1.6 - */ - protected Font(Font font) { - if (font.values != null) { - initFromValues(font.getAttributeValues().clone()); - } else { - this.name = font.name; - this.style = font.style; - this.size = font.size; - this.pointSize = font.pointSize; - } - this.font2DHandle = font.font2DHandle; - this.createdFont = font.createdFont; - } - - /** - * Font recognizes all attributes except FONT. - */ - private static final int RECOGNIZED_MASK = AttributeValues.MASK_ALL - & ~AttributeValues.getMask(EFONT); - - /** - * These attributes are considered primary by the FONT attribute. - */ - private static final int PRIMARY_MASK = - AttributeValues.getMask(EFAMILY, EWEIGHT, EWIDTH, EPOSTURE, ESIZE, - ETRANSFORM, ESUPERSCRIPT, ETRACKING); - - /** - * These attributes are considered secondary by the FONT attribute. - */ - private static final int SECONDARY_MASK = - RECOGNIZED_MASK & ~PRIMARY_MASK; - - /** - * These attributes are handled by layout. - */ - private static final int LAYOUT_MASK = - AttributeValues.getMask(ECHAR_REPLACEMENT, EFOREGROUND, EBACKGROUND, - EUNDERLINE, ESTRIKETHROUGH, ERUN_DIRECTION, - EBIDI_EMBEDDING, EJUSTIFICATION, - EINPUT_METHOD_HIGHLIGHT, EINPUT_METHOD_UNDERLINE, - ESWAP_COLORS, ENUMERIC_SHAPING, EKERNING, - ELIGATURES, ETRACKING, ESUPERSCRIPT); - - private static final int EXTRA_MASK = - AttributeValues.getMask(ETRANSFORM, ESUPERSCRIPT, EWIDTH); - - /** - * Initialize the standard Font fields from the values object. - */ - private void initFromValues(AttributeValues values) { - this.values = values; - values.defineAll(PRIMARY_MASK); // for 1.5 streaming compatibility - - this.name = values.getFamily(); - this.pointSize = values.getSize(); - this.size = (int)(values.getSize() + 0.5); - if (values.getWeight() >= 2f) this.style |= BOLD; // not == 2f - if (values.getPosture() >= .2f) this.style |= ITALIC; // not == .2f - - this.nonIdentityTx = values.anyNonDefault(EXTRA_MASK); - this.hasLayoutAttributes = values.anyNonDefault(LAYOUT_MASK); - } - - /** - * Returns a <code>Font</code> appropriate to the attributes. - * If <code>attributes</code>contains a <code>FONT</code> attribute - * with a valid <code>Font</code> as its value, it will be - * merged with any remaining attributes. See - * {@link java.awt.font.TextAttribute#FONT} for more - * information. - * - * @param attributes the attributes to assign to the new - * <code>Font</code> - * @return a new <code>Font</code> created with the specified - * attributes - * @throws NullPointerException if <code>attributes</code> is null. - * @since 1.2 - * @see java.awt.font.TextAttribute - */ - public static Font getFont(Map<? extends Attribute, ?> attributes) { - // optimize for two cases: - // 1) FONT attribute, and nothing else - // 2) attributes, but no FONT - - // avoid turning the attributemap into a regular map for no reason - if (attributes instanceof AttributeMap && - ((AttributeMap)attributes).getValues() != null) { - AttributeValues values = ((AttributeMap)attributes).getValues(); - if (values.isNonDefault(EFONT)) { - Font font = values.getFont(); - if (!values.anyDefined(SECONDARY_MASK)) { - return font; - } - // merge - values = font.getAttributeValues().clone(); - values.merge(attributes, SECONDARY_MASK); - return new Font(values, font.name, font.style, - font.createdFont, font.font2DHandle); - } - return new Font(attributes); - } - - Font font = (Font)attributes.get(TextAttribute.FONT); - if (font != null) { - if (attributes.size() > 1) { // oh well, check for anything else - AttributeValues values = font.getAttributeValues().clone(); - values.merge(attributes, SECONDARY_MASK); - return new Font(values, font.name, font.style, - font.createdFont, font.font2DHandle); - } - - return font; - } - - return new Font(attributes); - } - - private static class FontFamilyReference extends WeakReference<FontFamily> { - - private static final ReferenceQueue<FontFamily> fontFamilyQueue = new ReferenceQueue<>(); - private static final Set<FontFamilyReference> refs = Collections.synchronizedSet( new HashSet<FontFamilyReference>() ); - static { - sun.misc.SharedSecrets.getJavaLangAccess().registerShutdownHook( 5, // Shutdown hook invocation order - true, // register even if shutdown in progress - new Runnable() { - public void run() { - for( FontFamilyReference ref : refs ) { - ref.delete( false ); - } - } - } ); - } - private File fontFile; - - private FontFamilyReference( FontFamily family, File fontFile ) { - super( family, fontFamilyQueue ); - this.fontFile = fontFile; - refs.add( this ); - - do { - FontFamilyReference ref = (FontFamilyReference)fontFamilyQueue.poll(); - if( ref == null ) { - break; - } - ref.delete( true ); - } while(true); - } - - private void delete( boolean isQueue ) { - FontFamily family = get(); - if( family != null ) { - family.Dispose(); - } - - if( fontFile.delete() && isQueue) { - refs.remove( this ); - } - } - } - - /** - * Returns a new <code>Font</code> using the specified font type - * and input data. The new <code>Font</code> is - * created with a point size of 1 and style {@link #PLAIN PLAIN}. - * This base font can then be used with the <code>deriveFont</code> - * methods in this class to derive new <code>Font</code> objects with - * varying sizes, styles, transforms and font features. This - * method does not close the {@link InputStream}. - * <p> - * To make the <code>Font</code> available to Font constructors the - * returned <code>Font</code> must be registered in the - * <code>GraphicsEnviroment</code> by calling - * {@link GraphicsEnvironment#registerFont(Font) registerFont(Font)}. - * @param fontFormat the type of the <code>Font</code>, which is - * {@link #TRUETYPE_FONT TRUETYPE_FONT} if a TrueType resource is specified. - * or {@link #TYPE1_FONT TYPE1_FONT} if a Type 1 resource is specified. - * @param fontStream an <code>InputStream</code> object representing the - * input data for the font. - * @return a new <code>Font</code> created with the specified font type. - * @throws IllegalArgumentException if <code>fontFormat</code> is not - * <code>TRUETYPE_FONT</code>or<code>TYPE1_FONT</code>. - * @throws FontFormatException if the <code>fontStream</code> data does - * not contain the required font tables for the specified format. - * @throws IOException if the <code>fontStream</code> - * cannot be completely read. - * @see GraphicsEnvironment#registerFont(Font) - * @since 1.3 - */ - public static Font createFont(int fontFormat, InputStream fontStream) - throws java.awt.FontFormatException, java.io.IOException { - - if (fontFormat != Font.TRUETYPE_FONT && - fontFormat != Font.TYPE1_FONT) { - throw new IllegalArgumentException ("font format not recognized"); - } - - File fontFile; - try { - fontFile = AccessController.doPrivileged( - new PrivilegedExceptionAction<File>() { - public File run() throws IOException { - return Files.createTempFile("+~JF", ".tmp").toFile(); - } - } - ); - } catch( PrivilegedActionException ex ) { - throw (IOException)ex.getException(); - } - Files.copy( fontStream, fontFile.toPath(), StandardCopyOption.REPLACE_EXISTING ); - - // create a private Font Collection and add the font data - PrivateFontCollection pfc = new PrivateFontCollection(); - try { - String fileName = fontFile.getPath(); - pfc.AddFontFile( fileName ); - RemoveFontResourceEx( fileName ); // hack for bug http://stackoverflow.com/questions/26671026/how-to-delete-the-file-of-a-privatefontcollection-addfontfile - if (false) throw new cli.System.IO.FileNotFoundException(); - } catch( cli.System.IO.FileNotFoundException x ) { - FontFormatException ffe = new FontFormatException(x.getMessage()); - ffe.initCause(x); - fontFile.delete(); - throw ffe; - } - - FontFamily family = pfc.get_Families()[0]; - new FontFamilyReference( family, fontFile ); - - // create the font object - Font2D font2D = SunFontManager.createFont2D( family, 0 ); - Font2DHandle font2DHandle = font2D.handle; - Font font = new Font( font2D.getFontName( Locale.getDefault() ), PLAIN, 1, true, font2DHandle ); - return font; - } - - @DllImportAttribute.Annotation(value="gdi32") - private static native int RemoveFontResourceEx(String filename, int fl, IntPtr pdv); - - @cli.System.Security.SecuritySafeCriticalAttribute.Annotation - private static void RemoveFontResourceEx(String filename) { - if( ikvm.internal.Util.WINDOWS ) { - RemoveFontResourceEx( filename, 16, IntPtr.Zero ); - } - } - - /** - * Returns a new <code>Font</code> using the specified font type - * and the specified font file. The new <code>Font</code> is - * created with a point size of 1 and style {@link #PLAIN PLAIN}. - * This base font can then be used with the <code>deriveFont</code> - * methods in this class to derive new <code>Font</code> objects with - * varying sizes, styles, transforms and font features. - * @param fontFormat the type of the <code>Font</code>, which is - * {@link #TRUETYPE_FONT TRUETYPE_FONT} if a TrueType resource is - * specified or {@link #TYPE1_FONT TYPE1_FONT} if a Type 1 resource is - * specified. - * So long as the returned font, or its derived fonts are referenced - * the implementation may continue to access <code>fontFile</code> - * to retrieve font data. Thus the results are undefined if the file - * is changed, or becomes inaccessible. - * <p> - * To make the <code>Font</code> available to Font constructors the - * returned <code>Font</code> must be registered in the - * <code>GraphicsEnviroment</code> by calling - * {@link GraphicsEnvironment#registerFont(Font) registerFont(Font)}. - * @param fontFile a <code>File</code> object representing the - * input data for the font. - * @return a new <code>Font</code> created with the specified font type. - * @throws IllegalArgumentException if <code>fontFormat</code> is not - * <code>TRUETYPE_FONT</code>or<code>TYPE1_FONT</code>. - * @throws NullPointerException if <code>fontFile</code> is null. - * @throws IOException if the <code>fontFile</code> cannot be read. - * @throws FontFormatException if <code>fontFile</code> does - * not contain the required font tables for the specified format. - * @throws SecurityException if the executing code does not have - * permission to read from the file. - * @see GraphicsEnvironment#registerFont(Font) - * @since 1.5 - */ - public static Font createFont(int fontFormat, File fontFile) - throws java.awt.FontFormatException, java.io.IOException { - - fontFile = new File(fontFile.getPath()); - - if (fontFormat != Font.TRUETYPE_FONT && - fontFormat != Font.TYPE1_FONT) { - throw new IllegalArgumentException ("font format not recognized"); - } - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - FilePermission filePermission = - new FilePermission(fontFile.getPath(), "read"); - sm.checkPermission(filePermission); - } - if (!fontFile.canRead()) { - throw new IOException("Can't read " + fontFile); - } - // create a private Font Collection and add the font data - PrivateFontCollection pfc = new PrivateFontCollection(); - try { - String fileName = fontFile.getPath(); - pfc.AddFontFile( fileName ); - RemoveFontResourceEx( fileName );// hack for bug http://stackoverflow.com/questions/26671026/how-to-delete-the-file-of-a-privatefontcollection-addfontfile - if (false) throw new cli.System.IO.FileNotFoundException(); - } catch( cli.System.IO.FileNotFoundException fnfe ) { - FileNotFoundException ex = new FileNotFoundException(fnfe.getMessage()); - ex.initCause( fnfe ); - throw ex; - } - // create the font object - Font2D font2D = SunFontManager.createFont2D( pfc.get_Families()[0], 0 ); - Font2DHandle font2DHandle = font2D.handle; - Font font = new Font( font2D.getFontName( Locale.getDefault() ), PLAIN, 1, true, font2DHandle ); - return font; - } - - /** - * Returns a copy of the transform associated with this - * <code>Font</code>. This transform is not necessarily the one - * used to construct the font. If the font has algorithmic - * superscripting or width adjustment, this will be incorporated - * into the returned <code>AffineTransform</code>. - * <p> - * Typically, fonts will not be transformed. Clients generally - * should call {@link #isTransformed} first, and only call this - * method if <code>isTransformed</code> returns true. - * - * @return an {@link AffineTransform} object representing the - * transform attribute of this <code>Font</code> object. - */ - public AffineTransform getTransform() { - /* The most common case is the identity transform. Most callers - * should call isTransformed() first, to decide if they need to - * get the transform, but some may not. Here we check to see - * if we have a nonidentity transform, and only do the work to - * fetch and/or compute it if so, otherwise we return a new - * identity transform. - * - * Note that the transform is _not_ necessarily the same as - * the transform passed in as an Attribute in a Map, as the - * transform returned will also reflect the effects of WIDTH and - * SUPERSCRIPT attributes. Clients who want the actual transform - * need to call getRequestedAttributes. - */ - if (nonIdentityTx) { - AttributeValues values = getAttributeValues(); - - AffineTransform at = values.isNonDefault(ETRANSFORM) - ? new AffineTransform(values.getTransform()) - : new AffineTransform(); - - if (values.getSuperscript() != 0) { - // can't get ascent and descent here, recursive call to this fn, - // so use pointsize - // let users combine super- and sub-scripting - - int superscript = values.getSuperscript(); - - double trans = 0; - int n = 0; - boolean up = superscript > 0; - int sign = up ? -1 : 1; - int ss = up ? superscript : -superscript; - - while ((ss & 7) > n) { - int newn = ss & 7; - trans += sign * (ssinfo[newn] - ssinfo[n]); - ss >>= 3; - sign = -sign; - n = newn; - } - trans *= pointSize; - double scale = Math.pow(2./3., n); - - at.preConcatenate(AffineTransform.getTranslateInstance(0, trans)); - at.scale(scale, scale); - - // note on placement and italics - // We preconcatenate the transform because we don't want to translate along - // the italic angle, but purely perpendicular to the baseline. While this - // looks ok for superscripts, it can lead subscripts to stack on each other - // and bring the following text too close. The way we deal with potential - // collisions that can occur in the case of italics is by adjusting the - // horizontal spacing of the adjacent glyphvectors. Examine the italic - // angle of both vectors, if one is non-zero, compute the minimum ascent - // and descent, and then the x position at each for each vector along its - // italic angle starting from its (offset) baseline. Compute the difference - // between the x positions and use the maximum difference to adjust the - // position of the right gv. - } - - if (values.isNonDefault(EWIDTH)) { - at.scale(values.getWidth(), 1f); - } - - return at; - } - - return new AffineTransform(); - } - - // x = r^0 + r^1 + r^2... r^n - // rx = r^1 + r^2 + r^3... r^(n+1) - // x - rx = r^0 - r^(n+1) - // x (1 - r) = r^0 - r^(n+1) - // x = (r^0 - r^(n+1)) / (1 - r) - // x = (1 - r^(n+1)) / (1 - r) - - // scale ratio is 2/3 - // trans = 1/2 of ascent * x - // assume ascent is 3/4 of point size - - private static final float[] ssinfo = { - 0.0f, - 0.375f, - 0.625f, - 0.7916667f, - 0.9027778f, - 0.9768519f, - 1.0262346f, - 1.0591564f, - }; - - /** - * Returns the family name of this <code>Font</code>. - * - * <p>The family name of a font is font specific. Two fonts such as - * Helvetica Italic and Helvetica Bold have the same family name, - * <i>Helvetica</i>, whereas their font face names are - * <i>Helvetica Bold</i> and <i>Helvetica Italic</i>. The list of - * available family names may be obtained by using the - * {@link GraphicsEnvironment#getAvailableFontFamilyNames()} method. - * - * <p>Use <code>getName</code> to get the logical name of the font. - * Use <code>getFontName</code> to get the font face name of the font. - * @return a <code>String</code> that is the family name of this - * <code>Font</code>. - * - * @see #getName - * @see #getFontName - * @since JDK1.1 - */ - public String getFamily() { - return getFamily_NoClientCode(); - } - // NOTE: This method is called by privileged threads. - // We implement this functionality in a package-private - // method to insure that it cannot be overridden by client - // subclasses. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - final String getFamily_NoClientCode() { - return getFamily(Locale.getDefault()); - } - - /** - * Returns the family name of this <code>Font</code>, localized for - * the specified locale. - * - * <p>The family name of a font is font specific. Two fonts such as - * Helvetica Italic and Helvetica Bold have the same family name, - * <i>Helvetica</i>, whereas their font face names are - * <i>Helvetica Bold</i> and <i>Helvetica Italic</i>. The list of - * available family names may be obtained by using the - * {@link GraphicsEnvironment#getAvailableFontFamilyNames()} method. - * - * <p>Use <code>getFontName</code> to get the font face name of the font. - * @param l locale for which to get the family name - * @return a <code>String</code> representing the family name of the - * font, localized for the specified locale. - * @see #getFontName - * @see java.util.Locale - * @since 1.2 - */ - public String getFamily(Locale l) { - if (l == null) { - throw new NullPointerException("null locale doesn't mean default"); - } - return getFont2D().getFamilyName(l); - } - - /** - * Returns the postscript name of this <code>Font</code>. - * Use <code>getFamily</code> to get the family name of the font. - * Use <code>getFontName</code> to get the font face name of the font. - * @return a <code>String</code> representing the postscript name of - * this <code>Font</code>. - * @since 1.2 - */ - public String getPSName() { - return getFont2D().getPostscriptName(); - } - - /** - * Returns the logical name of this <code>Font</code>. - * Use <code>getFamily</code> to get the family name of the font. - * Use <code>getFontName</code> to get the font face name of the font. - * @return a <code>String</code> representing the logical name of - * this <code>Font</code>. - * @see #getFamily - * @see #getFontName - * @since JDK1.0 - */ - public String getName() { - return name; - } - - /** - * Returns the font face name of this <code>Font</code>. For example, - * Helvetica Bold could be returned as a font face name. - * Use <code>getFamily</code> to get the family name of the font. - * Use <code>getName</code> to get the logical name of the font. - * @return a <code>String</code> representing the font face name of - * this <code>Font</code>. - * @see #getFamily - * @see #getName - * @since 1.2 - */ - public String getFontName() { - return getFontName(Locale.getDefault()); - } - - /** - * Returns the font face name of the <code>Font</code>, localized - * for the specified locale. For example, Helvetica Fett could be - * returned as the font face name. - * Use <code>getFamily</code> to get the family name of the font. - * @param l a locale for which to get the font face name - * @return a <code>String</code> representing the font face name, - * localized for the specified locale. - * @see #getFamily - * @see java.util.Locale - */ - public String getFontName(Locale l) { - if (l == null) { - throw new NullPointerException("null locale doesn't mean default"); - } - return getFont2D().getFontName(l); - } - - /** - * Returns the style of this <code>Font</code>. The style can be - * PLAIN, BOLD, ITALIC, or BOLD+ITALIC. - * @return the style of this <code>Font</code> - * @see #isPlain - * @see #isBold - * @see #isItalic - * @since JDK1.0 - */ - public int getStyle() { - return style; - } - - /** - * Returns the point size of this <code>Font</code>, rounded to - * an integer. - * Most users are familiar with the idea of using <i>point size</i> to - * specify the size of glyphs in a font. This point size defines a - * measurement between the baseline of one line to the baseline of the - * following line in a single spaced text document. The point size is - * based on <i>typographic points</i>, approximately 1/72 of an inch. - * <p> - * The Java(tm)2D API adopts the convention that one point is - * equivalent to one unit in user coordinates. When using a - * normalized transform for converting user space coordinates to - * device space coordinates 72 user - * space units equal 1 inch in device space. In this case one point - * is 1/72 of an inch. - * @return the point size of this <code>Font</code> in 1/72 of an - * inch units. - * @see #getSize2D - * @see GraphicsConfiguration#getDefaultTransform - * @see GraphicsConfiguration#getNormalizingTransform - * @since JDK1.0 - */ - public int getSize() { - return size; - } - - /** - * Returns the point size of this <code>Font</code> in - * <code>float</code> value. - * @return the point size of this <code>Font</code> as a - * <code>float</code> value. - * @see #getSize - * @since 1.2 - */ - public float getSize2D() { - return pointSize; - } - - /** - * Indicates whether or not this <code>Font</code> object's style is - * PLAIN. - * @return <code>true</code> if this <code>Font</code> has a - * PLAIN style; - * <code>false</code> otherwise. - * @see java.awt.Font#getStyle - * @since JDK1.0 - */ - public boolean isPlain() { - return style == 0; - } - - /** - * Indicates whether or not this <code>Font</code> object's style is - * BOLD. - * @return <code>true</code> if this <code>Font</code> object's - * style is BOLD; - * <code>false</code> otherwise. - * @see java.awt.Font#getStyle - * @since JDK1.0 - */ - public boolean isBold() { - return (style & BOLD) != 0; - } - - /** - * Indicates whether or not this <code>Font</code> object's style is - * ITALIC. - * @return <code>true</code> if this <code>Font</code> object's - * style is ITALIC; - * <code>false</code> otherwise. - * @see java.awt.Font#getStyle - * @since JDK1.0 - */ - public boolean isItalic() { - return (style & ITALIC) != 0; - } - - /** - * Indicates whether or not this <code>Font</code> object has a - * transform that affects its size in addition to the Size - * attribute. - * @return <code>true</code> if this <code>Font</code> object - * has a non-identity AffineTransform attribute. - * <code>false</code> otherwise. - * @see java.awt.Font#getTransform - * @since 1.4 - */ - public boolean isTransformed() { - return nonIdentityTx; - } - - /** - * Return true if this Font contains attributes that require extra - * layout processing. - * @return true if the font has layout attributes - * @since 1.6 - */ - public boolean hasLayoutAttributes() { - return hasLayoutAttributes; - } - - /** - * Returns a <code>Font</code> object from the system properties list. - * <code>nm</code> is treated as the name of a system property to be - * obtained. The <code>String</code> value of this property is then - * interpreted as a <code>Font</code> object according to the - * specification of <code>Font.decode(String)</code> - * If the specified property is not found, or the executing code does - * not have permission to read the property, null is returned instead. - * - * @param nm the property name - * @return a <code>Font</code> object that the property name - * describes, or null if no such property exists. - * @throws NullPointerException if nm is null. - * @since 1.2 - * @see #decode(String) - */ - public static Font getFont(String nm) { - return getFont(nm, null); - } - - /** - * Returns the <code>Font</code> that the <code>str</code> - * argument describes. - * To ensure that this method returns the desired Font, - * format the <code>str</code> parameter in - * one of these ways - * - * <ul> - * <li><em>fontname-style-pointsize</em> - * <li><em>fontname-pointsize</em> - * <li><em>fontname-style</em> - * <li><em>fontname</em> - * <li><em>fontname style pointsize</em> - * <li><em>fontname pointsize</em> - * <li><em>fontname style</em> - * <li><em>fontname</em> - * </ul> - * in which <i>style</i> is one of the four - * case-insensitive strings: - * <code>"PLAIN"</code>, <code>"BOLD"</code>, <code>"BOLDITALIC"</code>, or - * <code>"ITALIC"</code>, and pointsize is a positive decimal integer - * representation of the point size. - * For example, if you want a font that is Arial, bold, with - * a point size of 18, you would call this method with: - * "Arial-BOLD-18". - * This is equivalent to calling the Font constructor : - * <code>new Font("Arial", Font.BOLD, 18);</code> - * and the values are interpreted as specified by that constructor. - * <p> - * A valid trailing decimal field is always interpreted as the pointsize. - * Therefore a fontname containing a trailing decimal value should not - * be used in the fontname only form. - * <p> - * If a style name field is not one of the valid style strings, it is - * interpreted as part of the font name, and the default style is used. - * <p> - * Only one of ' ' or '-' may be used to separate fields in the input. - * The identified separator is the one closest to the end of the string - * which separates a valid pointsize, or a valid style name from - * the rest of the string. - * Null (empty) pointsize and style fields are treated - * as valid fields with the default value for that field. - *<p> - * Some font names may include the separator characters ' ' or '-'. - * If <code>str</code> is not formed with 3 components, e.g. such that - * <code>style</code> or <code>pointsize</code> fields are not present in - * <code>str</code>, and <code>fontname</code> also contains a - * character determined to be the separator character - * then these characters where they appear as intended to be part of - * <code>fontname</code> may instead be interpreted as separators - * so the font name may not be properly recognised. - * - * <p> - * The default size is 12 and the default style is PLAIN. - * If <code>str</code> does not specify a valid size, the returned - * <code>Font</code> has a size of 12. If <code>str</code> does not - * specify a valid style, the returned Font has a style of PLAIN. - * If you do not specify a valid font name in - * the <code>str</code> argument, this method will return - * a font with the family name "Dialog". - * To determine what font family names are available on - * your system, use the - * {@link GraphicsEnvironment#getAvailableFontFamilyNames()} method. - * If <code>str</code> is <code>null</code>, a new <code>Font</code> - * is returned with the family name "Dialog", a size of 12 and a - * PLAIN style. - * @param str the name of the font, or <code>null</code> - * @return the <code>Font</code> object that <code>str</code> - * describes, or a new default <code>Font</code> if - * <code>str</code> is <code>null</code>. - * @see #getFamily - * @since JDK1.1 - */ - public static Font decode(String str) { - String fontName = str; - String styleName = ""; - int fontSize = 12; - int fontStyle = Font.PLAIN; - - if (str == null) { - return new Font(DIALOG, fontStyle, fontSize); - } - - int lastHyphen = str.lastIndexOf('-'); - int lastSpace = str.lastIndexOf(' '); - char sepChar = (lastHyphen > lastSpace) ? '-' : ' '; - int sizeIndex = str.lastIndexOf(sepChar); - int styleIndex = str.lastIndexOf(sepChar, sizeIndex-1); - int strlen = str.length(); - - if (sizeIndex > 0 && sizeIndex+1 < strlen) { - try { - fontSize = - Integer.valueOf(str.substring(sizeIndex+1)).intValue(); - if (fontSize <= 0) { - fontSize = 12; - } - } catch (NumberFormatException e) { - /* It wasn't a valid size, if we didn't also find the - * start of the style string perhaps this is the style */ - styleIndex = sizeIndex; - sizeIndex = strlen; - if (str.charAt(sizeIndex-1) == sepChar) { - sizeIndex--; - } - } - } - - if (styleIndex >= 0 && styleIndex+1 < strlen) { - styleName = str.substring(styleIndex+1, sizeIndex); - styleName = styleName.toLowerCase(Locale.ENGLISH); - if (styleName.equals("bolditalic")) { - fontStyle = Font.BOLD | Font.ITALIC; - } else if (styleName.equals("italic")) { - fontStyle = Font.ITALIC; - } else if (styleName.equals("bold")) { - fontStyle = Font.BOLD; - } else if (styleName.equals("plain")) { - fontStyle = Font.PLAIN; - } else { - /* this string isn't any of the expected styles, so - * assume its part of the font name - */ - styleIndex = sizeIndex; - if (str.charAt(styleIndex-1) == sepChar) { - styleIndex--; - } - } - fontName = str.substring(0, styleIndex); - - } else { - int fontEnd = strlen; - if (styleIndex > 0) { - fontEnd = styleIndex; - } else if (sizeIndex > 0) { - fontEnd = sizeIndex; - } - if (fontEnd > 0 && str.charAt(fontEnd-1) == sepChar) { - fontEnd--; - } - fontName = str.substring(0, fontEnd); - } - - return new Font(fontName, fontStyle, fontSize); - } - - /** - * Gets the specified <code>Font</code> from the system properties - * list. As in the <code>getProperty</code> method of - * <code>System</code>, the first - * argument is treated as the name of a system property to be - * obtained. The <code>String</code> value of this property is then - * interpreted as a <code>Font</code> object. - * <p> - * The property value should be one of the forms accepted by - * <code>Font.decode(String)</code> - * If the specified property is not found, or the executing code does not - * have permission to read the property, the <code>font</code> - * argument is returned instead. - * @param nm the case-insensitive property name - * @param font a default <code>Font</code> to return if property - * <code>nm</code> is not defined - * @return the <code>Font</code> value of the property. - * @throws NullPointerException if nm is null. - * @see #decode(String) - */ - public static Font getFont(String nm, Font font) { - String str = null; - try { - str =System.getProperty(nm); - } catch(SecurityException e) { - } - if (str == null) { - return font; - } - return decode ( str ); - } - - transient int hash; - /** - * Returns a hashcode for this <code>Font</code>. - * @return a hashcode value for this <code>Font</code>. - * @since JDK1.0 - */ - public int hashCode() { - if (hash == 0) { - hash = name.hashCode() ^ style ^ size; - /* It is possible many fonts differ only in transform. - * So include the transform in the hash calculation. - * nonIdentityTx is set whenever there is a transform in - * 'values'. The tests for null are required because it can - * also be set for other reasons. - */ - if (nonIdentityTx && - values != null && values.getTransform() != null) { - hash ^= values.getTransform().hashCode(); - } - } - return hash; - } - - /** - * Compares this <code>Font</code> object to the specified - * <code>Object</code>. - * @param obj the <code>Object</code> to compare - * @return <code>true</code> if the objects are the same - * or if the argument is a <code>Font</code> object - * describing the same font as this object; - * <code>false</code> otherwise. - * @since JDK1.0 - */ - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - - if (obj != null) { - try { - Font font = (Font)obj; - if (size == font.size && - style == font.style && - nonIdentityTx == font.nonIdentityTx && - hasLayoutAttributes == font.hasLayoutAttributes && - pointSize == font.pointSize && - name.equals(font.name)) { - - /* 'values' is usually initialized lazily, except when - * the font is constructed from a Map, or derived using - * a Map or other values. So if only one font has - * the field initialized we need to initialize it in - * the other instance and compare. - */ - if (values == null) { - if (font.values == null) { - return true; - } else { - return getAttributeValues().equals(font.values); - } - } else { - return values.equals(font.getAttributeValues()); - } - } - } - catch (ClassCastException e) { - } - } - return false; - } - - /** - * Converts this <code>Font</code> object to a <code>String</code> - * representation. - * @return a <code>String</code> representation of this - * <code>Font</code> object. - * @since JDK1.0 - */ - // NOTE: This method may be called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public String toString() { - String strStyle; - - if (isBold()) { - strStyle = isItalic() ? "bolditalic" : "bold"; - } else { - strStyle = isItalic() ? "italic" : "plain"; - } - - return getClass().getName() + "[family=" + getFamily() + ",name=" + name + ",style=" + - strStyle + ",size=" + size + "]"; - } // toString() - - - /** Serialization support. A <code>readObject</code> - * method is neccessary because the constructor creates - * the font's peer, and we can't serialize the peer. - * Similarly the computed font "family" may be different - * at <code>readObject</code> time than at - * <code>writeObject</code> time. An integer version is - * written so that future versions of this class will be - * able to recognize serialized output from this one. - */ - /** - * The <code>Font</code> Serializable Data Form. - * - * @serial - */ - private int fontSerializedDataVersion = 1; - - /** - * Writes default serializable fields to a stream. - * - * @param s the <code>ObjectOutputStream</code> to write - * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener) - * @see #readObject(java.io.ObjectInputStream) - */ - private void writeObject(java.io.ObjectOutputStream s) - throws java.lang.ClassNotFoundException, - java.io.IOException - { - if (values != null) { - synchronized(values) { - // transient - fRequestedAttributes = values.toSerializableHashtable(); - s.defaultWriteObject(); - fRequestedAttributes = null; - } - } else { - s.defaultWriteObject(); - } - } - - /** - * Reads the <code>ObjectInputStream</code>. - * Unrecognized keys or values will be ignored. - * - * @param s the <code>ObjectInputStream</code> to read - * @serial - * @see #writeObject(java.io.ObjectOutputStream) - */ - private void readObject(java.io.ObjectInputStream s) - throws java.lang.ClassNotFoundException, - java.io.IOException - { - s.defaultReadObject(); - if (pointSize == 0) { - pointSize = (float)size; - } - - // Handle fRequestedAttributes. - // in 1.5, we always streamed out the font values plus - // TRANSFORM, SUPERSCRIPT, and WIDTH, regardless of whether the - // values were default or not. In 1.6 we only stream out - // defined values. So, 1.6 streams in from a 1.5 stream, - // it check each of these values and 'undefines' it if the - // value is the default. - - if (fRequestedAttributes != null) { - values = getAttributeValues(); // init - AttributeValues extras = - AttributeValues.fromSerializableHashtable(fRequestedAttributes); - if (!AttributeValues.is16Hashtable(fRequestedAttributes)) { - extras.unsetDefault(); // if legacy stream, undefine these - } - values = getAttributeValues().merge(extras); - this.nonIdentityTx = values.anyNonDefault(EXTRA_MASK); - this.hasLayoutAttributes = values.anyNonDefault(LAYOUT_MASK); - - fRequestedAttributes = null; // don't need it any more - } - } - - /** - * Returns the number of glyphs in this <code>Font</code>. Glyph codes - * for this <code>Font</code> range from 0 to - * <code>getNumGlyphs()</code> - 1. - * @return the number of glyphs in this <code>Font</code>. - * @since 1.2 - */ - public int getNumGlyphs() { - return getFont2D().getNumGlyphs(); - } - - /** - * Returns the glyphCode which is used when this <code>Font</code> - * does not have a glyph for a specified unicode code point. - * @return the glyphCode of this <code>Font</code>. - * @since 1.2 - */ - public int getMissingGlyphCode() { - return getFont2D().getMissingGlyphCode(); - } - - /** - * Returns the baseline appropriate for displaying this character. - * <p> - * Large fonts can support different writing systems, and each system can - * use a different baseline. - * The character argument determines the writing system to use. Clients - * should not assume all characters use the same baseline. - * - * @param c a character used to identify the writing system - * @return the baseline appropriate for the specified character. - * @see LineMetrics#getBaselineOffsets - * @see #ROMAN_BASELINE - * @see #CENTER_BASELINE - * @see #HANGING_BASELINE - * @since 1.2 - */ - public byte getBaselineFor(char c) { - return getFont2D().getBaselineFor(c); - } - - /** - * Returns a map of font attributes available in this - * <code>Font</code>. Attributes include things like ligatures and - * glyph substitution. - * @return the attributes map of this <code>Font</code>. - */ - public Map<TextAttribute,?> getAttributes(){ - return new AttributeMap(getAttributeValues()); - } - - /** - * Returns the keys of all the attributes supported by this - * <code>Font</code>. These attributes can be used to derive other - * fonts. - * @return an array containing the keys of all the attributes - * supported by this <code>Font</code>. - * @since 1.2 - */ - public Attribute[] getAvailableAttributes() { - // FONT is not supported by Font - - Attribute attributes[] = { - TextAttribute.FAMILY, - TextAttribute.WEIGHT, - TextAttribute.WIDTH, - TextAttribute.POSTURE, - TextAttribute.SIZE, - TextAttribute.TRANSFORM, - TextAttribute.SUPERSCRIPT, - TextAttribute.CHAR_REPLACEMENT, - TextAttribute.FOREGROUND, - TextAttribute.BACKGROUND, - TextAttribute.UNDERLINE, - TextAttribute.STRIKETHROUGH, - TextAttribute.RUN_DIRECTION, - TextAttribute.BIDI_EMBEDDING, - TextAttribute.JUSTIFICATION, - TextAttribute.INPUT_METHOD_HIGHLIGHT, - TextAttribute.INPUT_METHOD_UNDERLINE, - TextAttribute.SWAP_COLORS, - TextAttribute.NUMERIC_SHAPING, - TextAttribute.KERNING, - TextAttribute.LIGATURES, - TextAttribute.TRACKING, - }; - - return attributes; - } - - /** - * Creates a new <code>Font</code> object by replicating this - * <code>Font</code> object and applying a new style and size. - * @param style the style for the new <code>Font</code> - * @param size the size for the new <code>Font</code> - * @return a new <code>Font</code> object. - * @since 1.2 - */ - public Font deriveFont(int style, float size){ - if (values == null) { - return new Font(name, style, size, createdFont, font2DHandle); - } - AttributeValues newValues = getAttributeValues().clone(); - int oldStyle = (this.style != style) ? this.style : -1; - applyStyle(style, newValues); - newValues.setSize(size); - return new Font(newValues, null, oldStyle, createdFont, font2DHandle); - } - - /** - * Creates a new <code>Font</code> object by replicating this - * <code>Font</code> object and applying a new style and transform. - * @param style the style for the new <code>Font</code> - * @param trans the <code>AffineTransform</code> associated with the - * new <code>Font</code> - * @return a new <code>Font</code> object. - * @throws IllegalArgumentException if <code>trans</code> is - * <code>null</code> - * @since 1.2 - */ - public Font deriveFont(int style, AffineTransform trans){ - AttributeValues newValues = getAttributeValues().clone(); - int oldStyle = (this.style != style) ? this.style : -1; - applyStyle(style, newValues); - applyTransform(trans, newValues); - return new Font(newValues, null, oldStyle, createdFont, font2DHandle); - } - - /** - * Creates a new <code>Font</code> object by replicating the current - * <code>Font</code> object and applying a new size to it. - * @param size the size for the new <code>Font</code>. - * @return a new <code>Font</code> object. - * @since 1.2 - */ - public Font deriveFont(float size){ - if (values == null) { - return new Font(name, style, size, createdFont, font2DHandle); - } - AttributeValues newValues = getAttributeValues().clone(); - newValues.setSize(size); - return new Font(newValues, null, -1, createdFont, font2DHandle); - } - - /** - * Creates a new <code>Font</code> object by replicating the current - * <code>Font</code> object and applying a new transform to it. - * @param trans the <code>AffineTransform</code> associated with the - * new <code>Font</code> - * @return a new <code>Font</code> object. - * @throws IllegalArgumentException if <code>trans</code> is - * <code>null</code> - * @since 1.2 - */ - public Font deriveFont(AffineTransform trans){ - AttributeValues newValues = getAttributeValues().clone(); - applyTransform(trans, newValues); - return new Font(newValues, null, -1, createdFont, font2DHandle); - } - - /** - * Creates a new <code>Font</code> object by replicating the current - * <code>Font</code> object and applying a new style to it. - * @param style the style for the new <code>Font</code> - * @return a new <code>Font</code> object. - * @since 1.2 - */ - public Font deriveFont(int style){ - if (values == null) { - return new Font(name, style, size, createdFont, font2DHandle); - } - AttributeValues newValues = getAttributeValues().clone(); - int oldStyle = (this.style != style) ? this.style : -1; - applyStyle(style, newValues); - return new Font(newValues, null, oldStyle, createdFont, font2DHandle); - } - - /** - * Creates a new <code>Font</code> object by replicating the current - * <code>Font</code> object and applying a new set of font attributes - * to it. - * - * @param attributes a map of attributes enabled for the new - * <code>Font</code> - * @return a new <code>Font</code> object. - * @since 1.2 - */ - public Font deriveFont(Map<? extends Attribute, ?> attributes) { - if (attributes == null) { - return this; - } - AttributeValues newValues = getAttributeValues().clone(); - newValues.merge(attributes, RECOGNIZED_MASK); - - return new Font(newValues, name, style, createdFont, font2DHandle); - } - - /** - * Checks if this <code>Font</code> has a glyph for the specified - * character. - * - * <p> <b>Note:</b> This method cannot handle <a - * href="../../java/lang/Character.html#supplementary"> supplementary - * characters</a>. To support all Unicode characters, including - * supplementary characters, use the {@link #canDisplay(int)} - * method or <code>canDisplayUpTo</code> methods. - * - * @param c the character for which a glyph is needed - * @return <code>true</code> if this <code>Font</code> has a glyph for this - * character; <code>false</code> otherwise. - * @since 1.2 - */ - public boolean canDisplay(char c){ - return getFont2D().canDisplay(c); - } - - /** - * Checks if this <code>Font</code> has a glyph for the specified - * character. - * - * @param codePoint the character (Unicode code point) for which a glyph - * is needed. - * @return <code>true</code> if this <code>Font</code> has a glyph for the - * character; <code>false</code> otherwise. - * @throws IllegalArgumentException if the code point is not a valid Unicode - * code point. - * @see Character#isValidCodePoint(int) - * @since 1.5 - */ - public boolean canDisplay(int codePoint) { - if (!Character.isValidCodePoint(codePoint)) { - throw new IllegalArgumentException("invalid code point: " + - Integer.toHexString(codePoint)); - } - return getFont2D().canDisplay(codePoint); - } - - /** - * Indicates whether or not this <code>Font</code> can display a - * specified <code>String</code>. For strings with Unicode encoding, - * it is important to know if a particular font can display the - * string. This method returns an offset into the <code>String</code> - * <code>str</code> which is the first character this - * <code>Font</code> cannot display without using the missing glyph - * code. If the <code>Font</code> can display all characters, -1 is - * returned. - * @param str a <code>String</code> object - * @return an offset into <code>str</code> that points - * to the first character in <code>str</code> that this - * <code>Font</code> cannot display; or <code>-1</code> if - * this <code>Font</code> can display all characters in - * <code>str</code>. - * @since 1.2 - */ - public int canDisplayUpTo(String str) { - Font2D font2d = getFont2D(); - int len = str.length(); - for (int i = 0; i < len; i++) { - char c = str.charAt(i); - if (font2d.canDisplay(c)) { - continue; - } - if (!Character.isHighSurrogate(c)) { - return i; - } - if (!font2d.canDisplay(str.codePointAt(i))) { - return i; - } - i++; - } - return -1; - } - - /** - * Indicates whether or not this <code>Font</code> can display - * the characters in the specified <code>text</code> - * starting at <code>start</code> and ending at - * <code>limit</code>. This method is a convenience overload. - * @param text the specified array of <code>char</code> values - * @param start the specified starting offset (in - * <code>char</code>s) into the specified array of - * <code>char</code> values - * @param limit the specified ending offset (in - * <code>char</code>s) into the specified array of - * <code>char</code> values - * @return an offset into <code>text</code> that points - * to the first character in <code>text</code> that this - * <code>Font</code> cannot display; or <code>-1</code> if - * this <code>Font</code> can display all characters in - * <code>text</code>. - * @since 1.2 - */ - public int canDisplayUpTo(char[] text, int start, int limit) { - Font2D font2d = getFont2D(); - for (int i = start; i < limit; i++) { - char c = text[i]; - if (font2d.canDisplay(c)) { - continue; - } - if (!Character.isHighSurrogate(c)) { - return i; - } - if (!font2d.canDisplay(Character.codePointAt(text, i, limit))) { - return i; - } - i++; - } - return -1; - } - - /** - * Indicates whether or not this <code>Font</code> can display the - * text specified by the <code>iter</code> starting at - * <code>start</code> and ending at <code>limit</code>. - * - * @param iter a {@link CharacterIterator} object - * @param start the specified starting offset into the specified - * <code>CharacterIterator</code>. - * @param limit the specified ending offset into the specified - * <code>CharacterIterator</code>. - * @return an offset into <code>iter</code> that points - * to the first character in <code>iter</code> that this - * <code>Font</code> cannot display; or <code>-1</code> if - * this <code>Font</code> can display all characters in - * <code>iter</code>. - * @since 1.2 - */ - public int canDisplayUpTo(CharacterIterator iter, int start, int limit) { - Font2D font2d = getFont2D(); - char c = iter.setIndex(start); - for (int i = start; i < limit; i++, c = iter.next()) { - if (font2d.canDisplay(c)) { - continue; - } - if (!Character.isHighSurrogate(c)) { - return i; - } - char c2 = iter.next(); - // c2 could be CharacterIterator.DONE which is not a low surrogate. - if (!Character.isLowSurrogate(c2)) { - return i; - } - if (!font2d.canDisplay(Character.toCodePoint(c, c2))) { - return i; - } - i++; - } - return -1; - } - - /** - * Returns the italic angle of this <code>Font</code>. The italic angle - * is the inverse slope of the caret which best matches the posture of this - * <code>Font</code>. - * @see TextAttribute#POSTURE - * @return the angle of the ITALIC style of this <code>Font</code>. - */ - public float getItalicAngle() { - return getItalicAngle(null); - } - - /* The FRC hints don't affect the value of the italic angle but - * we need to pass them in to look up a strike. - * If we can pass in ones already being used it can prevent an extra - * strike from being allocated. Note that since italic angle is - * a property of the font, the font transform is needed not the - * device transform. Finally, this is private but the only caller of this - * in the JDK - and the only likely caller - is in this same class. - */ - private float getItalicAngle(FontRenderContext frc) { - Object aa, fm; - if (frc == null) { - aa = RenderingHints.VALUE_TEXT_ANTIALIAS_OFF; - fm = RenderingHints.VALUE_FRACTIONALMETRICS_OFF; - } else { - aa = frc.getAntiAliasingHint(); - fm = frc.getFractionalMetricsHint(); - } - return getFont2D().getItalicAngle(this, identityTx, aa, fm); - } - - /** - * Checks whether or not this <code>Font</code> has uniform - * line metrics. A logical <code>Font</code> might be a - * composite font, which means that it is composed of different - * physical fonts to cover different code ranges. Each of these - * fonts might have different <code>LineMetrics</code>. If the - * logical <code>Font</code> is a single - * font then the metrics would be uniform. - * @return <code>true</code> if this <code>Font</code> has - * uniform line metrics; <code>false</code> otherwise. - */ - public boolean hasUniformLineMetrics() { - return false; // REMIND always safe, but prevents caller optimize - } - - private transient SoftReference<FontLineMetrics> flmref; - private FontLineMetrics defaultLineMetrics(FontRenderContext frc) { - FontLineMetrics flm = null; - if (flmref == null - || (flm = flmref.get()) == null - || !flm.frc.equals(frc)) { - - /* The device transform in the frc is not used in obtaining line - * metrics, although it probably should be: REMIND find why not? - * The font transform is used but its applied in getFontMetrics, so - * just pass identity here - */ - float [] metrics = new float[8]; - getFont2D().getFontMetrics(this, identityTx, - frc.getAntiAliasingHint(), - frc.getFractionalMetricsHint(), - metrics); - float ascent = metrics[0]; - float descent = metrics[1]; - float leading = metrics[2]; - float ssOffset = 0; - if (values != null && values.getSuperscript() != 0) { - ssOffset = (float)getTransform().getTranslateY(); - ascent -= ssOffset; - descent += ssOffset; - } - float height = ascent + descent + leading; - - int baselineIndex = 0; // need real index, assumes roman for everything - // need real baselines eventually - float[] baselineOffsets = { 0, (descent/2f - ascent) / 2f, -ascent }; - - float strikethroughOffset = metrics[4]; - float strikethroughThickness = metrics[5]; - - float underlineOffset = metrics[6]; - float underlineThickness = metrics[7]; - - float italicAngle = getItalicAngle(frc); - - if (isTransformed()) { - AffineTransform ctx = values.getCharTransform(); // extract rotation - if (ctx != null) { - Point2D.Float pt = new Point2D.Float(); - pt.setLocation(0, strikethroughOffset); - ctx.deltaTransform(pt, pt); - strikethroughOffset = pt.y; - pt.setLocation(0, strikethroughThickness); - ctx.deltaTransform(pt, pt); - strikethroughThickness = pt.y; - pt.setLocation(0, underlineOffset); - ctx.deltaTransform(pt, pt); - underlineOffset = pt.y; - pt.setLocation(0, underlineThickness); - ctx.deltaTransform(pt, pt); - underlineThickness = pt.y; - } - } - strikethroughOffset += ssOffset; - underlineOffset += ssOffset; - - CoreMetrics cm = new CoreMetrics(ascent, descent, leading, height, - baselineIndex, baselineOffsets, - strikethroughOffset, strikethroughThickness, - underlineOffset, underlineThickness, - ssOffset, italicAngle); - - flm = new FontLineMetrics(0, cm, frc); - flmref = new SoftReference<FontLineMetrics>(flm); - } - - return (FontLineMetrics)flm.clone(); - } - - /** - * Returns a {@link LineMetrics} object created with the specified - * <code>String</code> and {@link FontRenderContext}. - * @param str the specified <code>String</code> - * @param frc the specified <code>FontRenderContext</code> - * @return a <code>LineMetrics</code> object created with the - * specified <code>String</code> and {@link FontRenderContext}. - */ - public LineMetrics getLineMetrics( String str, FontRenderContext frc) { - FontLineMetrics flm = defaultLineMetrics(frc); - flm.numchars = str.length(); - return flm; - } - - /** - * Returns a <code>LineMetrics</code> object created with the - * specified arguments. - * @param str the specified <code>String</code> - * @param beginIndex the initial offset of <code>str</code> - * @param limit the end offset of <code>str</code> - * @param frc the specified <code>FontRenderContext</code> - * @return a <code>LineMetrics</code> object created with the - * specified arguments. - */ - public LineMetrics getLineMetrics( String str, - int beginIndex, int limit, - FontRenderContext frc) { - FontLineMetrics flm = defaultLineMetrics(frc); - int numChars = limit - beginIndex; - flm.numchars = (numChars < 0)? 0: numChars; - return flm; - } - - /** - * Returns a <code>LineMetrics</code> object created with the - * specified arguments. - * @param chars an array of characters - * @param beginIndex the initial offset of <code>chars</code> - * @param limit the end offset of <code>chars</code> - * @param frc the specified <code>FontRenderContext</code> - * @return a <code>LineMetrics</code> object created with the - * specified arguments. - */ - public LineMetrics getLineMetrics(char [] chars, - int beginIndex, int limit, - FontRenderContext frc) { - FontLineMetrics flm = defaultLineMetrics(frc); - int numChars = limit - beginIndex; - flm.numchars = (numChars < 0)? 0: numChars; - return flm; - } - - /** - * Returns a <code>LineMetrics</code> object created with the - * specified arguments. - * @param ci the specified <code>CharacterIterator</code> - * @param beginIndex the initial offset in <code>ci</code> - * @param limit the end offset of <code>ci</code> - * @param frc the specified <code>FontRenderContext</code> - * @return a <code>LineMetrics</code> object created with the - * specified arguments. - */ - public LineMetrics getLineMetrics(CharacterIterator ci, - int beginIndex, int limit, - FontRenderContext frc) { - FontLineMetrics flm = defaultLineMetrics(frc); - int numChars = limit - beginIndex; - flm.numchars = (numChars < 0)? 0: numChars; - return flm; - } - - /** - * Returns the logical bounds of the specified <code>String</code> in - * the specified <code>FontRenderContext</code>. The logical bounds - * contains the origin, ascent, advance, and height, which includes - * the leading. The logical bounds does not always enclose all the - * text. For example, in some languages and in some fonts, accent - * marks can be positioned above the ascent or below the descent. - * To obtain a visual bounding box, which encloses all the text, - * use the {@link TextLayout#getBounds() getBounds} method of - * <code>TextLayout</code>. - * <p>Note: The returned bounds is in baseline-relative coordinates - * (see {@link java.awt.Font class notes}). - * @param str the specified <code>String</code> - * @param frc the specified <code>FontRenderContext</code> - * @return a {@link Rectangle2D} that is the bounding box of the - * specified <code>String</code> in the specified - * <code>FontRenderContext</code>. - * @see FontRenderContext - * @see Font#createGlyphVector - * @since 1.2 - */ - public Rectangle2D getStringBounds( String str, FontRenderContext frc) { - char[] array = str.toCharArray(); - return getStringBounds(array, 0, array.length, frc); - } - - /** - * Returns the logical bounds of the specified <code>String</code> in - * the specified <code>FontRenderContext</code>. The logical bounds - * contains the origin, ascent, advance, and height, which includes - * the leading. The logical bounds does not always enclose all the - * text. For example, in some languages and in some fonts, accent - * marks can be positioned above the ascent or below the descent. - * To obtain a visual bounding box, which encloses all the text, - * use the {@link TextLayout#getBounds() getBounds} method of - * <code>TextLayout</code>. - * <p>Note: The returned bounds is in baseline-relative coordinates - * (see {@link java.awt.Font class notes}). - * @param str the specified <code>String</code> - * @param beginIndex the initial offset of <code>str</code> - * @param limit the end offset of <code>str</code> - * @param frc the specified <code>FontRenderContext</code> - * @return a <code>Rectangle2D</code> that is the bounding box of the - * specified <code>String</code> in the specified - * <code>FontRenderContext</code>. - * @throws IndexOutOfBoundsException if <code>beginIndex</code> is - * less than zero, or <code>limit</code> is greater than the - * length of <code>str</code>, or <code>beginIndex</code> - * is greater than <code>limit</code>. - * @see FontRenderContext - * @see Font#createGlyphVector - * @since 1.2 - */ - public Rectangle2D getStringBounds( String str, - int beginIndex, int limit, - FontRenderContext frc) { - String substr = str.substring(beginIndex, limit); - return getStringBounds(substr, frc); - } - - /** - * Returns the logical bounds of the specified array of characters - * in the specified <code>FontRenderContext</code>. The logical - * bounds contains the origin, ascent, advance, and height, which - * includes the leading. The logical bounds does not always enclose - * all the text. For example, in some languages and in some fonts, - * accent marks can be positioned above the ascent or below the - * descent. To obtain a visual bounding box, which encloses all the - * text, use the {@link TextLayout#getBounds() getBounds} method of - * <code>TextLayout</code>. - * <p>Note: The returned bounds is in baseline-relative coordinates - * (see {@link java.awt.Font class notes}). - * @param chars an array of characters - * @param beginIndex the initial offset in the array of - * characters - * @param limit the end offset in the array of characters - * @param frc the specified <code>FontRenderContext</code> - * @return a <code>Rectangle2D</code> that is the bounding box of the - * specified array of characters in the specified - * <code>FontRenderContext</code>. - * @throws IndexOutOfBoundsException if <code>beginIndex</code> is - * less than zero, or <code>limit</code> is greater than the - * length of <code>chars</code>, or <code>beginIndex</code> - * is greater than <code>limit</code>. - * @see FontRenderContext - * @see Font#createGlyphVector - * @since 1.2 - */ - public Rectangle2D getStringBounds(char [] chars, - int beginIndex, int limit, - FontRenderContext frc) { - if (beginIndex < 0) { - throw new IndexOutOfBoundsException("beginIndex: " + beginIndex); - } - if (limit > chars.length) { - throw new IndexOutOfBoundsException("limit: " + limit); - } - if (beginIndex > limit) { - throw new IndexOutOfBoundsException("range length: " + - (limit - beginIndex)); - } - - // this code should be in textlayout - // quick check for simple text, assume GV ok to use if simple - - boolean simple = values == null || - (values.getKerning() == 0 && values.getLigatures() == 0 && - values.getBaselineTransform() == null); - if (simple) { - simple = ! FontUtilities.isComplexText(chars, beginIndex, limit); - } - - if (simple) { - GlyphVector gv = new StandardGlyphVector(this, chars, beginIndex, - limit - beginIndex, frc); - return gv.getLogicalBounds(); - } else { - // need char array constructor on textlayout - String str = new String(chars, beginIndex, limit - beginIndex); - TextLayout tl = new TextLayout(str, this, frc); - return new Rectangle2D.Float(0, -tl.getAscent(), tl.getAdvance(), - tl.getAscent() + tl.getDescent() + - tl.getLeading()); - } - } - - /** - * Returns the logical bounds of the characters indexed in the - * specified {@link CharacterIterator} in the - * specified <code>FontRenderContext</code>. The logical bounds - * contains the origin, ascent, advance, and height, which includes - * the leading. The logical bounds does not always enclose all the - * text. For example, in some languages and in some fonts, accent - * marks can be positioned above the ascent or below the descent. - * To obtain a visual bounding box, which encloses all the text, - * use the {@link TextLayout#getBounds() getBounds} method of - * <code>TextLayout</code>. - * <p>Note: The returned bounds is in baseline-relative coordinates - * (see {@link java.awt.Font class notes}). - * @param ci the specified <code>CharacterIterator</code> - * @param beginIndex the initial offset in <code>ci</code> - * @param limit the end offset in <code>ci</code> - * @param frc the specified <code>FontRenderContext</code> - * @return a <code>Rectangle2D</code> that is the bounding box of the - * characters indexed in the specified <code>CharacterIterator</code> - * in the specified <code>FontRenderContext</code>. - * @see FontRenderContext - * @see Font#createGlyphVector - * @since 1.2 - * @throws IndexOutOfBoundsException if <code>beginIndex</code> is - * less than the start index of <code>ci</code>, or - * <code>limit</code> is greater than the end index of - * <code>ci</code>, or <code>beginIndex</code> is greater - * than <code>limit</code> - */ - public Rectangle2D getStringBounds(CharacterIterator ci, - int beginIndex, int limit, - FontRenderContext frc) { - int start = ci.getBeginIndex(); - int end = ci.getEndIndex(); - - if (beginIndex < start) { - throw new IndexOutOfBoundsException("beginIndex: " + beginIndex); - } - if (limit > end) { - throw new IndexOutOfBoundsException("limit: " + limit); - } - if (beginIndex > limit) { - throw new IndexOutOfBoundsException("range length: " + - (limit - beginIndex)); - } - - char[] arr = new char[limit - beginIndex]; - - ci.setIndex(beginIndex); - for(int idx = 0; idx < arr.length; idx++) { - arr[idx] = ci.current(); - ci.next(); - } - - return getStringBounds(arr,0,arr.length,frc); - } - - /** - * Returns the bounds for the character with the maximum - * bounds as defined in the specified <code>FontRenderContext</code>. - * <p>Note: The returned bounds is in baseline-relative coordinates - * (see {@link java.awt.Font class notes}). - * @param frc the specified <code>FontRenderContext</code> - * @return a <code>Rectangle2D</code> that is the bounding box - * for the character with the maximum bounds. - */ - public Rectangle2D getMaxCharBounds(FontRenderContext frc) { - float [] metrics = new float[4]; - - getFont2D().getFontMetrics(this, frc, metrics); - - return new Rectangle2D.Float(0, -metrics[0], - metrics[3], - metrics[0] + metrics[1] + metrics[2]); - } - - /** - * Creates a {@link java.awt.font.GlyphVector GlyphVector} by - * mapping characters to glyphs one-to-one based on the - * Unicode cmap in this <code>Font</code>. This method does no other - * processing besides the mapping of glyphs to characters. This - * means that this method is not useful for some scripts, such - * as Arabic, Hebrew, Thai, and Indic, that require reordering, - * shaping, or ligature substitution. - * @param frc the specified <code>FontRenderContext</code> - * @param str the specified <code>String</code> - * @return a new <code>GlyphVector</code> created with the - * specified <code>String</code> and the specified - * <code>FontRenderContext</code>. - */ - public GlyphVector createGlyphVector(FontRenderContext frc, String str) - { - return (GlyphVector)new StandardGlyphVector(this, str, frc); - } - - /** - * Creates a {@link java.awt.font.GlyphVector GlyphVector} by - * mapping characters to glyphs one-to-one based on the - * Unicode cmap in this <code>Font</code>. This method does no other - * processing besides the mapping of glyphs to characters. This - * means that this method is not useful for some scripts, such - * as Arabic, Hebrew, Thai, and Indic, that require reordering, - * shaping, or ligature substitution. - * @param frc the specified <code>FontRenderContext</code> - * @param chars the specified array of characters - * @return a new <code>GlyphVector</code> created with the - * specified array of characters and the specified - * <code>FontRenderContext</code>. - */ - public GlyphVector createGlyphVector(FontRenderContext frc, char[] chars) - { - return (GlyphVector)new StandardGlyphVector(this, chars, frc); - } - - /** - * Creates a {@link java.awt.font.GlyphVector GlyphVector} by - * mapping the specified characters to glyphs one-to-one based on the - * Unicode cmap in this <code>Font</code>. This method does no other - * processing besides the mapping of glyphs to characters. This - * means that this method is not useful for some scripts, such - * as Arabic, Hebrew, Thai, and Indic, that require reordering, - * shaping, or ligature substitution. - * @param frc the specified <code>FontRenderContext</code> - * @param ci the specified <code>CharacterIterator</code> - * @return a new <code>GlyphVector</code> created with the - * specified <code>CharacterIterator</code> and the specified - * <code>FontRenderContext</code>. - */ - public GlyphVector createGlyphVector( FontRenderContext frc, - CharacterIterator ci) - { - return (GlyphVector)new StandardGlyphVector(this, ci, frc); - } - - /** - * Creates a {@link java.awt.font.GlyphVector GlyphVector} by - * mapping characters to glyphs one-to-one based on the - * Unicode cmap in this <code>Font</code>. This method does no other - * processing besides the mapping of glyphs to characters. This - * means that this method is not useful for some scripts, such - * as Arabic, Hebrew, Thai, and Indic, that require reordering, - * shaping, or ligature substitution. - * @param frc the specified <code>FontRenderContext</code> - * @param glyphCodes the specified integer array - * @return a new <code>GlyphVector</code> created with the - * specified integer array and the specified - * <code>FontRenderContext</code>. - */ - public GlyphVector createGlyphVector( FontRenderContext frc, - int [] glyphCodes) - { - return (GlyphVector)new StandardGlyphVector(this, glyphCodes, frc); - } - - /** - * Returns a new <code>GlyphVector</code> object, performing full - * layout of the text if possible. Full layout is required for - * complex text, such as Arabic or Hindi. Support for different - * scripts depends on the font and implementation. - * <p> - * Layout requires bidi analysis, as performed by - * <code>Bidi</code>, and should only be performed on text that - * has a uniform direction. The direction is indicated in the - * flags parameter,by using LAYOUT_RIGHT_TO_LEFT to indicate a - * right-to-left (Arabic and Hebrew) run direction, or - * LAYOUT_LEFT_TO_RIGHT to indicate a left-to-right (English) - * run direction. - * <p> - * In addition, some operations, such as Arabic shaping, require - * context, so that the characters at the start and limit can have - * the proper shapes. Sometimes the data in the buffer outside - * the provided range does not have valid data. The values - * LAYOUT_NO_START_CONTEXT and LAYOUT_NO_LIMIT_CONTEXT can be - * added to the flags parameter to indicate that the text before - * start, or after limit, respectively, should not be examined - * for context. - * <p> - * All other values for the flags parameter are reserved. - * - * @param frc the specified <code>FontRenderContext</code> - * @param text the text to layout - * @param start the start of the text to use for the <code>GlyphVector</code> - * @param limit the limit of the text to use for the <code>GlyphVector</code> - * @param flags control flags as described above - * @return a new <code>GlyphVector</code> representing the text between - * start and limit, with glyphs chosen and positioned so as to best represent - * the text - * @throws ArrayIndexOutOfBoundsException if start or limit is - * out of bounds - * @see java.text.Bidi - * @see #LAYOUT_LEFT_TO_RIGHT - * @see #LAYOUT_RIGHT_TO_LEFT - * @see #LAYOUT_NO_START_CONTEXT - * @see #LAYOUT_NO_LIMIT_CONTEXT - * @since 1.4 - */ - public GlyphVector layoutGlyphVector(FontRenderContext frc, - char[] text, - int start, - int limit, - int flags) { - - return new StandardGlyphVector(this,text,start, limit-start, frc); - } - - /** - * A flag to layoutGlyphVector indicating that text is left-to-right as - * determined by Bidi analysis. - */ - public static final int LAYOUT_LEFT_TO_RIGHT = 0; - - /** - * A flag to layoutGlyphVector indicating that text is right-to-left as - * determined by Bidi analysis. - */ - public static final int LAYOUT_RIGHT_TO_LEFT = 1; - - /** - * A flag to layoutGlyphVector indicating that text in the char array - * before the indicated start should not be examined. - */ - public static final int LAYOUT_NO_START_CONTEXT = 2; - - /** - * A flag to layoutGlyphVector indicating that text in the char array - * after the indicated limit should not be examined. - */ - public static final int LAYOUT_NO_LIMIT_CONTEXT = 4; - - - private static void applyTransform(AffineTransform trans, AttributeValues values) { - if (trans == null) { - throw new IllegalArgumentException("transform must not be null"); - } - values.setTransform(trans); - } - - private static void applyStyle(int style, AttributeValues values) { - // WEIGHT_BOLD, WEIGHT_REGULAR - values.setWeight((style & BOLD) != 0 ? 2f : 1f); - // POSTURE_OBLIQUE, POSTURE_REGULAR - values.setPosture((style & ITALIC) != 0 ? .2f : 0f); - } - -} diff --git a/openjdk/java/awt/GraphicsConfiguration.java b/openjdk/java/awt/GraphicsConfiguration.java deleted file mode 100644 index 429ddc02..00000000 --- a/openjdk/java/awt/GraphicsConfiguration.java +++ /dev/null @@ -1,452 +0,0 @@ -/* - * Copyright (c) 1997, 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.awt; - -import java.awt.geom.AffineTransform; -import java.awt.image.BufferedImage; -import java.awt.image.ColorModel; -import java.awt.image.VolatileImage; -import java.awt.image.WritableRaster; - -/** - * The <code>GraphicsConfiguration</code> class describes the - * characteristics of a graphics destination such as a printer or monitor. - * There can be many <code>GraphicsConfiguration</code> objects associated - * with a single graphics device, representing different drawing modes or - * capabilities. The corresponding native structure will vary from platform - * to platform. For example, on X11 windowing systems, - * each visual is a different <code>GraphicsConfiguration</code>. - * On Microsoft Windows, <code>GraphicsConfiguration</code>s represent - * PixelFormats available in the current resolution and color depth. - * <p> - * In a virtual device multi-screen environment in which the desktop - * area could span multiple physical screen devices, the bounds of the - * <code>GraphicsConfiguration</code> objects are relative to the - * virtual coordinate system. When setting the location of a - * component, use {@link #getBounds() getBounds} to get the bounds of - * the desired <code>GraphicsConfiguration</code> and offset the location - * with the coordinates of the <code>GraphicsConfiguration</code>, - * as the following code sample illustrates: - * </p> - * - * <pre> - * Frame f = new Frame(gc); // where gc is a GraphicsConfiguration - * Rectangle bounds = gc.getBounds(); - * f.setLocation(10 + bounds.x, 10 + bounds.y); </pre> - * - * <p> - * To determine if your environment is a virtual device - * environment, call <code>getBounds</code> on all of the - * <code>GraphicsConfiguration</code> objects in your system. If - * any of the origins of the returned bounds is not (0, 0), - * your environment is a virtual device environment. - * - * <p> - * You can also use <code>getBounds</code> to determine the bounds - * of the virtual device. To do this, first call <code>getBounds</code> on all - * of the <code>GraphicsConfiguration</code> objects in your - * system. Then calculate the union of all of the bounds returned - * from the calls to <code>getBounds</code>. The union is the - * bounds of the virtual device. The following code sample - * calculates the bounds of the virtual device. - * - * <pre> - * Rectangle virtualBounds = new Rectangle(); - * GraphicsEnvironment ge = GraphicsEnvironment. - * getLocalGraphicsEnvironment(); - * GraphicsDevice[] gs = - * ge.getScreenDevices(); - * for (int j = 0; j < gs.length; j++) { - * GraphicsDevice gd = gs[j]; - * GraphicsConfiguration[] gc = - * gd.getConfigurations(); - * for (int i=0; i < gc.length; i++) { - * virtualBounds = - * virtualBounds.union(gc[i].getBounds()); - * } - * } </pre> - * - * @see Window - * @see Frame - * @see GraphicsEnvironment - * @see GraphicsDevice - */ -/* - * REMIND: What to do about capabilities? - * The - * capabilities of the device can be determined by enumerating the possible - * capabilities and checking if the GraphicsConfiguration - * implements the interface for that capability. - * - */ - - -public abstract class GraphicsConfiguration { - - private static BufferCapabilities defaultBufferCaps; - private static ImageCapabilities defaultImageCaps; - - /** - * This is an abstract class that cannot be instantiated directly. - * Instances must be obtained from a suitable factory or query method. - * - * @see GraphicsDevice#getConfigurations - * @see GraphicsDevice#getDefaultConfiguration - * @see GraphicsDevice#getBestConfiguration - * @see Graphics2D#getDeviceConfiguration - */ - protected GraphicsConfiguration() { - } - - /** - * Returns the {@link GraphicsDevice} associated with this - * <code>GraphicsConfiguration</code>. - * @return a <code>GraphicsDevice</code> object that is - * associated with this <code>GraphicsConfiguration</code>. - */ - public abstract GraphicsDevice getDevice(); - - /** - * Returns a {@link BufferedImage} with a data layout and color model - * compatible with this <code>GraphicsConfiguration</code>. This - * method has nothing to do with memory-mapping - * a device. The returned <code>BufferedImage</code> has - * a layout and color model that is closest to this native device - * configuration and can therefore be optimally blitted to this - * device. - * @param width the width of the returned <code>BufferedImage</code> - * @param height the height of the returned <code>BufferedImage</code> - * @return a <code>BufferedImage</code> whose data layout and color - * model is compatible with this <code>GraphicsConfiguration</code>. - */ - public BufferedImage createCompatibleImage(int width, int height) { - ColorModel model = getColorModel(); - WritableRaster raster = - model.createCompatibleWritableRaster(width, height); - return new BufferedImage(model, raster, - model.isAlphaPremultiplied(), null); - } - - /** - * Returns a <code>BufferedImage</code> that supports the specified - * transparency and has a data layout and color model - * compatible with this <code>GraphicsConfiguration</code>. This - * method has nothing to do with memory-mapping - * a device. The returned <code>BufferedImage</code> has a layout and - * color model that can be optimally blitted to a device - * with this <code>GraphicsConfiguration</code>. - * @param width the width of the returned <code>BufferedImage</code> - * @param height the height of the returned <code>BufferedImage</code> - * @param transparency the specified transparency mode - * @return a <code>BufferedImage</code> whose data layout and color - * model is compatible with this <code>GraphicsConfiguration</code> - * and also supports the specified transparency. - * @throws IllegalArgumentException if the transparency is not a valid value - * @see Transparency#OPAQUE - * @see Transparency#BITMASK - * @see Transparency#TRANSLUCENT - */ - public BufferedImage createCompatibleImage(int width, int height, - int transparency) - { - if (getColorModel().getTransparency() == transparency) { - return createCompatibleImage(width, height); - } - - ColorModel cm = getColorModel(transparency); - if (cm == null) { - throw new IllegalArgumentException("Unknown transparency: " + - transparency); - } - WritableRaster wr = cm.createCompatibleWritableRaster(width, height); - return new BufferedImage(cm, wr, cm.isAlphaPremultiplied(), null); - } - - - /** - * Returns a {@link VolatileImage} with a data layout and color model - * compatible with this <code>GraphicsConfiguration</code>. - * The returned <code>VolatileImage</code> - * may have data that is stored optimally for the underlying graphics - * device and may therefore benefit from platform-specific rendering - * acceleration. - * @param width the width of the returned <code>VolatileImage</code> - * @param height the height of the returned <code>VolatileImage</code> - * @return a <code>VolatileImage</code> whose data layout and color - * model is compatible with this <code>GraphicsConfiguration</code>. - * @see Component#createVolatileImage(int, int) - * @since 1.4 - */ - public VolatileImage createCompatibleVolatileImage(int width, int height) { - VolatileImage vi = null; - try { - vi = createCompatibleVolatileImage(width, height, - null, Transparency.OPAQUE); - } catch (AWTException e) { - // shouldn't happen: we're passing in null caps - assert false; - } - return vi; - } - - /** - * Returns a {@link VolatileImage} with a data layout and color model - * compatible with this <code>GraphicsConfiguration</code>. - * The returned <code>VolatileImage</code> - * may have data that is stored optimally for the underlying graphics - * device and may therefore benefit from platform-specific rendering - * acceleration. - * @param width the width of the returned <code>VolatileImage</code> - * @param height the height of the returned <code>VolatileImage</code> - * @param transparency the specified transparency mode - * @return a <code>VolatileImage</code> whose data layout and color - * model is compatible with this <code>GraphicsConfiguration</code>. - * @throws IllegalArgumentException if the transparency is not a valid value - * @see Transparency#OPAQUE - * @see Transparency#BITMASK - * @see Transparency#TRANSLUCENT - * @see Component#createVolatileImage(int, int) - * @since 1.5 - */ - public VolatileImage createCompatibleVolatileImage(int width, int height, - int transparency) - { - VolatileImage vi = null; - try { - vi = createCompatibleVolatileImage(width, height, null, transparency); - } catch (AWTException e) { - // shouldn't happen: we're passing in null caps - assert false; - } - return vi; - } - - /** - * Returns a {@link VolatileImage} with a data layout and color model - * compatible with this <code>GraphicsConfiguration</code>, using - * the specified image capabilities. - * If the <code>caps</code> parameter is null, it is effectively ignored - * and this method will create a VolatileImage without regard to - * <code>ImageCapabilities</code> constraints. - * - * The returned <code>VolatileImage</code> has - * a layout and color model that is closest to this native device - * configuration and can therefore be optimally blitted to this - * device. - * @return a <code>VolatileImage</code> whose data layout and color - * model is compatible with this <code>GraphicsConfiguration</code>. - * @param width the width of the returned <code>VolatileImage</code> - * @param height the height of the returned <code>VolatileImage</code> - * @param caps the image capabilities - * @exception AWTException if the supplied image capabilities could not - * be met by this graphics configuration - * @since 1.4 - */ - public VolatileImage createCompatibleVolatileImage(int width, int height, - ImageCapabilities caps) throws AWTException - { - return createCompatibleVolatileImage(width, height, caps, - Transparency.OPAQUE); - } - - /** - * Returns a {@link VolatileImage} with a data layout and color model - * compatible with this <code>GraphicsConfiguration</code>, using - * the specified image capabilities and transparency value. - * If the <code>caps</code> parameter is null, it is effectively ignored - * and this method will create a VolatileImage without regard to - * <code>ImageCapabilities</code> constraints. - * - * The returned <code>VolatileImage</code> has - * a layout and color model that is closest to this native device - * configuration and can therefore be optimally blitted to this - * device. - * @param width the width of the returned <code>VolatileImage</code> - * @param height the height of the returned <code>VolatileImage</code> - * @param caps the image capabilities - * @param transparency the specified transparency mode - * @return a <code>VolatileImage</code> whose data layout and color - * model is compatible with this <code>GraphicsConfiguration</code>. - * @see Transparency#OPAQUE - * @see Transparency#BITMASK - * @see Transparency#TRANSLUCENT - * @throws IllegalArgumentException if the transparency is not a valid value - * @exception AWTException if the supplied image capabilities could not - * be met by this graphics configuration - * @see Component#createVolatileImage(int, int) - * @since 1.5 - */ - public VolatileImage createCompatibleVolatileImage(int width, int height, - ImageCapabilities caps, int transparency) throws AWTException - { - VolatileImage vi = - new Container().createVolatileImage(width, height, caps); - if (caps != null && caps.isAccelerated() && - !vi.getCapabilities().isAccelerated()) - { - throw new AWTException("Supplied image capabilities could not " + - "be met by this graphics configuration."); - } - return vi; - } - - /** - * Returns the {@link ColorModel} associated with this - * <code>GraphicsConfiguration</code>. - * @return a <code>ColorModel</code> object that is associated with - * this <code>GraphicsConfiguration</code>. - */ - public abstract ColorModel getColorModel(); - - /** - * Returns the <code>ColorModel</code> associated with this - * <code>GraphicsConfiguration</code> that supports the specified - * transparency. - * @param transparency the specified transparency mode - * @return a <code>ColorModel</code> object that is associated with - * this <code>GraphicsConfiguration</code> and supports the - * specified transparency or null if the transparency is not a valid - * value. - * @see Transparency#OPAQUE - * @see Transparency#BITMASK - * @see Transparency#TRANSLUCENT - */ - public abstract ColorModel getColorModel(int transparency); - - /** - * Returns the default {@link AffineTransform} for this - * <code>GraphicsConfiguration</code>. This - * <code>AffineTransform</code> is typically the Identity transform - * for most normal screens. The default <code>AffineTransform</code> - * maps coordinates onto the device such that 72 user space - * coordinate units measure approximately 1 inch in device - * space. The normalizing transform can be used to make - * this mapping more exact. Coordinates in the coordinate space - * defined by the default <code>AffineTransform</code> for screen and - * printer devices have the origin in the upper left-hand corner of - * the target region of the device, with X coordinates - * increasing to the right and Y coordinates increasing downwards. - * For image buffers not associated with a device, such as those not - * created by <code>createCompatibleImage</code>, - * this <code>AffineTransform</code> is the Identity transform. - * @return the default <code>AffineTransform</code> for this - * <code>GraphicsConfiguration</code>. - */ - public abstract AffineTransform getDefaultTransform(); - - /** - * - * Returns a <code>AffineTransform</code> that can be concatenated - * with the default <code>AffineTransform</code> - * of a <code>GraphicsConfiguration</code> so that 72 units in user - * space equals 1 inch in device space. - * <p> - * For a particular {@link Graphics2D}, g, one - * can reset the transformation to create - * such a mapping by using the following pseudocode: - * <pre> - * GraphicsConfiguration gc = g.getDeviceConfiguration(); - * - * g.setTransform(gc.getDefaultTransform()); - * g.transform(gc.getNormalizingTransform()); - * </pre> - * Note that sometimes this <code>AffineTransform</code> is identity, - * such as for printers or metafile output, and that this - * <code>AffineTransform</code> is only as accurate as the information - * supplied by the underlying system. For image buffers not - * associated with a device, such as those not created by - * <code>createCompatibleImage</code>, this - * <code>AffineTransform</code> is the Identity transform - * since there is no valid distance measurement. - * @return an <code>AffineTransform</code> to concatenate to the - * default <code>AffineTransform</code> so that 72 units in user - * space is mapped to 1 inch in device space. - */ - public abstract AffineTransform getNormalizingTransform(); - - /** - * Returns the bounds of the <code>GraphicsConfiguration</code> - * in the device coordinates. In a multi-screen environment - * with a virtual device, the bounds can have negative X - * or Y origins. - * @return the bounds of the area covered by this - * <code>GraphicsConfiguration</code>. - * @since 1.3 - */ - public abstract Rectangle getBounds(); - - private static class DefaultBufferCapabilities extends BufferCapabilities { - public DefaultBufferCapabilities(ImageCapabilities imageCaps) { - super(imageCaps, imageCaps, null); - } - } - - /** - * Returns the buffering capabilities of this - * <code>GraphicsConfiguration</code>. - * @return the buffering capabilities of this graphics - * configuration object - * @since 1.4 - */ - public BufferCapabilities getBufferCapabilities() { - if (defaultBufferCaps == null) { - defaultBufferCaps = new DefaultBufferCapabilities( - getImageCapabilities()); - } - return defaultBufferCaps; - } - - /** - * Returns the image capabilities of this - * <code>GraphicsConfiguration</code>. - * @return the image capabilities of this graphics - * configuration object - * @since 1.4 - */ - public ImageCapabilities getImageCapabilities() { - if (defaultImageCaps == null) { - defaultImageCaps = new ImageCapabilities(false); - } - return defaultImageCaps; - } - - /** - * Returns whether this {@code GraphicsConfiguration} supports - * the {@link GraphicsDevice.WindowTranslucency#PERPIXEL_TRANSLUCENT - * PERPIXEL_TRANSLUCENT} kind of translucency. - * - * @return whether the given GraphicsConfiguration supports - * the translucency effects. - * - * @see Window#setBackground(Color) - * - * @since 1.7 - */ - public boolean isTranslucencyCapable() { - // Overridden in subclasses - return false; - } -} diff --git a/openjdk/java/awt/Image.java b/openjdk/java/awt/Image.java deleted file mode 100644 index bc643781..00000000 --- a/openjdk/java/awt/Image.java +++ /dev/null @@ -1,353 +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.awt; - -import java.awt.image.ImageProducer; -import java.awt.image.ImageObserver; -import java.awt.image.ImageFilter; -import java.awt.image.FilteredImageSource; -import java.awt.image.AreaAveragingScaleFilter; -import java.awt.image.ReplicateScaleFilter; - -//import sun.awt.image.SurfaceManager; - -/** - * The abstract class <code>Image</code> is the superclass of all - * classes that represent graphical images. The image must be - * obtained in a platform-specific manner. - * - * @author Sami Shaio - * @author Arthur van Hoff - * @since JDK1.0 - */ -public abstract class Image { - - /** - * convenience object; we can use this single static object for - * all images that do not create their own image caps; it holds the - * default (unaccelerated) properties. - */ - private static ImageCapabilities defaultImageCaps = - new ImageCapabilities(false); - - /** - * Priority for accelerating this image. Subclasses are free to - * set different default priorities and applications are free to - * set the priority for specific images via the - * <code>setAccelerationPriority(float)</code> method. - * @since 1.5 - */ - protected float accelerationPriority = .5f; - - /** - * Determines the width of the image. If the width is not yet known, - * this method returns <code>-1</code> and the specified - * <code>ImageObserver</code> object is notified later. - * @param observer an object waiting for the image to be loaded. - * @return the width of this image, or <code>-1</code> - * if the width is not yet known. - * @see java.awt.Image#getHeight - * @see java.awt.image.ImageObserver - */ - public abstract int getWidth(ImageObserver observer); - - /** - * Determines the height of the image. If the height is not yet known, - * this method returns <code>-1</code> and the specified - * <code>ImageObserver</code> object is notified later. - * @param observer an object waiting for the image to be loaded. - * @return the height of this image, or <code>-1</code> - * if the height is not yet known. - * @see java.awt.Image#getWidth - * @see java.awt.image.ImageObserver - */ - public abstract int getHeight(ImageObserver observer); - - /** - * Gets the object that produces the pixels for the image. - * This method is called by the image filtering classes and by - * methods that perform image conversion and scaling. - * @return the image producer that produces the pixels - * for this image. - * @see java.awt.image.ImageProducer - */ - public abstract ImageProducer getSource(); - - /** - * Creates a graphics context for drawing to an off-screen image. - * This method can only be called for off-screen images. - * @return a graphics context to draw to the off-screen image. - * @exception UnsupportedOperationException if called for a - * non-off-screen image. - * @see java.awt.Graphics - * @see java.awt.Component#createImage(int, int) - */ - public abstract Graphics getGraphics(); - - /** - * Gets a property of this image by name. - * <p> - * Individual property names are defined by the various image - * formats. If a property is not defined for a particular image, this - * method returns the <code>UndefinedProperty</code> object. - * <p> - * If the properties for this image are not yet known, this method - * returns <code>null</code>, and the <code>ImageObserver</code> - * object is notified later. - * <p> - * The property name <code>"comment"</code> should be used to store - * an optional comment which can be presented to the application as a - * description of the image, its source, or its author. - * @param name a property name. - * @param observer an object waiting for this image to be loaded. - * @return the value of the named property. - * @throws <code>NullPointerException</code> if the property name is null. - * @see java.awt.image.ImageObserver - * @see java.awt.Image#UndefinedProperty - */ - public abstract Object getProperty(String name, ImageObserver observer); - - /** - * The <code>UndefinedProperty</code> object should be returned whenever a - * property which was not defined for a particular image is fetched. - */ - public static final Object UndefinedProperty = new Object(); - - /** - * Creates a scaled version of this image. - * A new <code>Image</code> object is returned which will render - * the image at the specified <code>width</code> and - * <code>height</code> by default. The new <code>Image</code> object - * may be loaded asynchronously even if the original source image - * has already been loaded completely. - * - * <p> - * - * If either <code>width</code> - * or <code>height</code> is a negative number then a value is - * substituted to maintain the aspect ratio of the original image - * dimensions. If both <code>width</code> and <code>height</code> - * are negative, then the original image dimensions are used. - * - * @param width the width to which to scale the image. - * @param height the height to which to scale the image. - * @param hints flags to indicate the type of algorithm to use - * for image resampling. - * @return a scaled version of the image. - * @exception IllegalArgumentException if <code>width</code> - * or <code>height</code> is zero. - * @see java.awt.Image#SCALE_DEFAULT - * @see java.awt.Image#SCALE_FAST - * @see java.awt.Image#SCALE_SMOOTH - * @see java.awt.Image#SCALE_REPLICATE - * @see java.awt.Image#SCALE_AREA_AVERAGING - * @since JDK1.1 - */ - public Image getScaledInstance(int width, int height, int hints) { - ImageFilter filter; - if ((hints & (SCALE_SMOOTH | SCALE_AREA_AVERAGING)) != 0) { - filter = new AreaAveragingScaleFilter(width, height); - } else { - filter = new ReplicateScaleFilter(width, height); - } - ImageProducer prod; - prod = new FilteredImageSource(getSource(), filter); - return Toolkit.getDefaultToolkit().createImage(prod); - } - - /** - * Use the default image-scaling algorithm. - * @since JDK1.1 - */ - public static final int SCALE_DEFAULT = 1; - - /** - * Choose an image-scaling algorithm that gives higher priority - * to scaling speed than smoothness of the scaled image. - * @since JDK1.1 - */ - public static final int SCALE_FAST = 2; - - /** - * Choose an image-scaling algorithm that gives higher priority - * to image smoothness than scaling speed. - * @since JDK1.1 - */ - public static final int SCALE_SMOOTH = 4; - - /** - * Use the image scaling algorithm embodied in the - * <code>ReplicateScaleFilter</code> class. - * The <code>Image</code> object is free to substitute a different filter - * that performs the same algorithm yet integrates more efficiently - * into the imaging infrastructure supplied by the toolkit. - * @see java.awt.image.ReplicateScaleFilter - * @since JDK1.1 - */ - public static final int SCALE_REPLICATE = 8; - - /** - * Use the Area Averaging image scaling algorithm. The - * image object is free to substitute a different filter that - * performs the same algorithm yet integrates more efficiently - * into the image infrastructure supplied by the toolkit. - * @see java.awt.image.AreaAveragingScaleFilter - * @since JDK1.1 - */ - public static final int SCALE_AREA_AVERAGING = 16; - - /** - * Flushes all reconstructable resources being used by this Image object. - * This includes any pixel data that is being cached for rendering to - * the screen as well as any system resources that are being used - * to store data or pixels for the image if they can be recreated. - * The image is reset to a state similar to when it was first created - * so that if it is again rendered, the image data will have to be - * recreated or fetched again from its source. - * <p> - * Examples of how this method affects specific types of Image object: - * <ul> - * <li> - * BufferedImage objects leave the primary Raster which stores their - * pixels untouched, but flush any information cached about those - * pixels such as copies uploaded to the display hardware for - * accelerated blits. - * <li> - * Image objects created by the Component methods which take a - * width and height leave their primary buffer of pixels untouched, - * but have all cached information released much like is done for - * BufferedImage objects. - * <li> - * VolatileImage objects release all of their pixel resources - * including their primary copy which is typically stored on - * the display hardware where resources are scarce. - * These objects can later be restored using their - * {@link java.awt.image.VolatileImage#validate validate} - * method. - * <li> - * Image objects created by the Toolkit and Component classes which are - * loaded from files, URLs or produced by an {@link ImageProducer} - * are unloaded and all local resources are released. - * These objects can later be reloaded from their original source - * as needed when they are rendered, just as when they were first - * created. - * </ul> - */ - public void flush() { -// if (surfaceManager != null) { -// surfaceManager.flush(); -// } - } - - /** - * Returns an ImageCapabilities object which can be - * inquired as to the capabilities of this - * Image on the specified GraphicsConfiguration. - * This allows programmers to find - * out more runtime information on the specific Image - * object that they have created. For example, the user - * might create a BufferedImage but the system may have - * no video memory left for creating an image of that - * size on the given GraphicsConfiguration, so although the object - * may be acceleratable in general, it - * does not have that capability on this GraphicsConfiguration. - * @param gc a <code>GraphicsConfiguration</code> object. A value of null - * for this parameter will result in getting the image capabilities - * for the default <code>GraphicsConfiguration</code>. - * @return an <code>ImageCapabilities</code> object that contains - * the capabilities of this <code>Image</code> on the specified - * GraphicsConfiguration. - * @see java.awt.image.VolatileImage#getCapabilities() - * VolatileImage.getCapabilities() - * @since 1.5 - */ - public ImageCapabilities getCapabilities(GraphicsConfiguration gc) { -// if (surfaceManager != null) { -// return surfaceManager.getCapabilities(gc); -// } - // Note: this is just a default object that gets returned in the - // absence of any more specific information from a surfaceManager. - // Subclasses of Image should either override this method or - // make sure that they always have a non-null SurfaceManager - // to return an ImageCapabilities object that is appropriate - // for their given subclass type. - return defaultImageCaps; - } - - /** - * Sets a hint for this image about how important acceleration is. - * This priority hint is used to compare to the priorities of other - * Image objects when determining how to use scarce acceleration - * resources such as video memory. When and if it is possible to - * accelerate this Image, if there are not enough resources available - * to provide that acceleration but enough can be freed up by - * de-accelerating some other image of lower priority, then that other - * Image may be de-accelerated in deference to this one. Images - * that have the same priority take up resources on a first-come, - * first-served basis. - * @param priority a value between 0 and 1, inclusive, where higher - * values indicate more importance for acceleration. A value of 0 - * means that this Image should never be accelerated. Other values - * are used simply to determine acceleration priority relative to other - * Images. - * @throws IllegalArgumentException if <code>priority</code> is less - * than zero or greater than 1. - * @since 1.5 - */ - public void setAccelerationPriority(float priority) { - if (priority < 0 || priority > 1) { - throw new IllegalArgumentException("Priority must be a value " + - "between 0 and 1, inclusive"); - } - accelerationPriority = priority; -// if (surfaceManager != null) { -// surfaceManager.setAccelerationPriority(accelerationPriority); -// } - } - - /** - * Returns the current value of the acceleration priority hint. - * @see #setAccelerationPriority(float priority) setAccelerationPriority - * @return value between 0 and 1, inclusive, which represents the current - * priority value - * @since 1.5 - */ - public float getAccelerationPriority() { - return accelerationPriority; - } - -// SurfaceManager surfaceManager; -// -// static { -// SurfaceManager.setImageAccessor(new SurfaceManager.ImageAccessor() { -// public SurfaceManager getSurfaceManager(Image img) { -// return img.surfaceManager; -// } -// public void setSurfaceManager(Image img, SurfaceManager mgr) { -// img.surfaceManager = mgr; -// } -// }); -// } -} diff --git a/openjdk/java/awt/color/ICC_ColorSpace.java b/openjdk/java/awt/color/ICC_ColorSpace.java deleted file mode 100644 index 465d7dc4..00000000 --- a/openjdk/java/awt/color/ICC_ColorSpace.java +++ /dev/null @@ -1,295 +0,0 @@ -/* ICC_ColorSpace.java -- the canonical color space implementation - Copyright (C) 2000, 2002, 2004 Free Software Foundation - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - - -package java.awt.color; - -import gnu.java.awt.color.CieXyzConverter; -import gnu.java.awt.color.ClutProfileConverter; -import gnu.java.awt.color.ColorSpaceConverter; -import gnu.java.awt.color.GrayProfileConverter; -import gnu.java.awt.color.GrayScaleConverter; -import gnu.java.awt.color.RgbProfileConverter; -import gnu.java.awt.color.SrgbConverter; - -import java.io.IOException; -import java.io.ObjectInputStream; - -/** - * ICC_ColorSpace - an implementation of ColorSpace - * - * While an ICC_Profile class abstracts the data in an ICC profile file - * an ICC_ColorSpace performs the color space conversions defined by - * an ICC_Profile instance. - * - * Typically, an ICC_Profile will either be created using getInstance, - * either from the built-in colorspaces, or from an ICC profile file. - * Then a ICC_Colorspace will be used to perform transforms from the - * device colorspace to and from the profile color space. - * - * The PCS used by ColorSpace is CIE XYZ relative a D50 white point. - * (Profiles using a CIE Lab PCS will have their input and output converted - * to D50 CIE XYZ accordingly. - * - * Note that a valid profile may not contain transforms in both directions, - * in which case the output may be undefined. - * All built-in colorspaces have bidirectional transforms, but developers - * using an ICC profile file may want to check the profile class using - * the ICC_Profile.getProfileClass() method. Input class profiles are - * guaranteed to have transforms to the PCS, output class profiles are - * guaranteed to have transforms from the PCS to device space. - * - * @author Sven de Marothy - * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) - * @since 1.2 - */ -public class ICC_ColorSpace extends ColorSpace -{ - /** - * Compatible with JDK 1.2+. - */ - private static final long serialVersionUID = 3455889114070431483L; - - /** - * @serial - */ - private ICC_Profile thisProfile; - - /** - * @serial - */ - private float[] minVal; - - /** - * @serial - */ - private float[] maxVal; - - /** - * @serial - */ - private float[] diffMinMax; - - /** - * @serial - */ - private float[] invDiffMinMax; - - /** - * @serial - */ - private boolean needScaleInit; - - /** - * Tells us if the PCS is CIE LAB (must be CIEXYZ otherwise) - */ - private transient int type; - private transient int nComponents; - private transient ColorSpaceConverter converter; - - /** - * Constructs a new ICC_ColorSpace from an ICC_Profile object. - * - * @exception IllegalArgumentException If profile is inappropriate for - * representing a ColorSpace. - */ - public ICC_ColorSpace(ICC_Profile profile) - { - super(profile.getColorSpaceType(), profile.getNumComponents()); - - converter = getConverter(profile); - thisProfile = profile; - nComponents = profile.getNumComponents(); - type = profile.getColorSpaceType(); - makeArrays(); - } - - /** - * Return the profile - */ - public ICC_Profile getProfile() - { - return thisProfile; - } - - /** - * Transforms a color value assumed to be in this ColorSpace into a value in - * the default CS_sRGB color space. - * - * @exception ArrayIndexOutOfBoundsException If array length is not at least - * the number of components in this ColorSpace. - */ - public float[] toRGB(float[] colorvalue) - { - return converter.toRGB(colorvalue); - } - - /** - * Transforms a color value assumed to be in the default CS_sRGB color space - * into this ColorSpace. - * - * @exception ArrayIndexOutOfBoundsException If array length is not at - * least 3. - */ - public float[] fromRGB(float[] rgbvalue) - { - return converter.fromRGB(rgbvalue); - } - - /** - * Transforms a color value assumed to be in this ColorSpace into the - * CS_CIEXYZ conversion color space. - * - * @exception ArrayIndexOutOfBoundsException If array length is not at - * least the number of components in this ColorSpace. - */ - public float[] toCIEXYZ(float[] colorvalue) - { - return converter.toCIEXYZ(colorvalue); - } - - /** - * Transforms a color value assumed to be in the CS_CIEXYZ conversion color - * space into this ColorSpace. - * - * @exception ArrayIndexOutOfBoundsException If array length is not at - * least 3. - */ - public float[] fromCIEXYZ(float[] colorvalue) - { - return converter.fromCIEXYZ(colorvalue); - } - - /** - * Returns the minimum normalized color component value for the specified - * component. - * - * @exception IllegalArgumentException If component is less than 0 or greater - * than numComponents - 1. - * - * @since 1.4 - */ - public float getMinValue(int idx) - { - // FIXME: Not 100% certain of this. - if (type == ColorSpace.TYPE_Lab && (idx == 1 || idx == 2)) - return -128f; - - if (idx < 0 || idx >= nComponents) - throw new IllegalArgumentException(); - return 0; - } - - /** - * Returns the maximum normalized color component value for the specified - * component. - * - * @exception IllegalArgumentException If component is less than 0 or greater - * than numComponents - 1. - * - * @since 1.4 - */ - public float getMaxValue(int idx) - { - if (type == ColorSpace.TYPE_XYZ && idx >= 0 && idx <= 2) - return 1 + 32767 / 32768f; - else if (type == ColorSpace.TYPE_Lab) - { - if (idx == 0) - return 100; - if (idx == 1 || idx == 2) - return 127; - } - if (idx < 0 || idx >= nComponents) - throw new IllegalArgumentException(); - return 1; - } - - /** - * Returns a colorspace converter suitable for a given profile - */ - private ColorSpaceConverter getConverter(ICC_Profile profile) - { - ColorSpaceConverter converter; - switch (profile.getColorSpaceType()) - { - case TYPE_XYZ: - converter = new CieXyzConverter(); - break; - default: - if (profile instanceof ICC_ProfileRGB) - converter = new RgbProfileConverter((ICC_ProfileRGB) profile); - else if (profile instanceof ICC_ProfileGray) - converter = new GrayProfileConverter((ICC_ProfileGray) profile); - else - converter = new ClutProfileConverter(profile); - break; - } - return converter; - } - - /** - * Serialization compatibility requires these variable to be set, - * although we don't use them. Perhaps we should? - */ - private void makeArrays() - { - minVal = new float[nComponents]; - maxVal = new float[nComponents]; - - invDiffMinMax = diffMinMax = null; - for (int i = 0; i < nComponents; i++) - { - minVal[i] = getMinValue(i); - maxVal[i] = getMaxValue(i); - } - needScaleInit = true; - } - - /** - * Deserializes the object - */ - private void readObject(ObjectInputStream s) - throws IOException, ClassNotFoundException - { - s.defaultReadObject(); - // set up objects - converter = getConverter(thisProfile); - nComponents = thisProfile.getNumComponents(); - type = thisProfile.getColorSpaceType(); - } -} // class ICC_ColorSpace diff --git a/openjdk/java/awt/image/AffineTransformOp.java b/openjdk/java/awt/image/AffineTransformOp.java deleted file mode 100644 index df9db7d9..00000000 --- a/openjdk/java/awt/image/AffineTransformOp.java +++ /dev/null @@ -1,608 +0,0 @@ -/* AffineTransformOp.java -- This class performs affine - transformation between two images or rasters in 2 dimensions. - Copyright (C) 2004, 2006 Free Software Foundation - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - -package java.awt.image; - -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.RenderingHints; -import java.awt.geom.AffineTransform; -import java.awt.geom.NoninvertibleTransformException; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.util.Arrays; - -/** - * AffineTransformOp performs matrix-based transformations (translations, - * scales, flips, rotations, and shears). - * - * If interpolation is required, nearest neighbour, bilinear, and bicubic - * methods are available. - * - * @author Olga Rodimina (rodimina@redhat.com) - * @author Francis Kung (fkung@redhat.com) - */ -public class AffineTransformOp implements BufferedImageOp, RasterOp -{ - public static final int TYPE_NEAREST_NEIGHBOR = 1; - - public static final int TYPE_BILINEAR = 2; - - /** - * @since 1.5.0 - */ - public static final int TYPE_BICUBIC = 3; - - private AffineTransform transform; - private RenderingHints hints; - - /** - * Construct AffineTransformOp with the given xform and interpolationType. - * Interpolation type can be TYPE_BILINEAR, TYPE_BICUBIC or - * TYPE_NEAREST_NEIGHBOR. - * - * @param xform AffineTransform that will applied to the source image - * @param interpolationType type of interpolation used - * @throws ImagingOpException if the transform matrix is noninvertible - */ - public AffineTransformOp (AffineTransform xform, int interpolationType) - { - this.transform = xform; - if (xform.getDeterminant() == 0) - throw new ImagingOpException(null); - - switch (interpolationType) - { - case TYPE_BILINEAR: - hints = new RenderingHints (RenderingHints.KEY_INTERPOLATION, - RenderingHints.VALUE_INTERPOLATION_BILINEAR); - break; - case TYPE_BICUBIC: - hints = new RenderingHints (RenderingHints.KEY_INTERPOLATION, - RenderingHints.VALUE_INTERPOLATION_BICUBIC); - break; - default: - hints = new RenderingHints (RenderingHints.KEY_INTERPOLATION, - RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR); - } - } - - /** - * Construct AffineTransformOp with the given xform and rendering hints. - * - * @param xform AffineTransform that will applied to the source image - * @param hints rendering hints that will be used during transformation - * @throws ImagingOpException if the transform matrix is noninvertible - */ - public AffineTransformOp (AffineTransform xform, RenderingHints hints) - { - this.transform = xform; - this.hints = hints; - if (xform.getDeterminant() == 0) - throw new ImagingOpException(null); - } - - /** - * Creates a new BufferedImage with the size equal to that of the - * transformed image and the correct number of bands. The newly created - * image is created with the specified ColorModel. - * If a ColorModel is not specified, an appropriate ColorModel is used. - * - * @param src the source image. - * @param destCM color model for the destination image (can be null). - * @return a new compatible destination image. - */ - public BufferedImage createCompatibleDestImage (BufferedImage src, - ColorModel destCM) - { - if (destCM != null) - return new BufferedImage(destCM, - createCompatibleDestRaster(src.getRaster()), - src.isAlphaPremultiplied(), null); - - // This behaviour was determined by Mauve testcases, and is compatible - // with the reference implementation - if (src.getType() == BufferedImage.TYPE_INT_ARGB_PRE - || src.getType() == BufferedImage.TYPE_4BYTE_ABGR - || src.getType() == BufferedImage.TYPE_4BYTE_ABGR_PRE) - return new BufferedImage(src.getWidth(), src.getHeight(), src.getType()); - - else - return new BufferedImage(src.getWidth(), src.getHeight(), - BufferedImage.TYPE_INT_ARGB); - } - - /** - * Creates a new WritableRaster with the size equal to the transformed - * source raster and correct number of bands . - * - * @param src the source raster. - * @throws RasterFormatException if resulting width or height of raster is 0. - * @return a new compatible raster. - */ - public WritableRaster createCompatibleDestRaster (Raster src) - { - Rectangle2D rect = getBounds2D(src); - - if (rect.getWidth() == 0 || rect.getHeight() == 0) - throw new RasterFormatException("width or height is 0"); - - return src.createCompatibleWritableRaster((int) rect.getWidth(), - (int) rect.getHeight()); - } - - /** - * Transforms source image using transform specified at the constructor. - * The resulting transformed image is stored in the destination image if one - * is provided; otherwise a new BufferedImage is created and returned. - * - * @param src source image - * @param dst destination image - * @throws IllegalArgumentException if the source and destination image are - * the same - * @return transformed source image. - */ - public final BufferedImage filter (BufferedImage src, BufferedImage dst) - { - if (dst == src) - throw new IllegalArgumentException("src image cannot be the same as " - + "the dst image"); - - // If the destination image is null, then use a compatible BufferedImage - if (dst == null) - dst = createCompatibleDestImage(src, null); - - Graphics2D gr = dst.createGraphics(); - gr.setRenderingHints(hints); - gr.drawImage(src, transform, null); - return dst; - } - - /** - * Transforms source raster using transform specified at the constructor. - * The resulting raster is stored in the destination raster if it is not - * null, otherwise a new raster is created and returned. - * - * @param src source raster - * @param dst destination raster - * @throws IllegalArgumentException if the source and destination are not - * compatible - * @return transformed raster. - */ - public final WritableRaster filter(Raster src, WritableRaster dst) - { - // Initial checks - if (dst == src) - throw new IllegalArgumentException("src image cannot be the same as" - + " the dst image"); - - if (dst == null) - dst = createCompatibleDestRaster(src); - - if (src.getNumBands() != dst.getNumBands()) - throw new IllegalArgumentException("src and dst must have same number" - + " of bands"); - - // Optimization for rasters that can be represented in the RGB colormodel: - // wrap the rasters in images, and let Cairo do the transformation - if (ColorModel.getRGBdefault().isCompatibleSampleModel(src.getSampleModel()) - && ColorModel.getRGBdefault().isCompatibleSampleModel(dst.getSampleModel())) - { - WritableRaster src2 = Raster.createWritableRaster(src.getSampleModel(), - src.getDataBuffer(), - new Point(src.getMinX(), - src.getMinY())); - BufferedImage iSrc = new BufferedImage(ColorModel.getRGBdefault(), - src2, false, null); - BufferedImage iDst = new BufferedImage(ColorModel.getRGBdefault(), dst, - false, null); - - return filter(iSrc, iDst).getRaster(); - } - - // Otherwise, we need to do the transformation in java code... - // Create arrays to hold all the points - double[] dstPts = new double[dst.getHeight() * dst.getWidth() * 2]; - double[] srcPts = new double[dst.getHeight() * dst.getWidth() * 2]; - - // Populate array with all points in the *destination* raster - int i = 0; - for (int x = 0; x < dst.getWidth(); x++) - { - for (int y = 0; y < dst.getHeight(); y++) - { - dstPts[i++] = x; - dstPts[i++] = y; - } - } - Rectangle srcbounds = src.getBounds(); - - // Use an inverse transform to map each point in the destination to - // a point in the source. Note that, while all points in the destination - // matrix are integers, this is not necessarily true for points in the - // source (hence why interpolation is required) - try - { - AffineTransform inverseTx = transform.createInverse(); - inverseTx.transform(dstPts, 0, srcPts, 0, dstPts.length / 2); - } - catch (NoninvertibleTransformException e) - { - // Shouldn't happen since the constructor traps this - throw new ImagingOpException(e.getMessage()); - } - - // Different interpolation methods... - if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)) - filterNearest(src, dst, dstPts, srcPts); - - else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR)) - filterBilinear(src, dst, dstPts, srcPts); - - else // bicubic - filterBicubic(src, dst, dstPts, srcPts); - - return dst; - } - - /** - * Transforms source image using transform specified at the constructor and - * returns bounds of the transformed image. - * - * @param src image to be transformed - * @return bounds of the transformed image. - */ - public final Rectangle2D getBounds2D (BufferedImage src) - { - return getBounds2D (src.getRaster()); - } - - /** - * Returns bounds of the transformed raster. - * - * @param src raster to be transformed - * @return bounds of the transformed raster. - */ - public final Rectangle2D getBounds2D (Raster src) - { - return transform.createTransformedShape(src.getBounds()).getBounds2D(); - } - - /** - * Returns interpolation type used during transformations. - * - * @return interpolation type - */ - public final int getInterpolationType () - { - if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR)) - return TYPE_BILINEAR; - - else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BICUBIC)) - return TYPE_BICUBIC; - - else - return TYPE_NEAREST_NEIGHBOR; - } - - /** - * Returns location of the transformed source point. The resulting point - * is stored in the dstPt if one is specified. - * - * @param srcPt point to be transformed - * @param dstPt destination point - * @return the location of the transformed source point. - */ - public final Point2D getPoint2D (Point2D srcPt, Point2D dstPt) - { - return transform.transform (srcPt, dstPt); - } - - /** - * Returns rendering hints that are used during transformation. - * - * @return the rendering hints used in this Op. - */ - public final RenderingHints getRenderingHints () - { - return hints; - } - - /** - * Returns transform used in transformation between source and destination - * image. - * - * @return the transform used in this Op. - */ - public final AffineTransform getTransform () - { - return transform; - } - - /** - * Perform nearest-neighbour filtering - * - * @param src the source raster - * @param dst the destination raster - * @param dpts array of points on the destination raster - * @param pts array of corresponding points on the source raster - */ - private void filterNearest(Raster src, WritableRaster dst, double[] dpts, - double[] pts) - { - Rectangle srcbounds = src.getBounds(); - - // For all points on the destination raster, copy the value from the - // corrosponding (rounded) source point - for (int i = 0; i < dpts.length; i += 2) - { - int srcX = (int) Math.round(pts[i]) + src.getMinX(); - int srcY = (int) Math.round(pts[i + 1]) + src.getMinY(); - - if (srcbounds.contains(srcX, srcY)) - dst.setDataElements((int) dpts[i] + dst.getMinX(), - (int) dpts[i + 1] + dst.getMinY(), - src.getDataElements(srcX, srcY, null)); - } - } - - /** - * Perform bilinear filtering - * - * @param src the source raster - * @param dst the destination raster - * @param dpts array of points on the destination raster - * @param pts array of corresponding points on the source raster - */ - private void filterBilinear(Raster src, WritableRaster dst, double[] dpts, - double[] pts) - { - Rectangle srcbounds = src.getBounds(); - - Object xyarr = null; - Object xp1arr = null; - Object yp1arr = null; - Object xyp1arr = null; - - double xy; - double xp1; - double yp1; - double xyp1; - - double[] result = new double[src.getNumBands()]; - - // For all points in the destination raster, use bilinear interpolation - // to find the value from the corrosponding source points - for (int i = 0; i < dpts.length; i += 2) - { - int srcX = (int) Math.round(pts[i]) + src.getMinX(); - int srcY = (int) Math.round(pts[i + 1]) + src.getMinY(); - - if (srcbounds.contains(srcX, srcY)) - { - // Corner case at the bottom or right edge; use nearest neighbour - if (pts[i] >= src.getWidth() - 1 - || pts[i + 1] >= src.getHeight() - 1) - dst.setDataElements((int) dpts[i] + dst.getMinX(), - (int) dpts[i + 1] + dst.getMinY(), - src.getDataElements(srcX, srcY, null)); - - // Standard case, apply the bilinear formula - else - { - int x = (int) Math.floor(pts[i] + src.getMinX()); - int y = (int) Math.floor(pts[i + 1] + src.getMinY()); - double xdiff = pts[i] + src.getMinX() - x; - double ydiff = pts[i + 1] + src.getMinY() - y; - - // Get surrounding pixels used in interpolation... optimized - // to use the smallest datatype possible. - if (src.getTransferType() == DataBuffer.TYPE_DOUBLE - || src.getTransferType() == DataBuffer.TYPE_FLOAT) - { - xyarr = src.getPixel(x, y, (double[])xyarr); - xp1arr = src.getPixel(x+1, y, (double[])xp1arr); - yp1arr = src.getPixel(x, y+1, (double[])yp1arr); - xyp1arr = src.getPixel(x+1, y+1, (double[])xyp1arr); - } - else - { - xyarr = src.getPixel(x, y, (int[])xyarr); - xp1arr = src.getPixel(x+1, y, (int[])xp1arr); - yp1arr = src.getPixel(x, y+1, (int[])yp1arr); - xyp1arr = src.getPixel(x+1, y+1, (int[])xyp1arr); - } - // using - // array[] pixels = src.getPixels(x, y, 2, 2, pixels); - // instead of doing four individual src.getPixel() calls - // should be faster, but benchmarking shows that it's not... - - // Run interpolation for each band - for (int j = 0; j < src.getNumBands(); j++) - { - // Pull individual sample values out of array - if (src.getTransferType() == DataBuffer.TYPE_DOUBLE - || src.getTransferType() == DataBuffer.TYPE_FLOAT) - { - xy = ((double[])xyarr)[j]; - xp1 = ((double[])xp1arr)[j]; - yp1 = ((double[])yp1arr)[j]; - xyp1 = ((double[])xyp1arr)[j]; - } - else - { - xy = ((int[])xyarr)[j]; - xp1 = ((int[])xp1arr)[j]; - yp1 = ((int[])yp1arr)[j]; - xyp1 = ((int[])xyp1arr)[j]; - } - - // If all four samples are identical, there's no need to - // calculate anything - if (xy == xp1 && xy == yp1 && xy == xyp1) - result[j] = xy; - - // Run bilinear interpolation formula - else - result[j] = (xy * (1-xdiff) + xp1 * xdiff) - * (1-ydiff) - + (yp1 * (1-xdiff) + xyp1 * xdiff) - * ydiff; - } - - dst.setPixel((int)dpts[i] + dst.getMinX(), - (int)dpts[i+1] + dst.getMinY(), - result); - } - } - } - } - - /** - * Perform bicubic filtering - * based on http://local.wasp.uwa.edu.au/~pbourke/colour/bicubic/ - * - * @param src the source raster - * @param dst the destination raster - * @param dpts array of points on the destination raster - * @param pts array of corresponding points on the source raster - */ - private void filterBicubic(Raster src, WritableRaster dst, double[] dpts, - double[] pts) - { - Rectangle srcbounds = src.getBounds(); - double[] result = new double[src.getNumBands()]; - Object pixels = null; - - // For all points on the destination raster, perform bicubic interpolation - // from corrosponding source points - for (int i = 0; i < dpts.length; i += 2) - { - if (srcbounds.contains((int) Math.round(pts[i]) + src.getMinX(), - (int) Math.round(pts[i + 1]) + src.getMinY())) - { - int x = (int) Math.floor(pts[i] + src.getMinX()); - int y = (int) Math.floor(pts[i + 1] + src.getMinY()); - double dx = pts[i] + src.getMinX() - x; - double dy = pts[i + 1] + src.getMinY() - y; - Arrays.fill(result, 0); - - for (int m = - 1; m < 3; m++) - for (int n = - 1; n < 3; n++) - { - // R(x) = ( P(x+2)^3 - 4 P(x+1)^3 + 6 P(x)^3 - 4 P(x-1)^3 ) / 6 - double r1 = 0; - double r2 = 0; - - // Calculate R(m - dx) - double rx = m - dx + 2; - r1 += rx * rx * rx; - - rx = m - dx + 1; - if (rx > 0) - r1 -= 4 * rx * rx * rx; - - rx = m - dx; - if (rx > 0) - r1 += 6 * rx * rx * rx; - - rx = m - dx - 1; - if (rx > 0) - r1 -= 4 * rx * rx * rx; - - r1 /= 6; - - // Calculate R(dy - n); - rx = dy - n + 2; - if (rx > 0) - r2 += rx * rx * rx; - - rx = dy - n + 1; - if (rx > 0) - r2 -= 4 * rx * rx * rx; - - rx = dy - n; - if (rx > 0) - r2 += 6 * rx * rx * rx; - - rx = dy - n - 1; - if (rx > 0) - r2 -= 4 * rx * rx * rx; - - r2 /= 6; - - // Calculate F(i+m, j+n) R(m - dx) R(dy - n) - // Check corner cases - int srcX = x + m; - if (srcX >= src.getMinX() + src.getWidth()) - srcX = src.getMinX() + src.getWidth() - 1; - else if (srcX < src.getMinX()) - srcX = src.getMinX(); - - int srcY = y + n; - if (srcY >= src.getMinY() + src.getHeight()) - srcY = src.getMinY() + src.getHeight() - 1; - else if (srcY < src.getMinY()) - srcY = src.getMinY(); - - // Calculate once for each band, using the smallest - // datatype possible - if (src.getTransferType() == DataBuffer.TYPE_DOUBLE - || src.getTransferType() == DataBuffer.TYPE_FLOAT) - { - pixels = src.getPixel(srcX, srcY, (double[])pixels); - for (int j = 0; j < result.length; j++) - result[j] += ((double[])pixels)[j] * r1 * r2; - } - else - { - pixels = src.getPixel(srcX, srcY, (int[])pixels); - for (int j = 0; j < result.length; j++) - result[j] += ((int[])pixels)[j] * r1 * r2; - } - } - - // Put it all together - dst.setPixel((int)dpts[i] + dst.getMinX(), - (int)dpts[i+1] + dst.getMinY(), - result); - } - } - } -} diff --git a/openjdk/java/awt/image/BandCombineOp.java b/openjdk/java/awt/image/BandCombineOp.java deleted file mode 100644 index d9ce16fa..00000000 --- a/openjdk/java/awt/image/BandCombineOp.java +++ /dev/null @@ -1,218 +0,0 @@ -/* BandCombineOp.java - perform a combination on the bands of a raster - Copyright (C) 2004, 2006 Free Software Foundation - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - -package java.awt.image; - -import java.awt.RenderingHints; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.util.Arrays; - -/** - * Filter Raster pixels by applying a matrix. - * - * BandCombineOp applies a matrix to each pixel to produce new pixel values. - * The width of the matrix must be the same or one more than the number of - * bands in the source Raster. If one more, the pixels in the source are - * assumed to contain an implicit 1.0 at the end. - * - * The rows of the matrix are multiplied by the pixel to produce the values - * for the destination. Therefore the destination Raster must contain the - * same number of bands as the number of rows in the filter matrix. - * - * This Op assumes that samples are integers; floating point sample types will - * be rounded to their nearest integer value during filtering. - * - * @author Jerry Quinn (jlquinn@optonline.net) - */ -public class BandCombineOp implements RasterOp -{ - private RenderingHints hints; - private float[][] matrix; - - /** - * Construct a BandCombineOp. - * - * @param matrix The matrix to filter pixels with. - * @param hints Rendering hints to apply. Ignored. - * @throws ArrayIndexOutOfBoundsException if the matrix is invalid - */ - public BandCombineOp(float[][] matrix, RenderingHints hints) - { - this.matrix = new float[matrix.length][]; - int width = matrix[0].length; - for (int i = 0; i < matrix.length; i++) - { - this.matrix[i] = new float[width + 1]; - for (int j = 0; j < width; j++) - this.matrix[i][j] = matrix[i][j]; - - // The reference implementation pads the array with a trailing zero... - this.matrix[i][width] = 0; - } - - this.hints = hints; - } - - /** - * Filter Raster pixels through a matrix. Applies the Op matrix to source - * pixes to produce dest pixels. Each row of the matrix is multiplied by the - * src pixel components to produce the dest pixel. If matrix is one more than - * the number of bands in the src, the last element is implicitly multiplied - * by 1, i.e. added to the sum for that dest component. If dest is null, a - * suitable Raster is created. This implementation uses - * createCompatibleDestRaster. - * - * @param src The source Raster. - * @param dest The destination Raster, or null. - * @throws IllegalArgumentException if the destination raster is incompatible - * with the source raster. - * @return The filtered Raster. - * @see java.awt.image.RasterOp#filter(java.awt.image.Raster, - * java.awt.image.WritableRaster) - */ - public WritableRaster filter(Raster src, WritableRaster dest) { - if (dest == null) - dest = createCompatibleDestRaster(src); - else if (dest.getNumBands() != src.getNumBands() - || dest.getTransferType() != src.getTransferType()) - throw new IllegalArgumentException("Destination raster is incompatible with source raster"); - - // Filter the pixels - int[] spix = new int[matrix[0].length - 1]; - int[] spix2 = new int[matrix[0].length - 1]; - int[] dpix = new int[matrix.length]; - for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) - for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) - { - // In case matrix rows have implicit translation - spix[spix.length - 1] = 1; - src.getPixel(x, y, spix); - - // Do not re-calculate if pixel is identical to the last one - // (ie, blocks of the same colour) - if (!Arrays.equals(spix, spix2)) - { - System.arraycopy(spix, 0, spix2, 0, spix.length); - for (int i = 0; i < matrix.length; i++) - { - dpix[i] = 0; - for (int j = 0; j < matrix[0].length - 1; j++) - dpix[i] += spix[j] * (int)matrix[i][j]; - } - } - dest.setPixel(x, y, dpix); - } - - return dest; - } - - /* (non-Javadoc) - * @see java.awt.image.RasterOp#getBounds2D(java.awt.image.Raster) - */ - public final Rectangle2D getBounds2D(Raster src) - { - return src.getBounds(); - } - - /** - * Creates a new WritableRaster that can be used as the destination for this - * Op. The number of bands in the source raster must equal the number of rows - * in the op matrix, which must also be equal to either the number of columns - * or (columns - 1) in the matrix. - * - * @param src The source raster. - * @return A compatible raster. - * @see java.awt.image.RasterOp#createCompatibleDestRaster(java.awt.image.Raster) - * @throws IllegalArgumentException if the raster is incompatible with the - * matrix. - */ - public WritableRaster createCompatibleDestRaster(Raster src) - { - // Destination raster must have same number of bands as source - if (src.getNumBands() != matrix.length) - throw new IllegalArgumentException("Number of rows in matrix specifies an " - + "incompatible number of bands"); - - // We use -1 and -2 because we previously padded the rows with a trailing 0 - if (src.getNumBands() != matrix[0].length - 1 - && src.getNumBands() != matrix[0].length - 2) - throw new IllegalArgumentException("Incompatible number of bands: " - + "the number of bands in the raster must equal the number of " - + "columns in the matrix, optionally minus one"); - - return src.createCompatibleWritableRaster(); - } - - /** - * Return corresponding destination point for source point. Because this is - * not a geometric operation, it simply returns a copy of the source. - * - * @param src The source point. - * @param dst The destination point. - * @return dst The destination point. - * @see java.awt.image.RasterOp#getPoint2D(java.awt.geom.Point2D, - *java.awt.geom.Point2D) - */ - public final Point2D getPoint2D(Point2D src, Point2D dst) - { - if (dst == null) - return (Point2D)src.clone(); - - dst.setLocation(src); - return dst; - } - - /* (non-Javadoc) - * @see java.awt.image.RasterOp#getRenderingHints() - */ - public final RenderingHints getRenderingHints() - { - return hints; - } - - /** - * Return the matrix used in this operation. - * - * @return The matrix used in this operation. - */ - public final float[][] getMatrix() - { - return matrix; - } - -} diff --git a/openjdk/java/awt/image/BufferedImage.java b/openjdk/java/awt/image/BufferedImage.java deleted file mode 100644 index 91be2dc5..00000000 --- a/openjdk/java/awt/image/BufferedImage.java +++ /dev/null @@ -1,1811 +0,0 @@ -/* - * 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 - * 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.awt.image; - -import cli.System.Drawing.Color; -import cli.System.Drawing.Imaging.*; - -import java.awt.Transparency; -import java.awt.color.ColorSpace; -import java.awt.Graphics2D; -import java.awt.GraphicsConfiguration; -import java.awt.GraphicsEnvironment; -import java.awt.ImageCapabilities; -import java.awt.geom.Rectangle2D; -import java.awt.geom.Point2D; -import java.awt.Point; -import java.awt.Rectangle; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.Hashtable; -import java.util.Vector; - -import sun.awt.image.BytePackedRaster; -import sun.awt.image.ShortComponentRaster; -import sun.awt.image.ByteComponentRaster; -import sun.awt.image.IntegerComponentRaster; -import sun.awt.image.OffScreenImageSource; - -/** - * - * The <code>BufferedImage</code> subclass describes an {@link - * java.awt.Image Image} with an accessible buffer of image data. - * A <code>BufferedImage</code> is comprised of a {@link ColorModel} and a - * {@link Raster} of image data. - * The number and types of bands in the {@link SampleModel} of the - * <code>Raster</code> must match the number and types required by the - * <code>ColorModel</code> to represent its color and alpha components. - * All <code>BufferedImage</code> objects have an upper left corner - * coordinate of (0, 0). Any <code>Raster</code> used to construct a - * <code>BufferedImage</code> must therefore have minX=0 and minY=0. - * - * <p> - * This class relies on the data fetching and setting methods - * of <code>Raster</code>, - * and on the color characterization methods of <code>ColorModel</code>. - * - * @see ColorModel - * @see Raster - * @see WritableRaster - */ - -public class BufferedImage extends java.awt.Image - implements WritableRenderedImage, Transparency -{ - int imageType = TYPE_CUSTOM; - ColorModel colorModel; - WritableRaster raster; - OffScreenImageSource osis; - Hashtable properties; - - boolean isAlphaPremultiplied;// If true, alpha has been premultiplied in - // color channels - - /** - * Image Type Constants - */ - - /** - * Image type is not recognized so it must be a customized - * image. This type is only used as a return value for the getType() - * method. - */ - public static final int TYPE_CUSTOM = 0; - - /** - * Represents an image with 8-bit RGB color components packed into - * integer pixels. The image has a {@link DirectColorModel} without - * alpha. - * When data with non-opaque alpha is stored - * in an image of this type, - * the color data must be adjusted to a non-premultiplied form - * and the alpha discarded, - * as described in the - * {@link java.awt.AlphaComposite} documentation. - */ - public static final int TYPE_INT_RGB = 1; - - /** - * Represents an image with 8-bit RGBA color components packed into - * integer pixels. The image has a <code>DirectColorModel</code> - * with alpha. The color data in this image is considered not to be - * premultiplied with alpha. When this type is used as the - * <code>imageType</code> argument to a <code>BufferedImage</code> - * constructor, the created image is consistent with images - * created in the JDK1.1 and earlier releases. - */ - public static final int TYPE_INT_ARGB = 2; - - /** - * Represents an image with 8-bit RGBA color components packed into - * integer pixels. The image has a <code>DirectColorModel</code> - * with alpha. The color data in this image is considered to be - * premultiplied with alpha. - */ - public static final int TYPE_INT_ARGB_PRE = 3; - - /** - * Represents an image with 8-bit RGB color components, corresponding - * to a Windows- or Solaris- style BGR color model, with the colors - * Blue, Green, and Red packed into integer pixels. There is no alpha. - * The image has a {@link DirectColorModel}. - * When data with non-opaque alpha is stored - * in an image of this type, - * the color data must be adjusted to a non-premultiplied form - * and the alpha discarded, - * as described in the - * {@link java.awt.AlphaComposite} documentation. - */ - public static final int TYPE_INT_BGR = 4; - - /** - * Represents an image with 8-bit RGB color components, corresponding - * to a Windows-style BGR color model) with the colors Blue, Green, - * and Red stored in 3 bytes. There is no alpha. The image has a - * <code>ComponentColorModel</code>. - * When data with non-opaque alpha is stored - * in an image of this type, - * the color data must be adjusted to a non-premultiplied form - * and the alpha discarded, - * as described in the - * {@link java.awt.AlphaComposite} documentation. - */ - public static final int TYPE_3BYTE_BGR = 5; - - /** - * Represents an image with 8-bit RGBA color components with the colors - * Blue, Green, and Red stored in 3 bytes and 1 byte of alpha. The - * image has a <code>ComponentColorModel</code> with alpha. The - * color data in this image is considered not to be premultiplied with - * alpha. The byte data is interleaved in a single - * byte array in the order A, B, G, R - * from lower to higher byte addresses within each pixel. - */ - public static final int TYPE_4BYTE_ABGR = 6; - - /** - * Represents an image with 8-bit RGBA color components with the colors - * Blue, Green, and Red stored in 3 bytes and 1 byte of alpha. The - * image has a <code>ComponentColorModel</code> with alpha. The color - * data in this image is considered to be premultiplied with alpha. - * The byte data is interleaved in a single byte array in the order - * A, B, G, R from lower to higher byte addresses within each pixel. - */ - public static final int TYPE_4BYTE_ABGR_PRE = 7; - - /** - * Represents an image with 5-6-5 RGB color components (5-bits red, - * 6-bits green, 5-bits blue) with no alpha. This image has - * a <code>DirectColorModel</code>. - * When data with non-opaque alpha is stored - * in an image of this type, - * the color data must be adjusted to a non-premultiplied form - * and the alpha discarded, - * as described in the - * {@link java.awt.AlphaComposite} documentation. - */ - public static final int TYPE_USHORT_565_RGB = 8; - - /** - * Represents an image with 5-5-5 RGB color components (5-bits red, - * 5-bits green, 5-bits blue) with no alpha. This image has - * a <code>DirectColorModel</code>. - * When data with non-opaque alpha is stored - * in an image of this type, - * the color data must be adjusted to a non-premultiplied form - * and the alpha discarded, - * as described in the - * {@link java.awt.AlphaComposite} documentation. - */ - public static final int TYPE_USHORT_555_RGB = 9; - - /** - * Represents a unsigned byte grayscale image, non-indexed. This - * image has a <code>ComponentColorModel</code> with a CS_GRAY - * {@link ColorSpace}. - * When data with non-opaque alpha is stored - * in an image of this type, - * the color data must be adjusted to a non-premultiplied form - * and the alpha discarded, - * as described in the - * {@link java.awt.AlphaComposite} documentation. - */ - public static final int TYPE_BYTE_GRAY = 10; - - /** - * Represents an unsigned short grayscale image, non-indexed). This - * image has a <code>ComponentColorModel</code> with a CS_GRAY - * <code>ColorSpace</code>. - * When data with non-opaque alpha is stored - * in an image of this type, - * the color data must be adjusted to a non-premultiplied form - * and the alpha discarded, - * as described in the - * {@link java.awt.AlphaComposite} documentation. - */ - public static final int TYPE_USHORT_GRAY = 11; - - /** - * Represents an opaque byte-packed 1, 2, or 4 bit image. The - * image has an {@link IndexColorModel} without alpha. When this - * type is used as the <code>imageType</code> argument to the - * <code>BufferedImage</code> constructor that takes an - * <code>imageType</code> argument but no <code>ColorModel</code> - * argument, a 1-bit image is created with an - * <code>IndexColorModel</code> with two colors in the default - * sRGB <code>ColorSpace</code>: {0, 0, 0} and - * {255, 255, 255}. - * - * <p> Images with 2 or 4 bits per pixel may be constructed via - * the <code>BufferedImage</code> constructor that takes a - * <code>ColorModel</code> argument by supplying a - * <code>ColorModel</code> with an appropriate map size. - * - * <p> Images with 8 bits per pixel should use the image types - * <code>TYPE_BYTE_INDEXED</code> or <code>TYPE_BYTE_GRAY</code> - * depending on their <code>ColorModel</code>. - - * <p> When color data is stored in an image of this type, - * the closest color in the colormap is determined - * by the <code>IndexColorModel</code> and the resulting index is stored. - * Approximation and loss of alpha or color components - * can result, depending on the colors in the - * <code>IndexColorModel</code> colormap. - */ - public static final int TYPE_BYTE_BINARY = 12; - - /** - * Represents an indexed byte image. When this type is used as the - * <code>imageType</code> argument to the <code>BufferedImage</code> - * constructor that takes an <code>imageType</code> argument - * but no <code>ColorModel</code> argument, an - * <code>IndexColorModel</code> is created with - * a 256-color 6/6/6 color cube palette with the rest of the colors - * from 216-255 populated by grayscale values in the - * default sRGB ColorSpace. - * - * <p> When color data is stored in an image of this type, - * the closest color in the colormap is determined - * by the <code>IndexColorModel</code> and the resulting index is stored. - * Approximation and loss of alpha or color components - * can result, depending on the colors in the - * <code>IndexColorModel</code> colormap. - */ - public static final int TYPE_BYTE_INDEXED = 13; - - private static final int DCM_RED_MASK = 0x00ff0000; - private static final int DCM_GREEN_MASK = 0x0000ff00; - private static final int DCM_BLUE_MASK = 0x000000ff; - private static final int DCM_ALPHA_MASK = 0xff000000; - private static final int DCM_565_RED_MASK = 0xf800; - private static final int DCM_565_GRN_MASK = 0x07E0; - private static final int DCM_565_BLU_MASK = 0x001F; - private static final int DCM_555_RED_MASK = 0x7C00; - private static final int DCM_555_GRN_MASK = 0x03E0; - private static final int DCM_555_BLU_MASK = 0x001F; - private static final int DCM_BGR_RED_MASK = 0x0000ff; - private static final int DCM_BGR_GRN_MASK = 0x00ff00; - private static final int DCM_BGR_BLU_MASK = 0xff0000; - - /** reference to the :NET equivalent */ - private cli.System.Drawing.Bitmap bitmap; - - /** Which buffer include the current data, raster or bitmap */ - private int currentBuffer; - - private static final int BUFFER_BITMAP = 1; - private static final int BUFFER_RASTER = 2; - private static final int BUFFER_BOTH = 3; - - /** - * Create a BufferedImage directly from the .NET Bitmap class - */ - @cli.IKVM.Attributes.HideFromJavaAttribute.Annotation - public BufferedImage(cli.System.Drawing.Bitmap bitmap){ - this.imageType = TYPE_INT_ARGB; - this.colorModel = createColorModel(); - this.bitmap = bitmap; - this.currentBuffer = BUFFER_BITMAP; - } - - /** - * Constructs a <code>BufferedImage</code> of one of the predefined - * image types. The <code>ColorSpace</code> for the image is the - * default sRGB space. - * @param width width of the created image - * @param height height of the created image - * @param imageType type of the created image - * @see ColorSpace - * @see #TYPE_INT_RGB - * @see #TYPE_INT_ARGB - * @see #TYPE_INT_ARGB_PRE - * @see #TYPE_INT_BGR - * @see #TYPE_3BYTE_BGR - * @see #TYPE_4BYTE_ABGR - * @see #TYPE_4BYTE_ABGR_PRE - * @see #TYPE_BYTE_GRAY - * @see #TYPE_USHORT_GRAY - * @see #TYPE_BYTE_BINARY - * @see #TYPE_BYTE_INDEXED - * @see #TYPE_USHORT_565_RGB - * @see #TYPE_USHORT_555_RGB - */ - public BufferedImage(int width, - int height, - int imageType) { - this.imageType = imageType; - this.colorModel = createColorModel(); - this.bitmap = createBitmap(width, height); - this.currentBuffer = BUFFER_BITMAP; - } - - /** - * Create a Bitmap if not already one exists - * @param width width of the created image - * @param height height of the created image - * @return a Bitmap object, never null - */ - private cli.System.Drawing.Bitmap createBitmap(int width, int height){ - if(bitmap != null){ - return bitmap; - } - if(width <= 0 || height <= 0){ - throw new IllegalArgumentException("Width (" + width + ") and height (" + height + ") cannot be <= 0"); - } - return new cli.System.Drawing.Bitmap(width, height, PixelFormat.wrap(PixelFormat.Format32bppArgb)); - } - - /** - * Constructs a <code>BufferedImage</code> of one of the predefined - * image types: - * TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED. - * - * <p> If the image type is TYPE_BYTE_BINARY, the number of - * entries in the color model is used to determine whether the - * image should have 1, 2, or 4 bits per pixel. If the color model - * has 1 or 2 entries, the image will have 1 bit per pixel. If it - * has 3 or 4 entries, the image with have 2 bits per pixel. If - * it has between 5 and 16 entries, the image will have 4 bits per - * pixel. Otherwise, an IllegalArgumentException will be thrown. - * - * @param width width of the created image - * @param height height of the created image - * @param imageType type of the created image - * @param cm <code>IndexColorModel</code> of the created image - * @throws IllegalArgumentException if the imageType is not - * TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED or if the imageType is - * TYPE_BYTE_BINARY and the color map has more than 16 entries. - * @see #TYPE_BYTE_BINARY - * @see #TYPE_BYTE_INDEXED - */ - public BufferedImage (int width, - int height, - int imageType, - IndexColorModel cm) { - if (cm.hasAlpha() && cm.isAlphaPremultiplied()) { - throw new IllegalArgumentException("This image types do not have "+ - "premultiplied alpha."); - } - - switch(imageType) { - case TYPE_BYTE_BINARY: - int bits; // Will be set below - int mapSize = cm.getMapSize(); - if (mapSize <= 2) { - bits = 1; - } else if (mapSize <= 4) { - bits = 2; - } else if (mapSize <= 16) { - bits = 4; - } else { - throw new IllegalArgumentException - ("Color map for TYPE_BYTE_BINARY " + - "must have no more than 16 entries"); - } - raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, - width, height, 1, bits, null); - break; - - case TYPE_BYTE_INDEXED: - raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, - width, height, 1, null); - break; - default: - throw new IllegalArgumentException("Invalid image type (" + - imageType+"). Image type must"+ - " be either TYPE_BYTE_BINARY or "+ - " TYPE_BYTE_INDEXED"); - } - - if (!cm.isCompatibleRaster(raster)) { - throw new IllegalArgumentException("Incompatible image type and IndexColorModel"); - } - - colorModel = cm; - this.imageType = imageType; - this.currentBuffer = BUFFER_RASTER; - raster.getDataBuffer().setImage( this ); - } - - /** - * Constructs a new <code>BufferedImage</code> with a specified - * <code>ColorModel</code> and <code>Raster</code>. If the number and - * types of bands in the <code>SampleModel</code> of the - * <code>Raster</code> do not match the number and types required by - * the <code>ColorModel</code> to represent its color and alpha - * components, a {@link RasterFormatException} is thrown. This - * method can multiply or divide the color <code>Raster</code> data by - * alpha to match the <code>alphaPremultiplied</code> state - * in the <code>ColorModel</code>. Properties for this - * <code>BufferedImage</code> can be established by passing - * in a {@link Hashtable} of <code>String</code>/<code>Object</code> - * pairs. - * @param cm <code>ColorModel</code> for the new image - * @param raster <code>Raster</code> for the image data - * @param isRasterPremultiplied if <code>true</code>, the data in - * the raster has been premultiplied with alpha. - * @param properties <code>Hashtable</code> of - * <code>String</code>/<code>Object</code> pairs. - * @exception RasterFormatException if the number and - * types of bands in the <code>SampleModel</code> of the - * <code>Raster</code> do not match the number and types required by - * the <code>ColorModel</code> to represent its color and alpha - * components. - * @exception IllegalArgumentException if - * <code>raster</code> is incompatible with <code>cm</code> - * @see ColorModel - * @see Raster - * @see WritableRaster - */ - - -/* - * - * FOR NOW THE CODE WHICH DEFINES THE RASTER TYPE IS DUPLICATED BY DVF - * SEE THE METHOD DEFINERASTERTYPE @ RASTEROUTPUTMANAGER - * - */ - public BufferedImage (ColorModel cm, - WritableRaster raster, - boolean isRasterPremultiplied, - Hashtable<?,?> properties) { - - if (!cm.isCompatibleRaster(raster)) { - throw new - IllegalArgumentException("Raster "+raster+ - " is incompatible with ColorModel "+ - cm); - } - - if ((raster.minX != 0) || (raster.minY != 0)) { - throw new - IllegalArgumentException("Raster "+raster+ - " has minX or minY not equal to zero: " - + raster.minX + " " + raster.minY); - } - - colorModel = cm; - this.raster = raster; - raster.getDataBuffer().setImage( this ); - this.currentBuffer = BUFFER_RASTER; - this.properties = properties; - int numBands = raster.getNumBands(); - boolean isAlphaPre = cm.isAlphaPremultiplied(); - final boolean isStandard = isStandard(cm, raster); - ColorSpace cs; - - // Force the raster data alpha state to match the premultiplied - // state in the color model - coerceData(isRasterPremultiplied); - - SampleModel sm = raster.getSampleModel(); - cs = cm.getColorSpace(); - int csType = cs.getType(); - if (csType != ColorSpace.TYPE_RGB) { - if (csType == ColorSpace.TYPE_GRAY && - isStandard && - cm instanceof ComponentColorModel) { - // Check if this might be a child raster (fix for bug 4240596) - if (sm instanceof ComponentSampleModel && - ((ComponentSampleModel)sm).getPixelStride() != numBands) { - imageType = TYPE_CUSTOM; - } else if (raster instanceof ByteComponentRaster && - raster.getNumBands() == 1 && - cm.getComponentSize(0) == 8 && - ((ByteComponentRaster)raster).getPixelStride() == 1) { - imageType = TYPE_BYTE_GRAY; - } else if (raster instanceof ShortComponentRaster && - raster.getNumBands() == 1 && - cm.getComponentSize(0) == 16 && - ((ShortComponentRaster)raster).getPixelStride() == 1) { - imageType = TYPE_USHORT_GRAY; - } - } else { - imageType = TYPE_CUSTOM; - } - return; - } - - if ((raster instanceof IntegerComponentRaster) && - (numBands == 3 || numBands == 4)) { - IntegerComponentRaster iraster = - (IntegerComponentRaster) raster; - // Check if the raster params and the color model - // are correct - int pixSize = cm.getPixelSize(); - if (iraster.getPixelStride() == 1 && - isStandard && - cm instanceof DirectColorModel && - (pixSize == 32 || pixSize == 24)) - { - // Now check on the DirectColorModel params - DirectColorModel dcm = (DirectColorModel) cm; - int rmask = dcm.getRedMask(); - int gmask = dcm.getGreenMask(); - int bmask = dcm.getBlueMask(); - if (rmask == DCM_RED_MASK && gmask == DCM_GREEN_MASK && - bmask == DCM_BLUE_MASK) - { - if (dcm.getAlphaMask() == DCM_ALPHA_MASK) { - imageType = (isAlphaPre - ? TYPE_INT_ARGB_PRE - : TYPE_INT_ARGB); - } - else { - // No Alpha - if (!dcm.hasAlpha()) { - imageType = TYPE_INT_RGB; - } - } - } // if (dcm.getRedMask() == DCM_RED_MASK && - else if (rmask == DCM_BGR_RED_MASK && gmask == DCM_BGR_GRN_MASK - && bmask == DCM_BGR_BLU_MASK) { - if (!dcm.hasAlpha()) { - imageType = TYPE_INT_BGR; - } - } // if (rmask == DCM_BGR_RED_MASK && - } // if (iraster.getPixelStride() == 1 - } // ((raster instanceof IntegerComponentRaster) && - else if ((cm instanceof IndexColorModel) && (numBands == 1) && - isStandard && - (!cm.hasAlpha() || !isAlphaPre)) - { - IndexColorModel icm = (IndexColorModel) cm; - int pixSize = icm.getPixelSize(); - - if (raster instanceof BytePackedRaster) { - imageType = TYPE_BYTE_BINARY; - } // if (raster instanceof BytePackedRaster) - else if (raster instanceof ByteComponentRaster) { - ByteComponentRaster braster = (ByteComponentRaster) raster; - if (braster.getPixelStride() == 1 && pixSize <= 8) { - imageType = TYPE_BYTE_INDEXED; - } - } - } // else if (cm instanceof IndexColorModel) && (numBands == 1)) - else if ((raster instanceof ShortComponentRaster) - && (cm instanceof DirectColorModel) - && isStandard - && (numBands == 3) - && !cm.hasAlpha()) - { - DirectColorModel dcm = (DirectColorModel) cm; - if (dcm.getRedMask() == DCM_565_RED_MASK) { - if (dcm.getGreenMask() == DCM_565_GRN_MASK && - dcm.getBlueMask() == DCM_565_BLU_MASK) { - imageType = TYPE_USHORT_565_RGB; - } - } - else if (dcm.getRedMask() == DCM_555_RED_MASK) { - if (dcm.getGreenMask() == DCM_555_GRN_MASK && - dcm.getBlueMask() == DCM_555_BLU_MASK) { - imageType = TYPE_USHORT_555_RGB; - } - } - } // else if ((cm instanceof IndexColorModel) && (numBands == 1)) - else if ((raster instanceof ByteComponentRaster) - && (cm instanceof ComponentColorModel) - && isStandard - && (raster.getSampleModel() instanceof PixelInterleavedSampleModel) - && (numBands == 3 || numBands == 4)) - { - ComponentColorModel ccm = (ComponentColorModel) cm; - PixelInterleavedSampleModel csm = - (PixelInterleavedSampleModel)raster.getSampleModel(); - ByteComponentRaster braster = (ByteComponentRaster) raster; - int[] offs = csm.getBandOffsets(); - if (ccm.getNumComponents() != numBands) { - throw new RasterFormatException("Number of components in "+ - "ColorModel ("+ - ccm.getNumComponents()+ - ") does not match # in "+ - " Raster ("+numBands+")"); - } - int[] nBits = ccm.getComponentSize(); - boolean is8bit = true; - for (int i=0; i < numBands; i++) { - if (nBits[i] != 8) { - is8bit = false; - break; - } - } - if (is8bit && - braster.getPixelStride() == numBands && - offs[0] == numBands-1 && - offs[1] == numBands-2 && - offs[2] == numBands-3) - { - if (numBands == 3 && !ccm.hasAlpha()) { - imageType = TYPE_3BYTE_BGR; - } - else if (offs[3] == 0 && ccm.hasAlpha()) { - imageType = (isAlphaPre - ? TYPE_4BYTE_ABGR_PRE - : TYPE_4BYTE_ABGR); - } - } - } // else if ((raster instanceof ByteComponentRaster) && - } - - private static boolean isStandard(ColorModel cm, WritableRaster wr) { - final Class<? extends ColorModel> cmClass = cm.getClass(); - final Class<? extends WritableRaster> wrClass = wr.getClass(); - final Class<? extends SampleModel> smClass = wr.getSampleModel().getClass(); - - final PrivilegedAction<Boolean> checkClassLoadersAction = - new PrivilegedAction<Boolean>() - { - - @Override - public Boolean run() { - final ClassLoader std = System.class.getClassLoader(); - - return (cmClass.getClassLoader() == std) && - (smClass.getClassLoader() == std) && - (wrClass.getClassLoader() == std); - } - }; - return AccessController.doPrivileged(checkClassLoadersAction); - } - - /** - * Get the .NET Bitmap object. - */ - @cli.IKVM.Attributes.HideFromJavaAttribute.Annotation - public cli.System.Drawing.Bitmap getBitmap(){ - raster2Bitmap(); - return bitmap; - } - - /** - * Switch to the BITMAP buffer and invalidate the RASTER buffer before a graphics operation. - */ - final void toBitmap(){ - raster2Bitmap(); - currentBuffer = BUFFER_BITMAP; - } - - /** - * Switch to the RASTER buffer and invalidate the BITMAP buffer before a graphics operation. - */ - @cli.IKVM.Attributes.HideFromJavaAttribute.Annotation - final void toRaster() { - bitmap2Raster(); - currentBuffer = BUFFER_RASTER; - } - - /** - * This Implementation of BufferedImage has 2 different Buffer, - * a Java WritableRaster and a .NET Bitmap. - * This method convert a Java WritableRaster to a .NET Bitmap if needed. - */ - private void raster2Bitmap(){ - if(currentBuffer != BUFFER_RASTER){ - return; // BUFFER_BOTH and BUFFER_BITMAP - } - int width = getWidth(); - int height = getHeight(); - - bitmap = createBitmap(width, height); - synchronized( bitmap ) { - // First map the pixel from Java type to .NET type - switch (getType()){ - case TYPE_INT_ARGB: - copyToBitmap(width, height, ((DataBufferInt)raster.getDataBuffer()).getData()); - break; - default:{ - for( int y = 0; y<height; y++){ - for(int x = 0; x<width; x++){ - int rgb = colorModel.getRGB(raster.getDataElements(x, y, null)); - bitmap.SetPixel(x, y, cli.System.Drawing.Color.FromArgb(rgb)); - } - } - } - } - this.currentBuffer = BUFFER_BOTH; - } - return; - } - - /** - * Caller must synchronized the bitmap object - */ - @cli.System.Security.SecuritySafeCriticalAttribute.Annotation - private void copyToBitmap(int width, int height, int[] pixelData) - { - long size = (long)width * (long)height; - if (size > pixelData.length) - { - throw new IllegalArgumentException(); - } - cli.System.Drawing.Rectangle rect = new cli.System.Drawing.Rectangle(0, 0, width, height); - cli.System.Drawing.Imaging.BitmapData data = bitmap.LockBits(rect, ImageLockMode.wrap(ImageLockMode.WriteOnly), PixelFormat.wrap(PixelFormat.Format32bppArgb)); - cli.System.IntPtr pixelPtr = data.get_Scan0(); - cli.System.Runtime.InteropServices.Marshal.Copy(pixelData, 0, pixelPtr, (int)size); - bitmap.UnlockBits(data); - } - - /** - * This Implementation of BufferedImage has 2 different Buffer, - * a Java WritableRaster and a .NET Bitmap. - * This method convert the .NET Bitmap object to Java WritableRaster. - */ - private void bitmap2Raster(){ - if(currentBuffer != BUFFER_BITMAP){ - return; // BUFFER_BOTH and BUFFER_RASTER - } - synchronized( bitmap ) { - int width = bitmap.get_Width(); - int height = bitmap.get_Height(); - if(colorModel == null){ - colorModel = createColorModel(); - } - if(raster == null){ - raster = createRaster(width, height); - raster.getDataBuffer().setImage( this ); - } - - this.currentBuffer = BUFFER_BOTH; - switch (getType()){ - case TYPE_INT_ARGB: - copyFromBitmap(bitmap, ((DataBufferInt)raster.getDataBuffer()).getData()); - break; - default: - Object pixel = colorModel.getDataElements( 0, null ); //allocate a buffer for the follow loop - for( int y = 0; y<height; y++){ - for(int x = 0; x<width; x++){ - int rgb = bitmap.GetPixel(x, y).ToArgb(); - raster.setDataElements(x, y, colorModel.getDataElements(rgb, pixel)); - } - } - } - } - } - - @cli.System.Security.SecuritySafeCriticalAttribute.Annotation - private static void copyFromBitmap(cli.System.Drawing.Bitmap bitmap, int[] pixelData) - { - int width = bitmap.get_Width(); - int height = bitmap.get_Height(); - long size = (long)width * (long)height; - if (width <= 0 || height <= 0 || pixelData.length < size) - { - throw new IllegalArgumentException(); - } - cli.System.Drawing.Rectangle rect = new cli.System.Drawing.Rectangle(0, 0, width, height); - cli.System.Drawing.Imaging.BitmapData data = bitmap.LockBits(rect, ImageLockMode.wrap(ImageLockMode.ReadOnly), PixelFormat.wrap(PixelFormat.Format32bppArgb)); - cli.System.IntPtr pixelPtr = data.get_Scan0(); - cli.System.Runtime.InteropServices.Marshal.Copy(pixelPtr, pixelData, 0, (int)size); - bitmap.UnlockBits(data); - } - - /** - * Create a new ColorModel based on the current imageType. - */ - private ColorModel createColorModel(){ - switch(imageType){ - case TYPE_INT_RGB: { - return new DirectColorModel(24, 0x00ff0000, // Red - 0x0000ff00, // Green - 0x000000ff, // Blue - 0x0 // Alpha - ); - } - case TYPE_INT_ARGB: { - return ColorModel.getRGBdefault(); - } - case TYPE_INT_ARGB_PRE: { - return new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 32, 0x00ff0000,// Red - 0x0000ff00,// Green - 0x000000ff,// Blue - 0xff000000,// Alpha - true, // Alpha Premultiplied - DataBuffer.TYPE_INT); - } - case TYPE_INT_BGR: { - return new DirectColorModel(24, 0x000000ff, // Red - 0x0000ff00, // Green - 0x00ff0000 // Blue - ); - } - case TYPE_3BYTE_BGR: { - ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); - int[] nBits = {8, 8, 8}; - return new ComponentColorModel(cs, nBits, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); - } - case TYPE_4BYTE_ABGR: { - ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); - int[] nBits = {8, 8, 8, 8}; - return new ComponentColorModel(cs, nBits, true, false, Transparency.TRANSLUCENT, - DataBuffer.TYPE_BYTE); - } - case TYPE_4BYTE_ABGR_PRE: { - ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); - int[] nBits = {8, 8, 8, 8}; - return new ComponentColorModel(cs, nBits, true, true, Transparency.TRANSLUCENT, - DataBuffer.TYPE_BYTE); - } - case TYPE_BYTE_GRAY: { - ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY); - int[] nBits = {8}; - return new ComponentColorModel(cs, nBits, false, true, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); - } - case TYPE_USHORT_GRAY: { - ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY); - int[] nBits = {16}; - return new ComponentColorModel(cs, nBits, false, true, Transparency.OPAQUE, - DataBuffer.TYPE_USHORT); - } - case TYPE_BYTE_BINARY: { - byte[] arr = {(byte)0, (byte)0xff}; - - return new IndexColorModel(1, 2, arr, arr, arr); - } - case TYPE_BYTE_INDEXED: { - // Create a 6x6x6 color cube - int[] cmap = new int[256]; - int i = 0; - for(int r = 0; r < 256; r += 51){ - for(int g = 0; g < 256; g += 51){ - for(int b = 0; b < 256; b += 51){ - cmap[i++] = (r << 16) | (g << 8) | b; - } - } - } - // And populate the rest of the cmap with gray values - int grayIncr = 256 / (256 - i); - - // The gray ramp will be between 18 and 252 - int gray = grayIncr * 3; - for(; i < 256; i++){ - cmap[i] = (gray << 16) | (gray << 8) | gray; - gray += grayIncr; - } - - return new IndexColorModel(8, 256, cmap, 0, false, -1, DataBuffer.TYPE_BYTE); - } - case TYPE_USHORT_565_RGB: { - return new DirectColorModel(16, DCM_565_RED_MASK, DCM_565_GRN_MASK, DCM_565_BLU_MASK); - } - case TYPE_USHORT_555_RGB: { - return new DirectColorModel(15, DCM_555_RED_MASK, DCM_555_GRN_MASK, DCM_555_BLU_MASK); - } - default: - throw new IllegalArgumentException("Unknown image type " + imageType); - } - } - - /** - * Create a new WritableRaster based on the current imageType and ColorModel. - */ - private WritableRaster createRaster(int width, int height){ - switch(imageType){ - case TYPE_INT_RGB: - case TYPE_INT_ARGB: - case TYPE_INT_ARGB_PRE: - case TYPE_INT_BGR: - case TYPE_BYTE_GRAY: - case TYPE_USHORT_GRAY: - case TYPE_USHORT_565_RGB: - case TYPE_USHORT_555_RGB: { - return colorModel.createCompatibleWritableRaster(width, height); - } - case TYPE_3BYTE_BGR: { - int[] bOffs = {2, 1, 0}; - return Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, width * 3, 3, bOffs, null); - } - case TYPE_4BYTE_ABGR: - case TYPE_4BYTE_ABGR_PRE: { - int[] bOffs = {3, 2, 1, 0}; - return Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, width * 4, 4, bOffs, null); - } - case TYPE_BYTE_BINARY: { - return Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width, height, 1, 1, null); - } - case TYPE_BYTE_INDEXED: { - return Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, 1, null); - } - default: - throw new IllegalArgumentException("Unknown image type " + imageType); - } - } - - /** - * Returns the image type. If it is not one of the known types, - * TYPE_CUSTOM is returned. - * @return the image type of this <code>BufferedImage</code>. - * @see #TYPE_INT_RGB - * @see #TYPE_INT_ARGB - * @see #TYPE_INT_ARGB_PRE - * @see #TYPE_INT_BGR - * @see #TYPE_3BYTE_BGR - * @see #TYPE_4BYTE_ABGR - * @see #TYPE_4BYTE_ABGR_PRE - * @see #TYPE_BYTE_GRAY - * @see #TYPE_BYTE_BINARY - * @see #TYPE_BYTE_INDEXED - * @see #TYPE_USHORT_GRAY - * @see #TYPE_USHORT_565_RGB - * @see #TYPE_USHORT_555_RGB - * @see #TYPE_CUSTOM - */ - public int getType() { - return imageType; - } - - /** - * Returns the <code>ColorModel</code>. - * @return the <code>ColorModel</code> of this - * <code>BufferedImage</code>. - */ - public ColorModel getColorModel() { - return colorModel; - } - - /** - * Returns the {@link WritableRaster}. - * @return the <code>WriteableRaster</code> of this - * <code>BufferedImage</code>. - */ - public WritableRaster getRaster() { - bitmap2Raster(); - this.currentBuffer = BUFFER_RASTER; - return raster; - } - - - /** - * Returns a <code>WritableRaster</code> representing the alpha - * channel for <code>BufferedImage</code> objects - * with <code>ColorModel</code> objects that support a separate - * spatial alpha channel, such as <code>ComponentColorModel</code> and - * <code>DirectColorModel</code>. Returns <code>null</code> if there - * is no alpha channel associated with the <code>ColorModel</code> in - * this image. This method assumes that for all - * <code>ColorModel</code> objects other than - * <code>IndexColorModel</code>, if the <code>ColorModel</code> - * supports alpha, there is a separate alpha channel - * which is stored as the last band of image data. - * If the image uses an <code>IndexColorModel</code> that - * has alpha in the lookup table, this method returns - * <code>null</code> since there is no spatially discrete alpha - * channel. This method creates a new - * <code>WritableRaster</code>, but shares the data array. - * @return a <code>WritableRaster</code> or <code>null</code> if this - * <code>BufferedImage</code> has no alpha channel associated - * with its <code>ColorModel</code>. - */ - public WritableRaster getAlphaRaster() { - bitmap2Raster(); - return colorModel.getAlphaRaster(raster); - } - - /** - * Returns an integer pixel in the default RGB color model - * (TYPE_INT_ARGB) and default sRGB colorspace. Color - * conversion takes place if this default model does not match - * the image <code>ColorModel</code>. There are only 8-bits of - * precision for each color component in the returned data when using - * this method. - * - * <p> - * - * An <code>ArrayOutOfBoundsException</code> may be thrown - * if the coordinates are not in bounds. - * However, explicit bounds checking is not guaranteed. - * - * @param x the X coordinate of the pixel from which to get - * the pixel in the default RGB color model and sRGB - * color space - * @param y the Y coordinate of the pixel from which to get - * the pixel in the default RGB color model and sRGB - * color space - * @return an integer pixel in the default RGB color model and - * default sRGB colorspace. - * @see #setRGB(int, int, int) - * @see #setRGB(int, int, int, int, int[], int, int) - */ - public int getRGB(int x, int y) { - bitmap2Raster(); - return colorModel.getRGB(raster.getDataElements(x, y, null)); - } - - /** - * Returns an array of integer pixels in the default RGB color model - * (TYPE_INT_ARGB) and default sRGB color space, - * from a portion of the image data. Color conversion takes - * place if the default model does not match the image - * <code>ColorModel</code>. There are only 8-bits of precision for - * each color component in the returned data when - * using this method. With a specified coordinate (x, y) in the - * image, the ARGB pixel can be accessed in this way: - * - * <pre> - * pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)]; </pre> - * - * <p> - * - * An <code>ArrayOutOfBoundsException</code> may be thrown - * if the region is not in bounds. - * However, explicit bounds checking is not guaranteed. - * - * @param startX the starting X coordinate - * @param startY the starting Y coordinate - * @param w width of region - * @param h height of region - * @param rgbArray if not <code>null</code>, the rgb pixels are - * written here - * @param offset offset into the <code>rgbArray</code> - * @param scansize scanline stride for the <code>rgbArray</code> - * @return array of RGB pixels. - * @see #setRGB(int, int, int) - * @see #setRGB(int, int, int, int, int[], int, int) - */ - public int[] getRGB(int startX, int startY, int w, int h, - int[] rgbArray, int offset, int scansize) { - int yoff = offset; - int off; - Object data; - bitmap2Raster(); - int nbands = raster.getNumBands(); - int dataType = raster.getDataBuffer().getDataType(); - switch (dataType) { - case DataBuffer.TYPE_BYTE: - data = new byte[nbands]; - break; - case DataBuffer.TYPE_USHORT: - data = new short[nbands]; - break; - case DataBuffer.TYPE_INT: - data = new int[nbands]; - break; - case DataBuffer.TYPE_FLOAT: - data = new float[nbands]; - break; - case DataBuffer.TYPE_DOUBLE: - data = new double[nbands]; - break; - default: - throw new IllegalArgumentException("Unknown data buffer type: "+ - dataType); - } - - if (rgbArray == null) { - rgbArray = new int[offset+h*scansize]; - } - - for (int y = startY; y < startY+h; y++, yoff+=scansize) { - off = yoff; - for (int x = startX; x < startX+w; x++) { - rgbArray[off++] = colorModel.getRGB(raster.getDataElements(x, - y, - data)); - } - } - - return rgbArray; - } - - - /** - * Sets a pixel in this <code>BufferedImage</code> to the specified - * RGB value. The pixel is assumed to be in the default RGB color - * model, TYPE_INT_ARGB, and default sRGB color space. For images - * with an <code>IndexColorModel</code>, the index with the nearest - * color is chosen. - * - * <p> - * - * An <code>ArrayOutOfBoundsException</code> may be thrown - * if the coordinates are not in bounds. - * However, explicit bounds checking is not guaranteed. - * - * @param x the X coordinate of the pixel to set - * @param y the Y coordinate of the pixel to set - * @param rgb the RGB value - * @see #getRGB(int, int) - * @see #getRGB(int, int, int, int, int[], int, int) - */ - public synchronized void setRGB(int x, int y, int rgb) { - switch( currentBuffer ) { - case BUFFER_BITMAP: - synchronized (bitmap) { - bitmap.SetPixel(x, y, Color.FromArgb(rgb)); - } - break; - case BUFFER_RASTER: - raster.setDataElements(x, y, colorModel.getDataElements(rgb, null)); - break; - case BUFFER_BOTH: - raster.setDataElements(x, y, colorModel.getDataElements(rgb, null)); - synchronized (bitmap) { - bitmap.SetPixel(x, y, Color.FromArgb(rgb)); - } - break; - } - } - - /** - * Sets an array of integer pixels in the default RGB color model - * (TYPE_INT_ARGB) and default sRGB color space, - * into a portion of the image data. Color conversion takes place - * if the default model does not match the image - * <code>ColorModel</code>. There are only 8-bits of precision for - * each color component in the returned data when - * using this method. With a specified coordinate (x, y) in the - * this image, the ARGB pixel can be accessed in this way: - * <pre> - * pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)]; - * </pre> - * WARNING: No dithering takes place. - * - * <p> - * - * An <code>ArrayOutOfBoundsException</code> may be thrown - * if the region is not in bounds. - * However, explicit bounds checking is not guaranteed. - * - * @param startX the starting X coordinate - * @param startY the starting Y coordinate - * @param w width of the region - * @param h height of the region - * @param rgbArray the rgb pixels - * @param offset offset into the <code>rgbArray</code> - * @param scansize scanline stride for the <code>rgbArray</code> - * @see #getRGB(int, int) - * @see #getRGB(int, int, int, int, int[], int, int) - */ - public void setRGB(int startX, int startY, int w, int h, - int[] rgbArray, int offset, int scansize) { - int yoff = offset; - int off; - - for (int y = startY; y < startY+h; y++, yoff+=scansize) { - off = yoff; - for (int x = startX; x < startX+w; x++) { - setRGB(x, y, rgbArray[off++]); - } - } - } - - - /** - * Returns the width of the <code>BufferedImage</code>. - * @return the width of this <code>BufferedImage</code> - */ - public int getWidth() { - if(currentBuffer == BUFFER_BITMAP){ - synchronized( bitmap ) { - return bitmap.get_Width(); - } - }else{ - return raster.getWidth(); - } - } - - /** - * Returns the height of the <code>BufferedImage</code>. - * @return the height of this <code>BufferedImage</code> - */ - public int getHeight() { - if(currentBuffer == BUFFER_BITMAP){ - synchronized( bitmap ) { - return bitmap.get_Height(); - } - }else{ - return raster.getHeight(); - } - } - - /** - * Returns the width of the <code>BufferedImage</code>. - * @param observer ignored - * @return the width of this <code>BufferedImage</code> - */ - public int getWidth(ImageObserver observer) { - return getWidth(); - } - - /** - * Returns the height of the <code>BufferedImage</code>. - * @param observer ignored - * @return the height of this <code>BufferedImage</code> - */ - public int getHeight(ImageObserver observer) { - return getHeight(); - } - - /** - * Returns the object that produces the pixels for the image. - * @return the {@link ImageProducer} that is used to produce the - * pixels for this image. - * @see ImageProducer - */ - public ImageProducer getSource() { - if(currentBuffer != BUFFER_RASTER){ - synchronized( bitmap ) { - int width = bitmap.get_Width(); - int height = bitmap.get_Height(); - int[] pix = new int[width * height]; - for(int y = 0; y < height; y++){ - for(int x = 0; x < width; x++){ - pix[x + y * width] = bitmap.GetPixel(x, y).ToArgb(); - } - } - return new java.awt.image.MemoryImageSource(width, height, pix, 0, width); - } - }else{ - if(osis == null){ - if(properties == null){ - properties = new Hashtable(); - } - osis = new OffScreenImageSource(this, properties); - } - return osis; - } - } - - - /** - * Returns a property of the image by name. Individual property names - * are defined by the various image formats. If a property is not - * defined for a particular image, this method returns the - * <code>UndefinedProperty</code> field. If the properties - * for this image are not yet known, then this method returns - * <code>null</code> and the <code>ImageObserver</code> object is - * notified later. The property name "comment" should be used to - * store an optional comment that can be presented to the user as a - * description of the image, its source, or its author. - * @param name the property name - * @param observer the <code>ImageObserver</code> that receives - * notification regarding image information - * @return an {@link Object} that is the property referred to by the - * specified <code>name</code> or <code>null</code> if the - * properties of this image are not yet known. - * @throws NullPointerException if the property name is null. - * @see ImageObserver - * @see java.awt.Image#UndefinedProperty - */ - public Object getProperty(String name, ImageObserver observer) { - return getProperty(name); - } - - /** - * Returns a property of the image by name. - * @param name the property name - * @return an <code>Object</code> that is the property referred to by - * the specified <code>name</code>. - * @throws NullPointerException if the property name is null. - */ - public Object getProperty(String name) { - if (name == null) { - throw new NullPointerException("null property name is not allowed"); - } - if (properties == null) { - return java.awt.Image.UndefinedProperty; - } - Object o = properties.get(name); - if (o == null) { - o = java.awt.Image.UndefinedProperty; - } - return o; - } - - /** - * This method returns a {@link Graphics2D}, but is here - * for backwards compatibility. {@link #createGraphics() createGraphics} is more - * convenient, since it is declared to return a - * <code>Graphics2D</code>. - * @return a <code>Graphics2D</code>, which can be used to draw into - * this image. - */ - public java.awt.Graphics getGraphics() { - return createGraphics(); - } - - /** - * Creates a <code>Graphics2D</code>, which can be used to draw into - * this <code>BufferedImage</code>. - * @return a <code>Graphics2D</code>, used for drawing into this - * image. - */ - public Graphics2D createGraphics() { - GraphicsEnvironment env = - GraphicsEnvironment.getLocalGraphicsEnvironment(); - return env.createGraphics(this); - } - - /** - * Returns a subimage defined by a specified rectangular region. - * The returned <code>BufferedImage</code> shares the same - * data array as the original image. - * @param x the X coordinate of the upper-left corner of the - * specified rectangular region - * @param y the Y coordinate of the upper-left corner of the - * specified rectangular region - * @param w the width of the specified rectangular region - * @param h the height of the specified rectangular region - * @return a <code>BufferedImage</code> that is the subimage of this - * <code>BufferedImage</code>. - * @exception RasterFormatException if the specified - * area is not contained within this <code>BufferedImage</code>. - */ - public BufferedImage getSubimage (int x, int y, int w, int h) { - bitmap2Raster(); - return new BufferedImage (colorModel, - raster.createWritableChild(x, y, w, h, - 0, 0, null), - colorModel.isAlphaPremultiplied(), - properties); - } - - /** - * Returns whether or not the alpha has been premultiplied. It - * returns <code>false</code> if there is no alpha. - * @return <code>true</code> if the alpha has been premultiplied; - * <code>false</code> otherwise. - */ - public boolean isAlphaPremultiplied() { - return colorModel.isAlphaPremultiplied(); - } - - /** - * Forces the data to match the state specified in the - * <code>isAlphaPremultiplied</code> variable. It may multiply or - * divide the color raster data by alpha, or do nothing if the data is - * in the correct state. - * @param isAlphaPremultiplied <code>true</code> if the alpha has been - * premultiplied; <code>false</code> otherwise. - */ - public void coerceData (boolean isAlphaPremultiplied) { - if (colorModel.hasAlpha() && - colorModel.isAlphaPremultiplied() != isAlphaPremultiplied) { - bitmap2Raster(); - this.currentBuffer = BUFFER_RASTER; - // Make the color model do the conversion - colorModel = colorModel.coerceData (raster, isAlphaPremultiplied); - } - } - - /** - * Returns a <code>String</code> representation of this - * <code>BufferedImage</code> object and its values. - * @return a <code>String</code> representing this - * <code>BufferedImage</code>. - */ - public String toString() { - return "BufferedImage@"+Integer.toHexString(hashCode()) - +": type = "+imageType - +" "+colorModel+" "+raster; - } - - /** - * Returns a {@link Vector} of {@link RenderedImage} objects that are - * the immediate sources, not the sources of these immediate sources, - * of image data for this <code>BufferedImage</code>. This - * method returns <code>null</code> if the <code>BufferedImage</code> - * has no information about its immediate sources. It returns an - * empty <code>Vector</code> if the <code>BufferedImage</code> has no - * immediate sources. - * @return a <code>Vector</code> containing immediate sources of - * this <code>BufferedImage</code> object's image date, or - * <code>null</code> if this <code>BufferedImage</code> has - * no information about its immediate sources, or an empty - * <code>Vector</code> if this <code>BufferedImage</code> - * has no immediate sources. - */ - public Vector<RenderedImage> getSources() { - return null; - } - - /** - * Returns an array of names recognized by - * {@link #getProperty(String) getProperty(String)} - * or <code>null</code>, if no property names are recognized. - * @return a <code>String</code> array containing all of the property - * names that <code>getProperty(String)</code> recognizes; - * or <code>null</code> if no property names are recognized. - */ - public String[] getPropertyNames() { - return null; - } - - /** - * Returns the minimum x coordinate of this - * <code>BufferedImage</code>. This is always zero. - * @return the minimum x coordinate of this - * <code>BufferedImage</code>. - */ - public int getMinX() { - return 0; - } - - /** - * Returns the minimum y coordinate of this - * <code>BufferedImage</code>. This is always zero. - * @return the minimum y coordinate of this - * <code>BufferedImage</code>. - */ - public int getMinY() { - return 0; - } - - /** - * Returns the <code>SampleModel</code> associated with this - * <code>BufferedImage</code>. - * @return the <code>SampleModel</code> of this - * <code>BufferedImage</code>. - */ - public SampleModel getSampleModel() { - bitmap2Raster(); - return raster.getSampleModel(); - } - - /** - * Returns the number of tiles in the x direction. - * This is always one. - * @return the number of tiles in the x direction. - */ - public int getNumXTiles() { - return 1; - } - - /** - * Returns the number of tiles in the y direction. - * This is always one. - * @return the number of tiles in the y direction. - */ - public int getNumYTiles() { - return 1; - } - - /** - * Returns the minimum tile index in the x direction. - * This is always zero. - * @return the minimum tile index in the x direction. - */ - public int getMinTileX() { - return 0; - } - - /** - * Returns the minimum tile index in the y direction. - * This is always zero. - * @return the minimum tile index in the y direction. - */ - public int getMinTileY() { - return 0; - } - - /** - * Returns the tile width in pixels. - * @return the tile width in pixels. - */ - public int getTileWidth() { - return getWidth(); - } - - /** - * Returns the tile height in pixels. - * @return the tile height in pixels. - */ - public int getTileHeight() { - return getHeight(); - } - - /** - * Returns the x offset of the tile grid relative to the origin, - * For example, the x coordinate of the location of tile - * (0, 0). This is always zero. - * @return the x offset of the tile grid. - */ - public int getTileGridXOffset() { - bitmap2Raster(); - return raster.getSampleModelTranslateX(); - } - - /** - * Returns the y offset of the tile grid relative to the origin, - * For example, the y coordinate of the location of tile - * (0, 0). This is always zero. - * @return the y offset of the tile grid. - */ - public int getTileGridYOffset() { - bitmap2Raster(); - return raster.getSampleModelTranslateY(); - } - - /** - * Returns tile (<code>tileX</code>, <code>tileY</code>). Note - * that <code>tileX</code> and <code>tileY</code> are indices - * into the tile array, not pixel locations. The <code>Raster</code> - * that is returned is live, which means that it is updated if the - * image is changed. - * @param tileX the x index of the requested tile in the tile array - * @param tileY the y index of the requested tile in the tile array - * @return a <code>Raster</code> that is the tile defined by the - * arguments <code>tileX</code> and <code>tileY</code>. - * @exception ArrayIndexOutOfBoundsException if both - * <code>tileX</code> and <code>tileY</code> are not - * equal to 0 - */ - public Raster getTile(int tileX, int tileY) { - if (tileX == 0 && tileY == 0) { - bitmap2Raster(); - return raster; - } - throw new ArrayIndexOutOfBoundsException("BufferedImages only have"+ - " one tile with index 0,0"); - } - - /** - * Returns the image as one large tile. The <code>Raster</code> - * returned is a copy of the image data is not updated if the - * image is changed. - * @return a <code>Raster</code> that is a copy of the image data. - * @see #setData(Raster) - */ - public Raster getData() { - bitmap2Raster(); - - // REMIND : this allocates a whole new tile if raster is a - // subtile. (It only copies in the requested area) - // We should do something smarter. - int width = raster.getWidth(); - int height = raster.getHeight(); - int startX = raster.getMinX(); - int startY = raster.getMinY(); - WritableRaster wr = - Raster.createWritableRaster(raster.getSampleModel(), - new Point(raster.getSampleModelTranslateX(), - raster.getSampleModelTranslateY())); - - Object tdata = null; - - for (int i = startY; i < startY+height; i++) { - tdata = raster.getDataElements(startX,i,width,1,tdata); - wr.setDataElements(startX,i,width,1, tdata); - } - return wr; - } - - /** - * Computes and returns an arbitrary region of the - * <code>BufferedImage</code>. The <code>Raster</code> returned is a - * copy of the image data and is not updated if the image is - * changed. - * @param rect the region of the <code>BufferedImage</code> to be - * returned. - * @return a <code>Raster</code> that is a copy of the image data of - * the specified region of the <code>BufferedImage</code> - * @see #setData(Raster) - */ - public Raster getData(Rectangle rect) { - bitmap2Raster(); - SampleModel sm = raster.getSampleModel(); - SampleModel nsm = sm.createCompatibleSampleModel(rect.width, - rect.height); - WritableRaster wr = Raster.createWritableRaster(nsm, - rect.getLocation()); - int width = rect.width; - int height = rect.height; - int startX = rect.x; - int startY = rect.y; - - Object tdata = null; - - for (int i = startY; i < startY+height; i++) { - tdata = raster.getDataElements(startX,i,width,1,tdata); - wr.setDataElements(startX,i,width,1, tdata); - } - return wr; - } - - /** - * Computes an arbitrary rectangular region of the - * <code>BufferedImage</code> and copies it into a specified - * <code>WritableRaster</code>. The region to be computed is - * determined from the bounds of the specified - * <code>WritableRaster</code>. The specified - * <code>WritableRaster</code> must have a - * <code>SampleModel</code> that is compatible with this image. If - * <code>outRaster</code> is <code>null</code>, - * an appropriate <code>WritableRaster</code> is created. - * @param outRaster a <code>WritableRaster</code> to hold the returned - * part of the image, or <code>null</code> - * @return a reference to the supplied or created - * <code>WritableRaster</code>. - */ - public WritableRaster copyData(WritableRaster outRaster) { - bitmap2Raster(); - if (outRaster == null) { - return (WritableRaster) getData(); - } - int width = outRaster.getWidth(); - int height = outRaster.getHeight(); - int startX = outRaster.getMinX(); - int startY = outRaster.getMinY(); - - Object tdata = null; - - for (int i = startY; i < startY+height; i++) { - tdata = raster.getDataElements(startX,i,width,1,tdata); - outRaster.setDataElements(startX,i,width,1, tdata); - } - - return outRaster; - } - - /** - * Sets a rectangular region of the image to the contents of the - * specified <code>Raster</code> <code>r</code>, which is - * assumed to be in the same coordinate space as the - * <code>BufferedImage</code>. The operation is clipped to the bounds - * of the <code>BufferedImage</code>. - * @param r the specified <code>Raster</code> - * @see #getData - * @see #getData(Rectangle) - */ - public void setData(Raster r) { - bitmap2Raster(); - this.currentBuffer = BUFFER_RASTER; - - int width = r.getWidth(); - int height = r.getHeight(); - int startX = r.getMinX(); - int startY = r.getMinY(); - - int[] tdata = null; - - // Clip to the current Raster - Rectangle rclip = new Rectangle(startX, startY, width, height); - Rectangle bclip = new Rectangle(0, 0, raster.width, raster.height); - Rectangle intersect = rclip.intersection(bclip); - if (intersect.isEmpty()) { - return; - } - width = intersect.width; - height = intersect.height; - startX = intersect.x; - startY = intersect.y; - - // remind use get/setDataElements for speed if Rasters are - // compatible - for (int i = startY; i < startY+height; i++) { - tdata = r.getPixels(startX,i,width,1,tdata); - raster.setPixels(startX,i,width,1, tdata); - } - } - - - /** - * Adds a tile observer. If the observer is already present, - * it receives multiple notifications. - * @param to the specified {@link TileObserver} - */ - public void addTileObserver (TileObserver to) { - } - - /** - * Removes a tile observer. If the observer was not registered, - * nothing happens. If the observer was registered for multiple - * notifications, it is now registered for one fewer notification. - * @param to the specified <code>TileObserver</code>. - */ - public void removeTileObserver (TileObserver to) { - } - - /** - * Returns whether or not a tile is currently checked out for writing. - * @param tileX the x index of the tile. - * @param tileY the y index of the tile. - * @return <code>true</code> if the tile specified by the specified - * indices is checked out for writing; <code>false</code> - * otherwise. - * @exception ArrayIndexOutOfBoundsException if both - * <code>tileX</code> and <code>tileY</code> are not equal - * to 0 - */ - public boolean isTileWritable (int tileX, int tileY) { - if (tileX == 0 && tileY == 0) { - return true; - } - throw new IllegalArgumentException("Only 1 tile in image"); - } - - /** - * Returns an array of {@link Point} objects indicating which tiles - * are checked out for writing. Returns <code>null</code> if none are - * checked out. - * @return a <code>Point</code> array that indicates the tiles that - * are checked out for writing, or <code>null</code> if no - * tiles are checked out for writing. - */ - public Point[] getWritableTileIndices() { - Point[] p = new Point[1]; - p[0] = new Point(0, 0); - - return p; - } - - /** - * Returns whether or not any tile is checked out for writing. - * Semantically equivalent to - * <pre> - * (getWritableTileIndices() != null). - * </pre> - * @return <code>true</code> if any tile is checked out for writing; - * <code>false</code> otherwise. - */ - public boolean hasTileWriters () { - return true; - } - - /** - * Checks out a tile for writing. All registered - * <code>TileObservers</code> are notified when a tile goes from having - * no writers to having one writer. - * @param tileX the x index of the tile - * @param tileY the y index of the tile - * @return a <code>WritableRaster</code> that is the tile, indicated by - * the specified indices, to be checked out for writing. - */ - public WritableRaster getWritableTile (int tileX, int tileY) { - bitmap2Raster(); - this.currentBuffer = BUFFER_RASTER; - return raster; - } - - /** - * Relinquishes permission to write to a tile. If the caller - * continues to write to the tile, the results are undefined. - * Calls to this method should only appear in matching pairs - * with calls to {@link #getWritableTile(int, int) getWritableTile(int, int)}. Any other leads - * to undefined results. All registered <code>TileObservers</code> - * are notified when a tile goes from having one writer to having no - * writers. - * @param tileX the x index of the tile - * @param tileY the y index of the tile - */ - public void releaseWritableTile (int tileX, int tileY) { - } - - /** - * Returns the transparency. Returns either OPAQUE, BITMASK, - * or TRANSLUCENT. - * @return the transparency of this <code>BufferedImage</code>. - * @see Transparency#OPAQUE - * @see Transparency#BITMASK - * @see Transparency#TRANSLUCENT - * @since 1.5 - */ - public int getTransparency() { - return colorModel.getTransparency(); - } - - public void flush(){ - } -} diff --git a/openjdk/java/awt/image/ColorConvertOp.java b/openjdk/java/awt/image/ColorConvertOp.java deleted file mode 100644 index 0fb74978..00000000 --- a/openjdk/java/awt/image/ColorConvertOp.java +++ /dev/null @@ -1,537 +0,0 @@ -/* ColorConvertOp.java -- - Copyright (C) 2004, 2006 Free Software Foundation - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - - -package java.awt.image; - -import gnu.java.awt.Buffers; - -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.RenderingHints; -import java.awt.color.ColorSpace; -import java.awt.color.ICC_ColorSpace; -import java.awt.color.ICC_Profile; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; - -/** - * ColorConvertOp is a filter for converting images or rasters between - * colorspaces, either through a sequence of colorspaces or just from source to - * destination. - * - * Color conversion is done on the color components without alpha. Thus - * if a BufferedImage has alpha premultiplied, this is divided out before - * color conversion, and premultiplication applied if the destination - * requires it. - * - * Color rendering and dithering hints may be applied if specified. This is - * likely platform-dependent. - * - * @author jlquinn@optonline.net - */ -public class ColorConvertOp implements BufferedImageOp, RasterOp -{ - private RenderingHints hints; - private ICC_Profile[] profiles = null; - private ColorSpace[] spaces; - - - /** - * Convert a BufferedImage through a ColorSpace. - * - * Objects created with this constructor can be used to convert - * BufferedImage's to a destination ColorSpace. Attempts to convert Rasters - * with this constructor will result in an IllegalArgumentException when the - * filter(Raster, WritableRaster) method is called. - * - * @param cspace The target color space. - * @param hints Rendering hints to use in conversion, if any (may be null) - * @throws NullPointerException if the ColorSpace is null. - */ - public ColorConvertOp(ColorSpace cspace, RenderingHints hints) - { - if (cspace == null) - throw new NullPointerException(); - spaces = new ColorSpace[]{cspace}; - this.hints = hints; - } - - /** - * Convert from a source colorspace to a destination colorspace. - * - * This constructor takes two ColorSpace arguments as the source and - * destination color spaces. It is usually used with the - * filter(Raster, WritableRaster) method, in which case the source colorspace - * is assumed to correspond to the source Raster, and the destination - * colorspace with the destination Raster. - * - * If used with BufferedImages that do not match the source or destination - * colorspaces specified here, there is an implicit conversion from the - * source image to the source ColorSpace, or the destination ColorSpace to - * the destination image. - * - * @param srcCspace The source ColorSpace. - * @param dstCspace The destination ColorSpace. - * @param hints Rendering hints to use in conversion, if any (may be null). - * @throws NullPointerException if any ColorSpace is null. - */ - public ColorConvertOp(ColorSpace srcCspace, ColorSpace dstCspace, - RenderingHints hints) - { - if (srcCspace == null || dstCspace == null) - throw new NullPointerException(); - spaces = new ColorSpace[]{srcCspace, dstCspace}; - this.hints = hints; - } - - /** - * Convert from a source colorspace to a destinatino colorspace. - * - * This constructor builds a ColorConvertOp from an array of ICC_Profiles. - * The source will be converted through the sequence of color spaces - * defined by the profiles. If the sequence of profiles doesn't give a - * well-defined conversion, an IllegalArgumentException is thrown. - * - * If used with BufferedImages that do not match the source or destination - * colorspaces specified here, there is an implicit conversion from the - * source image to the source ColorSpace, or the destination ColorSpace to - * the destination image. - * - * For Rasters, the first and last profiles must have the same number of - * bands as the source and destination Rasters, respectively. If this is - * not the case, or there fewer than 2 profiles, an IllegalArgumentException - * will be thrown. - * - * @param profiles An array of ICC_Profile's to convert through. - * @param hints Rendering hints to use in conversion, if any (may be null). - * @throws NullPointerException if the profile array is null. - * @throws IllegalArgumentException if the array is not a well-defined - * conversion. - */ - public ColorConvertOp(ICC_Profile[] profiles, RenderingHints hints) - { - if (profiles == null) - throw new NullPointerException(); - - this.hints = hints; - this.profiles = profiles; - - // Create colorspace array with space for src and dest colorspace - // Note that the ICC_ColorSpace constructor will throw an - // IllegalArgumentException if the profile is invalid; thus we check - // for a "well defined conversion" - spaces = new ColorSpace[profiles.length]; - for (int i = 0; i < profiles.length; i++) - spaces[i] = new ICC_ColorSpace(profiles[i]); - } - - /** - * Convert from source color space to destination color space. - * - * Only valid for BufferedImage objects, this Op converts from the source - * image's color space to the destination image's color space. - * - * The destination in the filter(BufferedImage, BufferedImage) method cannot - * be null for this operation, and it also cannot be used with the - * filter(Raster, WritableRaster) method. - * - * @param hints Rendering hints to use in conversion, if any (may be null). - */ - public ColorConvertOp(RenderingHints hints) - { - this.hints = hints; - spaces = new ColorSpace[0]; - } - - /** - * Converts the source image using the conversion path specified in the - * constructor. The resulting image is stored in the destination image if one - * is provided; otherwise a new BufferedImage is created and returned. - * - * The source and destination BufferedImage (if one is supplied) must have - * the same dimensions. - * - * @param src The source image. - * @param dst The destination image. - * @throws IllegalArgumentException if the rasters and/or color spaces are - * incompatible. - * @return The transformed image. - */ - public final BufferedImage filter(BufferedImage src, BufferedImage dst) - { - // TODO: The plan is to create a scanline buffer for intermediate buffers. - // For now we just suck it up and create intermediate buffers. - - if (dst == null && spaces.length == 0) - throw new IllegalArgumentException("Not enough color space information " - + "to complete conversion."); - - if (dst != null - && (src.getHeight() != dst.getHeight() || src.getWidth() != dst.getWidth())) - throw new IllegalArgumentException("Source and destination images have " - + "different dimensions"); - - // Make sure input isn't premultiplied by alpha - if (src.isAlphaPremultiplied()) - { - BufferedImage tmp = createCompatibleDestImage(src, src.getColorModel()); - copyimage(src, tmp); - tmp.coerceData(false); - src = tmp; - } - - // Convert through defined intermediate conversions - BufferedImage tmp; - for (int i = 0; i < spaces.length; i++) - { - if (src.getColorModel().getColorSpace().getType() != spaces[i].getType()) - { - tmp = createCompatibleDestImage(src, - createCompatibleColorModel(src, - spaces[i])); - copyimage(src, tmp); - src = tmp; - } - } - - // No implicit conversion to destination type needed; return result from the - // last intermediate conversions (which was left in src) - if (dst == null) - dst = src; - - // Implicit conversion to destination image's color space - else - copyimage(src, dst); - - return dst; - } - - /** - * Converts the source raster using the conversion path specified in the - * constructor. The resulting raster is stored in the destination raster if - * one is provided; otherwise a new WritableRaster is created and returned. - * - * This operation is not valid with every constructor of this class; see - * the constructors for details. Further, the source raster must have the - * same number of bands as the source ColorSpace, and the destination raster - * must have the same number of bands as the destination ColorSpace. - * - * The source and destination raster (if one is supplied) must also have the - * same dimensions. - * - * @param src The source raster. - * @param dest The destination raster. - * @throws IllegalArgumentException if the rasters and/or color spaces are - * incompatible. - * @return The transformed raster. - */ - public final WritableRaster filter(Raster src, WritableRaster dest) - { - // Various checks to ensure that the rasters and color spaces are compatible - if (spaces.length < 2) - throw new IllegalArgumentException("Not enough information about " + - "source and destination colorspaces."); - - if (spaces[0].getNumComponents() != src.getNumBands() - || (dest != null && spaces[spaces.length - 1].getNumComponents() != dest.getNumBands())) - throw new IllegalArgumentException("Source or destination raster " + - "contains the wrong number of bands."); - - if (dest != null - && (src.getHeight() != dest.getHeight() || src.getWidth() != dest.getWidth())) - throw new IllegalArgumentException("Source and destination rasters " + - "have different dimensions"); - - // Need to iterate through each color space. - // spaces[0] corresponds to the ColorSpace of the source raster, and - // spaces[spaces.length - 1] corresponds to the ColorSpace of the - // destination, with any number (or zero) of intermediate conversions. - - for (int i = 0; i < spaces.length - 2; i++) - { - WritableRaster tmp = createCompatibleDestRaster(src, spaces[i + 1], - false, - src.getTransferType()); - copyraster(src, spaces[i], tmp, spaces[i + 1]); - src = tmp; - } - - // The last conversion is done outside of the loop so that we can - // use the dest raster supplied, instead of creating our own temp raster - if (dest == null) - dest = createCompatibleDestRaster(src, spaces[spaces.length - 1], false, - DataBuffer.TYPE_BYTE); - copyraster(src, spaces[spaces.length - 2], dest, spaces[spaces.length - 1]); - - return dest; - } - - /** - * Creates an empty BufferedImage with the size equal to the source and the - * correct number of bands for the conversion defined in this Op. The newly - * created image is created with the specified ColorModel, or if no ColorModel - * is supplied, an appropriate one is chosen. - * - * @param src The source image. - * @param dstCM A color model for the destination image (may be null). - * @throws IllegalArgumentException if an appropriate colormodel cannot be - * chosen with the information given. - * @return The new compatible destination image. - */ - public BufferedImage createCompatibleDestImage(BufferedImage src, - ColorModel dstCM) - { - if (dstCM == null && spaces.length == 0) - throw new IllegalArgumentException("Don't know the destination " + - "colormodel"); - - if (dstCM == null) - { - dstCM = createCompatibleColorModel(src, spaces[spaces.length - 1]); - } - - return new BufferedImage(dstCM, - createCompatibleDestRaster(src.getRaster(), - dstCM.getColorSpace(), - src.getColorModel().hasAlpha(), - dstCM.getTransferType()), - src.isAlphaPremultiplied, null); - } - - /** - * Creates a new WritableRaster with the size equal to the source and the - * correct number of bands. - * - * Note, the new Raster will always use a BYTE storage size, regardless of - * the color model or defined destination; this is for compatibility with - * the reference implementation. - * - * @param src The source Raster. - * @throws IllegalArgumentException if there isn't enough colorspace - * information to create a compatible Raster. - * @return The new compatible destination raster. - */ - public WritableRaster createCompatibleDestRaster(Raster src) - { - if (spaces.length < 2) - throw new IllegalArgumentException("Not enough destination colorspace " + - "information"); - - // Create a new raster with the last ColorSpace in the conversion - // chain, and with no alpha (implied) - return createCompatibleDestRaster(src, spaces[spaces.length-1], false, - DataBuffer.TYPE_BYTE); - } - - /** - * Returns the array of ICC_Profiles used to create this Op, or null if the - * Op was created using ColorSpace arguments. - * - * @return The array of ICC_Profiles, or null. - */ - public final ICC_Profile[] getICC_Profiles() - { - return profiles; - } - - /** - * Returns the rendering hints for this op. - * - * @return The rendering hints for this Op, or null. - */ - public final RenderingHints getRenderingHints() - { - return hints; - } - - /** - * Returns the corresponding destination point for a source point. - * Because this is not a geometric operation, the destination and source - * points will be identical. - * - * @param src The source point. - * @param dst The transformed destination point. - * @return The transformed destination point. - */ - public final Point2D getPoint2D(Point2D src, Point2D dst) - { - if (dst == null) - return (Point2D)src.clone(); - - dst.setLocation(src); - return dst; - } - - /** - * Returns the corresponding destination boundary of a source boundary. - * Because this is not a geometric operation, the destination and source - * boundaries will be identical. - * - * @param src The source boundary. - * @return The boundaries of the destination. - */ - public final Rectangle2D getBounds2D(BufferedImage src) - { - return src.getRaster().getBounds(); - } - - /** - * Returns the corresponding destination boundary of a source boundary. - * Because this is not a geometric operation, the destination and source - * boundaries will be identical. - * - * @param src The source boundary. - * @return The boundaries of the destination. - */ - public final Rectangle2D getBounds2D(Raster src) - { - return src.getBounds(); - } - - /** - * Copy a source image to a destination image, respecting their colorspaces - * and performing colorspace conversions if necessary. - * - * @param src The source image. - * @param dst The destination image. - */ - private void copyimage(BufferedImage src, BufferedImage dst) - { - // This is done using Graphics2D in order to respect the rendering hints. - Graphics2D gg = dst.createGraphics(); - - // If no hints are set there is no need to call - // setRenderingHints on the Graphics2D object. - if (hints != null) - gg.setRenderingHints(hints); - - gg.drawImage(src, 0, 0, null); - gg.dispose(); - } - - /** - * Copy a source raster to a destination raster, performing a colorspace - * conversion between the two. The conversion will respect the - * KEY_COLOR_RENDERING rendering hint if one is present. - * - * @param src The source raster. - * @param scs The colorspace of the source raster. - * @dst The destination raster. - * @dcs The colorspace of the destination raster. - */ - private void copyraster(Raster src, ColorSpace scs, WritableRaster dst, ColorSpace dcs) - { - float[] sbuf = new float[src.getNumBands()]; - - if (hints != null - && hints.get(RenderingHints.KEY_COLOR_RENDERING) == - RenderingHints.VALUE_COLOR_RENDER_QUALITY) - { - // use cie for accuracy - for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) - for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) - dst.setPixel(x, y, - dcs.fromCIEXYZ(scs.toCIEXYZ(src.getPixel(x, y, sbuf)))); - } - else - { - // use rgb - it's probably faster - for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) - for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) - dst.setPixel(x, y, - dcs.fromRGB(scs.toRGB(src.getPixel(x, y, sbuf)))); - } - } - - /** - * This method creates a color model with the same colorspace and alpha - * settings as the source image. The created color model will always be a - * ComponentColorModel and have a BYTE transfer type. - * - * @param img The source image. - * @param cs The ColorSpace to use. - * @return A color model compatible with the source image. - */ - private ColorModel createCompatibleColorModel(BufferedImage img, ColorSpace cs) - { - // The choice of ComponentColorModel and DataBuffer.TYPE_BYTE is based on - // Mauve testing of the reference implementation. - return new ComponentColorModel(cs, - img.getColorModel().hasAlpha(), - img.isAlphaPremultiplied(), - img.getColorModel().getTransparency(), - DataBuffer.TYPE_BYTE); - } - - /** - * This method creates a compatible Raster, given a source raster, colorspace, - * alpha value, and transfer type. - * - * @param src The source raster. - * @param cs The ColorSpace to use. - * @param hasAlpha Whether the raster should include a component for an alpha. - * @param transferType The size of a single data element. - * @return A compatible WritableRaster. - */ - private WritableRaster createCompatibleDestRaster(Raster src, ColorSpace cs, - boolean hasAlpha, - int transferType) - { - // The use of a PixelInterleavedSampleModel weas determined using mauve - // tests, based on the reference implementation - - int numComponents = cs.getNumComponents(); - if (hasAlpha) - numComponents++; - - int[] offsets = new int[numComponents]; - for (int i = 0; i < offsets.length; i++) - offsets[i] = i; - - DataBuffer db = Buffers.createBuffer(transferType, - src.getWidth() * src.getHeight() * numComponents, - 1); - return new WritableRaster(new PixelInterleavedSampleModel(transferType, - src.getWidth(), - src.getHeight(), - numComponents, - numComponents * src.getWidth(), - offsets), - db, new Point(src.getMinX(), src.getMinY())); - } -} diff --git a/openjdk/java/awt/image/ConvolveOp.java b/openjdk/java/awt/image/ConvolveOp.java deleted file mode 100644 index cf30e762..00000000 --- a/openjdk/java/awt/image/ConvolveOp.java +++ /dev/null @@ -1,380 +0,0 @@ -/* ConvolveOp.java -- - Copyright (C) 2004, 2005, 2006, Free Software Foundation -- ConvolveOp - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - - -package java.awt.image; - -import java.awt.RenderingHints; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; - -/** - * Convolution filter. - * - * ConvolveOp convolves the source image with a Kernel to generate a - * destination image. This involves multiplying each pixel and its neighbors - * with elements in the kernel to compute a new pixel. - * - * Each band in a Raster is convolved and copied to the destination Raster. - * For BufferedImages, convolution is applied to all components. Color - * conversion will be applied if needed. - * - * Note that this filter ignores whether the source or destination is alpha - * premultiplied. The reference spec states that data will be premultiplied - * prior to convolving and divided back out afterwards (if needed), but testing - * has shown that this is not the case with their implementation. - * - * @author jlquinn@optonline.net - */ -public class ConvolveOp implements BufferedImageOp, RasterOp -{ - /** Edge pixels are set to 0. */ - public static final int EDGE_ZERO_FILL = 0; - - /** Edge pixels are copied from the source. */ - public static final int EDGE_NO_OP = 1; - - private Kernel kernel; - private int edge; - private RenderingHints hints; - - /** - * Construct a ConvolveOp. - * - * The edge condition specifies that pixels outside the area that can be - * filtered are either set to 0 or copied from the source image. - * - * @param kernel The kernel to convolve with. - * @param edgeCondition Either EDGE_ZERO_FILL or EDGE_NO_OP. - * @param hints Rendering hints for color conversion, or null. - */ - public ConvolveOp(Kernel kernel, - int edgeCondition, - RenderingHints hints) - { - this.kernel = kernel; - edge = edgeCondition; - this.hints = hints; - } - - /** - * Construct a ConvolveOp. - * - * The edge condition defaults to EDGE_ZERO_FILL. - * - * @param kernel The kernel to convolve with. - */ - public ConvolveOp(Kernel kernel) - { - this.kernel = kernel; - edge = EDGE_ZERO_FILL; - hints = null; - } - - /** - * Converts the source image using the kernel specified in the - * constructor. The resulting image is stored in the destination image if one - * is provided; otherwise a new BufferedImage is created and returned. - * - * The source and destination BufferedImage (if one is supplied) must have - * the same dimensions. - * - * @param src The source image. - * @param dst The destination image. - * @throws IllegalArgumentException if the rasters and/or color spaces are - * incompatible. - * @return The convolved image. - */ - public final BufferedImage filter(BufferedImage src, BufferedImage dst) - { - if (src == dst) - throw new IllegalArgumentException("Source and destination images " + - "cannot be the same."); - - if (dst == null) - dst = createCompatibleDestImage(src, src.getColorModel()); - - // Make sure source image is premultiplied - BufferedImage src1 = src; - // The spec says we should do this, but mauve testing shows that Sun's - // implementation does not check this. - /* - if (!src.isAlphaPremultiplied()) - { - src1 = createCompatibleDestImage(src, src.getColorModel()); - src.copyData(src1.getRaster()); - src1.coerceData(true); - } - */ - - BufferedImage dst1 = dst; - if (src1.getColorModel().getColorSpace().getType() != dst.getColorModel().getColorSpace().getType()) - dst1 = createCompatibleDestImage(src, src.getColorModel()); - - filter(src1.getRaster(), dst1.getRaster()); - - // Since we don't coerceData above, we don't need to divide it back out. - // This is wrong (one mauve test specifically tests converting a non- - // premultiplied image to a premultiplied image, and it shows that Sun - // simply ignores the premultipled flag, contrary to the spec), but we - // mimic it for compatibility. - /* - if (! dst.isAlphaPremultiplied()) - dst1.coerceData(false); - */ - - // Convert between color models if needed - if (dst1 != dst) - new ColorConvertOp(hints).filter(dst1, dst); - - return dst; - } - - /** - * Creates an empty BufferedImage with the size equal to the source and the - * correct number of bands. The new image is created with the specified - * ColorModel, or if no ColorModel is supplied, an appropriate one is chosen. - * - * @param src The source image. - * @param dstCM A color model for the destination image (may be null). - * @return The new compatible destination image. - */ - public BufferedImage createCompatibleDestImage(BufferedImage src, - ColorModel dstCM) - { - if (dstCM != null) - return new BufferedImage(dstCM, - src.getRaster().createCompatibleWritableRaster(), - src.isAlphaPremultiplied(), null); - - return new BufferedImage(src.getWidth(), src.getHeight(), src.getType()); - } - - /* (non-Javadoc) - * @see java.awt.image.RasterOp#getRenderingHints() - */ - public final RenderingHints getRenderingHints() - { - return hints; - } - - /** - * Get the edge condition for this Op. - * - * @return The edge condition. - */ - public int getEdgeCondition() - { - return edge; - } - - /** - * Returns (a clone of) the convolution kernel. - * - * @return The convolution kernel. - */ - public final Kernel getKernel() - { - return (Kernel) kernel.clone(); - } - - /** - * Converts the source raster using the kernel specified in the constructor. - * The resulting raster is stored in the destination raster if one is - * provided; otherwise a new WritableRaster is created and returned. - * - * If the convolved value for a sample is outside the range of [0-255], it - * will be clipped. - * - * The source and destination raster (if one is supplied) cannot be the same, - * and must also have the same dimensions. - * - * @param src The source raster. - * @param dest The destination raster. - * @throws IllegalArgumentException if the rasters identical. - * @throws ImagingOpException if the convolution is not possible. - * @return The transformed raster. - */ - public final WritableRaster filter(Raster src, WritableRaster dest) - { - if (src == dest) - throw new IllegalArgumentException("src == dest is not allowed."); - if (kernel.getWidth() > src.getWidth() - || kernel.getHeight() > src.getHeight()) - throw new ImagingOpException("The kernel is too large."); - if (dest == null) - dest = createCompatibleDestRaster(src); - else if (src.getNumBands() != dest.getNumBands()) - throw new ImagingOpException("src and dest have different band counts."); - - // calculate the borders that the op can't reach... - int kWidth = kernel.getWidth(); - int kHeight = kernel.getHeight(); - int left = kernel.getXOrigin(); - int right = Math.max(kWidth - left - 1, 0); - int top = kernel.getYOrigin(); - int bottom = Math.max(kHeight - top - 1, 0); - - // Calculate max sample values for clipping - int[] maxValue = src.getSampleModel().getSampleSize(); - for (int i = 0; i < maxValue.length; i++) - maxValue[i] = (int)Math.pow(2, maxValue[i]) - 1; - - // process the region that is reachable... - int regionW = src.width - left - right; - int regionH = src.height - top - bottom; - float[] kvals = kernel.getKernelData(null); - float[] tmp = new float[kWidth * kHeight]; - - for (int x = 0; x < regionW; x++) - { - for (int y = 0; y < regionH; y++) - { - // FIXME: This needs a much more efficient implementation - for (int b = 0; b < src.getNumBands(); b++) - { - float v = 0; - src.getSamples(x, y, kWidth, kHeight, b, tmp); - for (int i = 0; i < tmp.length; i++) - v += tmp[tmp.length - i - 1] * kvals[i]; - // FIXME: in the above line, I've had to reverse the order of - // the samples array to make the tests pass. I haven't worked - // out why this is necessary. - - // This clipping is is undocumented, but determined by testing. - if (v > maxValue[b]) - v = maxValue[b]; - else if (v < 0) - v = 0; - - dest.setSample(x + kernel.getXOrigin(), y + kernel.getYOrigin(), - b, v); - } - } - } - - // fill in the top border - fillEdge(src, dest, 0, 0, src.width, top, edge); - - // fill in the bottom border - fillEdge(src, dest, 0, src.height - bottom, src.width, bottom, edge); - - // fill in the left border - fillEdge(src, dest, 0, top, left, regionH, edge); - - // fill in the right border - fillEdge(src, dest, src.width - right, top, right, regionH, edge); - - return dest; - } - - /** - * Fills a range of pixels (typically at the edge of a raster) with either - * zero values (if <code>edgeOp</code> is <code>EDGE_ZERO_FILL</code>) or the - * corresponding pixel values from the source raster (if <code>edgeOp</code> - * is <code>EDGE_NO_OP</code>). This utility method is called by the - * {@link #fillEdge(Raster, WritableRaster, int, int, int, int, int)} method. - * - * @param src the source raster. - * @param dest the destination raster. - * @param x the x-coordinate of the top left pixel in the range. - * @param y the y-coordinate of the top left pixel in the range. - * @param w the width of the pixel range. - * @param h the height of the pixel range. - * @param edgeOp indicates how to determine the values for the range - * (either {@link #EDGE_ZERO_FILL} or {@link #EDGE_NO_OP}). - */ - private void fillEdge(Raster src, WritableRaster dest, int x, int y, int w, - int h, int edgeOp) - { - if (w <= 0) - return; - if (h <= 0) - return; - if (edgeOp == EDGE_ZERO_FILL) // fill region with zeroes - { - float[] zeros = new float[src.getNumBands() * w * h]; - dest.setPixels(x, y, w, h, zeros); - } - else // copy pixels from source - { - float[] pixels = new float[src.getNumBands() * w * h]; - src.getPixels(x, y, w, h, pixels); - dest.setPixels(x, y, w, h, pixels); - } - } - - /* (non-Javadoc) - * @see java.awt.image.RasterOp#createCompatibleDestRaster(java.awt.image.Raster) - */ - public WritableRaster createCompatibleDestRaster(Raster src) - { - return src.createCompatibleWritableRaster(); - } - - /* (non-Javadoc) - * @see java.awt.image.BufferedImageOp#getBounds2D(java.awt.image.BufferedImage) - */ - public final Rectangle2D getBounds2D(BufferedImage src) - { - return src.getRaster().getBounds(); - } - - /* (non-Javadoc) - * @see java.awt.image.RasterOp#getBounds2D(java.awt.image.Raster) - */ - public final Rectangle2D getBounds2D(Raster src) - { - return src.getBounds(); - } - - /** - * Returns the corresponding destination point for a source point. Because - * this is not a geometric operation, the destination and source points will - * be identical. - * - * @param src The source point. - * @param dst The transformed destination point. - * @return The transformed destination point. - */ - public final Point2D getPoint2D(Point2D src, Point2D dst) - { - if (dst == null) return (Point2D)src.clone(); - dst.setLocation(src); - return dst; - } -} diff --git a/openjdk/java/awt/image/IndexColorModel.java b/openjdk/java/awt/image/IndexColorModel.java deleted file mode 100644 index b76f924c..00000000 --- a/openjdk/java/awt/image/IndexColorModel.java +++ /dev/null @@ -1,1527 +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.awt.image; - -import java.awt.Transparency; -import java.awt.color.ColorSpace; -import java.math.BigInteger; - -/** - * The <code>IndexColorModel</code> class is a <code>ColorModel</code> - * class that works with pixel values consisting of a - * single sample that is an index into a fixed colormap in the default - * sRGB color space. The colormap specifies red, green, blue, and - * optional alpha components corresponding to each index. All components - * are represented in the colormap as 8-bit unsigned integral values. - * Some constructors allow the caller to specify "holes" in the colormap - * by indicating which colormap entries are valid and which represent - * unusable colors via the bits set in a <code>BigInteger</code> object. - * This color model is similar to an X11 PseudoColor visual. - * <p> - * Some constructors provide a means to specify an alpha component - * for each pixel in the colormap, while others either provide no - * such means or, in some cases, a flag to indicate whether the - * colormap data contains alpha values. If no alpha is supplied to - * the constructor, an opaque alpha component (alpha = 1.0) is - * assumed for each entry. - * An optional transparent pixel value can be supplied that indicates a - * pixel to be made completely transparent, regardless of any alpha - * component supplied or assumed for that pixel value. - * Note that the color components in the colormap of an - * <code>IndexColorModel</code> objects are never pre-multiplied with - * the alpha components. - * <p> - * <a name="transparency"> - * The transparency of an <code>IndexColorModel</code> object is - * determined by examining the alpha components of the colors in the - * colormap and choosing the most specific value after considering - * the optional alpha values and any transparent index specified. - * The transparency value is <code>Transparency.OPAQUE</code> - * only if all valid colors in - * the colormap are opaque and there is no valid transparent pixel. - * If all valid colors - * in the colormap are either completely opaque (alpha = 1.0) or - * completely transparent (alpha = 0.0), which typically occurs when - * a valid transparent pixel is specified, - * the value is <code>Transparency.BITMASK</code>. - * Otherwise, the value is <code>Transparency.TRANSLUCENT</code>, indicating - * that some valid color has an alpha component that is - * neither completely transparent nor completely opaque - * (0.0 < alpha < 1.0). - * </a> - * - * <p> - * If an <code>IndexColorModel</code> object has - * a transparency value of <code>Transparency.OPAQUE</code>, - * then the <code>hasAlpha</code> - * and <code>getNumComponents</code> methods - * (both inherited from <code>ColorModel</code>) - * return false and 3, respectively. - * For any other transparency value, - * <code>hasAlpha</code> returns true - * and <code>getNumComponents</code> returns 4. - * - * <p> - * <a name="index_values"> - * The values used to index into the colormap are taken from the least - * significant <em>n</em> bits of pixel representations where - * <em>n</em> is based on the pixel size specified in the constructor. - * For pixel sizes smaller than 8 bits, <em>n</em> is rounded up to a - * power of two (3 becomes 4 and 5,6,7 become 8). - * For pixel sizes between 8 and 16 bits, <em>n</em> is equal to the - * pixel size. - * Pixel sizes larger than 16 bits are not supported by this class. - * Higher order bits beyond <em>n</em> are ignored in pixel representations. - * Index values greater than or equal to the map size, but less than - * 2<sup><em>n</em></sup>, are undefined and return 0 for all color and - * alpha components. - * <p> - * For those methods that use a primitive array pixel representation of - * type <code>transferType</code>, the array length is always one. - * The transfer types supported are <code>DataBuffer.TYPE_BYTE</code> and - * <code>DataBuffer.TYPE_USHORT</code>. A single int pixel - * representation is valid for all objects of this class, since it is - * always possible to represent pixel values used with this class in a - * single int. Therefore, methods that use this representation do - * not throw an <code>IllegalArgumentException</code> due to an invalid - * pixel value. - * <p> - * Many of the methods in this class are final. The reason for - * this is that the underlying native graphics code makes assumptions - * about the layout and operation of this class and those assumptions - * are reflected in the implementations of the methods here that are - * marked final. You can subclass this class for other reasons, but - * you cannot override or modify the behaviour of those methods. - * - * @see ColorModel - * @see ColorSpace - * @see DataBuffer - * - */ -public class IndexColorModel extends ColorModel { - private int rgb[]; - private int map_size; - private int pixel_mask; - private int transparent_index = -1; - private boolean allgrayopaque; - private BigInteger validBits; - - private static int[] opaqueBits = {8, 8, 8}; - private static int[] alphaBits = {8, 8, 8, 8}; - - /** - * Constructs an <code>IndexColorModel</code> from the specified - * arrays of red, green, and blue components. Pixels described - * by this color model all have alpha components of 255 - * unnormalized (1.0 normalized), which means they - * are fully opaque. All of the arrays specifying the color - * components must have at least the specified number of entries. - * The <code>ColorSpace</code> is the default sRGB space. - * Since there is no alpha information in any of the arguments - * to this constructor, the transparency value is always - * <code>Transparency.OPAQUE</code>. - * The transfer type is the smallest of <code>DataBuffer.TYPE_BYTE</code> - * or <code>DataBuffer.TYPE_USHORT</code> that can hold a single pixel. - * @param bits the number of bits each pixel occupies - * @param size the size of the color component arrays - * @param r the array of red color components - * @param g the array of green color components - * @param b the array of blue color components - * @throws IllegalArgumentException if <code>bits</code> is less - * than 1 or greater than 16 - * @throws IllegalArgumentException if <code>size</code> is less - * than 1 - */ - public IndexColorModel(int bits, int size, - byte r[], byte g[], byte b[]) { - super(bits, opaqueBits, - ColorSpace.getInstance(ColorSpace.CS_sRGB), - false, false, OPAQUE, - ColorModel.getDefaultTransferType(bits)); - if (bits < 1 || bits > 16) { - throw new IllegalArgumentException("Number of bits must be between" - +" 1 and 16."); - } - setRGBs(size, r, g, b, null); - calculatePixelMask(); - } - - /** - * Constructs an <code>IndexColorModel</code> from the given arrays - * of red, green, and blue components. Pixels described by this color - * model all have alpha components of 255 unnormalized - * (1.0 normalized), which means they are fully opaque, except - * for the indicated pixel to be made transparent. All of the arrays - * specifying the color components must have at least the specified - * number of entries. - * The <code>ColorSpace</code> is the default sRGB space. - * The transparency value may be <code>Transparency.OPAQUE</code> or - * <code>Transparency.BITMASK</code> depending on the arguments, as - * specified in the <a href="#transparency">class description</a> above. - * The transfer type is the smallest of <code>DataBuffer.TYPE_BYTE</code> - * or <code>DataBuffer.TYPE_USHORT</code> that can hold a - * single pixel. - * @param bits the number of bits each pixel occupies - * @param size the size of the color component arrays - * @param r the array of red color components - * @param g the array of green color components - * @param b the array of blue color components - * @param trans the index of the transparent pixel - * @throws IllegalArgumentException if <code>bits</code> is less than - * 1 or greater than 16 - * @throws IllegalArgumentException if <code>size</code> is less than - * 1 - */ - public IndexColorModel(int bits, int size, - byte r[], byte g[], byte b[], int trans) { - super(bits, opaqueBits, - ColorSpace.getInstance(ColorSpace.CS_sRGB), - false, false, OPAQUE, - ColorModel.getDefaultTransferType(bits)); - if (bits < 1 || bits > 16) { - throw new IllegalArgumentException("Number of bits must be between" - +" 1 and 16."); - } - setRGBs(size, r, g, b, null); - setTransparentPixel(trans); - calculatePixelMask(); - } - - /** - * Constructs an <code>IndexColorModel</code> from the given - * arrays of red, green, blue and alpha components. All of the - * arrays specifying the components must have at least the specified - * number of entries. - * The <code>ColorSpace</code> is the default sRGB space. - * The transparency value may be any of <code>Transparency.OPAQUE</code>, - * <code>Transparency.BITMASK</code>, - * or <code>Transparency.TRANSLUCENT</code> - * depending on the arguments, as specified - * in the <a href="#transparency">class description</a> above. - * The transfer type is the smallest of <code>DataBuffer.TYPE_BYTE</code> - * or <code>DataBuffer.TYPE_USHORT</code> that can hold a single pixel. - * @param bits the number of bits each pixel occupies - * @param size the size of the color component arrays - * @param r the array of red color components - * @param g the array of green color components - * @param b the array of blue color components - * @param a the array of alpha value components - * @throws IllegalArgumentException if <code>bits</code> is less - * than 1 or greater than 16 - * @throws IllegalArgumentException if <code>size</code> is less - * than 1 - */ - public IndexColorModel(int bits, int size, - byte r[], byte g[], byte b[], byte a[]) { - super (bits, alphaBits, - ColorSpace.getInstance(ColorSpace.CS_sRGB), - true, false, TRANSLUCENT, - ColorModel.getDefaultTransferType(bits)); - if (bits < 1 || bits > 16) { - throw new IllegalArgumentException("Number of bits must be between" - +" 1 and 16."); - } - setRGBs (size, r, g, b, a); - calculatePixelMask(); - } - - /** - * Constructs an <code>IndexColorModel</code> from a single - * array of interleaved red, green, blue and optional alpha - * components. The array must have enough values in it to - * fill all of the needed component arrays of the specified - * size. The <code>ColorSpace</code> is the default sRGB space. - * The transparency value may be any of <code>Transparency.OPAQUE</code>, - * <code>Transparency.BITMASK</code>, - * or <code>Transparency.TRANSLUCENT</code> - * depending on the arguments, as specified - * in the <a href="#transparency">class description</a> above. - * The transfer type is the smallest of - * <code>DataBuffer.TYPE_BYTE</code> or <code>DataBuffer.TYPE_USHORT</code> - * that can hold a single pixel. - * - * @param bits the number of bits each pixel occupies - * @param size the size of the color component arrays - * @param cmap the array of color components - * @param start the starting offset of the first color component - * @param hasalpha indicates whether alpha values are contained in - * the <code>cmap</code> array - * @throws IllegalArgumentException if <code>bits</code> is less - * than 1 or greater than 16 - * @throws IllegalArgumentException if <code>size</code> is less - * than 1 - */ - public IndexColorModel(int bits, int size, byte cmap[], int start, - boolean hasalpha) { - this(bits, size, cmap, start, hasalpha, -1); - if (bits < 1 || bits > 16) { - throw new IllegalArgumentException("Number of bits must be between" - +" 1 and 16."); - } - } - - /** - * Constructs an <code>IndexColorModel</code> from a single array of - * interleaved red, green, blue and optional alpha components. The - * specified transparent index represents a pixel that is made - * entirely transparent regardless of any alpha value specified - * for it. The array must have enough values in it to fill all - * of the needed component arrays of the specified size. - * The <code>ColorSpace</code> is the default sRGB space. - * The transparency value may be any of <code>Transparency.OPAQUE</code>, - * <code>Transparency.BITMASK</code>, - * or <code>Transparency.TRANSLUCENT</code> - * depending on the arguments, as specified - * in the <a href="#transparency">class description</a> above. - * The transfer type is the smallest of - * <code>DataBuffer.TYPE_BYTE</code> or <code>DataBuffer.TYPE_USHORT</code> - * that can hold a single pixel. - * @param bits the number of bits each pixel occupies - * @param size the size of the color component arrays - * @param cmap the array of color components - * @param start the starting offset of the first color component - * @param hasalpha indicates whether alpha values are contained in - * the <code>cmap</code> array - * @param trans the index of the fully transparent pixel - * @throws IllegalArgumentException if <code>bits</code> is less than - * 1 or greater than 16 - * @throws IllegalArgumentException if <code>size</code> is less than - * 1 - */ - public IndexColorModel(int bits, int size, byte cmap[], int start, - boolean hasalpha, int trans) { - // REMIND: This assumes the ordering: RGB[A] - super(bits, opaqueBits, - ColorSpace.getInstance(ColorSpace.CS_sRGB), - false, false, OPAQUE, - ColorModel.getDefaultTransferType(bits)); - - if (bits < 1 || bits > 16) { - throw new IllegalArgumentException("Number of bits must be between" - +" 1 and 16."); - } - if (size < 1) { - throw new IllegalArgumentException("Map size ("+size+ - ") must be >= 1"); - } - map_size = size; - rgb = new int[calcRealMapSize(bits, size)]; - int j = start; - int alpha = 0xff; - boolean allgray = true; - int transparency = OPAQUE; - for (int i = 0; i < size; i++) { - int r = cmap[j++] & 0xff; - int g = cmap[j++] & 0xff; - int b = cmap[j++] & 0xff; - allgray = allgray && (r == g) && (g == b); - if (hasalpha) { - alpha = cmap[j++] & 0xff; - if (alpha != 0xff) { - if (alpha == 0x00) { - if (transparency == OPAQUE) { - transparency = BITMASK; - } - if (transparent_index < 0) { - transparent_index = i; - } - } else { - transparency = TRANSLUCENT; - } - allgray = false; - } - } - rgb[i] = (alpha << 24) | (r << 16) | (g << 8) | b; - } - this.allgrayopaque = allgray; - setTransparency(transparency); - setTransparentPixel(trans); - calculatePixelMask(); - } - - /** - * Constructs an <code>IndexColorModel</code> from an array of - * ints where each int is comprised of red, green, blue, and - * optional alpha components in the default RGB color model format. - * The specified transparent index represents a pixel that is made - * entirely transparent regardless of any alpha value specified - * for it. The array must have enough values in it to fill all - * of the needed component arrays of the specified size. - * The <code>ColorSpace</code> is the default sRGB space. - * The transparency value may be any of <code>Transparency.OPAQUE</code>, - * <code>Transparency.BITMASK</code>, - * or <code>Transparency.TRANSLUCENT</code> - * depending on the arguments, as specified - * in the <a href="#transparency">class description</a> above. - * @param bits the number of bits each pixel occupies - * @param size the size of the color component arrays - * @param cmap the array of color components - * @param start the starting offset of the first color component - * @param hasalpha indicates whether alpha values are contained in - * the <code>cmap</code> array - * @param trans the index of the fully transparent pixel - * @param transferType the data type of the array used to represent - * pixel values. The data type must be either - * <code>DataBuffer.TYPE_BYTE</code> or - * <code>DataBuffer.TYPE_USHORT</code>. - * @throws IllegalArgumentException if <code>bits</code> is less - * than 1 or greater than 16 - * @throws IllegalArgumentException if <code>size</code> is less - * than 1 - * @throws IllegalArgumentException if <code>transferType</code> is not - * one of <code>DataBuffer.TYPE_BYTE</code> or - * <code>DataBuffer.TYPE_USHORT</code> - */ - public IndexColorModel(int bits, int size, - int cmap[], int start, - boolean hasalpha, int trans, int transferType) { - // REMIND: This assumes the ordering: RGB[A] - super(bits, opaqueBits, - ColorSpace.getInstance(ColorSpace.CS_sRGB), - false, false, OPAQUE, - transferType); - - if (bits < 1 || bits > 16) { - throw new IllegalArgumentException("Number of bits must be between" - +" 1 and 16."); - } - if (size < 1) { - throw new IllegalArgumentException("Map size ("+size+ - ") must be >= 1"); - } - if ((transferType != DataBuffer.TYPE_BYTE) && - (transferType != DataBuffer.TYPE_USHORT)) { - throw new IllegalArgumentException("transferType must be either" + - "DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT"); - } - - setRGBs(size, cmap, start, hasalpha); - setTransparentPixel(trans); - calculatePixelMask(); - } - - /** - * Constructs an <code>IndexColorModel</code> from an - * <code>int</code> array where each <code>int</code> is - * comprised of red, green, blue, and alpha - * components in the default RGB color model format. - * The array must have enough values in it to fill all - * of the needed component arrays of the specified size. - * The <code>ColorSpace</code> is the default sRGB space. - * The transparency value may be any of <code>Transparency.OPAQUE</code>, - * <code>Transparency.BITMASK</code>, - * or <code>Transparency.TRANSLUCENT</code> - * depending on the arguments, as specified - * in the <a href="#transparency">class description</a> above. - * The transfer type must be one of <code>DataBuffer.TYPE_BYTE</code> - * <code>DataBuffer.TYPE_USHORT</code>. - * The <code>BigInteger</code> object specifies the valid/invalid pixels - * in the <code>cmap</code> array. A pixel is valid if the - * <code>BigInteger</code> value at that index is set, and is invalid - * if the <code>BigInteger</code> bit at that index is not set. - * @param bits the number of bits each pixel occupies - * @param size the size of the color component array - * @param cmap the array of color components - * @param start the starting offset of the first color component - * @param transferType the specified data type - * @param validBits a <code>BigInteger</code> object. If a bit is - * set in the BigInteger, the pixel at that index is valid. - * If a bit is not set, the pixel at that index - * is considered invalid. If null, all pixels are valid. - * Only bits from 0 to the map size are considered. - * @throws IllegalArgumentException if <code>bits</code> is less - * than 1 or greater than 16 - * @throws IllegalArgumentException if <code>size</code> is less - * than 1 - * @throws IllegalArgumentException if <code>transferType</code> is not - * one of <code>DataBuffer.TYPE_BYTE</code> or - * <code>DataBuffer.TYPE_USHORT</code> - * - * @since 1.3 - */ - public IndexColorModel(int bits, int size, int cmap[], int start, - int transferType, BigInteger validBits) { - super (bits, alphaBits, - ColorSpace.getInstance(ColorSpace.CS_sRGB), - true, false, TRANSLUCENT, - transferType); - - if (bits < 1 || bits > 16) { - throw new IllegalArgumentException("Number of bits must be between" - +" 1 and 16."); - } - if (size < 1) { - throw new IllegalArgumentException("Map size ("+size+ - ") must be >= 1"); - } - if ((transferType != DataBuffer.TYPE_BYTE) && - (transferType != DataBuffer.TYPE_USHORT)) { - throw new IllegalArgumentException("transferType must be either" + - "DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT"); - } - - if (validBits != null) { - // Check to see if it is all valid - for (int i=0; i < size; i++) { - if (!validBits.testBit(i)) { - this.validBits = validBits; - break; - } - } - } - - setRGBs(size, cmap, start, true); - calculatePixelMask(); - } - - private void setRGBs(int size, byte r[], byte g[], byte b[], byte a[]) { - if (size < 1) { - throw new IllegalArgumentException("Map size ("+size+ - ") must be >= 1"); - } - map_size = size; - rgb = new int[calcRealMapSize(pixel_bits, size)]; - int alpha = 0xff; - int transparency = OPAQUE; - boolean allgray = true; - for (int i = 0; i < size; i++) { - int rc = r[i] & 0xff; - int gc = g[i] & 0xff; - int bc = b[i] & 0xff; - allgray = allgray && (rc == gc) && (gc == bc); - if (a != null) { - alpha = a[i] & 0xff; - if (alpha != 0xff) { - if (alpha == 0x00) { - if (transparency == OPAQUE) { - transparency = BITMASK; - } - if (transparent_index < 0) { - transparent_index = i; - } - } else { - transparency = TRANSLUCENT; - } - allgray = false; - } - } - rgb[i] = (alpha << 24) | (rc << 16) | (gc << 8) | bc; - } - this.allgrayopaque = allgray; - setTransparency(transparency); - } - - private void setRGBs(int size, int cmap[], int start, boolean hasalpha) { - map_size = size; - rgb = new int[calcRealMapSize(pixel_bits, size)]; - int j = start; - int transparency = OPAQUE; - boolean allgray = true; - BigInteger validBits = this.validBits; - for (int i = 0; i < size; i++, j++) { - if (validBits != null && !validBits.testBit(i)) { - continue; - } - int cmaprgb = cmap[j]; - int r = (cmaprgb >> 16) & 0xff; - int g = (cmaprgb >> 8) & 0xff; - int b = (cmaprgb ) & 0xff; - allgray = allgray && (r == g) && (g == b); - if (hasalpha) { - int alpha = cmaprgb >>> 24; - if (alpha != 0xff) { - if (alpha == 0x00) { - if (transparency == OPAQUE) { - transparency = BITMASK; - } - if (transparent_index < 0) { - transparent_index = i; - } - } else { - transparency = TRANSLUCENT; - } - allgray = false; - } - } else { - cmaprgb |= 0xff000000; - } - rgb[i] = cmaprgb; - } - this.allgrayopaque = allgray; - setTransparency(transparency); - } - - private int calcRealMapSize(int bits, int size) { - int newSize = Math.max(1 << bits, size); - return Math.max(newSize, 256); - } - - private BigInteger getAllValid() { - int numbytes = (map_size+7)/8; - byte[] valid = new byte[numbytes]; - java.util.Arrays.fill(valid, (byte)0xff); - valid[0] = (byte)(0xff >>> (numbytes*8 - map_size)); - - return new BigInteger(1, valid); - } - - /** - * Returns the transparency. Returns either OPAQUE, BITMASK, - * or TRANSLUCENT - * @return the transparency of this <code>IndexColorModel</code> - * @see Transparency#OPAQUE - * @see Transparency#BITMASK - * @see Transparency#TRANSLUCENT - */ - public int getTransparency() { - return transparency; - } - - /** - * Returns an array of the number of bits for each color/alpha component. - * The array contains the color components in the order red, green, - * blue, followed by the alpha component, if present. - * @return an array containing the number of bits of each color - * and alpha component of this <code>IndexColorModel</code> - */ - public int[] getComponentSize() { - if (nBits == null) { - if (supportsAlpha) { - nBits = new int[4]; - nBits[3] = 8; - } - else { - nBits = new int[3]; - } - nBits[0] = nBits[1] = nBits[2] = 8; - } - return nBits.clone(); - } - - /** - * Returns the size of the color/alpha component arrays in this - * <code>IndexColorModel</code>. - * @return the size of the color and alpha component arrays. - */ - final public int getMapSize() { - return map_size; - } - - /** - * Returns the index of a transparent pixel in this - * <code>IndexColorModel</code> or -1 if there is no pixel - * with an alpha value of 0. If a transparent pixel was - * explicitly specified in one of the constructors by its - * index, then that index will be preferred, otherwise, - * the index of any pixel which happens to be fully transparent - * may be returned. - * @return the index of a transparent pixel in this - * <code>IndexColorModel</code> object, or -1 if there - * is no such pixel - */ - final public int getTransparentPixel() { - return transparent_index; - } - - /** - * Copies the array of red color components into the specified array. - * Only the initial entries of the array as specified by - * {@link #getMapSize() getMapSize} are written. - * @param r the specified array into which the elements of the - * array of red color components are copied - */ - final public void getReds(byte r[]) { - for (int i = 0; i < map_size; i++) { - r[i] = (byte) (rgb[i] >> 16); - } - } - - /** - * Copies the array of green color components into the specified array. - * Only the initial entries of the array as specified by - * <code>getMapSize</code> are written. - * @param g the specified array into which the elements of the - * array of green color components are copied - */ - final public void getGreens(byte g[]) { - for (int i = 0; i < map_size; i++) { - g[i] = (byte) (rgb[i] >> 8); - } - } - - /** - * Copies the array of blue color components into the specified array. - * Only the initial entries of the array as specified by - * <code>getMapSize</code> are written. - * @param b the specified array into which the elements of the - * array of blue color components are copied - */ - final public void getBlues(byte b[]) { - for (int i = 0; i < map_size; i++) { - b[i] = (byte) rgb[i]; - } - } - - /** - * Copies the array of alpha transparency components into the - * specified array. Only the initial entries of the array as specified - * by <code>getMapSize</code> are written. - * @param a the specified array into which the elements of the - * array of alpha components are copied - */ - final public void getAlphas(byte a[]) { - for (int i = 0; i < map_size; i++) { - a[i] = (byte) (rgb[i] >> 24); - } - } - - /** - * Converts data for each index from the color and alpha component - * arrays to an int in the default RGB ColorModel format and copies - * the resulting 32-bit ARGB values into the specified array. Only - * the initial entries of the array as specified by - * <code>getMapSize</code> are - * written. - * @param rgb the specified array into which the converted ARGB - * values from this array of color and alpha components - * are copied. - */ - final public void getRGBs(int rgb[]) { - System.arraycopy(this.rgb, 0, rgb, 0, map_size); - } - - private void setTransparentPixel(int trans) { - if (trans >= 0 && trans < map_size) { - rgb[trans] &= 0x00ffffff; - transparent_index = trans; - allgrayopaque = false; - if (this.transparency == OPAQUE) { - setTransparency(BITMASK); - } - } - } - - private void setTransparency(int transparency) { - if (this.transparency != transparency) { - this.transparency = transparency; - if (transparency == OPAQUE) { - supportsAlpha = false; - numComponents = 3; - nBits = opaqueBits; - } else { - supportsAlpha = true; - numComponents = 4; - nBits = alphaBits; - } - } - } - - /** - * This method is called from the constructors to set the pixel_mask - * value, which is based on the value of pixel_bits. The pixel_mask - * value is used to mask off the pixel parameters for methods such - * as getRed(), getGreen(), getBlue(), getAlpha(), and getRGB(). - */ - private final void calculatePixelMask() { - // Note that we adjust the mask so that our masking behavior here - // is consistent with that of our native rendering loops. - int maskbits = pixel_bits; - if (maskbits == 3) { - maskbits = 4; - } else if (maskbits > 4 && maskbits < 8) { - maskbits = 8; - } - pixel_mask = (1 << maskbits) - 1; - } - - /** - * Returns the red color component for the specified pixel, scaled - * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value - * is specified as an int. - * Only the lower <em>n</em> bits of the pixel value, as specified in the - * <a href="#index_values">class description</a> above, are used to - * calculate the returned value. - * The returned value is a non pre-multiplied value. - * @param pixel the specified pixel - * @return the value of the red color component for the specified pixel - */ - final public int getRed(int pixel) { - return (rgb[pixel & pixel_mask] >> 16) & 0xff; - } - - /** - * Returns the green color component for the specified pixel, scaled - * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value - * is specified as an int. - * Only the lower <em>n</em> bits of the pixel value, as specified in the - * <a href="#index_values">class description</a> above, are used to - * calculate the returned value. - * The returned value is a non pre-multiplied value. - * @param pixel the specified pixel - * @return the value of the green color component for the specified pixel - */ - final public int getGreen(int pixel) { - return (rgb[pixel & pixel_mask] >> 8) & 0xff; - } - - /** - * Returns the blue color component for the specified pixel, scaled - * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value - * is specified as an int. - * Only the lower <em>n</em> bits of the pixel value, as specified in the - * <a href="#index_values">class description</a> above, are used to - * calculate the returned value. - * The returned value is a non pre-multiplied value. - * @param pixel the specified pixel - * @return the value of the blue color component for the specified pixel - */ - final public int getBlue(int pixel) { - return rgb[pixel & pixel_mask] & 0xff; - } - - /** - * Returns the alpha component for the specified pixel, scaled - * from 0 to 255. The pixel value is specified as an int. - * Only the lower <em>n</em> bits of the pixel value, as specified in the - * <a href="#index_values">class description</a> above, are used to - * calculate the returned value. - * @param pixel the specified pixel - * @return the value of the alpha component for the specified pixel - */ - final public int getAlpha(int pixel) { - return (rgb[pixel & pixel_mask] >> 24) & 0xff; - } - - /** - * Returns the color/alpha components of the pixel in the default - * RGB color model format. The pixel value is specified as an int. - * Only the lower <em>n</em> bits of the pixel value, as specified in the - * <a href="#index_values">class description</a> above, are used to - * calculate the returned value. - * The returned value is in a non pre-multiplied format. - * @param pixel the specified pixel - * @return the color and alpha components of the specified pixel - * @see ColorModel#getRGBdefault - */ - final public int getRGB(int pixel) { - return rgb[pixel & pixel_mask]; - } - - private static final int CACHESIZE = 40; - private int lookupcache[] = new int[CACHESIZE]; - - /** - * Returns a data element array representation of a pixel in this - * ColorModel, given an integer pixel representation in the - * default RGB color model. This array can then be passed to the - * {@link WritableRaster#setDataElements(int, int, java.lang.Object) setDataElements} - * method of a {@link WritableRaster} object. If the pixel variable is - * <code>null</code>, a new array is allocated. If <code>pixel</code> - * is not <code>null</code>, it must be - * a primitive array of type <code>transferType</code>; otherwise, a - * <code>ClassCastException</code> is thrown. An - * <code>ArrayIndexOutOfBoundsException</code> is - * thrown if <code>pixel</code> is not large enough to hold a pixel - * value for this <code>ColorModel</code>. The pixel array is returned. - * <p> - * Since <code>IndexColorModel</code> can be subclassed, subclasses - * inherit the implementation of this method and if they don't - * override it then they throw an exception if they use an - * unsupported <code>transferType</code>. - * - * @param rgb the integer pixel representation in the default RGB - * color model - * @param pixel the specified pixel - * @return an array representation of the specified pixel in this - * <code>IndexColorModel</code>. - * @throws ClassCastException if <code>pixel</code> - * is not a primitive array of type <code>transferType</code> - * @throws ArrayIndexOutOfBoundsException if - * <code>pixel</code> is not large enough to hold a pixel value - * for this <code>ColorModel</code> - * @throws UnsupportedOperationException if <code>transferType</code> - * is invalid - * @see WritableRaster#setDataElements - * @see SampleModel#setDataElements - */ - public synchronized Object getDataElements(int rgb, Object pixel) { - int red = (rgb>>16) & 0xff; - int green = (rgb>>8) & 0xff; - int blue = rgb & 0xff; - int alpha = (rgb>>>24); - int pix = 0; - - // Note that pixels are stored at lookupcache[2*i] - // and the rgb that was searched is stored at - // lookupcache[2*i+1]. Also, the pixel is first - // inverted using the unary complement operator - // before storing in the cache so it can never be 0. - for (int i = CACHESIZE - 2; i >= 0; i -= 2) { - if ((pix = lookupcache[i]) == 0) { - break; - } - if (rgb == lookupcache[i+1]) { - return installpixel(pixel, ~pix); - } - } - - if (allgrayopaque) { - // IndexColorModel objects are all tagged as - // non-premultiplied so ignore the alpha value - // of the incoming color, convert the - // non-premultiplied color components to a - // grayscale value and search for the closest - // gray value in the palette. Since all colors - // in the palette are gray, we only need compare - // to one of the color components for a match - // using a simple linear distance formula. - - int minDist = 256; - int d; - int gray = (int) (red*77 + green*150 + blue*29 + 128)/256; - - for (int i = 0; i < map_size; i++) { - if (this.rgb[i] == 0x0) { - // For allgrayopaque colormaps, entries are 0 - // iff they are an invalid color and should be - // ignored during color searches. - continue; - } - d = (this.rgb[i] & 0xff) - gray; - if (d < 0) d = -d; - if (d < minDist) { - pix = i; - if (d == 0) { - break; - } - minDist = d; - } - } - } else if (transparency == OPAQUE) { - // IndexColorModel objects are all tagged as - // non-premultiplied so ignore the alpha value - // of the incoming color and search for closest - // color match independently using a 3 component - // Euclidean distance formula. - // For opaque colormaps, palette entries are 0 - // iff they are an invalid color and should be - // ignored during color searches. - // As an optimization, exact color searches are - // likely to be fairly common in opaque colormaps - // so first we will do a quick search for an - // exact match. - - int smallestError = Integer.MAX_VALUE; - int lut[] = this.rgb; - int lutrgb; - for (int i=0; i < map_size; i++) { - lutrgb = lut[i]; - if (lutrgb == rgb && lutrgb != 0) { - pix = i; - smallestError = 0; - break; - } - } - - if (smallestError != 0) { - for (int i=0; i < map_size; i++) { - lutrgb = lut[i]; - if (lutrgb == 0) { - continue; - } - - int tmp = ((lutrgb >> 16) & 0xff) - red; - int currentError = tmp*tmp; - if (currentError < smallestError) { - tmp = ((lutrgb >> 8) & 0xff) - green; - currentError += tmp * tmp; - if (currentError < smallestError) { - tmp = (lutrgb & 0xff) - blue; - currentError += tmp * tmp; - if (currentError < smallestError) { - pix = i; - smallestError = currentError; - } - } - } - } - } - } else if (alpha == 0 && transparent_index >= 0) { - // Special case - transparent color maps to the - // specified transparent pixel, if there is one - - pix = transparent_index; - } else { - // IndexColorModel objects are all tagged as - // non-premultiplied so use non-premultiplied - // color components in the distance calculations. - // Look for closest match using a 4 component - // Euclidean distance formula. - - int smallestError = Integer.MAX_VALUE; - int lut[] = this.rgb; - for (int i=0; i < map_size; i++) { - int lutrgb = lut[i]; - if (lutrgb == rgb) { - if (validBits != null && !validBits.testBit(i)) { - continue; - } - pix = i; - break; - } - - int tmp = ((lutrgb >> 16) & 0xff) - red; - int currentError = tmp*tmp; - if (currentError < smallestError) { - tmp = ((lutrgb >> 8) & 0xff) - green; - currentError += tmp * tmp; - if (currentError < smallestError) { - tmp = (lutrgb & 0xff) - blue; - currentError += tmp * tmp; - if (currentError < smallestError) { - tmp = (lutrgb >>> 24) - alpha; - currentError += tmp * tmp; - if (currentError < smallestError && - (validBits == null || validBits.testBit(i))) - { - pix = i; - smallestError = currentError; - } - } - } - } - } - } - System.arraycopy(lookupcache, 2, lookupcache, 0, CACHESIZE - 2); - lookupcache[CACHESIZE - 1] = rgb; - lookupcache[CACHESIZE - 2] = ~pix; - return installpixel(pixel, pix); - } - - private Object installpixel(Object pixel, int pix) { - switch (transferType) { - case DataBuffer.TYPE_INT: - int[] intObj; - if (pixel == null) { - pixel = intObj = new int[1]; - } else { - intObj = (int[]) pixel; - } - intObj[0] = pix; - break; - case DataBuffer.TYPE_BYTE: - byte[] byteObj; - if (pixel == null) { - pixel = byteObj = new byte[1]; - } else { - byteObj = (byte[]) pixel; - } - byteObj[0] = (byte) pix; - break; - case DataBuffer.TYPE_USHORT: - short[] shortObj; - if (pixel == null) { - pixel = shortObj = new short[1]; - } else { - shortObj = (short[]) pixel; - } - shortObj[0] = (short) pix; - break; - default: - throw new UnsupportedOperationException("This method has not been "+ - "implemented for transferType " + transferType); - } - return pixel; - } - - /** - * Returns an array of unnormalized color/alpha components for a - * specified pixel in this <code>ColorModel</code>. The pixel value - * is specified as an int. If the <code>components</code> array is <code>null</code>, - * a new array is allocated that contains - * <code>offset + getNumComponents()</code> elements. - * The <code>components</code> array is returned, - * with the alpha component included - * only if <code>hasAlpha</code> returns true. - * Color/alpha components are stored in the <code>components</code> array starting - * at <code>offset</code> even if the array is allocated by this method. - * An <code>ArrayIndexOutOfBoundsException</code> - * is thrown if the <code>components</code> array is not <code>null</code> and is - * not large enough to hold all the color and alpha components - * starting at <code>offset</code>. - * @param pixel the specified pixel - * @param components the array to receive the color and alpha - * components of the specified pixel - * @param offset the offset into the <code>components</code> array at - * which to start storing the color and alpha components - * @return an array containing the color and alpha components of the - * specified pixel starting at the specified offset. - * @see ColorModel#hasAlpha - * @see ColorModel#getNumComponents - */ - public int[] getComponents(int pixel, int[] components, int offset) { - if (components == null) { - components = new int[offset+numComponents]; - } - - // REMIND: Needs to change if different color space - components[offset+0] = getRed(pixel); - components[offset+1] = getGreen(pixel); - components[offset+2] = getBlue(pixel); - if (supportsAlpha && (components.length-offset) > 3) { - components[offset+3] = getAlpha(pixel); - } - - return components; - } - - /** - * Returns an array of unnormalized color/alpha components for - * a specified pixel in this <code>ColorModel</code>. The pixel - * value is specified by an array of data elements of type - * <code>transferType</code> passed in as an object reference. - * If <code>pixel</code> is not a primitive array of type - * <code>transferType</code>, a <code>ClassCastException</code> - * is thrown. An <code>ArrayIndexOutOfBoundsException</code> - * is thrown if <code>pixel</code> is not large enough to hold - * a pixel value for this <code>ColorModel</code>. If the - * <code>components</code> array is <code>null</code>, a new array - * is allocated that contains - * <code>offset + getNumComponents()</code> elements. - * The <code>components</code> array is returned, - * with the alpha component included - * only if <code>hasAlpha</code> returns true. - * Color/alpha components are stored in the <code>components</code> - * array starting at <code>offset</code> even if the array is - * allocated by this method. An - * <code>ArrayIndexOutOfBoundsException</code> is also - * thrown if the <code>components</code> array is not - * <code>null</code> and is not large enough to hold all the color - * and alpha components starting at <code>offset</code>. - * <p> - * Since <code>IndexColorModel</code> can be subclassed, subclasses - * inherit the implementation of this method and if they don't - * override it then they throw an exception if they use an - * unsupported <code>transferType</code>. - * - * @param pixel the specified pixel - * @param components an array that receives the color and alpha - * components of the specified pixel - * @param offset the index into the <code>components</code> array at - * which to begin storing the color and alpha components of the - * specified pixel - * @return an array containing the color and alpha components of the - * specified pixel starting at the specified offset. - * @throws ArrayIndexOutOfBoundsException if <code>pixel</code> - * is not large enough to hold a pixel value for this - * <code>ColorModel</code> or if the - * <code>components</code> array is not <code>null</code> - * and is not large enough to hold all the color - * and alpha components starting at <code>offset</code> - * @throws ClassCastException if <code>pixel</code> is not a - * primitive array of type <code>transferType</code> - * @throws UnsupportedOperationException if <code>transferType</code> - * is not one of the supported transer types - * @see ColorModel#hasAlpha - * @see ColorModel#getNumComponents - */ - public int[] getComponents(Object pixel, int[] components, int offset) { - int intpixel; - switch (transferType) { - case DataBuffer.TYPE_BYTE: - byte bdata[] = (byte[])pixel; - intpixel = bdata[0] & 0xff; - break; - case DataBuffer.TYPE_USHORT: - short sdata[] = (short[])pixel; - intpixel = sdata[0] & 0xffff; - break; - case DataBuffer.TYPE_INT: - int idata[] = (int[])pixel; - intpixel = idata[0]; - break; - default: - throw new UnsupportedOperationException("This method has not been "+ - "implemented for transferType " + transferType); - } - return getComponents(intpixel, components, offset); - } - - /** - * Returns a pixel value represented as an int in this - * <code>ColorModel</code> given an array of unnormalized - * color/alpha components. An - * <code>ArrayIndexOutOfBoundsException</code> - * is thrown if the <code>components</code> array is not large - * enough to hold all of the color and alpha components starting - * at <code>offset</code>. Since - * <code>ColorModel</code> can be subclassed, subclasses inherit the - * implementation of this method and if they don't override it then - * they throw an exception if they use an unsupported transferType. - * @param components an array of unnormalized color and alpha - * components - * @param offset the index into <code>components</code> at which to - * begin retrieving the color and alpha components - * @return an <code>int</code> pixel value in this - * <code>ColorModel</code> corresponding to the specified components. - * @throws ArrayIndexOutOfBoundsException if - * the <code>components</code> array is not large enough to - * hold all of the color and alpha components starting at - * <code>offset</code> - * @throws UnsupportedOperationException if <code>transferType</code> - * is invalid - */ - public int getDataElement(int[] components, int offset) { - int rgb = (components[offset+0]<<16) - | (components[offset+1]<<8) | (components[offset+2]); - if (supportsAlpha) { - rgb |= (components[offset+3]<<24); - } - else { - rgb |= 0xff000000; - } - Object inData = getDataElements(rgb, null); - int pixel; - switch (transferType) { - case DataBuffer.TYPE_BYTE: - byte bdata[] = (byte[])inData; - pixel = bdata[0] & 0xff; - break; - case DataBuffer.TYPE_USHORT: - short sdata[] = (short[])inData; - pixel = sdata[0]; - break; - case DataBuffer.TYPE_INT: - int idata[] = (int[])inData; - pixel = idata[0]; - break; - default: - throw new UnsupportedOperationException("This method has not been "+ - "implemented for transferType " + transferType); - } - return pixel; - } - - /** - * Returns a data element array representation of a pixel in this - * <code>ColorModel</code> given an array of unnormalized color/alpha - * components. This array can then be passed to the - * <code>setDataElements</code> method of a <code>WritableRaster</code> - * object. An <code>ArrayIndexOutOfBoundsException</code> is - * thrown if the - * <code>components</code> array is not large enough to hold all of the - * color and alpha components starting at <code>offset</code>. - * If the pixel variable is <code>null</code>, a new array - * is allocated. If <code>pixel</code> is not <code>null</code>, - * it must be a primitive array of type <code>transferType</code>; - * otherwise, a <code>ClassCastException</code> is thrown. - * An <code>ArrayIndexOutOfBoundsException</code> is thrown if pixel - * is not large enough to hold a pixel value for this - * <code>ColorModel</code>. - * <p> - * Since <code>IndexColorModel</code> can be subclassed, subclasses - * inherit the implementation of this method and if they don't - * override it then they throw an exception if they use an - * unsupported <code>transferType</code> - * - * @param components an array of unnormalized color and alpha - * components - * @param offset the index into <code>components</code> at which to - * begin retrieving color and alpha components - * @param pixel the <code>Object</code> representing an array of color - * and alpha components - * @return an <code>Object</code> representing an array of color and - * alpha components. - * @throws ClassCastException if <code>pixel</code> - * is not a primitive array of type <code>transferType</code> - * @throws ArrayIndexOutOfBoundsException if - * <code>pixel</code> is not large enough to hold a pixel value - * for this <code>ColorModel</code> or the <code>components</code> - * array is not large enough to hold all of the color and alpha - * components starting at <code>offset</code> - * @throws UnsupportedOperationException if <code>transferType</code> - * is not one of the supported transer types - * @see WritableRaster#setDataElements - * @see SampleModel#setDataElements - */ - public Object getDataElements(int[] components, int offset, Object pixel) { - int rgb = (components[offset+0]<<16) | (components[offset+1]<<8) - | (components[offset+2]); - if (supportsAlpha) { - rgb |= (components[offset+3]<<24); - } - else { - rgb &= 0xff000000; - } - return getDataElements(rgb, pixel); - } - - /** - * Creates a <code>WritableRaster</code> with the specified width - * and height that has a data layout (<code>SampleModel</code>) - * compatible with this <code>ColorModel</code>. This method - * only works for color models with 16 or fewer bits per pixel. - * <p> - * Since <code>IndexColorModel</code> can be subclassed, any - * subclass that supports greater than 16 bits per pixel must - * override this method. - * - * @param w the width to apply to the new <code>WritableRaster</code> - * @param h the height to apply to the new <code>WritableRaster</code> - * @return a <code>WritableRaster</code> object with the specified - * width and height. - * @throws UnsupportedOperationException if the number of bits in a - * pixel is greater than 16 - * @see WritableRaster - * @see SampleModel - */ - public WritableRaster createCompatibleWritableRaster(int w, int h) { - WritableRaster raster; - - if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) { - // TYPE_BINARY - raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, - w, h, 1, pixel_bits, null); - } - else if (pixel_bits <= 8) { - raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, - w,h,1,null); - } - else if (pixel_bits <= 16) { - raster = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT, - w,h,1,null); - } - else { - throw new - UnsupportedOperationException("This method is not supported "+ - " for pixel bits > 16."); - } - return raster; - } - - /** - * Returns <code>true</code> if <code>raster</code> is compatible - * with this <code>ColorModel</code> or <code>false</code> if it - * is not compatible with this <code>ColorModel</code>. - * @param raster the {@link Raster} object to test for compatibility - * @return <code>true</code> if <code>raster</code> is compatible - * with this <code>ColorModel</code>; <code>false</code> otherwise. - * - */ - public boolean isCompatibleRaster(Raster raster) { - - int size = raster.getSampleModel().getSampleSize(0); - return ((raster.getTransferType() == transferType) && - (raster.getNumBands() == 1) && ((1 << size) >= map_size)); - } - - /** - * Creates a <code>SampleModel</code> with the specified - * width and height that has a data layout compatible with - * this <code>ColorModel</code>. - * @param w the width to apply to the new <code>SampleModel</code> - * @param h the height to apply to the new <code>SampleModel</code> - * @return a <code>SampleModel</code> object with the specified - * width and height. - * @throws IllegalArgumentException if <code>w</code> or - * <code>h</code> is not greater than 0 - * @see SampleModel - */ - public SampleModel createCompatibleSampleModel(int w, int h) { - int[] off = new int[1]; - off[0] = 0; - if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) { - return new MultiPixelPackedSampleModel(transferType, w, h, - pixel_bits); - } - else { - return new ComponentSampleModel(transferType, w, h, 1, w, - off); - } - } - - /** - * Checks if the specified <code>SampleModel</code> is compatible - * with this <code>ColorModel</code>. If <code>sm</code> is - * <code>null</code>, this method returns <code>false</code>. - * @param sm the specified <code>SampleModel</code>, - * or <code>null</code> - * @return <code>true</code> if the specified <code>SampleModel</code> - * is compatible with this <code>ColorModel</code>; <code>false</code> - * otherwise. - * @see SampleModel - */ - public boolean isCompatibleSampleModel(SampleModel sm) { - // fix 4238629 - if (! (sm instanceof ComponentSampleModel) && - ! (sm instanceof MultiPixelPackedSampleModel) ) { - return false; - } - - // Transfer type must be the same - if (sm.getTransferType() != transferType) { - return false; - } - - if (sm.getNumBands() != 1) { - return false; - } - - return true; - } - - /** - * Returns a new <code>BufferedImage</code> of TYPE_INT_ARGB or - * TYPE_INT_RGB that has a <code>Raster</code> with pixel data - * computed by expanding the indices in the source <code>Raster</code> - * using the color/alpha component arrays of this <code>ColorModel</code>. - * Only the lower <em>n</em> bits of each index value in the source - * <code>Raster</code>, as specified in the - * <a href="#index_values">class description</a> above, are used to - * compute the color/alpha values in the returned image. - * If <code>forceARGB</code> is <code>true</code>, a TYPE_INT_ARGB image is - * returned regardless of whether or not this <code>ColorModel</code> - * has an alpha component array or a transparent pixel. - * @param raster the specified <code>Raster</code> - * @param forceARGB if <code>true</code>, the returned - * <code>BufferedImage</code> is TYPE_INT_ARGB; otherwise it is - * TYPE_INT_RGB - * @return a <code>BufferedImage</code> created with the specified - * <code>Raster</code> - * @throws IllegalArgumentException if the raster argument is not - * compatible with this IndexColorModel - */ - public BufferedImage convertToIntDiscrete(Raster raster, - boolean forceARGB) { - ColorModel cm; - - if (!isCompatibleRaster(raster)) { - throw new IllegalArgumentException("This raster is not compatible" + - "with this IndexColorModel."); - } - if (forceARGB || transparency == TRANSLUCENT) { - cm = ColorModel.getRGBdefault(); - } - else if (transparency == BITMASK) { - cm = new DirectColorModel(25, 0xff0000, 0x00ff00, 0x0000ff, - 0x1000000); - } - else { - cm = new DirectColorModel(24, 0xff0000, 0x00ff00, 0x0000ff); - } - - int w = raster.getWidth(); - int h = raster.getHeight(); - WritableRaster discreteRaster = - cm.createCompatibleWritableRaster(w, h); - Object obj = null; - int[] data = null; - - int rX = raster.getMinX(); - int rY = raster.getMinY(); - - for (int y=0; y < h; y++, rY++) { - obj = raster.getDataElements(rX, rY, w, 1, obj); - if (obj instanceof int[]) { - data = (int[])obj; - } else { - data = DataBuffer.toIntArray(obj); - } - for (int x=0; x < w; x++) { - data[x] = rgb[data[x] & pixel_mask]; - } - discreteRaster.setDataElements(0, y, w, 1, data); - } - - return new BufferedImage(cm, discreteRaster, false, null); - } - - /** - * Returns whether or not the pixel is valid. - * @param pixel the specified pixel value - * @return <code>true</code> if <code>pixel</code> - * is valid; <code>false</code> otherwise. - * @since 1.3 - */ - public boolean isValid(int pixel) { - return ((pixel >= 0 && pixel < map_size) && - (validBits == null || validBits.testBit(pixel))); - } - - /** - * Returns whether or not all of the pixels are valid. - * @return <code>true</code> if all pixels are valid; - * <code>false</code> otherwise. - * @since 1.3 - */ - public boolean isValid() { - return (validBits == null); - } - - /** - * Returns a <code>BigInteger</code> that indicates the valid/invalid - * pixels in the colormap. A bit is valid if the - * <code>BigInteger</code> value at that index is set, and is invalid - * if the <code>BigInteger</code> value at that index is not set. - * The only valid ranges to query in the <code>BigInteger</code> are - * between 0 and the map size. - * @return a <code>BigInteger</code> indicating the valid/invalid pixels. - * @since 1.3 - */ - public BigInteger getValidPixels() { - if (validBits == null) { - return getAllValid(); - } - else { - return validBits; - } - } - - /** - * Disposes of system resources associated with this - * <code>ColorModel</code> once this <code>ColorModel</code> is no - * longer referenced. - */ - public void finalize() { - } - - /** - * Returns the <code>String</code> representation of the contents of - * this <code>ColorModel</code>object. - * @return a <code>String</code> representing the contents of this - * <code>ColorModel</code> object. - */ - public String toString() { - return new String("IndexColorModel: #pixelBits = "+pixel_bits - + " numComponents = "+numComponents - + " color space = "+colorSpace - + " transparency = "+transparency - + " transIndex = "+transparent_index - + " has alpha = "+supportsAlpha - + " isAlphaPre = "+isAlphaPremultiplied - ); - } -} diff --git a/openjdk/java/awt/image/LookupOp.java b/openjdk/java/awt/image/LookupOp.java deleted file mode 100644 index 5b0cf783..00000000 --- a/openjdk/java/awt/image/LookupOp.java +++ /dev/null @@ -1,307 +0,0 @@ -/* LookupOp.java -- Filter that converts each pixel using a lookup table. - Copyright (C) 2004 Free Software Foundation - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - - -package java.awt.image; - -import java.awt.RenderingHints; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; - -/** - * LookupOp is a filter that converts each pixel using a lookup table. - * - * For filtering Rasters, the lookup table must have either one component - * that is applied to all bands, or one component for every band in the - * Rasters. - * - * For BufferedImages, the lookup table may apply to both color and alpha - * components. If the lookup table contains one component, or if there are - * the same number of components as color components in the source, the table - * applies to all color components. Otherwise the table applies to all - * components including alpha. Alpha premultiplication is ignored during the - * lookup filtering. - * - * After filtering, if color conversion is necessary, the conversion happens, - * taking alpha premultiplication into account. - * - * @author jlquinn - */ -public class LookupOp implements BufferedImageOp, RasterOp -{ - private LookupTable lut; - private RenderingHints hints; - - /** - * Construct a new LookupOp using the given LookupTable. - * - * @param lookup LookupTable to use. - * @param hints Rendering hints (can be null). - */ - public LookupOp(LookupTable lookup, RenderingHints hints) - { - lut = lookup; - this.hints = hints; - } - - /** - * Converts the source image using the lookup table specified in the - * constructor. The resulting image is stored in the destination image if one - * is provided; otherwise a new BufferedImage is created and returned. - * - * The source image cannot use an IndexColorModel, and the destination image - * (if one is provided) must have the same size. - * - * @param src The source image. - * @param dst The destination image. - * @throws IllegalArgumentException if the rasters and/or color spaces are - * incompatible. - * @throws ArrayIndexOutOfBoundsException if a pixel in the source is not - * contained in the LookupTable. - * @return The convolved image. - */ - public final BufferedImage filter(BufferedImage src, BufferedImage dst) - { - if (src.getColorModel() instanceof IndexColorModel) - throw new IllegalArgumentException("LookupOp.filter: IndexColorModel " - + "not allowed"); - - if (lut.getNumComponents() != 1 - && lut.getNumComponents() != src.getColorModel().getNumComponents() - && lut.getNumComponents() != src.getColorModel().getNumColorComponents()) - throw new IllegalArgumentException("LookupOp.filter: Incompatible " + - "lookup table and source image"); - - if (dst == null) - dst = createCompatibleDestImage(src, null); - - else if (src.getHeight() != dst.getHeight() || src.getWidth() != dst.getWidth()) - throw new IllegalArgumentException("Source and destination images are " + - "different sizes."); - - // Set up for potential colormodel mismatch - BufferedImage tgt; - if (dst.getColorModel().equals(src.getColorModel())) - tgt = dst; - else - tgt = createCompatibleDestImage(src, src.getColorModel()); - - Raster sr = src.getRaster(); - WritableRaster dr = tgt.getRaster(); - - if (src.getColorModel().hasAlpha() && - (lut.getNumComponents() == 1 || - lut.getNumComponents() == src.getColorModel().getNumColorComponents())) - { - // Need to ignore alpha for lookup - int[] dbuf = new int[src.getColorModel().getNumComponents()]; - int tmpBands = src.getColorModel().getNumColorComponents(); - int[] tmp = new int[tmpBands]; - - // Filter the pixels - for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) - for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) - { - // Filter only color components, but also copy alpha - sr.getPixel(x, y, dbuf); - System.arraycopy(dbuf, 0, tmp, 0, tmpBands); - dr.setPixel(x, y, lut.lookupPixel(tmp, dbuf)); - - /* The reference implementation does not use LookupTable.lookupPixel, - * but rather it seems to copy the table into a native array. The - * effect of this (a probable bug in their implementation) is that - * an out-of-bounds lookup on a ByteLookupTable will *not* throw an - * out of bounds exception, but will instead return random garbage. - * A bad lookup on a ShortLookupTable, however, will throw an - * exception. - * - * Instead of mimicing this behaviour, we always throw an - * ArrayOutofBoundsException by virtue of using - * LookupTable.lookupPixle. - */ - } - } - else - { - // No alpha to ignore - int[] dbuf = new int[src.getColorModel().getNumComponents()]; - - // Filter the pixels - for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) - for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) - dr.setPixel(x, y, lut.lookupPixel(sr.getPixel(x, y, dbuf), dbuf)); - } - - if (tgt != dst) - new ColorConvertOp(hints).filter(tgt, dst); - - return dst; - } - - /* (non-Javadoc) - * @see java.awt.image.BufferedImageOp#getBounds2D(java.awt.image.BufferedImage) - */ - public final Rectangle2D getBounds2D(BufferedImage src) - { - return src.getRaster().getBounds(); - } - - /* (non-Javadoc) - * @see java.awt.image.BufferedImageOp#createCompatibleDestImage(java.awt.image.BufferedImage, java.awt.image.ColorModel) - */ - public BufferedImage createCompatibleDestImage(BufferedImage src, - ColorModel dstCM) - { - if (dstCM != null) - return new BufferedImage(dstCM, - src.getRaster().createCompatibleWritableRaster(), - src.isAlphaPremultiplied(), null); - - // This is a strange exception, done for compatibility with the reference - // (as demonstrated by a mauve testcase) - int imgType = src.getType(); - if (imgType == BufferedImage.TYPE_USHORT_GRAY) - imgType = BufferedImage.TYPE_BYTE_GRAY; - - return new BufferedImage(src.getWidth(), src.getHeight(), imgType); - } - - /** - * Returns the corresponding destination point for a given source point. - * - * This Op will return the source point unchanged. - * - * @param src The source point. - * @param dst The destination point. - */ - public final Point2D getPoint2D(Point2D src, Point2D dst) - { - if (dst == null) - return (Point2D) src.clone(); - - dst.setLocation(src); - return dst; - } - - /** - * Return the LookupTable for this op. - * - * @return The lookup table. - */ - public final LookupTable getTable() - { - return lut; - } - - /* (non-Javadoc) - * @see java.awt.image.RasterOp#getRenderingHints() - */ - public final RenderingHints getRenderingHints() - { - return hints; - } - - /** - * Filter a raster through a lookup table. - * - * Applies the lookup table for this Rasterop to each pixel of src and - * puts the results in dest. If dest is null, a new Raster is created and - * returned. - * - * @param src The source raster. - * @param dest The destination raster. - * @return The WritableRaster with the filtered pixels. - * @throws IllegalArgumentException if lookup table has more than one - * component but not the same as src and dest. - * @throws ArrayIndexOutOfBoundsException if a pixel in the source is not - * contained in the LookupTable. - */ - public final WritableRaster filter(Raster src, WritableRaster dest) - { - if (dest == null) - // Allocate a raster if needed - dest = createCompatibleDestRaster(src); - else - if (src.getNumBands() != dest.getNumBands()) - throw new IllegalArgumentException("Source and destination rasters " + - "are incompatible."); - - if (lut.getNumComponents() != 1 - && lut.getNumComponents() != src.getNumBands()) - throw new IllegalArgumentException("Lookup table is incompatible with " + - "this raster."); - - // Allocate pixel storage. - int[] tmp = new int[src.getNumBands()]; - - // Filter the pixels - for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) - for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) - dest.setPixel(x, y, lut.lookupPixel(src.getPixel(x, y, tmp), tmp)); - - /* The reference implementation does not use LookupTable.lookupPixel, - * but rather it seems to copy the table into a native array. The - * effect of this (a probable bug in their implementation) is that - * an out-of-bounds lookup on a ByteLookupTable will *not* throw an - * out of bounds exception, but will instead return random garbage. - * A bad lookup on a ShortLookupTable, however, will throw an - * exception. - * - * Instead of mimicing this behaviour, we always throw an - * ArrayOutofBoundsException by virtue of using - * LookupTable.lookupPixle. - */ - return dest; - } - - /* (non-Javadoc) - * @see java.awt.image.RasterOp#getBounds2D(java.awt.image.Raster) - */ - public final Rectangle2D getBounds2D(Raster src) - { - return src.getBounds(); - } - - /* (non-Javadoc) - * @see java.awt.image.RasterOp#createCompatibleDestRaster(java.awt.image.Raster) - */ - public WritableRaster createCompatibleDestRaster(Raster src) - { - return src.createCompatibleWritableRaster(); - } - -} diff --git a/openjdk/java/awt/image/RescaleOp.java b/openjdk/java/awt/image/RescaleOp.java deleted file mode 100644 index d56b12cb..00000000 --- a/openjdk/java/awt/image/RescaleOp.java +++ /dev/null @@ -1,385 +0,0 @@ -/* Copyright (C) 2004, 2006 Free Software Foundation - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - - -package java.awt.image; - -import java.awt.RenderingHints; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.util.Arrays; - -/** - * RescaleOp is a filter that changes each pixel by a scaling factor and offset. - * - * For filtering Rasters, either one scaling factor and offset can be specified, - * which will be applied to all bands; or a scaling factor and offset can be - * specified for each band. - * - * For BufferedImages, the scaling may apply to both color and alpha components. - * If only one scaling factor is provided, or if the number of factors provided - * equals the number of color components, the scaling is performed on all color - * components. Otherwise, the scaling is performed on all components including - * alpha. Alpha premultiplication is ignored. - * - * After filtering, if color conversion is necessary, the conversion happens, - * taking alpha premultiplication into account. - * - * @author Jerry Quinn (jlquinn@optonline.net) - * @author Francis Kung (fkung@redhat.com) - */ -public class RescaleOp implements BufferedImageOp, RasterOp -{ - private float[] scale; - private float[] offsets; - private RenderingHints hints = null; - - /** - * Create a new RescaleOp object using the given scale factors and offsets. - * - * The length of the arrays must be equal to the number of bands (or number of - * data or color components) of the raster/image that this Op will be used on, - * otherwise an IllegalArgumentException will be thrown when calling the - * filter method. - * - * @param scaleFactors an array of scale factors. - * @param offsets an array of offsets. - * @param hints any rendering hints to use (can be null). - * @throws NullPointerException if the scaleFactors or offsets array is null. - */ - public RescaleOp(float[] scaleFactors, - float[] offsets, - RenderingHints hints) - { - int length = Math.min(scaleFactors.length, offsets.length); - - scale = new float[length]; - System.arraycopy(scaleFactors, 0, this.scale, 0, length); - - this.offsets = new float[length]; - System.arraycopy(offsets, 0, this.offsets, 0, length); - - this.hints = hints; - } - - /** - * Create a new RescaleOp object using the given scale factor and offset. - * - * The same scale factor and offset will be used on all bands/components. - * - * @param scaleFactor the scale factor to use. - * @param offset the offset to use. - * @param hints any rendering hints to use (can be null). - */ - public RescaleOp(float scaleFactor, - float offset, - RenderingHints hints) - { - scale = new float[]{ scaleFactor }; - offsets = new float[]{offset}; - this.hints = hints; - } - - /** - * Returns the scaling factors. This method accepts an optional array, which - * will be used to store the factors if not null (this avoids allocating a - * new array). If this array is too small to hold all the scaling factors, - * the array will be filled and the remaining factors discarded. - * - * @param scaleFactors array to store the scaling factors in (can be null). - * @return an array of scaling factors. - */ - public final float[] getScaleFactors(float[] scaleFactors) - { - if (scaleFactors == null) - scaleFactors = new float[scale.length]; - System.arraycopy(scale, 0, scaleFactors, 0, Math.min(scale.length, - scaleFactors.length)); - return scaleFactors; - } - - /** - * Returns the offsets. This method accepts an optional array, which - * will be used to store the offsets if not null (this avoids allocating a - * new array). If this array is too small to hold all the offsets, the array - * will be filled and the remaining factors discarded. - * - * @param offsets array to store the offsets in (can be null). - * @return an array of offsets. - */ - public final float[] getOffsets(float[] offsets) - { - if (offsets == null) - offsets = new float[this.offsets.length]; - System.arraycopy(this.offsets, 0, offsets, 0, Math.min(this.offsets.length, - offsets.length)); - return offsets; - } - - /** - * Returns the number of scaling factors / offsets. - * - * @return the number of scaling factors / offsets. - */ - public final int getNumFactors() - { - return scale.length; - } - - /* (non-Javadoc) - * @see java.awt.image.BufferedImageOp#getRenderingHints() - */ - public final RenderingHints getRenderingHints() - { - return hints; - } - - /** - * Converts the source image using the scale factors and offsets specified in - * the constructor. The resulting image is stored in the destination image if - * one is provided; otherwise a new BufferedImage is created and returned. - * - * The source image cannot use an IndexColorModel, and the destination image - * (if one is provided) must have the same size. - * - * If the final value of a sample is beyond the range of the color model, it - * will be clipped to the appropriate maximum / minimum. - * - * @param src The source image. - * @param dst The destination image. - * @throws IllegalArgumentException if the rasters and/or color spaces are - * incompatible. - * @return The rescaled image. - */ - public final BufferedImage filter(BufferedImage src, BufferedImage dst) - { - // Initial checks - if (scale.length != 1 - && scale.length != src.getColorModel().getNumComponents() - && (scale.length != src.getColorModel().getNumColorComponents())) - throw new IllegalArgumentException("Source image has wrong number of " - + "bands for these scaling factors."); - - if (dst == null) - dst = createCompatibleDestImage(src, null); - else if (src.getHeight() != dst.getHeight() - || src.getWidth() != dst.getWidth()) - throw new IllegalArgumentException("Source and destination images are " - + "different sizes."); - - // Prepare for possible colorspace conversion - BufferedImage dst2 = dst; - if (dst.getColorModel().getColorSpace().getType() != src.getColorModel().getColorSpace().getType()) - dst2 = createCompatibleDestImage(src, src.getColorModel()); - - // Figure out how many bands to scale - int numBands = scale.length; - if (scale.length == 1) - numBands = src.getColorModel().getNumColorComponents(); - boolean[] bands = new boolean[numBands]; - // this assumes the alpha, if present, is the last band - Arrays.fill(bands, true); - - // Perform rescaling - filter(src.getRaster(), dst2.getRaster(), bands); - - // Copy alpha band if needed (ie if it exists and wasn't scaled) - // NOTE: This assumes the alpha component is the last band! - if (src.getColorModel().hasAlpha() - && numBands == src.getColorModel().getNumColorComponents()) - { - - dst2.getRaster().setSamples(0, 0, src.getWidth(), src.getHeight(), - numBands, - src.getRaster().getSamples(0, 0, - src.getWidth(), - src.getHeight(), - numBands, - (int[]) null)); - } - - // Perform colorspace conversion if needed - if (dst != dst2) - new ColorConvertOp(hints).filter(dst2, dst); - - return dst; - } - - /* (non-Javadoc) - * @see java.awt.image.RasterOp#filter(java.awt.image.Raster, java.awt.image.WritableRaster) - */ - public final WritableRaster filter(Raster src, WritableRaster dest) - { - // Required sanity checks - if (scale.length != 1 && scale.length != src.numBands) - throw new IllegalArgumentException("Number of rasters is incompatible " - + "with the number of scaling " - + "factors provided."); - - if (dest == null) - dest = src.createCompatibleWritableRaster(); - else if (src.getHeight() != dest.getHeight() - || src.getWidth() != dest.getWidth()) - throw new IllegalArgumentException("Source and destination rasters are " - + "different sizes."); - else if (src.numBands != dest.numBands) - throw new IllegalArgumentException("Source and destination rasters " - + "are incompatible."); - - // Filter all bands - boolean[] bands = new boolean[src.getNumBands()]; - Arrays.fill(bands, true); - return filter(src, dest, bands); - } - - /** - * Perform raster-based filtering on a selected number of bands. - * - * The length of the bands array should equal the number of bands; a true - * element indicates filtering should happen on the corresponding band, while - * a false element will skip the band. - * - * The rasters are assumed to be compatible and non-null. - * - * @param src the source raster. - * @param dest the destination raster. - * @param bands an array indicating which bands to filter. - * @throws NullPointerException if any parameter is null. - * @throws ArrayIndexOutOfBoundsException if the bands array is too small. - * @return the destination raster. - */ - private WritableRaster filter(Raster src, WritableRaster dest, boolean[] bands) - { - int[] values = new int[src.getHeight() * src.getWidth()]; - float scaleFactor, offset; - - // Find max sample value, to be used for clipping later - int[] maxValue = src.getSampleModel().getSampleSize(); - for (int i = 0; i < maxValue.length; i++) - maxValue[i] = (int)Math.pow(2, maxValue[i]) - 1; - - // TODO: can this be optimized further? - // Filter all samples of all requested bands - for (int band = 0; band < bands.length; band++) - if (bands[band]) - { - values = src.getSamples(src.getMinX(), src.getMinY(), src.getWidth(), - src.getHeight(), band, values); - - if (scale.length == 1) - { - scaleFactor = scale[0]; - offset = offsets[0]; - } - else - { - scaleFactor = scale[band]; - offset = offsets[band]; - } - - for (int i = 0; i < values.length; i++) - { - values[i] = (int) (values[i] * scaleFactor + offset); - - // Clip if needed - if (values[i] < 0) - values[i] = 0; - if (values[i] > maxValue[band]) - values[i] = maxValue[band]; - } - - dest.setSamples(dest.getMinX(), dest.getMinY(), dest.getWidth(), - dest.getHeight(), band, values); - } - - return dest; - } - - /* - * (non-Javadoc) - * - * @see java.awt.image.BufferedImageOp#createCompatibleDestImage(java.awt.image.BufferedImage, - * java.awt.image.ColorModel) - */ - public BufferedImage createCompatibleDestImage(BufferedImage src, - ColorModel dstCM) - { - if (dstCM == null) - return new BufferedImage(src.getWidth(), src.getHeight(), src.getType()); - - return new BufferedImage(dstCM, - src.getRaster().createCompatibleWritableRaster(), - src.isAlphaPremultiplied(), null); - } - - /* (non-Javadoc) - * @see java.awt.image.RasterOp#createCompatibleDestRaster(java.awt.image.Raster) - */ - public WritableRaster createCompatibleDestRaster(Raster src) - { - return src.createCompatibleWritableRaster(); - } - - /* (non-Javadoc) - * @see java.awt.image.BufferedImageOp#getBounds2D(java.awt.image.BufferedImage) - */ - public final Rectangle2D getBounds2D(BufferedImage src) - { - return src.getRaster().getBounds(); - } - - /* (non-Javadoc) - * @see java.awt.image.RasterOp#getBounds2D(java.awt.image.Raster) - */ - public final Rectangle2D getBounds2D(Raster src) - { - return src.getBounds(); - } - - /* (non-Javadoc) - * @see java.awt.image.BufferedImageOp#getPoint2D(java.awt.geom.Point2D, java.awt.geom.Point2D) - */ - public final Point2D getPoint2D(Point2D src, Point2D dst) - { - if (dst == null) - dst = (Point2D) src.clone(); - else - dst.setLocation(src); - - return dst; - } - -} diff --git a/openjdk/java/io/FileDescriptor.java b/openjdk/java/io/FileDescriptor.java deleted file mode 100644 index af970b4c..00000000 --- a/openjdk/java/io/FileDescriptor.java +++ /dev/null @@ -1,731 +0,0 @@ -/* - * Copyright (c) 2003, 2012, 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 cli.System.IO.FileAccess; -import cli.System.IO.FileMode; -import cli.System.IO.FileShare; -import cli.System.IO.FileStream; -import cli.System.IO.SeekOrigin; -import cli.System.Runtime.InteropServices.DllImportAttribute; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Instances of the file descriptor class serve as an opaque handle - * to the underlying machine-specific structure representing an - * open file, an open socket, or another source or sink of bytes. - * The main practical use for a file descriptor is to create a - * {@link FileInputStream} or {@link FileOutputStream} to contain it. - * - * <p>Applications should not create their own file descriptors. - * - * @author Pavani Diwanji - * @since JDK1.0 - */ -public final class FileDescriptor { - - private volatile cli.System.IO.Stream stream; - private volatile cli.System.Net.Sockets.Socket socket; - private volatile boolean nonBlockingSocket; - private volatile cli.System.IAsyncResult asyncResult; - - /** - * HACK - * JRuby uses reflection to get at the handle (on Windows) and fd (on non-Windows) - * fields to convert it into a native handle and query if it is a tty. - */ - @ikvm.lang.Property(get = "get_handle") - private long handle; - - @ikvm.lang.Property(get = "get_fd") - private int fd; - - @cli.System.Security.SecurityCriticalAttribute.Annotation - private long get_handle() - { - if (ikvm.internal.Util.WINDOWS) - { - if (stream instanceof cli.System.IO.FileStream) - { - cli.System.IO.FileStream fs = (cli.System.IO.FileStream)stream; - return fs.get_Handle().ToInt64(); - } - else if (this == in) - { - return GetStdHandle(-10).ToInt64(); - } - else if (this == out) - { - return GetStdHandle(-11).ToInt64(); - } - else if (this == err) - { - return GetStdHandle(-12).ToInt64(); - } - } - return -1; - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - private int get_fd() - { - if (!ikvm.internal.Util.WINDOWS) - { - if (stream instanceof cli.System.IO.FileStream) - { - cli.System.IO.FileStream fs = (cli.System.IO.FileStream)stream; - return fs.get_Handle().ToInt32(); - } - else if (this == in) - { - return 0; - } - else if (this == out) - { - return 1; - } - else if (this == err) - { - return 2; - } - } - return -1; - } - - @DllImportAttribute.Annotation("kernel32") - private static native cli.System.IntPtr GetStdHandle(int nStdHandle); - - /** - * A use counter for tracking the FIS/FOS/RAF instances that - * use this FileDescriptor. The FIS/FOS.finalize() will not release - * the FileDescriptor if it is still under use by any stream. - */ - private AtomicInteger useCount; - - - /** - * Constructs an (invalid) FileDescriptor - * object. - */ - public /**/ FileDescriptor() { - useCount = new AtomicInteger(); - } - - /** - * A handle to the standard input stream. Usually, this file - * descriptor is not used directly, but rather via the input stream - * known as {@code System.in}. - * - * @see java.lang.System#in - */ - public static final FileDescriptor in = standardStream(0); - - /** - * A handle to the standard output stream. Usually, this file - * descriptor is not used directly, but rather via the output stream - * known as {@code System.out}. - * @see java.lang.System#out - */ - public static final FileDescriptor out = standardStream(1); - - /** - * A handle to the standard error stream. Usually, this file - * descriptor is not used directly, but rather via the output stream - * known as {@code System.err}. - * - * @see java.lang.System#err - */ - public static final FileDescriptor err = standardStream(2); - - /** - * Tests if this file descriptor object is valid. - * - * @return {@code true} if the file descriptor object represents a - * valid, open file, socket, or other active I/O connection; - * {@code false} otherwise. - */ - public boolean valid() { - return stream != null || socket != null; - } - - /** - * Force all system buffers to synchronize with the underlying - * device. This method returns after all modified data and - * attributes of this FileDescriptor have been written to the - * relevant device(s). In particular, if this FileDescriptor - * refers to a physical storage medium, such as a file in a file - * system, sync will not return until all in-memory modified copies - * of buffers associated with this FileDesecriptor have been - * written to the physical medium. - * - * sync is meant to be used by code that requires physical - * storage (such as a file) to be in a known state For - * example, a class that provided a simple transaction facility - * might use sync to ensure that all changes to a file caused - * by a given transaction were recorded on a storage medium. - * - * sync only affects buffers downstream of this FileDescriptor. If - * any in-memory buffering is being done by the application (for - * example, by a BufferedOutputStream object), those buffers must - * be flushed into the FileDescriptor (for example, by invoking - * OutputStream.flush) before that data will be affected by sync. - * - * @exception SyncFailedException - * Thrown when the buffers cannot be flushed, - * or because the system cannot guarantee that all the - * buffers have been synchronized with physical media. - * @since JDK1.1 - */ - public void sync() throws SyncFailedException - { - if (stream == null) - { - throw new SyncFailedException("sync failed"); - } - - if (!stream.get_CanWrite()) - { - return; - } - - try - { - if (false) throw new cli.System.IO.IOException(); - stream.Flush(); - } - catch (cli.System.IO.IOException x) - { - throw new SyncFailedException(x.getMessage()); - } - - if (stream instanceof FileStream) - { - FileStream fs = (FileStream)stream; - boolean ok = ikvm.internal.Util.WINDOWS ? flushWin32(fs) : flushPosix(fs); - if (!ok) - { - throw new SyncFailedException("sync failed"); - } - } - } - - private static native boolean flushPosix(FileStream fs); - - @cli.System.Security.SecuritySafeCriticalAttribute.Annotation - private static boolean flushWin32(FileStream fs) - { - return FlushFileBuffers(fs.get_SafeFileHandle()) != 0; - } - - @DllImportAttribute.Annotation("kernel32") - private static native int FlushFileBuffers(cli.Microsoft.Win32.SafeHandles.SafeFileHandle handle); - - private static FileDescriptor standardStream(int fd) { - FileDescriptor desc = new FileDescriptor(); - try - { - desc.stream = getStandardStream(fd); - } - catch (cli.System.MissingMethodException _) - { - desc.stream = cli.System.IO.Stream.Null; - } - return desc; - } - - private static cli.System.IO.Stream getStandardStream(int fd) throws cli.System.MissingMethodException - { - switch (fd) - { - case 0: - return cli.System.Console.OpenStandardInput(); - case 1: - return cli.System.Console.OpenStandardOutput(); - case 2: - return cli.System.Console.OpenStandardError(); - default: - throw new Error(); - } - } - - // package private methods used by FIS, FOS and RAF. - - int incrementAndGetUseCount() { - return useCount.incrementAndGet(); - } - - int decrementAndGetUseCount() { - return useCount.decrementAndGet(); - } - - void openReadOnly(String name) throws FileNotFoundException - { - open(name, FileMode.Open, FileAccess.Read); - } - - void openWriteOnly(String name) throws FileNotFoundException - { - open(name, FileMode.Create, FileAccess.Write); - } - - void openReadWrite(String name) throws FileNotFoundException - { - open(name, FileMode.OpenOrCreate, FileAccess.ReadWrite); - } - - void openAppend(String name) throws FileNotFoundException - { - open(name, FileMode.Append, FileAccess.Write); - } - - private static native cli.System.IO.Stream open(String name, FileMode fileMode, FileAccess fileAccess) - throws cli.System.IO.IOException, - cli.System.Security.SecurityException, - cli.System.UnauthorizedAccessException, - cli.System.ArgumentException, - cli.System.NotSupportedException; - - private void open(String name, int fileMode, int fileAccess) throws FileNotFoundException - { - try - { - stream = open(name, FileMode.wrap(fileMode), FileAccess.wrap(fileAccess)); - } - catch (cli.System.Security.SecurityException x1) - { - throw new SecurityException(x1.getMessage()); - } - catch (cli.System.IO.IOException x2) - { - throw new FileNotFoundException(x2.getMessage()); - } - catch (cli.System.UnauthorizedAccessException x3) - { - // this is caused by "name" being a directory instead of a file - // or by name being a read-only file - throw new FileNotFoundException(name + " (Access is denied)"); - } - catch (cli.System.ArgumentException x4) - { - throw new FileNotFoundException(x4.getMessage()); - } - catch (cli.System.NotSupportedException x5) - { - throw new FileNotFoundException(x5.getMessage()); - } - } - - private void checkOpen() throws IOException - { - if (stream == null) - { - throw new IOException("Stream Closed"); - } - } - - int read() throws IOException - { - checkOpen(); - try - { - if (false) throw new cli.System.NotSupportedException(); - if (false) throw new cli.System.IO.IOException(); - if (false) throw new cli.System.ObjectDisposedException(null); - return stream.ReadByte(); - } - catch (cli.System.NotSupportedException x) - { - throw new IOException(x.getMessage()); - } - catch (cli.System.IO.IOException x) - { - throw new IOException(x.getMessage()); - } - catch (cli.System.ObjectDisposedException x) - { - throw new java.nio.channels.ClosedChannelException(); - } - } - - @ikvm.lang.Internal - public int readBytes(byte buf[], int offset, int len) throws IOException - { - // NOTE we start by dereferencing buf, to make sure you get a NullPointerException first if you pass a null reference. - int bufLen = buf.length; - if ((offset < 0) || (offset > bufLen) || (len < 0) || (len > (bufLen - offset))) - { - throw new IndexOutOfBoundsException(); - } - - if (len == 0) - { - return 0; - } - - checkOpen(); - - try - { - if (false) throw new cli.System.NotSupportedException(); - if (false) throw new cli.System.IO.IOException(); - if (false) throw new cli.System.ObjectDisposedException(null); - int count = stream.Read(buf, offset, len); - if (count == 0) - { - count = -1; - } - return count; - } - catch (cli.System.NotSupportedException x) - { - throw new IOException(x.getMessage()); - } - catch (cli.System.IO.IOException x) - { - throw new IOException(x.getMessage()); - } - catch (cli.System.ObjectDisposedException x) - { - throw new java.nio.channels.ClosedChannelException(); - } - } - - long skip(long n) throws IOException - { - checkOpen(); - if (!stream.get_CanSeek()) - { - // in a somewhat bizar twist, for non-seekable streams the JDK throws an exception - throw new IOException("The handle is invalid"); - } - try - { - if (false) throw new cli.System.IO.IOException(); - if (false) throw new cli.System.NotSupportedException(); - if (false) throw new cli.System.ObjectDisposedException(null); - long cur = stream.get_Position(); - long end = stream.Seek(n, SeekOrigin.wrap(SeekOrigin.Current)); - return end - cur; - } - catch (cli.System.IO.IOException x) - { - throw new IOException(x.getMessage()); - } - catch (cli.System.NotSupportedException x1) - { - // this means we have a broken Stream, because if CanSeek returns true, it must - // support Length and Position - throw new IOException(x1); - } - catch (cli.System.ObjectDisposedException x) - { - throw new java.nio.channels.ClosedChannelException(); - } - } - - @ikvm.lang.Internal - public int available() throws IOException - { - checkOpen(); - try - { - if (false) throw new cli.System.IO.IOException(); - if (false) throw new cli.System.NotSupportedException(); - if (false) throw new cli.System.ObjectDisposedException(null); - if (stream.get_CanSeek()) - { - return (int)Math.min(Integer.MAX_VALUE, Math.max(0, stream.get_Length() - stream.get_Position())); - } - return 0; - } - catch (cli.System.IO.IOException x) - { - throw new IOException(x.getMessage()); - } - catch (cli.System.NotSupportedException x1) - { - // this means we have a broken Stream, because if CanSeek returns true, it must - // support Length and Position - throw new IOException(x1); - } - catch (cli.System.ObjectDisposedException x) - { - throw new java.nio.channels.ClosedChannelException(); - } - } - - void write(int b) throws IOException - { - checkOpen(); - try - { - if (false) throw new cli.System.NotSupportedException(); - if (false) throw new cli.System.IO.IOException(); - if (false) throw new cli.System.ObjectDisposedException(null); - stream.WriteByte((byte)b); - // NOTE FileStream buffers the output, so we have to flush explicitly - stream.Flush(); - } - catch (cli.System.NotSupportedException x) - { - throw new IOException(x.getMessage()); - } - catch (cli.System.IO.IOException x) - { - throw new IOException(x.getMessage()); - } - catch (cli.System.ObjectDisposedException x) - { - throw new java.nio.channels.ClosedChannelException(); - } - } - - @ikvm.lang.Internal - public void writeBytes(byte buf[], int offset, int len) throws IOException - { - // NOTE we start by dereferencing buf, to make sure you get a NullPointerException first if you pass a null reference. - int bufLen = buf.length; - if ((offset < 0) || (offset > bufLen) || (len < 0) || (len > (bufLen - offset))) - { - throw new IndexOutOfBoundsException(); - } - - if (len == 0) - { - return; - } - - checkOpen(); - - try - { - if (false) throw new cli.System.NotSupportedException(); - if (false) throw new cli.System.IO.IOException(); - if (false) throw new cli.System.ObjectDisposedException(null); - stream.Write(buf, offset, len); - // NOTE FileStream buffers the output, so we have to flush explicitly - stream.Flush(); - } - catch (cli.System.NotSupportedException x) - { - throw new IOException(x.getMessage()); - } - catch (cli.System.IO.IOException x) - { - throw new IOException(x.getMessage()); - } - catch (cli.System.ObjectDisposedException x) - { - throw new java.nio.channels.ClosedChannelException(); - } - } - - @ikvm.lang.Internal - public long getFilePointer() throws IOException - { - checkOpen(); - try - { - if (false) throw new cli.System.IO.IOException(); - if (false) throw new cli.System.NotSupportedException(); - if (false) throw new cli.System.ObjectDisposedException(null); - return stream.get_Position(); - } - catch (cli.System.IO.IOException x) - { - throw new IOException(x.getMessage()); - } - catch (cli.System.NotSupportedException x1) - { - throw new IOException(x1); - } - catch (cli.System.ObjectDisposedException x) - { - throw new java.nio.channels.ClosedChannelException(); - } - } - - @ikvm.lang.Internal - public void seek(long newPosition) throws IOException - { - checkOpen(); - try - { - if (false) throw new cli.System.IO.IOException(); - if (false) throw new cli.System.NotSupportedException(); - if (false) throw new cli.System.ObjectDisposedException(null); - if (false) throw new cli.System.ArgumentOutOfRangeException(); - stream.set_Position(newPosition); - } - catch (cli.System.IO.IOException x) - { - throw new IOException(x.getMessage()); - } - catch (cli.System.NotSupportedException x1) - { - throw new IOException(x1); - } - catch (cli.System.ObjectDisposedException x) - { - throw new java.nio.channels.ClosedChannelException(); - } - catch (cli.System.ArgumentOutOfRangeException _) - { - throw new IOException("Negative seek offset"); - } - } - - @ikvm.lang.Internal - public long length() throws IOException - { - checkOpen(); - try - { - if (false) throw new cli.System.IO.IOException(); - if (false) throw new cli.System.NotSupportedException(); - if (false) throw new cli.System.ObjectDisposedException(null); - return stream.get_Length(); - } - catch (cli.System.IO.IOException x) - { - throw new IOException(x.getMessage()); - } - catch (cli.System.NotSupportedException x1) - { - throw new IOException(x1); - } - catch (cli.System.ObjectDisposedException x) - { - throw new java.nio.channels.ClosedChannelException(); - } - } - - @ikvm.lang.Internal - public void setLength(long newLength) throws IOException - { - checkOpen(); - try - { - if (false) throw new cli.System.IO.IOException(); - if (false) throw new cli.System.NotSupportedException(); - if (false) throw new cli.System.ObjectDisposedException(null); - stream.SetLength(newLength); - } - catch (cli.System.IO.IOException x) - { - throw new IOException(x.getMessage()); - } - catch (cli.System.NotSupportedException x1) - { - throw new IOException(x1); - } - catch (cli.System.ObjectDisposedException x) - { - throw new java.nio.channels.ClosedChannelException(); - } - } - - @ikvm.lang.Internal - public void close() throws IOException - { - cli.System.IO.Stream s = stream; - stream = null; - if (s != null) - { - s.Close(); - } - } - - @ikvm.lang.Internal - public cli.System.IO.Stream getStream() - { - return stream; - } - - @ikvm.lang.Internal - public static FileDescriptor fromStream(cli.System.IO.Stream stream) - { - FileDescriptor desc = new FileDescriptor(); - desc.stream = stream; - return desc; - } - - @ikvm.lang.Internal - public cli.System.Net.Sockets.Socket getSocket() - { - return socket; - } - - @ikvm.lang.Internal - public void setSocket(cli.System.Net.Sockets.Socket socket) - { - this.socket = socket; - } - - @ikvm.lang.Internal - public void setSocketBlocking(boolean blocking) throws IOException - { - this.nonBlockingSocket = !blocking; - try - { - if (false) throw new cli.System.Net.Sockets.SocketException(); - if (false) throw new cli.System.ObjectDisposedException(""); - socket.set_Blocking(blocking); - } - catch (cli.System.Net.Sockets.SocketException x) - { - if (x.get_ErrorCode() == java.net.SocketUtil.WSAEINVAL) - { - // Work around for winsock issue. You can't set a socket to blocking if a connection request is pending, - // so we'll have to set the blocking again in SocketChannelImpl.checkConnect(). - return; - } - throw java.net.SocketUtil.convertSocketExceptionToIOException(x); - } - catch (cli.System.ObjectDisposedException _) - { - throw new java.net.SocketException("Socket is closed"); - } - } - - @ikvm.lang.Internal - public boolean isSocketBlocking() - { - return !nonBlockingSocket; - } - - @ikvm.lang.Internal - public cli.System.IAsyncResult getAsyncResult() - { - return asyncResult; - } - - @ikvm.lang.Internal - public void setAsyncResult(cli.System.IAsyncResult asyncResult) - { - this.asyncResult = asyncResult; - } -} diff --git a/openjdk/java/io/FileInputStream.java b/openjdk/java/io/FileInputStream.java deleted file mode 100644 index 3547947f..00000000 --- a/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 <code>FileInputStream</code> obtains input bytes - * from a file in a file system. What files - * are available depends on the host environment. - * - * <p><code>FileInputStream</code> is meant for reading streams of raw bytes - * such as image data. For reading streams of characters, consider using - * <code>FileReader</code>. - * - * @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<Boolean> runningFinalize = - new ThreadLocal<>(); - - private static boolean isRunningFinalize() { - Boolean val; - if ((val = runningFinalize.get()) != null) - return val.booleanValue(); - return false; - } - - /** - * Creates a <code>FileInputStream</code> by - * opening a connection to an actual file, - * the file named by the path name <code>name</code> - * in the file system. A new <code>FileDescriptor</code> - * object is created to represent this file - * connection. - * <p> - * First, if there is a security - * manager, its <code>checkRead</code> method - * is called with the <code>name</code> argument - * as its argument. - * <p> - * 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 - * <code>FileNotFoundException</code> 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 - * <code>checkRead</code> 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 <code>FileInputStream</code> by - * opening a connection to an actual file, - * the file named by the <code>File</code> - * object <code>file</code> in the file system. - * A new <code>FileDescriptor</code> object - * is created to represent this file connection. - * <p> - * First, if there is a security manager, - * its <code>checkRead</code> method is called - * with the path represented by the <code>file</code> - * argument as its argument. - * <p> - * 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 - * <code>FileNotFoundException</code> 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 - * <code>checkRead</code> 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 <code>FileInputStream</code> by using the file descriptor - * <code>fdObj</code>, which represents an existing connection to an - * actual file in the file system. - * <p> - * If there is a security manager, its <code>checkRead</code> method is - * called with the file descriptor <code>fdObj</code> as its argument to - * see if it's ok to read the file descriptor. If read access is denied - * to the file descriptor a <code>SecurityException</code> is thrown. - * <p> - * If <code>fdObj</code> is null then a <code>NullPointerException</code> - * is thrown. - * <p> - * This constructor does not throw an exception if <code>fdObj</code> - * 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 <code>IOException</code> is thrown. - * - * @param fdObj the file descriptor to be opened for reading. - * @throws SecurityException if a security manager exists and its - * <code>checkRead</code> 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 <code>-1</code> 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 <code>b.length</code> 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 - * <code>-1</code> 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 <code>len</code> bytes of data from this input stream - * into an array of bytes. If <code>len</code> is not zero, the method - * blocks until some input is available; otherwise, no - * bytes are read and <code>0</code> is returned. - * - * @param b the buffer into which the data is read. - * @param off the start offset in the destination array <code>b</code> - * @param len the maximum number of bytes read. - * @return the total number of bytes read into the buffer, or - * <code>-1</code> if there is no more data because the end of - * the file has been reached. - * @exception NullPointerException If <code>b</code> is <code>null</code>. - * @exception IndexOutOfBoundsException If <code>off</code> is negative, - * <code>len</code> is negative, or <code>len</code> is greater than - * <code>b.length - off</code> - * @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 <code>n</code> bytes of data from the - * input stream. - * - * <p>The <code>skip</code> method may, for a variety of - * reasons, end up skipping over some smaller number of bytes, - * possibly <code>0</code>. If <code>n</code> is negative, an - * <code>IOException</code> is thrown, even though the <code>skip</code> - * method of the {@link InputStream} superclass does nothing in this case. - * The actual number of bytes skipped is returned. - * - * <p>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. - * - * <p> 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. - * - * <p> 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 <code>FileDescriptor</code> - * object that represents the connection to - * the actual file in the file system being - * used by this <code>FileInputStream</code>. - * - * @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. - * - * <p> The initial {@link java.nio.channels.FileChannel#position() - * </code>position<code>} 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 <code>close</code> 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/openjdk/java/io/FileOutputStream.java b/openjdk/java/io/FileOutputStream.java deleted file mode 100644 index dae9d4bc..00000000 --- a/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 - * <code>File</code> or to a <code>FileDescriptor</code>. 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 <tt>FileOutputStream</tt> (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. - * - * <p><code>FileOutputStream</code> is meant for writing streams of raw bytes - * such as image data. For writing streams of characters, consider using - * <code>FileWriter</code>. - * - * @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<Boolean> 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 <code>FileDescriptor</code> object is - * created to represent this file connection. - * <p> - * First, if there is a security manager, its <code>checkWrite</code> - * method is called with <code>name</code> as its argument. - * <p> - * 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 <code>FileNotFoundException</code> 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 - * <code>checkWrite</code> 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 <code>true</code>, then - * bytes will be written to the end of the file rather than the beginning. - * A new <code>FileDescriptor</code> object is created to represent this - * file connection. - * <p> - * First, if there is a security manager, its <code>checkWrite</code> - * method is called with <code>name</code> as its argument. - * <p> - * 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 <code>FileNotFoundException</code> is thrown. - * - * @param name the system-dependent file name - * @param append if <code>true</code>, 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 - * <code>checkWrite</code> 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 <code>File</code> object. A new - * <code>FileDescriptor</code> object is created to represent this - * file connection. - * <p> - * First, if there is a security manager, its <code>checkWrite</code> - * method is called with the path represented by the <code>file</code> - * argument as its argument. - * <p> - * 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 <code>FileNotFoundException</code> 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 - * <code>checkWrite</code> 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 <code>File</code> object. If the second argument is - * <code>true</code>, then bytes will be written to the end of the file - * rather than the beginning. A new <code>FileDescriptor</code> object is - * created to represent this file connection. - * <p> - * First, if there is a security manager, its <code>checkWrite</code> - * method is called with the path represented by the <code>file</code> - * argument as its argument. - * <p> - * 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 <code>FileNotFoundException</code> is thrown. - * - * @param file the file to be opened for writing. - * @param append if <code>true</code>, 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 - * <code>checkWrite</code> 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. - * <p> - * First, if there is a security manager, its <code>checkWrite</code> - * method is called with the file descriptor <code>fdObj</code> - * argument as its argument. - * <p> - * If <code>fdObj</code> is null then a <code>NullPointerException</code> - * is thrown. - * <p> - * This constructor does not throw an exception if <code>fdObj</code> - * 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 <code>IOException</code> is thrown. - * - * @param fdObj the file descriptor to be opened for writing - * @exception SecurityException if a security manager exists and its - * <code>checkWrite</code> 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 <code>write</code> method of <code>OutputStream</code>. - * - * @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 <code>b.length</code> 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 <code>len</code> bytes from the specified byte array - * starting at offset <code>off</code> 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. - * - * <p> 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 <code>FileDescriptor</code> object that represents - * the connection to the file in the file system being used - * by this <code>FileOutputStream</code> 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. </p> - * - * <p> The initial {@link java.nio.channels.FileChannel#position() - * </code>position<code>} 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 - * <code>close</code> 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/openjdk/java/io/InteropObjectInputStream.java b/openjdk/java/io/InteropObjectInputStream.java deleted file mode 100644 index de08fe3a..00000000 --- a/openjdk/java/io/InteropObjectInputStream.java +++ /dev/null @@ -1,740 +0,0 @@ -/* - * Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved. - * Copyright 2009 Jeroen Frijters - * 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 cli.System.Runtime.Serialization.SerializationException; -import cli.System.Runtime.Serialization.SerializationInfo; -import java.util.concurrent.atomic.AtomicBoolean; - -@ikvm.lang.Internal -public final class InteropObjectInputStream extends ObjectInputStream -{ - private ObjectDataInputStream dis; - private CallbackContext curContext; - - public static void readObject(Object obj, SerializationInfo info) - { - try - { - new InteropObjectInputStream(obj, info); - } - catch (Exception x) - { - ikvm.runtime.Util.throwException(new SerializationException(x.getMessage(), x)); - } - } - - private InteropObjectInputStream(Object obj, SerializationInfo info) throws IOException, ClassNotFoundException - { - dis = new ObjectDataInputStream(info); - if (obj instanceof ObjectStreamClass) - { - switch (readByte()) - { - case TC_PROXYCLASSDESC: - readProxyDesc((ObjectStreamClass)obj); - break; - case TC_CLASSDESC: - readNonProxyDesc((ObjectStreamClass)obj); - break; - default: - throw new StreamCorruptedException(); - } - } - else - { - readOrdinaryObject(obj); - } - } - - private ObjectStreamClass readClassDesc() throws IOException, ClassNotFoundException - { - return (ObjectStreamClass)readObject(); - } - - private void readProxyDesc(ObjectStreamClass desc) throws IOException, ClassNotFoundException - { - int numIfaces = readInt(); - Class[] ifaces = new Class[numIfaces]; - for (int i = 0; i < numIfaces; i++) - { - ifaces[i] = (Class)readObject(); - } - Class cl = java.lang.reflect.Proxy.getProxyClass(Thread.currentThread().getContextClassLoader(), ifaces); - desc.initProxy(cl, null, readClassDesc()); - } - - private void readNonProxyDesc(ObjectStreamClass desc) throws IOException, ClassNotFoundException - { - Class cl = (Class)readObject(); - ObjectStreamClass readDesc = new ObjectStreamClass(); - readDesc.readNonProxy(this); - desc.initNonProxy(readDesc, cl, null, readClassDesc()); - } - - private void readOrdinaryObject(Object obj) throws IOException, ClassNotFoundException - { - ObjectStreamClass desc = readClassDesc(); - desc.checkDeserialize(); - - if (obj instanceof InteropObjectOutputStream.DynamicProxy) - { - InteropObjectOutputStream.DynamicProxy pp = (InteropObjectOutputStream.DynamicProxy)obj; - try - { - obj = desc.newInstance(); - pp.obj = obj; - } - catch (Exception ex) - { - throw (IOException) new InvalidClassException( - desc.forClass().getName(), - "unable to create instance").initCause(ex); - } - } - - if (desc.isExternalizable()) - { - readExternalData((Externalizable)obj, desc); - } - else - { - readSerialData(obj, desc); - } - } - - private void readExternalData(Externalizable obj, ObjectStreamClass desc) throws IOException, ClassNotFoundException - { - CallbackContext oldContext = curContext; - curContext = null; - try { - obj.readExternal(this); - skipCustomData(); - } finally { - curContext = oldContext; - } - } - - private void readSerialData(Object obj, ObjectStreamClass desc) throws IOException, ClassNotFoundException - { - ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout(); - for (int i = 0; i < slots.length; i++) - { - ObjectStreamClass slotDesc = slots[i].desc; - - if (slots[i].hasData) - { - if (slotDesc.hasReadObjectMethod()) - { - CallbackContext oldContext = curContext; - try - { - curContext = new CallbackContext(obj, slotDesc); - slotDesc.invokeReadObject(obj, this); - } - finally - { - curContext.setUsed(); - curContext = oldContext; - } - } - else - { - defaultReadFields(obj, slotDesc); - } - if (slotDesc.hasWriteObjectData()) - { - skipCustomData(); - } - } - else if (slotDesc.hasReadObjectNoDataMethod()) - { - slotDesc.invokeReadObjectNoData(obj); - } - } - } - - private void skipCustomData() throws IOException - { - dis.skipMarker(); - } - - private void defaultReadFields(Object obj, ObjectStreamClass desc) throws IOException, ClassNotFoundException - { - byte[] primVals = new byte[desc.getPrimDataSize()]; - readFully(primVals); - desc.setPrimFieldValues(obj, primVals); - - Object[] objVals = new Object[desc.getNumObjFields()]; - for (int i = 0; i < objVals.length; i++) - { - objVals[i] = readObject(); - } - desc.setObjFieldValues(obj, objVals); - } - - @Override - public void defaultReadObject() throws IOException, ClassNotFoundException - { - if (curContext == null) { - throw new NotActiveException("not in call to readObject"); - } - Object curObj = curContext.getObj(); - ObjectStreamClass curDesc = curContext.getDesc(); - defaultReadFields(curObj, curDesc); - } - - @Override - protected Object readObjectOverride() throws IOException - { - return dis.readObject(); - } - - @Override - public Object readUnshared() - { - throw new UnsupportedOperationException(); - } - - @Override - public ObjectInputStream.GetField readFields() throws IOException, ClassNotFoundException - { - if (curContext == null) { - throw new NotActiveException("not in call to readObject"); - } - Object curObj = curContext.getObj(); - ObjectStreamClass curDesc = curContext.getDesc(); - GetFieldImpl getField = new GetFieldImpl(curDesc); - getField.readFields(); - return getField; - } - - @Override - public void registerValidation(ObjectInputValidation obj, int prio) - { - throw new UnsupportedOperationException(); - } - - @Override - public int read() throws IOException - { - return dis.read(); - } - - @Override - public int read(byte[] buf, int off, int len) throws IOException - { - return dis.read(buf, off, len); - } - - @Override - public int available() throws IOException - { - return dis.available(); - } - - @Override - public void close() throws IOException - { - throw new UnsupportedOperationException(); - } - - @Override - public boolean readBoolean() throws IOException - { - return dis.readBoolean(); - } - - @Override - public byte readByte() throws IOException - { - return dis.readByte(); - } - - @Override - public int readUnsignedByte() throws IOException - { - return dis.readUnsignedByte(); - } - - @Override - public char readChar() throws IOException - { - return dis.readChar(); - } - - @Override - public short readShort() throws IOException - { - return dis.readShort(); - } - - @Override - public int readUnsignedShort() throws IOException - { - return dis.readUnsignedShort(); - } - - @Override - public int readInt() throws IOException - { - return dis.readInt(); - } - - @Override - public long readLong() throws IOException - { - return dis.readLong(); - } - - @Override - public float readFloat() throws IOException - { - return dis.readFloat(); - } - - @Override - public double readDouble() throws IOException - { - return dis.readDouble(); - } - - @Override - public void readFully(byte[] buf) throws IOException - { - readFully(buf, 0, buf.length); - } - - @Override - public void readFully(byte[] buf, int off, int len) throws IOException - { - dis.readFully(buf, off, len); - } - - @Override - public int skipBytes(int len) throws IOException - { - return dis.skipBytes(len); - } - - @Deprecated - @Override - public String readLine() throws IOException - { - return dis.readLine(); - } - - @Override - public String readUTF() throws IOException - { - return dis.readUTF(); - } - - // private API used by ObjectStreamClass - @Override - String readTypeString() throws IOException - { - return (String)readObjectOverride(); - } - - private final class GetFieldImpl extends GetField { - - /** class descriptor describing serializable fields */ - private final ObjectStreamClass desc; - /** primitive field values */ - private final byte[] primVals; - /** object field values */ - private final Object[] objVals; - /** object field value handles */ - private final int[] objHandles; - - /** - * Creates GetFieldImpl object for reading fields defined in given - * class descriptor. - */ - GetFieldImpl(ObjectStreamClass desc) { - this.desc = desc; - primVals = new byte[desc.getPrimDataSize()]; - objVals = new Object[desc.getNumObjFields()]; - objHandles = new int[objVals.length]; - } - - public ObjectStreamClass getObjectStreamClass() { - return desc; - } - - public boolean defaulted(String name) throws IOException { - return (getFieldOffset(name, null) < 0); - } - - public boolean get(String name, boolean val) throws IOException { - int off = getFieldOffset(name, Boolean.TYPE); - return (off >= 0) ? Bits.getBoolean(primVals, off) : val; - } - - public byte get(String name, byte val) throws IOException { - int off = getFieldOffset(name, Byte.TYPE); - return (off >= 0) ? primVals[off] : val; - } - - public char get(String name, char val) throws IOException { - int off = getFieldOffset(name, Character.TYPE); - return (off >= 0) ? Bits.getChar(primVals, off) : val; - } - - public short get(String name, short val) throws IOException { - int off = getFieldOffset(name, Short.TYPE); - return (off >= 0) ? Bits.getShort(primVals, off) : val; - } - - public int get(String name, int val) throws IOException { - int off = getFieldOffset(name, Integer.TYPE); - return (off >= 0) ? Bits.getInt(primVals, off) : val; - } - - public float get(String name, float val) throws IOException { - int off = getFieldOffset(name, Float.TYPE); - return (off >= 0) ? Bits.getFloat(primVals, off) : val; - } - - public long get(String name, long val) throws IOException { - int off = getFieldOffset(name, Long.TYPE); - return (off >= 0) ? Bits.getLong(primVals, off) : val; - } - - public double get(String name, double val) throws IOException { - int off = getFieldOffset(name, Double.TYPE); - return (off >= 0) ? Bits.getDouble(primVals, off) : val; - } - - public Object get(String name, Object val) throws IOException { - int off = getFieldOffset(name, Object.class); - if (off >= 0) { - return objVals[off]; - } else { - return val; - } - } - - /** - * Reads primitive and object field values from stream. - */ - void readFields() throws IOException { - readFully(primVals, 0, primVals.length); - - for (int i = 0; i < objVals.length; i++) { - objVals[i] = readObjectOverride(); - } - } - - /** - * Returns offset of field with given name and type. A specified type - * of null matches all types, Object.class matches all non-primitive - * types, and any other non-null type matches assignable types only. - * If no matching field is found in the (incoming) class - * descriptor but a matching field is present in the associated local - * class descriptor, returns -1. Throws IllegalArgumentException if - * neither incoming nor local class descriptor contains a match. - */ - private int getFieldOffset(String name, Class type) { - ObjectStreamField field = desc.getField(name, type); - if (field != null) { - return field.getOffset(); - } else if (desc.getLocalDesc().getField(name, type) != null) { - return -1; - } else { - throw new IllegalArgumentException("no such field " + name + - " with type " + type); - } - } - } - - private final static class CallbackContext { - private final Object obj; - private final ObjectStreamClass desc; - private final AtomicBoolean used = new AtomicBoolean(); - - public CallbackContext(Object obj, ObjectStreamClass desc) { - this.obj = obj; - this.desc = desc; - } - - public Object getObj() throws NotActiveException { - checkAndSetUsed(); - return obj; - } - - public ObjectStreamClass getDesc() { - return desc; - } - - private void checkAndSetUsed() throws NotActiveException { - if (!used.compareAndSet(false, true)) { - throw new NotActiveException( - "not in readObject invocation or fields already read"); - } - } - - public void setUsed() { - used.set(true); - } - } - - private static final class ObjectDataInputStream extends DataInputStream - { - private final static class Inp extends FilterInputStream - { - private static final byte MARKER = 0; - private static final byte OBJECTS = 10; - private static final byte BYTES = 20; - private final SerializationInfo info; - private byte[] buf; - private int pos; - private int blockEnd = -1; - private int objCount; - private int objId; - - Inp(SerializationInfo info) throws IOException - { - super(null); - this.info = info; - buf = (byte[])info.GetValue("$data", ikvm.runtime.Util.getInstanceTypeFromClass(cli.System.Object.class)); - modeSwitch(); - } - - private void modeSwitch() throws IOException - { - if (pos == buf.length) - { - // next read will report error - blockEnd = -1; - objCount = -1; - } - else if (buf[pos] == OBJECTS) - { - pos++; - objCount = readPacked(); - blockEnd = -1; - } - else if (buf[pos] == BYTES) - { - pos++; - switchToData(); - } - else if (buf[pos] == MARKER) - { - } - else - { - throw new StreamCorruptedException(); - } - } - - private int packedLength(int val) - { - if (val < 0) - { - // we only use packed integers for lengths or counts, so they can never be negative - throw new Error(); - } - else if (val < 128) - { - return 1; - } - else if (val < 16129) - { - return 2; - } - else - { - return 5; - } - } - - private int readPacked() - { - int b1 = buf[pos++] & 0xFF; - if (b1 < 128) - { - return b1; - } - else if (b1 != 128) - { - return ((b1 & 127) << 7) + (buf[pos++] & 0xFF); - } - else - { - int v = 0; - v |= (buf[pos++] & 0xFF) << 24; - v |= (buf[pos++] & 0xFF) << 16; - v |= (buf[pos++] & 0xFF) << 8; - v |= (buf[pos++] & 0xFF) << 0; - return v; - } - } - - private void switchToData() throws IOException - { - if (blockEnd != -1 || objCount != 0 || buf[pos] == MARKER) - { - throw new StreamCorruptedException(); - } - int len = readPacked(); - blockEnd = pos + len; - if (blockEnd > buf.length) - { - throw new StreamCorruptedException(); - } - } - - public int read() throws IOException - { - if (blockEnd - pos < 1) - { - switchToData(); - } - return buf[pos++] & 0xFF; - } - - public int read(byte b[], int off, int len) throws IOException - { - if (len == 0) - { - return 0; - } - if (blockEnd - pos < len) - { - switchToData(); - } - System.arraycopy(buf, pos, b, off, len); - pos += len; - return len; - } - - public long skip(long n) throws IOException - { - if (n == 0) - { - return 0; - } - if (blockEnd - pos < n) - { - switchToData(); - } - pos += (int)n; - return n; - } - - public int available() throws IOException - { - return 0; - } - - public void close() throws IOException - { - } - - public void mark(int readlimit) - { - } - - public void reset() throws IOException - { - } - - public boolean markSupported() - { - return false; - } - - Object readObject() throws IOException - { - if (objCount <= 0) - { - if (pos != blockEnd || buf[pos] == MARKER) - { - throw new StreamCorruptedException(); - } - blockEnd = -1; - objCount = readPacked(); - } - objCount--; - return info.GetValue("$" + (objId++), ikvm.runtime.Util.getInstanceTypeFromClass(cli.System.Object.class)); - } - - void skipMarker() throws IOException - { - for (;;) - { - if (objCount > 0) - { - objId += objCount; - objCount = 0; - if (buf[pos] == MARKER) - { - pos++; - modeSwitch(); - break; - } - switchToData(); - } - if (blockEnd != -1) - { - pos = blockEnd; - blockEnd = -1; - } - if (pos == buf.length) - { - throw new StreamCorruptedException(); - } - if (buf[pos] == MARKER) - { - pos++; - modeSwitch(); - break; - } - blockEnd = -1; - objCount = readPacked(); - } - } - } - - ObjectDataInputStream(SerializationInfo info) throws IOException - { - super(new Inp(info)); - } - - public Object readObject() throws IOException - { - return ((Inp)in).readObject(); - } - - public void skipMarker() throws IOException - { - ((Inp)in).skipMarker(); - } - } -} diff --git a/openjdk/java/io/InteropObjectOutputStream.java b/openjdk/java/io/InteropObjectOutputStream.java deleted file mode 100644 index f32c98b1..00000000 --- a/openjdk/java/io/InteropObjectOutputStream.java +++ /dev/null @@ -1,738 +0,0 @@ -/* - * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. - * Copyright 2009 Jeroen Frijters - * 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 cli.System.Runtime.Serialization.IObjectReference; -import cli.System.Runtime.Serialization.SerializationException; -import cli.System.Runtime.Serialization.SerializationInfo; -import cli.System.Runtime.Serialization.StreamingContext; -import cli.System.SerializableAttribute; -import java.util.ArrayList; - -@ikvm.lang.Internal -public final class InteropObjectOutputStream extends ObjectOutputStream -{ - private final ObjectDataOutputStream dos; - private Object curObj; - private ObjectStreamClass curDesc; - private PutFieldImpl curPut; - - @SerializableAttribute.Annotation - private static final class ReplaceProxy implements IObjectReference - { - private Object obj; - - @cli.System.Security.SecurityCriticalAttribute.Annotation - public Object GetRealObject(StreamingContext context) - { - return obj; - } - } - - static final class DynamicProxy implements Serializable - { - Object obj; - - private Object readResolve() - { - return obj; - } - } - - public static void writeObject(Object obj, SerializationInfo info) - { - try - { - boolean replaced = false; - Class cl = obj.getClass(); - ObjectStreamClass desc; - for (;;) - { - Class repCl; - desc = ObjectStreamClass.lookup(cl, true); - if (!desc.hasWriteReplaceMethod() || - (obj = desc.invokeWriteReplace(obj)) == null || - (repCl = obj.getClass()) == cl) - { - break; - } - cl = repCl; - replaced = true; - } - if (replaced) - { - info.AddValue("obj", obj); - info.SetType(ikvm.runtime.Util.getInstanceTypeFromClass(ReplaceProxy.class)); - } - else - { - new InteropObjectOutputStream(info, obj, cl, desc); - } - } - catch (IOException x) - { - ikvm.runtime.Util.throwException(new SerializationException(x.getMessage(), x)); - } - } - - private InteropObjectOutputStream(SerializationInfo info, Object obj, Class cl, ObjectStreamClass desc) throws IOException - { - dos = new ObjectDataOutputStream(info); - if (obj instanceof ObjectStreamClass) - { - ObjectStreamClass osc = (ObjectStreamClass)obj; - if (osc.isProxy()) - { - writeProxyDesc(osc); - } - else - { - writeNonProxyDesc(osc); - } - } - else if (obj instanceof Serializable) - { - if (desc.isDynamicClass()) - { - info.SetType(ikvm.runtime.Util.getInstanceTypeFromClass(DynamicProxy.class)); - } - writeOrdinaryObject(obj, desc); - } - else - { - throw new NotSerializableException(cl.getName()); - } - dos.close(); - } - - private void writeProxyDesc(ObjectStreamClass desc) throws IOException - { - writeByte(TC_PROXYCLASSDESC); - Class cl = desc.forClass(); - Class[] ifaces = cl.getInterfaces(); - writeInt(ifaces.length); - for (int i = 0; i < ifaces.length; i++) - { - writeObject(ifaces[i]); - } - writeObject(desc.getSuperDesc()); - } - - private void writeNonProxyDesc(ObjectStreamClass desc) throws IOException - { - writeByte(TC_CLASSDESC); - writeObject(desc.forClass()); - desc.writeNonProxy(this); - writeObject(desc.getSuperDesc()); - } - - private void writeOrdinaryObject(Object obj, ObjectStreamClass desc) throws IOException - { - desc.checkSerialize(); - writeObject(desc); - if (desc.isExternalizable() && !desc.isProxy()) - { - writeExternalData((Externalizable)obj); - } - else - { - writeSerialData(obj, desc); - } - } - - private void writeExternalData(Externalizable obj) throws IOException - { - Object oldObj = curObj; - ObjectStreamClass oldDesc = curDesc; - PutFieldImpl oldPut = curPut; - curObj = obj; - curDesc = null; - curPut = null; - - obj.writeExternal(this); - dos.writeMarker(); - - curObj = oldObj; - curDesc = oldDesc; - curPut = oldPut; - } - - private void writeSerialData(Object obj, ObjectStreamClass desc) throws IOException - { - ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout(); - for (int i = 0; i < slots.length; i++) - { - ObjectStreamClass slotDesc = slots[i].desc; - if (slotDesc.hasWriteObjectMethod()) - { - Object oldObj = curObj; - ObjectStreamClass oldDesc = curDesc; - PutFieldImpl oldPut = curPut; - curObj = obj; - curDesc = slotDesc; - curPut = null; - slotDesc.invokeWriteObject(obj, this); - dos.writeMarker(); - curObj = oldObj; - curDesc = oldDesc; - curPut = oldPut; - } - else - { - defaultWriteFields(obj, slotDesc); - } - } - } - - private void defaultWriteFields(Object obj, ObjectStreamClass desc) throws IOException - { - desc.checkDefaultSerialize(); - - byte[] primVals = new byte[desc.getPrimDataSize()]; - desc.getPrimFieldValues(obj, primVals); - write(primVals); - - Object[] objVals = new Object[desc.getNumObjFields()]; - desc.getObjFieldValues(obj, objVals); - for (int i = 0; i < objVals.length; i++) - { - writeObject(objVals[i]); - } - } - - @Override - public void defaultWriteObject() throws IOException - { - defaultWriteFields(curObj, curDesc); - } - - @Override - public void close() - { - throw new UnsupportedOperationException(); - } - - @Override - public void flush() - { - } - - @Override - public ObjectOutputStream.PutField putFields() throws IOException - { - if (curPut == null) - { - if (curObj == null || curDesc == null) - { - throw new NotActiveException("not in call to writeObject"); - } - curPut = new PutFieldImpl(curDesc); - } - return curPut; - } - - @Override - public void reset() throws IOException - { - throw new IOException("stream active"); - } - - @Override - protected void writeObjectOverride(Object obj) - { - // TODO consider tagging ghost arrays - dos.writeObject(obj); - } - - @Override - public void writeFields() throws IOException - { - if (curPut == null) - { - throw new NotActiveException("no current PutField object"); - } - curPut.writeFields(); - } - - @Override - public void writeUnshared(Object obj) - { - throw new UnsupportedOperationException(); - } - - @Override - public void useProtocolVersion(int version) - { - throw new IllegalStateException("stream non-empty"); - } - - @Override - public void write(byte[] buf) throws IOException - { - write(buf, 0, buf.length); - } - - @Override - public void write(int val) throws IOException - { - dos.write(val); - } - - @Override - public void write(byte[] buf, int off, int len) throws IOException - { - dos.write(buf, off, len); - } - - @Override - public void writeBoolean(boolean val) throws IOException - { - dos.writeBoolean(val); - } - - @Override - public void writeByte(int val) throws IOException - { - dos.writeByte(val); - } - - @Override - public void writeBytes(String str) throws IOException - { - dos.writeBytes(str); - } - - @Override - public void writeChar(int val) throws IOException - { - dos.writeChar(val); - } - - @Override - public void writeChars(String str) throws IOException - { - dos.writeChars(str); - } - - @Override - public void writeDouble(double val) throws IOException - { - dos.writeDouble(val); - } - - @Override - public void writeFloat(float val) throws IOException - { - dos.writeFloat(val); - } - - @Override - public void writeInt(int val) throws IOException - { - dos.writeInt(val); - } - - @Override - public void writeLong(long val) throws IOException - { - dos.writeLong(val); - } - - @Override - public void writeShort(int val) throws IOException - { - dos.writeShort(val); - } - - @Override - public void writeUTF(String str) throws IOException - { - dos.writeUTF(str); - } - - // private API used by ObjectStreamClass - @Override - void writeTypeString(String str) throws IOException - { - writeObject(str); - } - - private final class PutFieldImpl extends PutField { - - /** class descriptor describing serializable fields */ - private final ObjectStreamClass desc; - /** primitive field values */ - private final byte[] primVals; - /** object field values */ - private final Object[] objVals; - - /** - * Creates PutFieldImpl object for writing fields defined in given - * class descriptor. - */ - PutFieldImpl(ObjectStreamClass desc) { - this.desc = desc; - primVals = new byte[desc.getPrimDataSize()]; - objVals = new Object[desc.getNumObjFields()]; - } - - public void put(String name, boolean val) { - Bits.putBoolean(primVals, getFieldOffset(name, Boolean.TYPE), val); - } - - public void put(String name, byte val) { - primVals[getFieldOffset(name, Byte.TYPE)] = val; - } - - public void put(String name, char val) { - Bits.putChar(primVals, getFieldOffset(name, Character.TYPE), val); - } - - public void put(String name, short val) { - Bits.putShort(primVals, getFieldOffset(name, Short.TYPE), val); - } - - public void put(String name, int val) { - Bits.putInt(primVals, getFieldOffset(name, Integer.TYPE), val); - } - - public void put(String name, float val) { - Bits.putFloat(primVals, getFieldOffset(name, Float.TYPE), val); - } - - public void put(String name, long val) { - Bits.putLong(primVals, getFieldOffset(name, Long.TYPE), val); - } - - public void put(String name, double val) { - Bits.putDouble(primVals, getFieldOffset(name, Double.TYPE), val); - } - - public void put(String name, Object val) { - objVals[getFieldOffset(name, Object.class)] = val; - } - - // deprecated in ObjectOutputStream.PutField - public void write(ObjectOutput out) throws IOException { - /* - * Applications should *not* use this method to write PutField - * data, as it will lead to stream corruption if the PutField - * object writes any primitive data (since block data mode is not - * unset/set properly, as is done in OOS.writeFields()). This - * broken implementation is being retained solely for behavioral - * compatibility, in order to support applications which use - * OOS.PutField.write() for writing only non-primitive data. - * - * Serialization of unshared objects is not implemented here since - * it is not necessary for backwards compatibility; also, unshared - * semantics may not be supported by the given ObjectOutput - * instance. Applications which write unshared objects using the - * PutField API must use OOS.writeFields(). - */ - if (InteropObjectOutputStream.this != out) { - throw new IllegalArgumentException("wrong stream"); - } - out.write(primVals, 0, primVals.length); - - ObjectStreamField[] fields = desc.getFields(false); - int numPrimFields = fields.length - objVals.length; - // REMIND: warn if numPrimFields > 0? - for (int i = 0; i < objVals.length; i++) { - if (fields[numPrimFields + i].isUnshared()) { - throw new IOException("cannot write unshared object"); - } - out.writeObject(objVals[i]); - } - } - - /** - * Writes buffered primitive data and object fields to stream. - */ - void writeFields() throws IOException { - InteropObjectOutputStream.this.write(primVals, 0, primVals.length); - - ObjectStreamField[] fields = desc.getFields(false); - int numPrimFields = fields.length - objVals.length; - for (int i = 0; i < objVals.length; i++) { - writeObject(objVals[i]); - } - } - - /** - * Returns offset of field with given name and type. A specified type - * of null matches all types, Object.class matches all non-primitive - * types, and any other non-null type matches assignable types only. - * Throws IllegalArgumentException if no matching field found. - */ - private int getFieldOffset(String name, Class type) { - ObjectStreamField field = desc.getField(name, type); - if (field == null) { - throw new IllegalArgumentException("no such field " + name + - " with type " + type); - } - return field.getOffset(); - } - } - - private static final class ObjectDataOutputStream extends DataOutputStream - { - /* - * States: - * blockStart objCount - * -1 0 Previous byte was a marker (or we're at the start of the stream), next byte will be MARKER, OBJECTS or BYTES - * >=0 0 We're currently writing a byte stream (that starts at blockStart + 1) - * -1 >0 We're currently writing objects (just a count of objects really) - * - */ - private static final byte MARKER = 0; - private static final byte OBJECTS = 10; - private static final byte BYTES = 20; - private final SerializationInfo info; - private byte[] buf = new byte[16]; - private int pos; - private int blockStart = -1; - private int objCount; - private int objId; - - ObjectDataOutputStream(SerializationInfo info) - { - super(null); - out = this; - this.info = info; - } - - private void grow(int minGrow) - { - int newSize = buf.length + Math.max(buf.length, minGrow); - byte[] newBuf = new byte[newSize]; - System.arraycopy(buf, 0, newBuf, 0, pos); - buf = newBuf; - } - - private void switchToData() - { - if (objCount == 0) - { - if (pos == buf.length) - { - grow(1); - } - buf[pos++] = BYTES; - } - else - { - int len = packedLength(objCount); - if (pos + len >= buf.length) - { - grow(len); - } - writePacked(pos, objCount); - objCount = 0; - pos += len; - } - blockStart = pos; - // reserve space for the number of bytes - // (we assume that one byte will suffice, but if it won't the endData code will copy the data to make room) - if (pos == buf.length) - { - grow(1); - } - pos++; - } - - private void endData() - { - if (blockStart == -1) - { - if (pos == buf.length) - { - grow(1); - } - buf[pos++] = OBJECTS; - } - else - { - int len = (pos - blockStart) - 1; - int lenlen = packedLength(len); - if (lenlen > 1) - { - lenlen--; - if (buf.length - pos <= lenlen) - { - grow(lenlen); - } - System.arraycopy(buf, blockStart + 1, buf, blockStart + 1 + lenlen, pos - (blockStart + 1)); - pos += lenlen; - } - writePacked(blockStart, len); - blockStart = -1; - } - } - - private int packedLength(int val) - { - if (val < 0) - { - // we only use packed integers for lengths or counts, so they can never be negative - throw new Error(); - } - else if (val < 128) - { - return 1; - } - else if (val < 16129) - { - return 2; - } - else - { - return 5; - } - } - - private void writePacked(int pos, int v) - { - if (v < 128) - { - buf[pos] = (byte)v; - } - else if (v < 16129) - { - buf[pos + 0] = (byte)(128 | (v >> 7)); - buf[pos + 1] = (byte)(v & 127); - } - else - { - buf[pos + 0] = (byte)128; - buf[pos + 1] = (byte)(v >>> 24); - buf[pos + 2] = (byte)(v >>> 16); - buf[pos + 3] = (byte)(v >>> 8); - buf[pos + 4] = (byte)(v >>> 0); - } - } - - @Override - public void write(int b) - { - if (blockStart == -1) - { - switchToData(); - } - if (pos == buf.length) - { - grow(1); - } - buf[pos++] = (byte)b; - } - - @Override - public void write(byte[] b, int off, int len) - { - if (len == 0) - { - return; - } - if (blockStart == -1) - { - switchToData(); - } - if (pos + len >= buf.length) - { - grow(len); - } - System.arraycopy(b, off, buf, pos, len); - pos += len; - } - - public void writeObject(Object obj) - { - if (objCount == 0) - { - endData(); - } - objCount++; - info.AddValue("$" + (objId++), obj); - } - - @Override - public void close() - { - if (objCount == 0) - { - if (blockStart == -1) - { - // we've just written a marker, so we don't need to do anything else - } - else - { - endData(); - } - } - else - { - switchToData(); - } - trim(); - info.AddValue("$data", buf); - } - - private void trim() - { - if (buf.length != pos) - { - byte[] newBuf = new byte[pos]; - System.arraycopy(buf, 0, newBuf, 0, pos); - buf = newBuf; - } - } - - @Override - public void flush() - { - } - - public void writeMarker() - { - if (objCount == 0) - { - if (blockStart != -1) - { - endData(); - } - if (pos == buf.length) - { - grow(1); - } - buf[pos++] = MARKER; - } - else - { - switchToData(); - } - blockStart = -1; - } - } -} diff --git a/openjdk/java/io/ObjectStreamClass.java b/openjdk/java/io/ObjectStreamClass.java deleted file mode 100644 index 97489b1e..00000000 --- a/openjdk/java/io/ObjectStreamClass.java +++ /dev/null @@ -1,2361 +0,0 @@ -/* - * Copyright (c) 1996, 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 java.io; - -import ikvm.internal.FieldReflectorBase; -import java.lang.ref.Reference; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.SoftReference; -import java.lang.ref.WeakReference; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Member; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.Proxy; -import java.security.AccessController; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import sun.misc.Unsafe; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; -import sun.reflect.ReflectionFactory; -import sun.reflect.misc.ReflectUtil; - -/** - * Serialization's descriptor for classes. It contains the name and - * serialVersionUID of the class. The ObjectStreamClass for a specific class - * loaded in this Java VM can be found/created using the lookup method. - * - * <p>The algorithm to compute the SerialVersionUID is described in - * <a href="../../../platform/serialization/spec/class.html#4100">Object - * Serialization Specification, Section 4.6, Stream Unique Identifiers</a>. - * - * @author Mike Warres - * @author Roger Riggs - * @see ObjectStreamField - * @see <a href="../../../platform/serialization/spec/class.html">Object Serialization Specification, Section 4, Class Descriptors</a> - * @since JDK1.1 - */ -public class ObjectStreamClass implements Serializable { - - /** serialPersistentFields value indicating no serializable fields */ - public static final ObjectStreamField[] NO_FIELDS = - new ObjectStreamField[0]; - - private static final long serialVersionUID = -6120832682080437368L; - private static final ObjectStreamField[] serialPersistentFields = - NO_FIELDS; - - /** reflection factory for obtaining serialization constructors */ - private static final ReflectionFactory reflFactory = - AccessController.doPrivileged( - new ReflectionFactory.GetReflectionFactoryAction()); - - private static class Caches { - /** cache mapping local classes -> descriptors */ - static final ConcurrentMap<WeakClassKey,Reference<?>> localDescs = - new ConcurrentHashMap<>(); - - /** cache mapping field group/local desc pairs -> field reflectors */ - static final ConcurrentMap<FieldReflectorKey,Reference<?>> reflectors = - new ConcurrentHashMap<>(); - - /** queue for WeakReferences to local classes */ - private static final ReferenceQueue<Class<?>> localDescsQueue = - new ReferenceQueue<>(); - /** queue for WeakReferences to field reflectors keys */ - private static final ReferenceQueue<Class<?>> reflectorsQueue = - new ReferenceQueue<>(); - } - - /** class associated with this descriptor (if any) */ - private Class<?> cl; - /** name of class represented by this descriptor */ - private String name; - /** serialVersionUID of represented class (null if not computed yet) */ - private volatile Long suid; - - /** true if represents dynamic proxy class */ - private boolean isProxy; - /** true if represents enum type */ - private boolean isEnum; - /** true if represented class implements Serializable */ - private boolean serializable; - /** true if represented class implements Externalizable */ - private boolean externalizable; - /** true if desc has data written by class-defined writeObject method */ - private boolean hasWriteObjectData; - /** - * true if desc has externalizable data written in block data format; this - * must be true by default to accommodate ObjectInputStream subclasses which - * override readClassDescriptor() to return class descriptors obtained from - * ObjectStreamClass.lookup() (see 4461737) - */ - private boolean hasBlockExternalData = true; - - /** - * Contains information about InvalidClassException instances to be thrown - * when attempting operations on an invalid class. Note that instances of - * this class are immutable and are potentially shared among - * ObjectStreamClass instances. - */ - private static class ExceptionInfo { - private final String className; - private final String message; - - ExceptionInfo(String cn, String msg) { - className = cn; - message = msg; - } - - /** - * Returns (does not throw) an InvalidClassException instance created - * from the information in this object, suitable for being thrown by - * the caller. - */ - InvalidClassException newInvalidClassException() { - return new InvalidClassException(className, message); - } - } - - /** exception (if any) thrown while attempting to resolve class */ - private ClassNotFoundException resolveEx; - /** exception (if any) to throw if non-enum deserialization attempted */ - private ExceptionInfo deserializeEx; - /** exception (if any) to throw if non-enum serialization attempted */ - private ExceptionInfo serializeEx; - /** exception (if any) to throw if default serialization attempted */ - private ExceptionInfo defaultSerializeEx; - - /** serializable fields */ - private ObjectStreamField[] fields; - /** aggregate marshalled size of primitive fields */ - private int primDataSize; - /** number of non-primitive fields */ - private int numObjFields; - /** reflector for setting/getting serializable field values */ - private FieldReflectorBase fieldRefl; - /** data layout of serialized objects described by this class desc */ - private volatile ClassDataSlot[] dataLayout; - - /** serialization-appropriate constructor, or null if none */ - private Constructor cons; - /** class-defined writeObject method, or null if none */ - private Method writeObjectMethod; - /** class-defined readObject method, or null if none */ - private Method readObjectMethod; - /** class-defined readObjectNoData method, or null if none */ - private Method readObjectNoDataMethod; - /** class-defined writeReplace method, or null if none */ - private Method writeReplaceMethod; - /** class-defined readResolve method, or null if none */ - private Method readResolveMethod; - - /** local class descriptor for represented class (may point to self) */ - private ObjectStreamClass localDesc; - /** superclass descriptor appearing in stream */ - private ObjectStreamClass superDesc; - - /** [IKVM] true if the the class was dynamically loaded from Java bytecode */ - private boolean dynamicClass; - - /** - * Initializes native code. - */ - private static native void initNative(); - static { - initNative(); - } - - /** - * Find the descriptor for a class that can be serialized. Creates an - * ObjectStreamClass instance if one does not exist yet for class. Null is - * returned if the specified class does not implement java.io.Serializable - * or java.io.Externalizable. - * - * @param cl class for which to get the descriptor - * @return the class descriptor for the specified class - */ - public static ObjectStreamClass lookup(Class<?> cl) { - return lookup(cl, false); - } - - /** - * Returns the descriptor for any class, regardless of whether it - * implements {@link Serializable}. - * - * @param cl class for which to get the descriptor - * @return the class descriptor for the specified class - * @since 1.6 - */ - public static ObjectStreamClass lookupAny(Class<?> cl) { - return lookup(cl, true); - } - - /** - * Returns the name of the class described by this descriptor. - * This method returns the name of the class in the format that - * is used by the {@link Class#getName} method. - * - * @return a string representing the name of the class - */ - public String getName() { - return name; - } - - /** - * Return the serialVersionUID for this class. The serialVersionUID - * defines a set of classes all with the same name that have evolved from a - * common root class and agree to be serialized and deserialized using a - * common format. NonSerializable classes have a serialVersionUID of 0L. - * - * @return the SUID of the class described by this descriptor - */ - public long getSerialVersionUID() { - // REMIND: synchronize instead of relying on volatile? - if (suid == null) { - suid = AccessController.doPrivileged( - new PrivilegedAction<Long>() { - public Long run() { - return computeDefaultSUID(cl); - } - } - ); - } - return suid.longValue(); - } - - /** - * Return the class in the local VM that this version is mapped to. Null - * is returned if there is no corresponding local class. - * - * @return the <code>Class</code> instance that this descriptor represents - */ - @CallerSensitive - public Class<?> forClass() { - if (cl == null) { - return null; - } - if (System.getSecurityManager() != null) { - Class<?> caller = Reflection.getCallerClass(); - if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), cl.getClassLoader())) { - ReflectUtil.checkPackageAccess(cl); - } - } - return cl; - } - - /** - * Return an array of the fields of this serializable class. - * - * @return an array containing an element for each persistent field of - * this class. Returns an array of length zero if there are no - * fields. - * @since 1.2 - */ - public ObjectStreamField[] getFields() { - return getFields(true); - } - - /** - * Get the field of this class by name. - * - * @param name the name of the data field to look for - * @return The ObjectStreamField object of the named field or null if - * there is no such named field. - */ - public ObjectStreamField getField(String name) { - return getField(name, null); - } - - /** - * Return a string describing this ObjectStreamClass. - */ - public String toString() { - return name + ": static final long serialVersionUID = " + - getSerialVersionUID() + "L;"; - } - - /** - * Looks up and returns class descriptor for given class, or null if class - * is non-serializable and "all" is set to false. - * - * @param cl class to look up - * @param all if true, return descriptors for all classes; if false, only - * return descriptors for serializable classes - */ - static ObjectStreamClass lookup(Class<?> cl, boolean all) { - if (!(all || Serializable.class.isAssignableFrom(cl))) { - return null; - } - processQueue(Caches.localDescsQueue, Caches.localDescs); - WeakClassKey key = new WeakClassKey(cl, Caches.localDescsQueue); - Reference<?> ref = Caches.localDescs.get(key); - Object entry = null; - if (ref != null) { - entry = ref.get(); - } - EntryFuture future = null; - if (entry == null) { - EntryFuture newEntry = new EntryFuture(); - Reference<?> newRef = new SoftReference<>(newEntry); - do { - if (ref != null) { - Caches.localDescs.remove(key, ref); - } - ref = Caches.localDescs.putIfAbsent(key, newRef); - if (ref != null) { - entry = ref.get(); - } - } while (ref != null && entry == null); - if (entry == null) { - future = newEntry; - } - } - - if (entry instanceof ObjectStreamClass) { // check common case first - return (ObjectStreamClass) entry; - } - if (entry instanceof EntryFuture) { - future = (EntryFuture) entry; - if (future.getOwner() == Thread.currentThread()) { - /* - * Handle nested call situation described by 4803747: waiting - * for future value to be set by a lookup() call further up the - * stack will result in deadlock, so calculate and set the - * future value here instead. - */ - entry = null; - } else { - entry = future.get(); - } - } - if (entry == null) { - try { - entry = new ObjectStreamClass(cl); - } catch (Throwable th) { - entry = th; - } - if (future.set(entry)) { - Caches.localDescs.put(key, new SoftReference<Object>(entry)); - } else { - // nested lookup call already set future - entry = future.get(); - } - } - - if (entry instanceof ObjectStreamClass) { - return (ObjectStreamClass) entry; - } else if (entry instanceof RuntimeException) { - throw (RuntimeException) entry; - } else if (entry instanceof Error) { - throw (Error) entry; - } else { - throw new InternalError("unexpected entry: " + entry); - } - } - - /** - * Placeholder used in class descriptor and field reflector lookup tables - * for an entry in the process of being initialized. (Internal) callers - * which receive an EntryFuture belonging to another thread as the result - * of a lookup should call the get() method of the EntryFuture; this will - * return the actual entry once it is ready for use and has been set(). To - * conserve objects, EntryFutures synchronize on themselves. - */ - private static class EntryFuture { - - private static final Object unset = new Object(); - private final Thread owner = Thread.currentThread(); - private Object entry = unset; - - /** - * Attempts to set the value contained by this EntryFuture. If the - * EntryFuture's value has not been set already, then the value is - * saved, any callers blocked in the get() method are notified, and - * true is returned. If the value has already been set, then no saving - * or notification occurs, and false is returned. - */ - synchronized boolean set(Object entry) { - if (this.entry != unset) { - return false; - } - this.entry = entry; - notifyAll(); - return true; - } - - /** - * Returns the value contained by this EntryFuture, blocking if - * necessary until a value is set. - */ - synchronized Object get() { - boolean interrupted = false; - while (entry == unset) { - try { - wait(); - } catch (InterruptedException ex) { - interrupted = true; - } - } - if (interrupted) { - AccessController.doPrivileged( - new PrivilegedAction<Void>() { - public Void run() { - Thread.currentThread().interrupt(); - return null; - } - } - ); - } - return entry; - } - - /** - * Returns the thread that created this EntryFuture. - */ - Thread getOwner() { - return owner; - } - } - - /** - * Creates local class descriptor representing given class. - */ - private ObjectStreamClass(final Class<?> cl) { - this.cl = cl; - name = cl.getName(); - isProxy = Proxy.isProxyClass(cl); - isEnum = Enum.class.isAssignableFrom(cl); - serializable = Serializable.class.isAssignableFrom(cl); - externalizable = Externalizable.class.isAssignableFrom(cl); - dynamicClass = isDynamicTypeWrapper(cl); - - Class<?> superCl = cl.getSuperclass(); - superDesc = (superCl != null) ? lookup(superCl, false) : null; - localDesc = this; - - if (serializable) { - AccessController.doPrivileged(new PrivilegedAction<Void>() { - public Void run() { - if (isEnum) { - suid = Long.valueOf(0); - fields = NO_FIELDS; - return null; - } - if (cl.isArray()) { - fields = NO_FIELDS; - return null; - } - - suid = getDeclaredSUID(cl); - try { - fields = getSerialFields(cl); - computeFieldOffsets(); - } catch (InvalidClassException e) { - serializeEx = deserializeEx = - new ExceptionInfo(e.classname, e.getMessage()); - fields = NO_FIELDS; - } - - if (externalizable) { - cons = getExternalizableConstructor(cl); - } else { - cons = getSerializableConstructor(cl); - writeObjectMethod = getPrivateMethod(cl, "writeObject", - new Class<?>[] { ObjectOutputStream.class }, - Void.TYPE); - readObjectMethod = getPrivateMethod(cl, "readObject", - new Class<?>[] { ObjectInputStream.class }, - Void.TYPE); - readObjectNoDataMethod = getPrivateMethod( - cl, "readObjectNoData", null, Void.TYPE); - hasWriteObjectData = (writeObjectMethod != null); - } - writeReplaceMethod = getInheritableMethod( - cl, "writeReplace", null, Object.class); - readResolveMethod = getInheritableMethod( - cl, "readResolve", null, Object.class); - return null; - } - }); - } else { - suid = Long.valueOf(0); - fields = NO_FIELDS; - } - - try { - fieldRefl = getReflector(fields, this); - } catch (InvalidClassException ex) { - // field mismatches impossible when matching local fields vs. self - throw new InternalError(); - } - - if (deserializeEx == null) { - if (isEnum) { - deserializeEx = new ExceptionInfo(name, "enum type"); - } else if (cons == null) { - deserializeEx = new ExceptionInfo(name, "no valid constructor"); - } - } - for (int i = 0; i < fields.length; i++) { - if (fields[i].getField() == null) { - defaultSerializeEx = new ExceptionInfo( - name, "unmatched serializable field(s) declared"); - } - } - } - - /** - * Creates blank class descriptor which should be initialized via a - * subsequent call to initProxy(), initNonProxy() or readNonProxy(). - */ - ObjectStreamClass() { - } - - /** - * Initializes class descriptor representing a proxy class. - */ - void initProxy(Class<?> cl, - ClassNotFoundException resolveEx, - ObjectStreamClass superDesc) - throws InvalidClassException - { - this.cl = cl; - this.resolveEx = resolveEx; - this.superDesc = superDesc; - isProxy = true; - serializable = true; - suid = Long.valueOf(0); - fields = NO_FIELDS; - - if (cl != null) { - localDesc = lookup(cl, true); - if (!localDesc.isProxy) { - throw new InvalidClassException( - "cannot bind proxy descriptor to a non-proxy class"); - } - name = localDesc.name; - externalizable = localDesc.externalizable; - cons = localDesc.cons; - writeReplaceMethod = localDesc.writeReplaceMethod; - readResolveMethod = localDesc.readResolveMethod; - deserializeEx = localDesc.deserializeEx; - } - fieldRefl = getReflector(fields, localDesc); - } - - /** - * Initializes class descriptor representing a non-proxy class. - */ - void initNonProxy(ObjectStreamClass model, - Class<?> cl, - ClassNotFoundException resolveEx, - ObjectStreamClass superDesc) - throws InvalidClassException - { - this.cl = cl; - this.resolveEx = resolveEx; - this.superDesc = superDesc; - name = model.name; - suid = Long.valueOf(model.getSerialVersionUID()); - isProxy = false; - isEnum = model.isEnum; - serializable = model.serializable; - externalizable = model.externalizable; - hasBlockExternalData = model.hasBlockExternalData; - hasWriteObjectData = model.hasWriteObjectData; - fields = model.fields; - primDataSize = model.primDataSize; - numObjFields = model.numObjFields; - - if (cl != null) { - localDesc = lookup(cl, true); - if (localDesc.isProxy) { - throw new InvalidClassException( - "cannot bind non-proxy descriptor to a proxy class"); - } - if (isEnum != localDesc.isEnum) { - throw new InvalidClassException(isEnum ? - "cannot bind enum descriptor to a non-enum class" : - "cannot bind non-enum descriptor to an enum class"); - } - - if (serializable == localDesc.serializable && - !cl.isArray() && - suid.longValue() != localDesc.getSerialVersionUID()) - { - throw new InvalidClassException(localDesc.name, - "local class incompatible: " + - "stream classdesc serialVersionUID = " + suid + - ", local class serialVersionUID = " + - localDesc.getSerialVersionUID()); - } - - if (!classNamesEqual(name, localDesc.name)) { - throw new InvalidClassException(localDesc.name, - "local class name incompatible with stream class " + - "name \"" + name + "\""); - } - - if (!isEnum) { - if ((serializable == localDesc.serializable) && - (externalizable != localDesc.externalizable)) - { - throw new InvalidClassException(localDesc.name, - "Serializable incompatible with Externalizable"); - } - - if ((serializable != localDesc.serializable) || - (externalizable != localDesc.externalizable) || - !(serializable || externalizable)) - { - deserializeEx = new ExceptionInfo( - localDesc.name, "class invalid for deserialization"); - } - } - - cons = localDesc.cons; - writeObjectMethod = localDesc.writeObjectMethod; - readObjectMethod = localDesc.readObjectMethod; - readObjectNoDataMethod = localDesc.readObjectNoDataMethod; - writeReplaceMethod = localDesc.writeReplaceMethod; - readResolveMethod = localDesc.readResolveMethod; - if (deserializeEx == null) { - deserializeEx = localDesc.deserializeEx; - } - } - fieldRefl = getReflector(fields, localDesc); - // reassign to matched fields so as to reflect local unshared settings - fields = fieldRefl.getFields(); - } - - /** - * Reads non-proxy class descriptor information from given input stream. - * The resulting class descriptor is not fully functional; it can only be - * used as input to the ObjectInputStream.resolveClass() and - * ObjectStreamClass.initNonProxy() methods. - */ - void readNonProxy(ObjectInputStream in) - throws IOException, ClassNotFoundException - { - name = in.readUTF(); - suid = Long.valueOf(in.readLong()); - isProxy = false; - - byte flags = in.readByte(); - hasWriteObjectData = - ((flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0); - hasBlockExternalData = - ((flags & ObjectStreamConstants.SC_BLOCK_DATA) != 0); - externalizable = - ((flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0); - boolean sflag = - ((flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0); - if (externalizable && sflag) { - throw new InvalidClassException( - name, "serializable and externalizable flags conflict"); - } - serializable = externalizable || sflag; - isEnum = ((flags & ObjectStreamConstants.SC_ENUM) != 0); - if (isEnum && suid.longValue() != 0L) { - throw new InvalidClassException(name, - "enum descriptor has non-zero serialVersionUID: " + suid); - } - - int numFields = in.readShort(); - if (isEnum && numFields != 0) { - throw new InvalidClassException(name, - "enum descriptor has non-zero field count: " + numFields); - } - fields = (numFields > 0) ? - new ObjectStreamField[numFields] : NO_FIELDS; - for (int i = 0; i < numFields; i++) { - char tcode = (char) in.readByte(); - String fname = in.readUTF(); - String signature = ((tcode == 'L') || (tcode == '[')) ? - in.readTypeString() : new String(new char[] { tcode }); - try { - fields[i] = new ObjectStreamField(fname, signature, false); - } catch (RuntimeException e) { - throw (IOException) new InvalidClassException(name, - "invalid descriptor for field " + fname).initCause(e); - } - } - computeFieldOffsets(); - } - - /** - * Writes non-proxy class descriptor information to given output stream. - */ - void writeNonProxy(ObjectOutputStream out) throws IOException { - out.writeUTF(name); - out.writeLong(getSerialVersionUID()); - - byte flags = 0; - if (externalizable) { - flags |= ObjectStreamConstants.SC_EXTERNALIZABLE; - int protocol = out.getProtocolVersion(); - if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) { - flags |= ObjectStreamConstants.SC_BLOCK_DATA; - } - } else if (serializable) { - flags |= ObjectStreamConstants.SC_SERIALIZABLE; - } - if (hasWriteObjectData) { - flags |= ObjectStreamConstants.SC_WRITE_METHOD; - } - if (isEnum) { - flags |= ObjectStreamConstants.SC_ENUM; - } - out.writeByte(flags); - - out.writeShort(fields.length); - for (int i = 0; i < fields.length; i++) { - ObjectStreamField f = fields[i]; - out.writeByte(f.getTypeCode()); - out.writeUTF(f.getName()); - if (!f.isPrimitive()) { - out.writeTypeString(f.getTypeString()); - } - } - } - - /** - * Returns ClassNotFoundException (if any) thrown while attempting to - * resolve local class corresponding to this class descriptor. - */ - ClassNotFoundException getResolveException() { - return resolveEx; - } - - /** - * Throws an InvalidClassException if object instances referencing this - * class descriptor should not be allowed to deserialize. This method does - * not apply to deserialization of enum constants. - */ - void checkDeserialize() throws InvalidClassException { - if (deserializeEx != null) { - throw deserializeEx.newInvalidClassException(); - } - } - - /** - * Throws an InvalidClassException if objects whose class is represented by - * this descriptor should not be allowed to serialize. This method does - * not apply to serialization of enum constants. - */ - void checkSerialize() throws InvalidClassException { - if (serializeEx != null) { - throw serializeEx.newInvalidClassException(); - } - } - - /** - * Throws an InvalidClassException if objects whose class is represented by - * this descriptor should not be permitted to use default serialization - * (e.g., if the class declares serializable fields that do not correspond - * to actual fields, and hence must use the GetField API). This method - * does not apply to deserialization of enum constants. - */ - void checkDefaultSerialize() throws InvalidClassException { - if (defaultSerializeEx != null) { - throw defaultSerializeEx.newInvalidClassException(); - } - } - - /** - * Returns superclass descriptor. Note that on the receiving side, the - * superclass descriptor may be bound to a class that is not a superclass - * of the subclass descriptor's bound class. - */ - ObjectStreamClass getSuperDesc() { - return superDesc; - } - - /** - * Returns the "local" class descriptor for the class associated with this - * class descriptor (i.e., the result of - * ObjectStreamClass.lookup(this.forClass())) or null if there is no class - * associated with this descriptor. - */ - ObjectStreamClass getLocalDesc() { - return localDesc; - } - - /** - * Returns arrays of ObjectStreamFields representing the serializable - * fields of the represented class. If copy is true, a clone of this class - * descriptor's field array is returned, otherwise the array itself is - * returned. - */ - ObjectStreamField[] getFields(boolean copy) { - return copy ? fields.clone() : fields; - } - - /** - * Looks up a serializable field of the represented class by name and type. - * A specified type of null matches all types, Object.class matches all - * non-primitive types, and any other non-null type matches assignable - * types only. Returns matching field, or null if no match found. - */ - ObjectStreamField getField(String name, Class<?> type) { - for (int i = 0; i < fields.length; i++) { - ObjectStreamField f = fields[i]; - if (f.getName().equals(name)) { - if (type == null || - (type == Object.class && !f.isPrimitive())) - { - return f; - } - Class<?> ftype = f.getType(); - if (ftype != null && type.isAssignableFrom(ftype)) { - return f; - } - } - } - return null; - } - - /** - * Returns true if class descriptor represents a dynamic proxy class, false - * otherwise. - */ - boolean isProxy() { - return isProxy; - } - - /** - * Returns true if class descriptor represents an enum type, false - * otherwise. - */ - boolean isEnum() { - return isEnum; - } - - /** - * Returns true if represented class implements Externalizable, false - * otherwise. - */ - boolean isExternalizable() { - return externalizable; - } - - /** - * Returns true if represented class implements Serializable, false - * otherwise. - */ - boolean isSerializable() { - return serializable; - } - - /** - * Returns true if class descriptor represents externalizable class that - * has written its data in 1.2 (block data) format, false otherwise. - */ - boolean hasBlockExternalData() { - return hasBlockExternalData; - } - - /** - * Returns true if class descriptor represents serializable (but not - * externalizable) class which has written its data via a custom - * writeObject() method, false otherwise. - */ - boolean hasWriteObjectData() { - return hasWriteObjectData; - } - - /** - * Returns true if represented class is serializable/externalizable and can - * be instantiated by the serialization runtime--i.e., if it is - * externalizable and defines a public no-arg constructor, or if it is - * non-externalizable and its first non-serializable superclass defines an - * accessible no-arg constructor. Otherwise, returns false. - */ - boolean isInstantiable() { - return (cons != null); - } - - /** - * Returns true if represented class is serializable (but not - * externalizable) and defines a conformant writeObject method. Otherwise, - * returns false. - */ - boolean hasWriteObjectMethod() { - return (writeObjectMethod != null); - } - - /** - * Returns true if represented class is serializable (but not - * externalizable) and defines a conformant readObject method. Otherwise, - * returns false. - */ - boolean hasReadObjectMethod() { - return (readObjectMethod != null); - } - - /** - * Returns true if represented class is serializable (but not - * externalizable) and defines a conformant readObjectNoData method. - * Otherwise, returns false. - */ - boolean hasReadObjectNoDataMethod() { - return (readObjectNoDataMethod != null); - } - - /** - * Returns true if represented class is serializable or externalizable and - * defines a conformant writeReplace method. Otherwise, returns false. - */ - boolean hasWriteReplaceMethod() { - return (writeReplaceMethod != null); - } - - /** - * Returns true if represented class is serializable or externalizable and - * defines a conformant readResolve method. Otherwise, returns false. - */ - boolean hasReadResolveMethod() { - return (readResolveMethod != null); - } - - /** - * Creates a new instance of the represented class. If the class is - * externalizable, invokes its public no-arg constructor; otherwise, if the - * class is serializable, invokes the no-arg constructor of the first - * non-serializable superclass. Throws UnsupportedOperationException if - * this class descriptor is not associated with a class, if the associated - * class is non-serializable or if the appropriate no-arg constructor is - * inaccessible/unavailable. - */ - Object newInstance() - throws InstantiationException, InvocationTargetException, - UnsupportedOperationException - { - if (cons != null) { - try { - return cons.newInstance(); - } catch (IllegalAccessException ex) { - // should not occur, as access checks have been suppressed - throw new InternalError(); - } - } else { - throw new UnsupportedOperationException(); - } - } - - /** - * Invokes the writeObject method of the represented serializable class. - * Throws UnsupportedOperationException if this class descriptor is not - * associated with a class, or if the class is externalizable, - * non-serializable or does not define writeObject. - */ - void invokeWriteObject(Object obj, ObjectOutputStream out) - throws IOException, UnsupportedOperationException - { - if (writeObjectMethod != null) { - try { - writeObjectMethod.invoke(obj, new Object[]{ out }); - } catch (InvocationTargetException ex) { - Throwable th = ex.getTargetException(); - if (th instanceof IOException) { - throw (IOException) th; - } else { - throwMiscException(th); - } - } catch (IllegalAccessException ex) { - // should not occur, as access checks have been suppressed - throw new InternalError(); - } - } else { - throw new UnsupportedOperationException(); - } - } - - /** - * Invokes the readObject method of the represented serializable class. - * Throws UnsupportedOperationException if this class descriptor is not - * associated with a class, or if the class is externalizable, - * non-serializable or does not define readObject. - */ - void invokeReadObject(Object obj, ObjectInputStream in) - throws ClassNotFoundException, IOException, - UnsupportedOperationException - { - if (readObjectMethod != null) { - try { - readObjectMethod.invoke(obj, new Object[]{ in }); - } catch (InvocationTargetException ex) { - Throwable th = ex.getTargetException(); - if (th instanceof ClassNotFoundException) { - throw (ClassNotFoundException) th; - } else if (th instanceof IOException) { - throw (IOException) th; - } else { - throwMiscException(th); - } - } catch (IllegalAccessException ex) { - // should not occur, as access checks have been suppressed - throw new InternalError(); - } - } else { - throw new UnsupportedOperationException(); - } - } - - /** - * Invokes the readObjectNoData method of the represented serializable - * class. Throws UnsupportedOperationException if this class descriptor is - * not associated with a class, or if the class is externalizable, - * non-serializable or does not define readObjectNoData. - */ - void invokeReadObjectNoData(Object obj) - throws IOException, UnsupportedOperationException - { - if (readObjectNoDataMethod != null) { - try { - readObjectNoDataMethod.invoke(obj, (Object[]) null); - } catch (InvocationTargetException ex) { - Throwable th = ex.getTargetException(); - if (th instanceof ObjectStreamException) { - throw (ObjectStreamException) th; - } else { - throwMiscException(th); - } - } catch (IllegalAccessException ex) { - // should not occur, as access checks have been suppressed - throw new InternalError(); - } - } else { - throw new UnsupportedOperationException(); - } - } - - /** - * Invokes the writeReplace method of the represented serializable class and - * returns the result. Throws UnsupportedOperationException if this class - * descriptor is not associated with a class, or if the class is - * non-serializable or does not define writeReplace. - */ - Object invokeWriteReplace(Object obj) - throws IOException, UnsupportedOperationException - { - if (writeReplaceMethod != null) { - try { - return writeReplaceMethod.invoke(obj, (Object[]) null); - } catch (InvocationTargetException ex) { - Throwable th = ex.getTargetException(); - if (th instanceof ObjectStreamException) { - throw (ObjectStreamException) th; - } else { - throwMiscException(th); - throw new InternalError(); // never reached - } - } catch (IllegalAccessException ex) { - // should not occur, as access checks have been suppressed - throw new InternalError(); - } - } else { - throw new UnsupportedOperationException(); - } - } - - /** - * Invokes the readResolve method of the represented serializable class and - * returns the result. Throws UnsupportedOperationException if this class - * descriptor is not associated with a class, or if the class is - * non-serializable or does not define readResolve. - */ - Object invokeReadResolve(Object obj) - throws IOException, UnsupportedOperationException - { - if (readResolveMethod != null) { - try { - return readResolveMethod.invoke(obj, (Object[]) null); - } catch (InvocationTargetException ex) { - Throwable th = ex.getTargetException(); - if (th instanceof ObjectStreamException) { - throw (ObjectStreamException) th; - } else { - throwMiscException(th); - throw new InternalError(); // never reached - } - } catch (IllegalAccessException ex) { - // should not occur, as access checks have been suppressed - throw new InternalError(); - } - } else { - throw new UnsupportedOperationException(); - } - } - - /** - * Class representing the portion of an object's serialized form allotted - * to data described by a given class descriptor. If "hasData" is false, - * the object's serialized form does not contain data associated with the - * class descriptor. - */ - static class ClassDataSlot { - - /** class descriptor "occupying" this slot */ - final ObjectStreamClass desc; - /** true if serialized form includes data for this slot's descriptor */ - final boolean hasData; - - ClassDataSlot(ObjectStreamClass desc, boolean hasData) { - this.desc = desc; - this.hasData = hasData; - } - } - - /** - * Returns array of ClassDataSlot instances representing the data layout - * (including superclass data) for serialized objects described by this - * class descriptor. ClassDataSlots are ordered by inheritance with those - * containing "higher" superclasses appearing first. The final - * ClassDataSlot contains a reference to this descriptor. - */ - ClassDataSlot[] getClassDataLayout() throws InvalidClassException { - // REMIND: synchronize instead of relying on volatile? - if (dataLayout == null) { - dataLayout = getClassDataLayout0(); - } - return dataLayout; - } - - private ClassDataSlot[] getClassDataLayout0() - throws InvalidClassException - { - ArrayList<ClassDataSlot> slots = new ArrayList<>(); - Class<?> start = cl, end = cl; - - // locate closest non-serializable superclass - while (end != null && Serializable.class.isAssignableFrom(end)) { - end = end.getSuperclass(); - } - - HashSet<String> oscNames = new HashSet<>(3); - - for (ObjectStreamClass d = this; d != null; d = d.superDesc) { - if (oscNames.contains(d.name)) { - throw new InvalidClassException("Circular reference."); - } else { - oscNames.add(d.name); - } - - // search up inheritance hierarchy for class with matching name - String searchName = (d.cl != null) ? d.cl.getName() : d.name; - Class<?> match = null; - for (Class<?> c = start; c != end; c = c.getSuperclass()) { - if (searchName.equals(c.getName())) { - match = c; - break; - } - } - - // add "no data" slot for each unmatched class below match - if (match != null) { - for (Class<?> c = start; c != match; c = c.getSuperclass()) { - slots.add(new ClassDataSlot( - ObjectStreamClass.lookup(c, true), false)); - } - start = match.getSuperclass(); - } - - // record descriptor/class pairing - slots.add(new ClassDataSlot(d.getVariantFor(match), true)); - } - - // add "no data" slot for any leftover unmatched classes - for (Class<?> c = start; c != end; c = c.getSuperclass()) { - slots.add(new ClassDataSlot( - ObjectStreamClass.lookup(c, true), false)); - } - - // order slots from superclass -> subclass - Collections.reverse(slots); - return slots.toArray(new ClassDataSlot[slots.size()]); - } - - /** - * Returns aggregate size (in bytes) of marshalled primitive field values - * for represented class. - */ - int getPrimDataSize() { - return primDataSize; - } - - /** - * Returns number of non-primitive serializable fields of represented - * class. - */ - int getNumObjFields() { - return numObjFields; - } - - /** - * Fetches the serializable primitive field values of object obj and - * marshals them into byte array buf starting at offset 0. It is the - * responsibility of the caller to ensure that obj is of the proper type if - * non-null. - */ - void getPrimFieldValues(Object obj, byte[] buf) { - fieldRefl.getPrimFieldValues(obj, buf); - } - - /** - * Sets the serializable primitive fields of object obj using values - * unmarshalled from byte array buf starting at offset 0. It is the - * responsibility of the caller to ensure that obj is of the proper type if - * non-null. - */ - void setPrimFieldValues(Object obj, byte[] buf) { - fieldRefl.setPrimFieldValues(obj, buf); - } - - /** - * Fetches the serializable object field values of object obj and stores - * them in array vals starting at offset 0. It is the responsibility of - * the caller to ensure that obj is of the proper type if non-null. - */ - void getObjFieldValues(Object obj, Object[] vals) { - fieldRefl.getObjFieldValues(obj, vals); - } - - /** - * Sets the serializable object fields of object obj using values from - * array vals starting at offset 0. It is the responsibility of the caller - * to ensure that obj is of the proper type if non-null. - */ - void setObjFieldValues(Object obj, Object[] vals) { - fieldRefl.setObjFieldValues(obj, vals); - } - - /** - * Calculates and sets serializable field offsets, as well as primitive - * data size and object field count totals. Throws InvalidClassException - * if fields are illegally ordered. - */ - private void computeFieldOffsets() throws InvalidClassException { - primDataSize = 0; - numObjFields = 0; - int firstObjIndex = -1; - - for (int i = 0; i < fields.length; i++) { - ObjectStreamField f = fields[i]; - switch (f.getTypeCode()) { - case 'Z': - case 'B': - f.setOffset(primDataSize++); - break; - - case 'C': - case 'S': - f.setOffset(primDataSize); - primDataSize += 2; - break; - - case 'I': - case 'F': - f.setOffset(primDataSize); - primDataSize += 4; - break; - - case 'J': - case 'D': - f.setOffset(primDataSize); - primDataSize += 8; - break; - - case '[': - case 'L': - f.setOffset(numObjFields++); - if (firstObjIndex == -1) { - firstObjIndex = i; - } - break; - - default: - throw new InternalError(); - } - } - if (firstObjIndex != -1 && - firstObjIndex + numObjFields != fields.length) - { - throw new InvalidClassException(name, "illegal field order"); - } - } - - /** - * If given class is the same as the class associated with this class - * descriptor, returns reference to this class descriptor. Otherwise, - * returns variant of this class descriptor bound to given class. - */ - private ObjectStreamClass getVariantFor(Class<?> cl) - throws InvalidClassException - { - if (this.cl == cl) { - return this; - } - ObjectStreamClass desc = new ObjectStreamClass(); - if (isProxy) { - desc.initProxy(cl, null, superDesc); - } else { - desc.initNonProxy(this, cl, null, superDesc); - } - return desc; - } - - /** - * Returns public no-arg constructor of given class, or null if none found. - * Access checks are disabled on the returned constructor (if any), since - * the defining class may still be non-public. - */ - private static Constructor getExternalizableConstructor(Class<?> cl) { - try { - Constructor cons = cl.getDeclaredConstructor((Class<?>[]) null); - cons.setAccessible(true); - return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ? - cons : null; - } catch (NoSuchMethodException ex) { - return null; - } - } - - /** - * Returns subclass-accessible no-arg constructor of first non-serializable - * superclass, or null if none found. Access checks are disabled on the - * returned constructor (if any). - */ - private static Constructor getSerializableConstructor(Class<?> cl) { - Class<?> initCl = cl; - while (Serializable.class.isAssignableFrom(initCl)) { - if ((initCl = initCl.getSuperclass()) == null) { - return null; - } - } - try { - Constructor cons = initCl.getDeclaredConstructor((Class<?>[]) null); - int mods = cons.getModifiers(); - if ((mods & Modifier.PRIVATE) != 0 || - ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 && - !packageEquals(cl, initCl))) - { - return null; - } - cons = reflFactory.newConstructorForSerialization(cl, cons); - cons.setAccessible(true); - return cons; - } catch (NoSuchMethodException ex) { - return null; - } - } - - /** - * Returns non-static, non-abstract method with given signature provided it - * is defined by or accessible (via inheritance) by the given class, or - * null if no match found. Access checks are disabled on the returned - * method (if any). - */ - private static Method getInheritableMethod(Class<?> cl, String name, - Class<?>[] argTypes, - Class<?> returnType) - { - Method meth = null; - Class<?> defCl = cl; - while (defCl != null) { - try { - meth = defCl.getDeclaredMethod(name, argTypes); - break; - } catch (NoSuchMethodException ex) { - defCl = defCl.getSuperclass(); - } - } - - if ((meth == null) || (meth.getReturnType() != returnType)) { - return null; - } - meth.setAccessible(true); - int mods = meth.getModifiers(); - if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) { - return null; - } else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) { - return meth; - } else if ((mods & Modifier.PRIVATE) != 0) { - return (cl == defCl) ? meth : null; - } else { - return packageEquals(cl, defCl) ? meth : null; - } - } - - /** - * Returns non-static private method with given signature defined by given - * class, or null if none found. Access checks are disabled on the - * returned method (if any). - */ - private static Method getPrivateMethod(Class<?> cl, String name, - Class<?>[] argTypes, - Class<?> returnType) - { - try { - Method meth = cl.getDeclaredMethod(name, argTypes); - meth.setAccessible(true); - int mods = meth.getModifiers(); - return ((meth.getReturnType() == returnType) && - ((mods & Modifier.STATIC) == 0) && - ((mods & Modifier.PRIVATE) != 0)) ? meth : null; - } catch (NoSuchMethodException ex) { - return null; - } - } - - /** - * Returns true if classes are defined in the same runtime package, false - * otherwise. - */ - private static boolean packageEquals(Class<?> cl1, Class<?> cl2) { - return (cl1.getClassLoader() == cl2.getClassLoader() && - getPackageName(cl1).equals(getPackageName(cl2))); - } - - /** - * Returns package name of given class. - */ - private static String getPackageName(Class<?> cl) { - String s = cl.getName(); - int i = s.lastIndexOf('['); - if (i >= 0) { - s = s.substring(i + 2); - } - i = s.lastIndexOf('.'); - return (i >= 0) ? s.substring(0, i) : ""; - } - - /** - * Compares class names for equality, ignoring package names. Returns true - * if class names equal, false otherwise. - */ - private static boolean classNamesEqual(String name1, String name2) { - name1 = name1.substring(name1.lastIndexOf('.') + 1); - name2 = name2.substring(name2.lastIndexOf('.') + 1); - return name1.equals(name2); - } - - /** - * Returns JVM type signature for given class. - */ - private static String getClassSignature(Class<?> cl) { - StringBuilder sbuf = new StringBuilder(); - while (cl.isArray()) { - sbuf.append('['); - cl = cl.getComponentType(); - } - if (cl.isPrimitive()) { - if (cl == Integer.TYPE) { - sbuf.append('I'); - } else if (cl == Byte.TYPE) { - sbuf.append('B'); - } else if (cl == Long.TYPE) { - sbuf.append('J'); - } else if (cl == Float.TYPE) { - sbuf.append('F'); - } else if (cl == Double.TYPE) { - sbuf.append('D'); - } else if (cl == Short.TYPE) { - sbuf.append('S'); - } else if (cl == Character.TYPE) { - sbuf.append('C'); - } else if (cl == Boolean.TYPE) { - sbuf.append('Z'); - } else if (cl == Void.TYPE) { - sbuf.append('V'); - } else { - throw new InternalError(); - } - } else { - sbuf.append('L' + cl.getName().replace('.', '/') + ';'); - } - return sbuf.toString(); - } - - /** - * Returns JVM type signature for given list of parameters and return type. - */ - private static String getMethodSignature(Class<?>[] paramTypes, - Class<?> retType) - { - StringBuilder sbuf = new StringBuilder(); - sbuf.append('('); - for (int i = 0; i < paramTypes.length; i++) { - sbuf.append(getClassSignature(paramTypes[i])); - } - sbuf.append(')'); - sbuf.append(getClassSignature(retType)); - return sbuf.toString(); - } - - /** - * Convenience method for throwing an exception that is either a - * RuntimeException, Error, or of some unexpected type (in which case it is - * wrapped inside an IOException). - */ - private static void throwMiscException(Throwable th) throws IOException { - if (th instanceof RuntimeException) { - throw (RuntimeException) th; - } else if (th instanceof Error) { - throw (Error) th; - } else { - IOException ex = new IOException("unexpected exception type"); - ex.initCause(th); - throw ex; - } - } - - /** - * Returns ObjectStreamField array describing the serializable fields of - * the given class. Serializable fields backed by an actual field of the - * class are represented by ObjectStreamFields with corresponding non-null - * Field objects. Throws InvalidClassException if the (explicitly - * declared) serializable fields are invalid. - */ - private static ObjectStreamField[] getSerialFields(Class<?> cl) - throws InvalidClassException - { - ObjectStreamField[] fields; - if (Serializable.class.isAssignableFrom(cl) && - !Externalizable.class.isAssignableFrom(cl) && - !Proxy.isProxyClass(cl) && - !cl.isInterface()) - { - if ((fields = getDeclaredSerialFields(cl)) == null) { - fields = getDefaultSerialFields(cl); - } - Arrays.sort(fields); - } else { - fields = NO_FIELDS; - } - return fields; - } - - /** - * Returns serializable fields of given class as defined explicitly by a - * "serialPersistentFields" field, or null if no appropriate - * "serialPersistentFields" field is defined. Serializable fields backed - * by an actual field of the class are represented by ObjectStreamFields - * with corresponding non-null Field objects. For compatibility with past - * releases, a "serialPersistentFields" field with a null value is - * considered equivalent to not declaring "serialPersistentFields". Throws - * InvalidClassException if the declared serializable fields are - * invalid--e.g., if multiple fields share the same name. - */ - private static ObjectStreamField[] getDeclaredSerialFields(Class<?> cl) - throws InvalidClassException - { - ObjectStreamField[] serialPersistentFields = null; - try { - Field f = cl.getDeclaredField("serialPersistentFields"); - int mask = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL; - if ((f.getModifiers() & mask) == mask) { - f.setAccessible(true); - serialPersistentFields = (ObjectStreamField[]) f.get(null); - } - } catch (Exception ex) { - } - if (serialPersistentFields == null) { - return null; - } else if (serialPersistentFields.length == 0) { - return NO_FIELDS; - } - - ObjectStreamField[] boundFields = - new ObjectStreamField[serialPersistentFields.length]; - Set<String> fieldNames = new HashSet<>(serialPersistentFields.length); - - for (int i = 0; i < serialPersistentFields.length; i++) { - ObjectStreamField spf = serialPersistentFields[i]; - - String fname = spf.getName(); - if (fieldNames.contains(fname)) { - throw new InvalidClassException( - "multiple serializable fields named " + fname); - } - fieldNames.add(fname); - - try { - Field f = cl.getDeclaredField(fname); - if ((f.getType() == spf.getType()) && - ((f.getModifiers() & Modifier.STATIC) == 0)) - { - boundFields[i] = - new ObjectStreamField(f, spf.isUnshared(), true); - } - } catch (NoSuchFieldException ex) { - } - if (boundFields[i] == null) { - boundFields[i] = new ObjectStreamField( - fname, spf.getType(), spf.isUnshared()); - } - } - return boundFields; - } - - /** - * Returns array of ObjectStreamFields corresponding to all non-static - * non-transient fields declared by given class. Each ObjectStreamField - * contains a Field object for the field it represents. If no default - * serializable fields exist, NO_FIELDS is returned. - */ - private static ObjectStreamField[] getDefaultSerialFields(Class<?> cl) { - Field[] clFields = cl.getDeclaredFields(); - ArrayList<ObjectStreamField> list = new ArrayList<>(); - int mask = Modifier.STATIC | Modifier.TRANSIENT; - - for (int i = 0; i < clFields.length; i++) { - if ((clFields[i].getModifiers() & mask) == 0) { - list.add(new ObjectStreamField(clFields[i], false, true)); - } - } - int size = list.size(); - return (size == 0) ? NO_FIELDS : - list.toArray(new ObjectStreamField[size]); - } - - /** - * Returns explicit serial version UID value declared by given class, or - * null if none. - */ - private static Long getDeclaredSUID(Class<?> cl) { - try { - Field f = cl.getDeclaredField("serialVersionUID"); - int mask = Modifier.STATIC | Modifier.FINAL; - if ((f.getModifiers() & mask) == mask) { - f.setAccessible(true); - return Long.valueOf(f.getLong(null)); - } - } catch (Exception ex) { - } - return null; - } - - /** - * Computes the default serial version UID value for the given class. - */ - private static long computeDefaultSUID(Class<?> cl) { - if (!Serializable.class.isAssignableFrom(cl) || Proxy.isProxyClass(cl)) - { - return 0L; - } - - try { - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - DataOutputStream dout = new DataOutputStream(bout); - - dout.writeUTF(cl.getName()); - - int classMods = cl.getModifiers() & - (Modifier.PUBLIC | Modifier.FINAL | - Modifier.INTERFACE | Modifier.ABSTRACT); - - /* - * compensate for javac bug in which ABSTRACT bit was set for an - * interface only if the interface declared methods - */ - Method[] methods = cl.getDeclaredMethods(); - if ((classMods & Modifier.INTERFACE) != 0) { - classMods = (methods.length > 0) ? - (classMods | Modifier.ABSTRACT) : - (classMods & ~Modifier.ABSTRACT); - } - dout.writeInt(classMods); - - if (!cl.isArray()) { - /* - * compensate for change in 1.2FCS in which - * Class.getInterfaces() was modified to return Cloneable and - * Serializable for array classes. - */ - Class<?>[] interfaces = cl.getInterfaces(); - String[] ifaceNames = new String[interfaces.length]; - for (int i = 0; i < interfaces.length; i++) { - ifaceNames[i] = interfaces[i].getName(); - } - Arrays.sort(ifaceNames); - for (int i = 0; i < ifaceNames.length; i++) { - dout.writeUTF(ifaceNames[i]); - } - } - - Field[] fields = cl.getDeclaredFields(); - MemberSignature[] fieldSigs = new MemberSignature[fields.length]; - for (int i = 0; i < fields.length; i++) { - fieldSigs[i] = new MemberSignature(fields[i]); - } - Arrays.sort(fieldSigs, new Comparator<MemberSignature>() { - public int compare(MemberSignature ms1, MemberSignature ms2) { - return ms1.name.compareTo(ms2.name); - } - }); - for (int i = 0; i < fieldSigs.length; i++) { - MemberSignature sig = fieldSigs[i]; - int mods = sig.member.getModifiers() & - (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | - Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE | - Modifier.TRANSIENT); - if (((mods & Modifier.PRIVATE) == 0) || - ((mods & (Modifier.STATIC | Modifier.TRANSIENT)) == 0)) - { - dout.writeUTF(sig.name); - dout.writeInt(mods); - dout.writeUTF(sig.signature); - } - } - - if (hasStaticInitializer(cl)) { - dout.writeUTF("<clinit>"); - dout.writeInt(Modifier.STATIC); - dout.writeUTF("()V"); - } - - Constructor[] cons = cl.getDeclaredConstructors(); - MemberSignature[] consSigs = new MemberSignature[cons.length]; - for (int i = 0; i < cons.length; i++) { - consSigs[i] = new MemberSignature(cons[i]); - } - Arrays.sort(consSigs, new Comparator<MemberSignature>() { - public int compare(MemberSignature ms1, MemberSignature ms2) { - return ms1.signature.compareTo(ms2.signature); - } - }); - for (int i = 0; i < consSigs.length; i++) { - MemberSignature sig = consSigs[i]; - int mods = sig.member.getModifiers() & - (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | - Modifier.STATIC | Modifier.FINAL | - Modifier.SYNCHRONIZED | Modifier.NATIVE | - Modifier.ABSTRACT | Modifier.STRICT); - if ((mods & Modifier.PRIVATE) == 0) { - dout.writeUTF("<init>"); - dout.writeInt(mods); - dout.writeUTF(sig.signature.replace('/', '.')); - } - } - - MemberSignature[] methSigs = new MemberSignature[methods.length]; - for (int i = 0; i < methods.length; i++) { - methSigs[i] = new MemberSignature(methods[i]); - } - Arrays.sort(methSigs, new Comparator<MemberSignature>() { - public int compare(MemberSignature ms1, MemberSignature ms2) { - int comp = ms1.name.compareTo(ms2.name); - if (comp == 0) { - comp = ms1.signature.compareTo(ms2.signature); - } - return comp; - } - }); - for (int i = 0; i < methSigs.length; i++) { - MemberSignature sig = methSigs[i]; - int mods = sig.member.getModifiers() & - (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | - Modifier.STATIC | Modifier.FINAL | - Modifier.SYNCHRONIZED | Modifier.NATIVE | - Modifier.ABSTRACT | Modifier.STRICT); - if ((mods & Modifier.PRIVATE) == 0) { - dout.writeUTF(sig.name); - dout.writeInt(mods); - dout.writeUTF(sig.signature.replace('/', '.')); - } - } - - dout.flush(); - - MessageDigest md = MessageDigest.getInstance("SHA"); - byte[] hashBytes = md.digest(bout.toByteArray()); - long hash = 0; - for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) { - hash = (hash << 8) | (hashBytes[i] & 0xFF); - } - return hash; - } catch (IOException ex) { - throw new InternalError(); - } catch (NoSuchAlgorithmException ex) { - throw new SecurityException(ex.getMessage()); - } - } - - /** - * Returns true if the given class defines a static initializer method, - * false otherwise. - */ - private native static boolean hasStaticInitializer(Class<?> cl); - - /** - * Class for computing and caching field/constructor/method signatures - * during serialVersionUID calculation. - */ - private static class MemberSignature { - - public final Member member; - public final String name; - public final String signature; - - public MemberSignature(Field field) { - member = field; - name = field.getName(); - signature = getClassSignature(field.getType()); - } - - public MemberSignature(Constructor cons) { - member = cons; - name = cons.getName(); - signature = getMethodSignature( - cons.getParameterTypes(), Void.TYPE); - } - - public MemberSignature(Method meth) { - member = meth; - name = meth.getName(); - signature = getMethodSignature( - meth.getParameterTypes(), meth.getReturnType()); - } - } - - /** - * Class for setting and retrieving serializable field values in batch. - */ - // REMIND: dynamically generate these? - private static class FieldReflector extends FieldReflectorBase { - - /** handle for performing unsafe operations */ - private static final Unsafe unsafe = Unsafe.getUnsafe(); - - /** fields to operate on */ - private final ObjectStreamField[] fields; - /** number of primitive fields */ - private final int numPrimFields; - /** unsafe field keys for reading fields - may contain dupes */ - private final long[] readKeys; - /** unsafe fields keys for writing fields - no dupes */ - private final long[] writeKeys; - /** field data offsets */ - private final int[] offsets; - /** field type codes */ - private final char[] typeCodes; - /** field types */ - private final Class<?>[] types; - - /** - * Constructs FieldReflector capable of setting/getting values from the - * subset of fields whose ObjectStreamFields contain non-null - * reflective Field objects. ObjectStreamFields with null Fields are - * treated as filler, for which get operations return default values - * and set operations discard given values. - */ - FieldReflector(ObjectStreamField[] fields) { - this.fields = fields; - int nfields = fields.length; - readKeys = new long[nfields]; - writeKeys = new long[nfields]; - offsets = new int[nfields]; - typeCodes = new char[nfields]; - ArrayList<Class<?>> typeList = new ArrayList<>(); - Set<Long> usedKeys = new HashSet<>(); - - - for (int i = 0; i < nfields; i++) { - ObjectStreamField f = fields[i]; - Field rf = f.getField(); - long key = (rf != null) ? - unsafe.objectFieldOffset(rf) : Unsafe.INVALID_FIELD_OFFSET; - readKeys[i] = key; - writeKeys[i] = usedKeys.add(key) ? - key : Unsafe.INVALID_FIELD_OFFSET; - offsets[i] = f.getOffset(); - typeCodes[i] = f.getTypeCode(); - if (!f.isPrimitive()) { - typeList.add((rf != null) ? rf.getType() : null); - } - } - - types = typeList.toArray(new Class<?>[typeList.size()]); - numPrimFields = nfields - types.length; - } - - /** - * Returns list of ObjectStreamFields representing fields operated on - * by this reflector. The shared/unshared values and Field objects - * contained by ObjectStreamFields in the list reflect their bindings - * to locally defined serializable fields. - */ - public ObjectStreamField[] getFields() { - return fields; - } - - /** - * Fetches the serializable primitive field values of object obj and - * marshals them into byte array buf starting at offset 0. The caller - * is responsible for ensuring that obj is of the proper type. - */ - public void getPrimFieldValues(Object obj, byte[] buf) { - if (obj == null) { - throw new NullPointerException(); - } - /* assuming checkDefaultSerialize() has been called on the class - * descriptor this FieldReflector was obtained from, no field keys - * in array should be equal to Unsafe.INVALID_FIELD_OFFSET. - */ - for (int i = 0; i < numPrimFields; i++) { - long key = readKeys[i]; - int off = offsets[i]; - switch (typeCodes[i]) { - case 'Z': - Bits.putBoolean(buf, off, unsafe.getBoolean(obj, key)); - break; - - case 'B': - buf[off] = unsafe.getByte(obj, key); - break; - - case 'C': - Bits.putChar(buf, off, unsafe.getChar(obj, key)); - break; - - case 'S': - Bits.putShort(buf, off, unsafe.getShort(obj, key)); - break; - - case 'I': - Bits.putInt(buf, off, unsafe.getInt(obj, key)); - break; - - case 'F': - Bits.putFloat(buf, off, unsafe.getFloat(obj, key)); - break; - - case 'J': - Bits.putLong(buf, off, unsafe.getLong(obj, key)); - break; - - case 'D': - Bits.putDouble(buf, off, unsafe.getDouble(obj, key)); - break; - - default: - throw new InternalError(); - } - } - } - - /** - * Sets the serializable primitive fields of object obj using values - * unmarshalled from byte array buf starting at offset 0. The caller - * is responsible for ensuring that obj is of the proper type. - */ - public void setPrimFieldValues(Object obj, byte[] buf) { - if (obj == null) { - throw new NullPointerException(); - } - for (int i = 0; i < numPrimFields; i++) { - long key = writeKeys[i]; - if (key == Unsafe.INVALID_FIELD_OFFSET) { - continue; // discard value - } - int off = offsets[i]; - switch (typeCodes[i]) { - case 'Z': - unsafe.putBoolean(obj, key, Bits.getBoolean(buf, off)); - break; - - case 'B': - unsafe.putByte(obj, key, buf[off]); - break; - - case 'C': - unsafe.putChar(obj, key, Bits.getChar(buf, off)); - break; - - case 'S': - unsafe.putShort(obj, key, Bits.getShort(buf, off)); - break; - - case 'I': - unsafe.putInt(obj, key, Bits.getInt(buf, off)); - break; - - case 'F': - unsafe.putFloat(obj, key, Bits.getFloat(buf, off)); - break; - - case 'J': - unsafe.putLong(obj, key, Bits.getLong(buf, off)); - break; - - case 'D': - unsafe.putDouble(obj, key, Bits.getDouble(buf, off)); - break; - - default: - throw new InternalError(); - } - } - } - - /** - * Fetches the serializable object field values of object obj and - * stores them in array vals starting at offset 0. The caller is - * responsible for ensuring that obj is of the proper type. - */ - public void getObjFieldValues(Object obj, Object[] vals) { - if (obj == null) { - throw new NullPointerException(); - } - /* assuming checkDefaultSerialize() has been called on the class - * descriptor this FieldReflector was obtained from, no field keys - * in array should be equal to Unsafe.INVALID_FIELD_OFFSET. - */ - for (int i = numPrimFields; i < fields.length; i++) { - switch (typeCodes[i]) { - case 'L': - case '[': - vals[offsets[i]] = unsafe.getObject(obj, readKeys[i]); - break; - - default: - throw new InternalError(); - } - } - } - - /** - * Sets the serializable object fields of object obj using values from - * array vals starting at offset 0. The caller is responsible for - * ensuring that obj is of the proper type; however, attempts to set a - * field with a value of the wrong type will trigger an appropriate - * ClassCastException. - */ - public void setObjFieldValues(Object obj, Object[] vals) { - if (obj == null) { - throw new NullPointerException(); - } - for (int i = numPrimFields; i < fields.length; i++) { - long key = writeKeys[i]; - if (key == Unsafe.INVALID_FIELD_OFFSET) { - continue; // discard value - } - switch (typeCodes[i]) { - case 'L': - case '[': - Object val = vals[offsets[i]]; - if (val != null && - !types[i - numPrimFields].isInstance(val)) - { - Field f = fields[i].getField(); - throw new ClassCastException( - "cannot assign instance of " + - val.getClass().getName() + " to field " + - f.getDeclaringClass().getName() + "." + - f.getName() + " of type " + - f.getType().getName() + " in instance of " + - obj.getClass().getName()); - } - unsafe.putObject(obj, key, val); - break; - - default: - throw new InternalError(); - } - } - } - } - - /** - * Matches given set of serializable fields with serializable fields - * described by the given local class descriptor, and returns a - * FieldReflector instance capable of setting/getting values from the - * subset of fields that match (non-matching fields are treated as filler, - * for which get operations return default values and set operations - * discard given values). Throws InvalidClassException if unresolvable - * type conflicts exist between the two sets of fields. - */ - private static FieldReflectorBase getReflector(ObjectStreamField[] fields, - ObjectStreamClass localDesc) - throws InvalidClassException - { - // class irrelevant if no fields - Class<?> cl = (localDesc != null && fields.length > 0) ? - localDesc.cl : null; - processQueue(Caches.reflectorsQueue, Caches.reflectors); - FieldReflectorKey key = new FieldReflectorKey(cl, fields, - Caches.reflectorsQueue); - Reference<?> ref = Caches.reflectors.get(key); - Object entry = null; - if (ref != null) { - entry = ref.get(); - } - EntryFuture future = null; - if (entry == null) { - EntryFuture newEntry = new EntryFuture(); - Reference<?> newRef = new SoftReference<>(newEntry); - do { - if (ref != null) { - Caches.reflectors.remove(key, ref); - } - ref = Caches.reflectors.putIfAbsent(key, newRef); - if (ref != null) { - entry = ref.get(); - } - } while (ref != null && entry == null); - if (entry == null) { - future = newEntry; - } - } - - if (entry instanceof FieldReflectorBase) { // check common case first - return (FieldReflectorBase) entry; - } else if (entry instanceof EntryFuture) { - entry = ((EntryFuture) entry).get(); - } else if (entry == null) { - try { - ObjectStreamField[] matchedFields = matchFields(fields, localDesc); - entry = getFastFieldReflector(matchedFields); - if (entry == null) { - entry = new FieldReflector(matchedFields); - } - } catch (Throwable th) { - entry = th; - } - future.set(entry); - Caches.reflectors.put(key, new SoftReference<Object>(entry)); - } - - if (entry instanceof FieldReflectorBase) { - return (FieldReflectorBase) entry; - } else if (entry instanceof InvalidClassException) { - throw (InvalidClassException) entry; - } else if (entry instanceof RuntimeException) { - throw (RuntimeException) entry; - } else if (entry instanceof Error) { - throw (Error) entry; - } else { - throw new InternalError("unexpected entry: " + entry); - } - } - - private static native Object getFastFieldReflector(ObjectStreamField[] fields); - - /** - * FieldReflector cache lookup key. Keys are considered equal if they - * refer to the same class and equivalent field formats. - */ - private static class FieldReflectorKey extends WeakReference<Class<?>> { - - private final String sigs; - private final int hash; - private final boolean nullClass; - - FieldReflectorKey(Class<?> cl, ObjectStreamField[] fields, - ReferenceQueue<Class<?>> queue) - { - super(cl, queue); - nullClass = (cl == null); - StringBuilder sbuf = new StringBuilder(); - for (int i = 0; i < fields.length; i++) { - ObjectStreamField f = fields[i]; - sbuf.append(f.getName()).append(f.getSignature()); - } - sigs = sbuf.toString(); - hash = System.identityHashCode(cl) + sigs.hashCode(); - } - - public int hashCode() { - return hash; - } - - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - - if (obj instanceof FieldReflectorKey) { - FieldReflectorKey other = (FieldReflectorKey) obj; - Class<?> referent; - return (nullClass ? other.nullClass - : ((referent = get()) != null) && - (referent == other.get())) && - sigs.equals(other.sigs); - } else { - return false; - } - } - } - - /** - * Matches given set of serializable fields with serializable fields - * obtained from the given local class descriptor (which contain bindings - * to reflective Field objects). Returns list of ObjectStreamFields in - * which each ObjectStreamField whose signature matches that of a local - * field contains a Field object for that field; unmatched - * ObjectStreamFields contain null Field objects. Shared/unshared settings - * of the returned ObjectStreamFields also reflect those of matched local - * ObjectStreamFields. Throws InvalidClassException if unresolvable type - * conflicts exist between the two sets of fields. - */ - private static ObjectStreamField[] matchFields(ObjectStreamField[] fields, - ObjectStreamClass localDesc) - throws InvalidClassException - { - ObjectStreamField[] localFields = (localDesc != null) ? - localDesc.fields : NO_FIELDS; - - /* - * Even if fields == localFields, we cannot simply return localFields - * here. In previous implementations of serialization, - * ObjectStreamField.getType() returned Object.class if the - * ObjectStreamField represented a non-primitive field and belonged to - * a non-local class descriptor. To preserve this (questionable) - * behavior, the ObjectStreamField instances returned by matchFields - * cannot report non-primitive types other than Object.class; hence - * localFields cannot be returned directly. - */ - - ObjectStreamField[] matches = new ObjectStreamField[fields.length]; - for (int i = 0; i < fields.length; i++) { - ObjectStreamField f = fields[i], m = null; - for (int j = 0; j < localFields.length; j++) { - ObjectStreamField lf = localFields[j]; - if (f.getName().equals(lf.getName())) { - if ((f.isPrimitive() || lf.isPrimitive()) && - f.getTypeCode() != lf.getTypeCode()) - { - throw new InvalidClassException(localDesc.name, - "incompatible types for field " + f.getName()); - } - if (lf.getField() != null) { - m = new ObjectStreamField( - lf.getField(), lf.isUnshared(), false); - } else { - m = new ObjectStreamField( - lf.getName(), lf.getSignature(), lf.isUnshared()); - } - } - } - if (m == null) { - m = new ObjectStreamField( - f.getName(), f.getSignature(), false); - } - m.setOffset(f.getOffset()); - matches[i] = m; - } - return matches; - } - - /** - * Removes from the specified map any keys that have been enqueued - * on the specified reference queue. - */ - static void processQueue(ReferenceQueue<Class<?>> queue, - ConcurrentMap<? extends - WeakReference<Class<?>>, ?> map) - { - Reference<? extends Class<?>> ref; - while((ref = queue.poll()) != null) { - map.remove(ref); - } - } - - /** - * Weak key for Class objects. - * - **/ - static class WeakClassKey extends WeakReference<Class<?>> { - /** - * saved value of the referent's identity hash code, to maintain - * a consistent hash code after the referent has been cleared - */ - private final int hash; - - /** - * Create a new WeakClassKey to the given object, registered - * with a queue. - */ - WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) { - super(cl, refQueue); - hash = System.identityHashCode(cl); - } - - /** - * Returns the identity hash code of the original referent. - */ - public int hashCode() { - return hash; - } - - /** - * Returns true if the given object is this identical - * WeakClassKey instance, or, if this object's referent has not - * been cleared, if the given object is another WeakClassKey - * instance with the identical non-null referent as this one. - */ - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - - if (obj instanceof WeakClassKey) { - Object referent = get(); - return (referent != null) && - (referent == ((WeakClassKey) obj).get()); - } else { - return false; - } - } - } - - // [IKVM] interop serialization support - boolean isDynamicClass() { - return dynamicClass; - } - - private static native boolean isDynamicTypeWrapper(Class cl); - - // to force us to be resolved early (by the .NET deserialization engine) - // we implement readResolve() (which results in us implementing IObjectReference) - private Object readResolve() { - return this; - } -} diff --git a/openjdk/java/io/ObjectStreamField.java b/openjdk/java/io/ObjectStreamField.java deleted file mode 100644 index 1d7c2cdf..00000000 --- a/openjdk/java/io/ObjectStreamField.java +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Copyright (c) 1996, 2006, 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.lang.reflect.Field; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; -import sun.reflect.misc.ReflectUtil; - -/** - * A description of a Serializable field from a Serializable class. An array - * of ObjectStreamFields is used to declare the Serializable fields of a class. - * - * @author Mike Warres - * @author Roger Riggs - * @see ObjectStreamClass - * @since 1.2 - */ -public class ObjectStreamField - implements Comparable<Object> -{ - - /** field name */ - private final String name; - /** canonical JVM signature of field type */ - private String signature; - /** field type (Object.class if unknown non-primitive type) */ - private final Class<?> type; - /** whether or not to (de)serialize field values as unshared */ - private final boolean unshared; - /** corresponding reflective field object, if any */ - private final Field field; - /** offset of field value in enclosing field group */ - private int offset = 0; - - /** - * Create a Serializable field with the specified type. This field should - * be documented with a <code>serialField</code> tag. - * - * @param name the name of the serializable field - * @param type the <code>Class</code> object of the serializable field - */ - public ObjectStreamField(String name, Class<?> type) { - this(name, type, false); - } - - /** - * Creates an ObjectStreamField representing a serializable field with the - * given name and type. If unshared is false, values of the represented - * field are serialized and deserialized in the default manner--if the - * field is non-primitive, object values are serialized and deserialized as - * if they had been written and read by calls to writeObject and - * readObject. If unshared is true, values of the represented field are - * serialized and deserialized as if they had been written and read by - * calls to writeUnshared and readUnshared. - * - * @param name field name - * @param type field type - * @param unshared if false, write/read field values in the same manner - * as writeObject/readObject; if true, write/read in the same - * manner as writeUnshared/readUnshared - * @since 1.4 - */ - public ObjectStreamField(String name, Class<?> type, boolean unshared) { - if (name == null || type == null) { - throw new NullPointerException(); - } - this.name = name; - this.type = type; - this.unshared = unshared; - field = null; - } - - // [IKVM] added lazy signature computation, to avoid the reflection hit, unless we really need it - private void lazyInitSignature() { - if (signature == null) { - signature = getClassSignature(type).intern(); - } - } - - /** - * Creates an ObjectStreamField representing a field with the given name, - * signature and unshared setting. - */ - ObjectStreamField(String name, String signature, boolean unshared) { - if (name == null) { - throw new NullPointerException(); - } - this.name = name; - this.signature = signature.intern(); - this.unshared = unshared; - field = null; - - switch (signature.charAt(0)) { - case 'Z': type = Boolean.TYPE; break; - case 'B': type = Byte.TYPE; break; - case 'C': type = Character.TYPE; break; - case 'S': type = Short.TYPE; break; - case 'I': type = Integer.TYPE; break; - case 'J': type = Long.TYPE; break; - case 'F': type = Float.TYPE; break; - case 'D': type = Double.TYPE; break; - case 'L': - case '[': type = Object.class; break; - default: throw new IllegalArgumentException("illegal signature"); - } - } - - /** - * Creates an ObjectStreamField representing the given field with the - * specified unshared setting. For compatibility with the behavior of - * earlier serialization implementations, a "showType" parameter is - * necessary to govern whether or not a getType() call on this - * ObjectStreamField (if non-primitive) will return Object.class (as - * opposed to a more specific reference type). - */ - ObjectStreamField(Field field, boolean unshared, boolean showType) { - this.field = field; - this.unshared = unshared; - name = field.getName(); - Class<?> ftype = field.getType(); - type = (showType || ftype.isPrimitive()) ? ftype : Object.class; - signature = getClassSignature(ftype).intern(); - } - - /** - * Get the name of this field. - * - * @return a <code>String</code> representing the name of the serializable - * field - */ - public String getName() { - return name; - } - - /** - * Get the type of the field. If the type is non-primitive and this - * <code>ObjectStreamField</code> was obtained from a deserialized {@link - * ObjectStreamClass} instance, then <code>Object.class</code> is returned. - * Otherwise, the <code>Class</code> object for the type of the field is - * returned. - * - * @return a <code>Class</code> object representing the type of the - * serializable field - */ - @CallerSensitive - public Class<?> getType() { - if (System.getSecurityManager() != null) { - Class<?> caller = Reflection.getCallerClass(); - if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), type.getClassLoader())) { - ReflectUtil.checkPackageAccess(type); - } - } - return type; - } - - /** - * Returns character encoding of field type. The encoding is as follows: - * <blockquote><pre> - * B byte - * C char - * D double - * F float - * I int - * J long - * L class or interface - * S short - * Z boolean - * [ array - * </pre></blockquote> - * - * @return the typecode of the serializable field - */ - // REMIND: deprecate? - public char getTypeCode() { - lazyInitSignature(); - return signature.charAt(0); - } - - /** - * Return the JVM type signature. - * - * @return null if this field has a primitive type. - */ - // REMIND: deprecate? - public String getTypeString() { - lazyInitSignature(); - return isPrimitive() ? null : signature; - } - - /** - * Offset of field within instance data. - * - * @return the offset of this field - * @see #setOffset - */ - // REMIND: deprecate? - public int getOffset() { - return offset; - } - - /** - * Offset within instance data. - * - * @param offset the offset of the field - * @see #getOffset - */ - // REMIND: deprecate? - protected void setOffset(int offset) { - this.offset = offset; - } - - /** - * Return true if this field has a primitive type. - * - * @return true if and only if this field corresponds to a primitive type - */ - // REMIND: deprecate? - public boolean isPrimitive() { - lazyInitSignature(); - char tcode = signature.charAt(0); - return ((tcode != 'L') && (tcode != '[')); - } - - /** - * Returns boolean value indicating whether or not the serializable field - * represented by this ObjectStreamField instance is unshared. - * - * @since 1.4 - */ - public boolean isUnshared() { - return unshared; - } - - /** - * Compare this field with another <code>ObjectStreamField</code>. Return - * -1 if this is smaller, 0 if equal, 1 if greater. Types that are - * primitives are "smaller" than object types. If equal, the field names - * are compared. - */ - // REMIND: deprecate? - public int compareTo(Object obj) { - ObjectStreamField other = (ObjectStreamField) obj; - boolean isPrim = isPrimitive(); - if (isPrim != other.isPrimitive()) { - return isPrim ? -1 : 1; - } - return name.compareTo(other.name); - } - - /** - * Return a string that describes this field. - */ - public String toString() { - lazyInitSignature(); - return signature + ' ' + name; - } - - /** - * Returns field represented by this ObjectStreamField, or null if - * ObjectStreamField is not associated with an actual field. - */ - Field getField() { - return field; - } - - /** - * Returns JVM type signature of field (similar to getTypeString, except - * that signature strings are returned for primitive fields as well). - */ - String getSignature() { - lazyInitSignature(); - return signature; - } - - /** - * Returns JVM type signature for given class. - */ - private static String getClassSignature(Class<?> cl) { - StringBuilder sbuf = new StringBuilder(); - while (cl.isArray()) { - sbuf.append('['); - cl = cl.getComponentType(); - } - if (cl.isPrimitive()) { - if (cl == Integer.TYPE) { - sbuf.append('I'); - } else if (cl == Byte.TYPE) { - sbuf.append('B'); - } else if (cl == Long.TYPE) { - sbuf.append('J'); - } else if (cl == Float.TYPE) { - sbuf.append('F'); - } else if (cl == Double.TYPE) { - sbuf.append('D'); - } else if (cl == Short.TYPE) { - sbuf.append('S'); - } else if (cl == Character.TYPE) { - sbuf.append('C'); - } else if (cl == Boolean.TYPE) { - sbuf.append('Z'); - } else if (cl == Void.TYPE) { - sbuf.append('V'); - } else { - throw new InternalError(); - } - } else { - sbuf.append('L' + cl.getName().replace('.', '/') + ';'); - } - return sbuf.toString(); - } -} diff --git a/openjdk/java/io/RandomAccessFile.java b/openjdk/java/io/RandomAccessFile.java deleted file mode 100644 index 61fc27a7..00000000 --- a/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 <em>file pointer</em>; - * 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 - * <code>getFilePointer</code> method and set by the <code>seek</code> - * method. - * <p> - * 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 <code>EOFException</code> (which is a kind of - * <code>IOException</code>) is thrown. If any byte cannot be read for - * any reason other than end-of-file, an <code>IOException</code> other - * than <code>EOFException</code> is thrown. In particular, an - * <code>IOException</code> 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. - * - * <p> The <tt>mode</tt> argument specifies the access mode with which the - * file is to be opened. The permitted values and their meanings are as - * specified for the <a - * href="#mode"><tt>RandomAccessFile(File,String)</tt></a> constructor. - * - * <p> - * If there is a security manager, its <code>checkRead</code> method - * is called with the <code>name</code> argument - * as its argument to see if read access to the file is allowed. - * If the mode allows writing, the security manager's - * <code>checkWrite</code> method - * is also called with the <code>name</code> argument - * as its argument to see if write access to the file is allowed. - * - * @param name the system-dependent filename - * @param mode the access <a href="#mode">mode</a> - * @exception IllegalArgumentException if the mode argument is not equal - * to one of <tt>"r"</tt>, <tt>"rw"</tt>, <tt>"rws"</tt>, or - * <tt>"rwd"</tt> - * @exception FileNotFoundException - * if the mode is <tt>"r"</tt> but the given string does not - * denote an existing regular file, or if the mode begins with - * <tt>"rw"</tt> 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 - * <code>checkRead</code> method denies read access to the file - * or the mode is "rw" and the security manager's - * <code>checkWrite</code> 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. - * - * <a name="mode"><p> The <tt>mode</tt> argument specifies the access mode - * in which the file is to be opened. The permitted values and their - * meanings are: - * - * <blockquote><table summary="Access mode permitted values and meanings"> - * <tr><th><p align="left">Value</p></th><th><p align="left">Meaning</p></th></tr> - * <tr><td valign="top"><tt>"r"</tt></td> - * <td> Open for reading only. Invoking any of the <tt>write</tt> - * methods of the resulting object will cause an {@link - * java.io.IOException} to be thrown. </td></tr> - * <tr><td valign="top"><tt>"rw"</tt></td> - * <td> Open for reading and writing. If the file does not already - * exist then an attempt will be made to create it. </td></tr> - * <tr><td valign="top"><tt>"rws"</tt></td> - * <td> Open for reading and writing, as with <tt>"rw"</tt>, and also - * require that every update to the file's content or metadata be - * written synchronously to the underlying storage device. </td></tr> - * <tr><td valign="top"><tt>"rwd" </tt></td> - * <td> Open for reading and writing, as with <tt>"rw"</tt>, and also - * require that every update to the file's content be written - * synchronously to the underlying storage device. </td></tr> - * </table></blockquote> - * - * The <tt>"rws"</tt> and <tt>"rwd"</tt> 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 - * <tt>true</tt> and <tt>false</tt>, 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. - * - * <p> The <tt>"rwd"</tt> mode can be used to reduce the number of I/O - * operations performed. Using <tt>"rwd"</tt> only requires updates to the - * file's content to be written to storage; using <tt>"rws"</tt> 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. - * - * <p> If there is a security manager, its <code>checkRead</code> method is - * called with the pathname of the <code>file</code> argument as its - * argument to see if read access to the file is allowed. If the mode - * allows writing, the security manager's <code>checkWrite</code> 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 - * <a href="#mode">above</a> - * @exception IllegalArgumentException if the mode argument is not equal - * to one of <tt>"r"</tt>, <tt>"rw"</tt>, <tt>"rws"</tt>, or - * <tt>"rwd"</tt> - * @exception FileNotFoundException - * if the mode is <tt>"r"</tt> but the given file object does - * not denote an existing regular file, or if the mode begins - * with <tt>"rw"</tt> 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 - * <code>checkRead</code> method denies read access to the file - * or the mode is "rw" and the security manager's - * <code>checkWrite</code> 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. </p> - * - * @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. - * - * <p> The {@link java.nio.channels.FileChannel#position() - * </code>position<code>} 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 <code>mode</code> - * is true, else the file is opened as read-only. - * If the <code>name</code> 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 (<code>0x00-0x0ff</code>). This - * method blocks if no input is yet available. - * <p> - * Although <code>RandomAccessFile</code> is not a subclass of - * <code>InputStream</code>, this method behaves in exactly the same - * way as the {@link InputStream#read()} method of - * <code>InputStream</code>. - * - * @return the next byte of data, or <code>-1</code> 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 <code>len</code> bytes of data from this file into an - * array of bytes. This method blocks until at least one byte of input - * is available. - * <p> - * Although <code>RandomAccessFile</code> is not a subclass of - * <code>InputStream</code>, this method behaves in exactly the - * same way as the {@link InputStream#read(byte[], int, int)} method of - * <code>InputStream</code>. - * - * @param b the buffer into which the data is read. - * @param off the start offset in array <code>b</code> - * 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 - * <code>-1</code> 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 <code>b</code> is <code>null</code>. - * @exception IndexOutOfBoundsException If <code>off</code> is negative, - * <code>len</code> is negative, or <code>len</code> is greater than - * <code>b.length - off</code> - */ - public int read(byte b[], int off, int len) throws IOException { - return readBytes(b, off, len); - } - - /** - * Reads up to <code>b.length</code> bytes of data from this file - * into an array of bytes. This method blocks until at least one byte - * of input is available. - * <p> - * Although <code>RandomAccessFile</code> is not a subclass of - * <code>InputStream</code>, this method behaves in exactly the - * same way as the {@link InputStream#read(byte[])} method of - * <code>InputStream</code>. - * - * @param b the buffer into which the data is read. - * @return the total number of bytes read into the buffer, or - * <code>-1</code> 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 <code>b</code> is <code>null</code>. - */ - public int read(byte b[]) throws IOException { - return readBytes(b, 0, b.length); - } - - /** - * Reads <code>b.length</code> 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 <code>len</code> 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 <code>n</code> bytes of input discarding the - * skipped bytes. - * <p> - * - * 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 <code>n</code> bytes have been skipped is only one - * possibility. This method never throws an <code>EOFException</code>. - * The actual number of bytes skipped is returned. If <code>n</code> - * 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 <code>byte</code> 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 <code>b.length</code> 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 <code>len</code> bytes from the specified byte array - * starting at offset <code>off</code> 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 <code>pos</code> is less than - * <code>0</code> 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. - * - * <p> If the present length of the file as returned by the - * <code>length</code> method is greater than the <code>newLength</code> - * argument then the file will be truncated. In this case, if the file - * offset as returned by the <code>getFilePointer</code> method is greater - * than <code>newLength</code> then after this method returns the offset - * will be equal to <code>newLength</code>. - * - * <p> If the present length of the file as returned by the - * <code>length</code> method is smaller than the <code>newLength</code> - * 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. - * - * <p> 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 <code>boolean</code> from this file. This method reads a - * single byte from the file, starting at the current file pointer. - * A value of <code>0</code> represents - * <code>false</code>. Any other value represents <code>true</code>. - * This method blocks until the byte is read, the end of the stream - * is detected, or an exception is thrown. - * - * @return the <code>boolean</code> 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 <code>b</code>, where - * <code>0 <= b <= 255</code>, - * then the result is: - * <blockquote><pre> - * (byte)(b) - * </pre></blockquote> - * <p> - * 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 - * <code>byte</code>. - * @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. - * <p> - * 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 - * <code>b1</code> and <code>b2</code>, where each of the two values is - * between <code>0</code> and <code>255</code>, inclusive, then the - * result is equal to: - * <blockquote><pre> - * (short)((b1 << 8) | b2) - * </pre></blockquote> - * <p> - * 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 - * <code>b1</code> and <code>b2</code>, where - * <code>0 <= b1, b2 <= 255</code>, - * then the result is equal to: - * <blockquote><pre> - * (b1 << 8) | b2 - * </pre></blockquote> - * <p> - * 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 - * <code>b1</code> and <code>b2</code>, where - * <code>0 <= b1, b2 <= 255</code>, - * then the result is equal to: - * <blockquote><pre> - * (char)((b1 << 8) | b2) - * </pre></blockquote> - * <p> - * 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 - * <code>char</code>. - * @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 <code>b1</code>, - * <code>b2</code>, <code>b3</code>, and <code>b4</code>, where - * <code>0 <= b1, b2, b3, b4 <= 255</code>, - * then the result is equal to: - * <blockquote><pre> - * (b1 << 24) | (b2 << 16) + (b3 << 8) + b4 - * </pre></blockquote> - * <p> - * 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 - * <code>int</code>. - * @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 - * <code>b1</code>, <code>b2</code>, <code>b3</code>, - * <code>b4</code>, <code>b5</code>, <code>b6</code>, - * <code>b7</code>, and <code>b8,</code> where: - * <blockquote><pre> - * 0 <= b1, b2, b3, b4, b5, b6, b7, b8 <=255, - * </pre></blockquote> - * <p> - * then the result is equal to: - * <p><blockquote><pre> - * ((long)b1 << 56) + ((long)b2 << 48) - * + ((long)b3 << 40) + ((long)b4 << 32) - * + ((long)b5 << 24) + ((long)b6 << 16) - * + ((long)b7 << 8) + b8 - * </pre></blockquote> - * <p> - * 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 - * <code>long</code>. - * @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 <code>float</code> from this file. This method reads an - * <code>int</code> value, starting at the current file pointer, - * as if by the <code>readInt</code> method - * and then converts that <code>int</code> to a <code>float</code> - * using the <code>intBitsToFloat</code> method in class - * <code>Float</code>. - * <p> - * 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 - * <code>float</code>. - * @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 <code>double</code> from this file. This method reads a - * <code>long</code> value, starting at the current file pointer, - * as if by the <code>readLong</code> method - * and then converts that <code>long</code> to a <code>double</code> - * using the <code>longBitsToDouble</code> method in - * class <code>Double</code>. - * <p> - * 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 - * <code>double</code>. - * @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. - * - * <p> A line of text is terminated by a carriage-return character - * (<code>'\r'</code>), a newline character (<code>'\n'</code>), 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. - * - * <p> 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 - * <a href="DataInput.html#modified-utf-8">modified UTF-8</a> - * format. - * <p> - * The first two bytes are read, starting from the current file - * pointer, as if by - * <code>readUnsignedShort</code>. 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. - * <p> - * 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 <code>boolean</code> to the file as a one-byte value. The - * value <code>true</code> is written out as the value - * <code>(byte)1</code>; the value <code>false</code> is written out - * as the value <code>(byte)0</code>. The write starts at - * the current position of the file pointer. - * - * @param v a <code>boolean</code> 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 <code>byte</code> to the file as a one-byte value. The - * write starts at the current position of the file pointer. - * - * @param v a <code>byte</code> 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 <code>short</code> to the file as two bytes, high byte first. - * The write starts at the current position of the file pointer. - * - * @param v a <code>short</code> 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 <code>char</code> 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 <code>char</code> 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 <code>int</code> to the file as four bytes, high byte first. - * The write starts at the current position of the file pointer. - * - * @param v an <code>int</code> 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 <code>long</code> to the file as eight bytes, high byte first. - * The write starts at the current position of the file pointer. - * - * @param v a <code>long</code> 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 <code>int</code> using the - * <code>floatToIntBits</code> method in class <code>Float</code>, - * and then writes that <code>int</code> 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 <code>float</code> 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 <code>long</code> using the - * <code>doubleToLongBits</code> method in class <code>Double</code>, - * and then writes that <code>long</code> 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 <code>double</code> 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 - * <code>writeChar</code> method. The write starts at the current - * position of the file pointer. - * - * @param s a <code>String</code> 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 - * <a href="DataInput.html#modified-utf-8">modified UTF-8</a> - * encoding in a machine-independent manner. - * <p> - * First, two bytes are written to the file, starting at the - * current file pointer, as if by the - * <code>writeShort</code> 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/openjdk/java/lang/Class.java b/openjdk/java/lang/Class.java deleted file mode 100644 index 07fd7bd5..00000000 --- a/openjdk/java/lang/Class.java +++ /dev/null @@ -1,3601 +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.lang; - -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Array; -import java.lang.reflect.GenericArrayType; -import java.lang.reflect.GenericDeclaration; -import java.lang.reflect.Member; -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.lang.reflect.Type; -import java.lang.reflect.TypeVariable; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.AnnotatedType; -import java.lang.ref.SoftReference; -import java.io.InputStream; -import java.io.ObjectStreamField; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Set; -import java.util.Map; -import java.util.HashMap; -import java.util.Objects; -import sun.misc.Unsafe; -import sun.reflect.CallerSensitive; -import sun.reflect.ConstantPool; -import sun.reflect.Reflection; -import sun.reflect.ReflectionFactory; -import sun.reflect.generics.factory.CoreReflectionFactory; -import sun.reflect.generics.factory.GenericsFactory; -import sun.reflect.generics.repository.ClassRepository; -import sun.reflect.generics.repository.MethodRepository; -import sun.reflect.generics.repository.ConstructorRepository; -import sun.reflect.generics.scope.ClassScope; -import sun.security.util.SecurityConstants; -import java.lang.annotation.Annotation; -import java.lang.reflect.Proxy; -import sun.reflect.annotation.*; -import sun.reflect.misc.ReflectUtil; -import cli.System.Runtime.Serialization.IObjectReference; -import cli.System.Runtime.Serialization.SerializationException; -import cli.System.Runtime.Serialization.SerializationInfo; -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()); - } -} - -/** - * Instances of the class {@code Class} represent classes and - * interfaces in a running Java application. An enum is a kind of - * class and an annotation is a kind of interface. Every array also - * belongs to a class that is reflected as a {@code Class} object - * that is shared by all arrays with the same element type and number - * of dimensions. The primitive Java types ({@code boolean}, - * {@code byte}, {@code char}, {@code short}, - * {@code int}, {@code long}, {@code float}, and - * {@code double}), and the keyword {@code void} are also - * represented as {@code Class} objects. - * - * <p> {@code Class} has no public constructor. Instead {@code Class} - * objects are constructed automatically by the Java Virtual Machine as classes - * are loaded and by calls to the {@code defineClass} method in the class - * loader. - * - * <p> The following example uses a {@code Class} object to print the - * class name of an object: - * - * <blockquote><pre> - * void printClassName(Object obj) { - * System.out.println("The class of " + obj + - * " is " + obj.getClass().getName()); - * } - * </pre></blockquote> - * - * <p> It is also possible to get the {@code Class} object for a named - * type (or for void) using a class literal. See Section 15.8.2 of - * <cite>The Java™ Language Specification</cite>. - * For example: - * - * <blockquote> - * {@code System.out.println("The name of class Foo is: "+Foo.class.getName());} - * </blockquote> - * - * @param <T> the type of the class modeled by this {@code Class} - * object. For example, the type of {@code String.class} is {@code - * Class<String>}. Use {@code Class<?>} if the class being modeled is - * unknown. - * - * @author unascribed - * @see java.lang.ClassLoader#defineClass(byte[], int, int) - * @since JDK1.0 - */ -@cli.System.SerializableAttribute.Annotation -public final class Class<T> implements java.io.Serializable, - GenericDeclaration, - Type, - AnnotatedElement { - private static final int ANNOTATION= 0x00002000; - private static final int ENUM = 0x00004000; - private static final int SYNTHETIC = 0x00001000; - - // [IKVM] additional fields - java.security.ProtectionDomain pd; - Object[] signers; - - // For types that live in a static .NET assembly (i.e. ikvmc compiled or .NET types) - // this field contains the type (used for .NET serialization of Class objects). - // This field is also used by fast class literals to remember the type that can then - // lazily be resolved to the corresponding TypeWrapper. - // For dynamically loaded classes and primitives it is null. - final cli.System.Type type; - - /* - * Constructor. Only the Java Virtual Machine creates Class - * objects. - */ - private Class() - { - // this constructor is not used, but exists for compatibility - // (otherwise it would look as if this class doesn't have a constructor, which might break some code) - throw new InternalError(); - } - - @cli.IKVM.Attributes.HideFromJavaAttribute.Annotation - Class(cli.System.Type type) - { - this.type = type; - } - - // We use custom serialization, because we want to deserialize a via proxy that properly resolves the Class singletons. - // Note that we don't implement ISerializable in this source, but in map.xml to avoid it being visible to Java code. - // We don't have a security demand, because the information exposed is harmless. - @cli.IKVM.Attributes.HideFromJavaAttribute.Annotation - @cli.System.Security.SecurityCriticalAttribute.Annotation - public void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue("type", type); - info.AddValue("sig", type == null ? getSigName() : null); - info.SetType(ikvm.runtime.Util.getInstanceTypeFromClass(ClassSerializationProxy.class)); - } - - private native String getSigName(); - - // [IKVM] this provides an implicit conversion operator from System.Type to java.lang.Class - @cli.System.Runtime.CompilerServices.SpecialNameAttribute.Annotation - @cli.IKVM.Attributes.HideFromJavaAttribute.Annotation - public static Class op_Implicit(cli.System.Type type) - { - return ikvm.runtime.Util.getFriendlyClassFromType(type); - } - - /** - * Converts the object to a string. The string representation is the - * string "class" or "interface", followed by a space, and then by the - * fully qualified name of the class in the format returned by - * {@code getName}. If this {@code Class} object represents a - * primitive type, this method returns the name of the primitive type. If - * this {@code Class} object represents void this method returns - * "void". - * - * @return a string representation of this class object. - */ - public String toString() { - return (isInterface() ? "interface " : (isPrimitive() ? "" : "class ")) - + getName(); - } - - /** - * Returns a string describing this {@code Class}, including - * information about modifiers and type parameters. - * - * The string is formatted as a list of type modifiers, if any, - * followed by the kind of type (empty string for primitive types - * and {@code class}, {@code enum}, {@code interface}, or - * <code>@</code>{@code interface}, as appropriate), followed - * by the type's name, followed by an angle-bracketed - * comma-separated list of the type's type parameters, if any. - * - * A space is used to separate modifiers from one another and to - * separate any modifiers from the kind of type. The modifiers - * occur in canonical order. If there are no type parameters, the - * type parameter list is elided. - * - * <p>Note that since information about the runtime representation - * of a type is being generated, modifiers not present on the - * originating source code or illegal on the originating source - * code may be present. - * - * @return a string describing this {@code Class}, including - * information about modifiers and type parameters - * - * @since 1.8 - */ - public String toGenericString() { - if (isPrimitive()) { - return toString(); - } else { - StringBuilder sb = new StringBuilder(); - - // Class modifiers are a superset of interface modifiers - int modifiers = getModifiers() & Modifier.classModifiers(); - if (modifiers != 0) { - sb.append(Modifier.toString(modifiers)); - sb.append(' '); - } - - if (isAnnotation()) { - sb.append('@'); - } - if (isInterface()) { // Note: all annotation types are interfaces - sb.append("interface"); - } else { - if (isEnum()) - sb.append("enum"); - else - sb.append("class"); - } - sb.append(' '); - sb.append(getName()); - - TypeVariable<?>[] typeparms = getTypeParameters(); - if (typeparms.length > 0) { - boolean first = true; - sb.append('<'); - for(TypeVariable<?> typeparm: typeparms) { - if (!first) - sb.append(','); - sb.append(typeparm.getTypeName()); - first = false; - } - sb.append('>'); - } - - return sb.toString(); - } - } - - /** - * Returns the {@code Class} object associated with the class or - * interface with the given string name. Invoking this method is - * equivalent to: - * - * <blockquote> - * {@code Class.forName(className, true, currentLoader)} - * </blockquote> - * - * where {@code currentLoader} denotes the defining class loader of - * the current class. - * - * <p> For example, the following code fragment returns the - * runtime {@code Class} descriptor for the class named - * {@code java.lang.Thread}: - * - * <blockquote> - * {@code Class t = Class.forName("java.lang.Thread")} - * </blockquote> - * <p> - * A call to {@code forName("X")} causes the class named - * {@code X} to be initialized. - * - * @param className the fully qualified name of the desired class. - * @return the {@code Class} object for the class with the - * specified name. - * @exception LinkageError if the linkage fails - * @exception ExceptionInInitializerError if the initialization provoked - * by this method fails - * @exception ClassNotFoundException if the class cannot be located - */ - @CallerSensitive - public static Class<?> forName(String className) - throws ClassNotFoundException { - return forName0(className, true, - ClassLoader.getClassLoader(Reflection.getCallerClass())); - } - - - /** - * Returns the {@code Class} object associated with the class or - * interface with the given string name, using the given class loader. - * Given the fully qualified name for a class or interface (in the same - * format returned by {@code getName}) this method attempts to - * locate, load, and link the class or interface. The specified class - * loader is used to load the class or interface. If the parameter - * {@code loader} is null, the class is loaded through the bootstrap - * class loader. The class is initialized only if the - * {@code initialize} parameter is {@code true} and if it has - * not been initialized earlier. - * - * <p> If {@code name} denotes a primitive type or void, an attempt - * will be made to locate a user-defined class in the unnamed package whose - * name is {@code name}. Therefore, this method cannot be used to - * obtain any of the {@code Class} objects representing primitive - * types or void. - * - * <p> If {@code name} denotes an array class, the component type of - * the array class is loaded but not initialized. - * - * <p> For example, in an instance method the expression: - * - * <blockquote> - * {@code Class.forName("Foo")} - * </blockquote> - * - * is equivalent to: - * - * <blockquote> - * {@code Class.forName("Foo", true, this.getClass().getClassLoader())} - * </blockquote> - * - * Note that this method throws errors related to loading, linking or - * initializing as specified in Sections 12.2, 12.3 and 12.4 of <em>The - * Java Language Specification</em>. - * Note that this method does not check whether the requested class - * is accessible to its caller. - * - * <p> If the {@code loader} is {@code null}, and a security - * manager is present, and the caller's class loader is not null, then this - * method calls the security manager's {@code checkPermission} method - * with a {@code RuntimePermission("getClassLoader")} permission to - * ensure it's ok to access the bootstrap class loader. - * - * @param name fully qualified name of the desired class - * @param initialize if {@code true} the class will be initialized. - * See Section 12.4 of <em>The Java Language Specification</em>. - * @param loader class loader from which the class must be loaded - * @return class object representing the desired class - * - * @exception LinkageError if the linkage fails - * @exception ExceptionInInitializerError if the initialization provoked - * by this method fails - * @exception ClassNotFoundException if the class cannot be located by - * the specified class loader - * - * @see java.lang.Class#forName(String) - * @see java.lang.ClassLoader - * @since 1.2 - */ - @CallerSensitive - public static Class<?> forName(String name, boolean initialize, - ClassLoader loader) - throws ClassNotFoundException - { - if (sun.misc.VM.isSystemDomainLoader(loader)) { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - ClassLoader ccl = ClassLoader.getClassLoader(Reflection.getCallerClass()); - if (!sun.misc.VM.isSystemDomainLoader(ccl)) { - sm.checkPermission( - SecurityConstants.GET_CLASSLOADER_PERMISSION); - } - } - } - return forName0(name, initialize, loader); - } - - /** Called after security checks have been made. */ - private static native Class<?> forName0(String name, boolean initialize, - ClassLoader loader) - throws ClassNotFoundException; - - /** - * Creates a new instance of the class represented by this {@code Class} - * object. The class is instantiated as if by a {@code new} - * expression with an empty argument list. The class is initialized if it - * has not already been initialized. - * - * <p>Note that this method propagates any exception thrown by the - * nullary constructor, including a checked exception. Use of - * this method effectively bypasses the compile-time exception - * checking that would otherwise be performed by the compiler. - * The {@link - * java.lang.reflect.Constructor#newInstance(java.lang.Object...) - * Constructor.newInstance} method avoids this problem by wrapping - * any exception thrown by the constructor in a (checked) {@link - * java.lang.reflect.InvocationTargetException}. - * - * @return a newly allocated instance of the class represented by this - * object. - * @throws IllegalAccessException if the class or its nullary - * constructor is not accessible. - * @throws InstantiationException - * if this {@code Class} represents an abstract class, - * an interface, an array class, a primitive type, or void; - * or if the class has no nullary constructor; - * or if the instantiation fails for some other reason. - * @throws ExceptionInInitializerError if the initialization - * provoked by this method fails. - * @throws SecurityException - * If a security manager, <i>s</i>, is present and - * the caller's class loader is not the same as or an - * ancestor of the class loader for the current class and - * invocation of {@link SecurityManager#checkPackageAccess - * s.checkPackageAccess()} denies access to the package - * of this class. - */ - @CallerSensitive - public T newInstance() - throws InstantiationException, IllegalAccessException - { - if (System.getSecurityManager() != null) { - checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false); - } - - // NOTE: the following code may not be strictly correct under - // the current Java memory model. - - // Constructor lookup - if (cachedConstructor == null) { - if (this == Class.class) { - throw new IllegalAccessException( - "Can not call newInstance() on the Class for java.lang.Class" - ); - } - try { - Class<?>[] empty = {}; - final Constructor<T> c = getConstructor0(empty, Member.DECLARED); - // Disable accessibility checks on the constructor - // since we have to do the security check here anyway - // (the stack depth is wrong for the Constructor's - // security check to work) - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction<Void>() { - public Void run() { - c.setAccessible(true); - return null; - } - }); - cachedConstructor = c; - } catch (NoSuchMethodException e) { - throw (InstantiationException) - new InstantiationException(getName()).initCause(e); - } - } - Constructor<T> tmpConstructor = cachedConstructor; - // Security check (same as in java.lang.reflect.Constructor) - int modifiers = tmpConstructor.getModifiers(); - if (!Reflection.quickCheckMemberAccess(this, modifiers)) { - Class<?> caller = Reflection.getCallerClass(); - if (newInstanceCallerCache != caller) { - Reflection.ensureMemberAccess(caller, this, null, modifiers); - newInstanceCallerCache = caller; - } - } - // Run constructor - try { - return tmpConstructor.newInstance((Object[])null); - } catch (InvocationTargetException e) { - Unsafe.getUnsafe().throwException(e.getTargetException()); - // Not reached - return null; - } - } - private volatile transient Constructor<T> cachedConstructor; - private volatile transient Class<?> newInstanceCallerCache; - - - /** - * Determines if the specified {@code Object} is assignment-compatible - * with the object represented by this {@code Class}. This method is - * the dynamic equivalent of the Java language {@code instanceof} - * operator. The method returns {@code true} if the specified - * {@code Object} argument is non-null and can be cast to the - * reference type represented by this {@code Class} object without - * raising a {@code ClassCastException.} It returns {@code false} - * otherwise. - * - * <p> Specifically, if this {@code Class} object represents a - * declared class, this method returns {@code true} if the specified - * {@code Object} argument is an instance of the represented class (or - * of any of its subclasses); it returns {@code false} otherwise. If - * this {@code Class} object represents an array class, this method - * returns {@code true} if the specified {@code Object} argument - * can be converted to an object of the array class by an identity - * conversion or by a widening reference conversion; it returns - * {@code false} otherwise. If this {@code Class} object - * represents an interface, this method returns {@code true} if the - * class or any superclass of the specified {@code Object} argument - * implements this interface; it returns {@code false} otherwise. If - * this {@code Class} object represents a primitive type, this method - * returns {@code false}. - * - * @param obj the object to check - * @return true if {@code obj} is an instance of this class - * - * @since JDK1.1 - */ - public native boolean isInstance(Object obj); - - - /** - * Determines if the class or interface represented by this - * {@code Class} object is either the same as, or is a superclass or - * superinterface of, the class or interface represented by the specified - * {@code Class} parameter. It returns {@code true} if so; - * otherwise it returns {@code false}. If this {@code Class} - * object represents a primitive type, this method returns - * {@code true} if the specified {@code Class} parameter is - * exactly this {@code Class} object; otherwise it returns - * {@code false}. - * - * <p> Specifically, this method tests whether the type represented by the - * specified {@code Class} parameter can be converted to the type - * represented by this {@code Class} object via an identity conversion - * or via a widening reference conversion. See <em>The Java Language - * Specification</em>, sections 5.1.1 and 5.1.4 , for details. - * - * @param cls the {@code Class} object to be checked - * @return the {@code boolean} value indicating whether objects of the - * type {@code cls} can be assigned to objects of this class - * @exception NullPointerException if the specified Class parameter is - * null. - * @since JDK1.1 - */ - public native boolean isAssignableFrom(Class<?> cls); - - - /** - * Determines if the specified {@code Class} object represents an - * interface type. - * - * @return {@code true} if this object represents an interface; - * {@code false} otherwise. - */ - public native boolean isInterface(); - - - /** - * Determines if this {@code Class} object represents an array class. - * - * @return {@code true} if this object represents an array class; - * {@code false} otherwise. - * @since JDK1.1 - */ - public native boolean isArray(); - - - /** - * Determines if the specified {@code Class} object represents a - * primitive type. - * - * <p> There are nine predefined {@code Class} objects to represent - * the eight primitive types and void. These are created by the Java - * Virtual Machine, and have the same names as the primitive types that - * they represent, namely {@code boolean}, {@code byte}, - * {@code char}, {@code short}, {@code int}, - * {@code long}, {@code float}, and {@code double}. - * - * <p> These objects may only be accessed via the following public static - * final variables, and are the only {@code Class} objects for which - * this method returns {@code true}. - * - * @return true if and only if this class represents a primitive type - * - * @see java.lang.Boolean#TYPE - * @see java.lang.Character#TYPE - * @see java.lang.Byte#TYPE - * @see java.lang.Short#TYPE - * @see java.lang.Integer#TYPE - * @see java.lang.Long#TYPE - * @see java.lang.Float#TYPE - * @see java.lang.Double#TYPE - * @see java.lang.Void#TYPE - * @since JDK1.1 - */ - public native boolean isPrimitive(); - - /** - * Returns true if this {@code Class} object represents an annotation - * type. Note that if this method returns true, {@link #isInterface()} - * would also return true, as all annotation types are also interfaces. - * - * @return {@code true} if this class object represents an annotation - * type; {@code false} otherwise - * @since 1.5 - */ - public boolean isAnnotation() { - return (getModifiers() & ANNOTATION) != 0; - } - - /** - * Returns {@code true} if this class is a synthetic class; - * returns {@code false} otherwise. - * @return {@code true} if and only if this class is a synthetic class as - * defined by the Java Language Specification. - * @jls 13.1 The Form of a Binary - * @since 1.5 - */ - public boolean isSynthetic() { - return (getModifiers() & SYNTHETIC) != 0; - } - - /** - * Returns the name of the entity (class, interface, array class, - * primitive type, or void) represented by this {@code Class} object, - * as a {@code String}. - * - * <p> If this class object represents a reference type that is not an - * array type then the binary name of the class is returned, as specified - * by - * <cite>The Java™ Language Specification</cite>. - * - * <p> If this class object represents a primitive type or void, then the - * name returned is a {@code String} equal to the Java language - * keyword corresponding to the primitive type or void. - * - * <p> If this class object represents a class of arrays, then the internal - * form of the name consists of the name of the element type preceded by - * one or more '{@code [}' characters representing the depth of the array - * nesting. The encoding of element type names is as follows: - * - * <blockquote><table summary="Element types and encodings"> - * <tr><th> Element Type <th> <th> Encoding - * <tr><td> boolean <td> <td align=center> Z - * <tr><td> byte <td> <td align=center> B - * <tr><td> char <td> <td align=center> C - * <tr><td> class or interface - * <td> <td align=center> L<i>classname</i>; - * <tr><td> double <td> <td align=center> D - * <tr><td> float <td> <td align=center> F - * <tr><td> int <td> <td align=center> I - * <tr><td> long <td> <td align=center> J - * <tr><td> short <td> <td align=center> S - * </table></blockquote> - * - * <p> The class or interface name <i>classname</i> is the binary name of - * the class specified above. - * - * <p> Examples: - * <blockquote><pre> - * String.class.getName() - * returns "java.lang.String" - * byte.class.getName() - * returns "byte" - * (new Object[3]).getClass().getName() - * returns "[Ljava.lang.Object;" - * (new int[3][4][5][6][7][8][9]).getClass().getName() - * returns "[[[[[[[I" - * </pre></blockquote> - * - * @return the name of the class or interface - * represented by this object. - */ - public String getName() { - String name = this.name; - if (name == null) - this.name = name = getName0(); - return name; - } - - // cache the name to reduce the number of calls into the VM - private transient String name; - private native String getName0(); - - /** - * Returns the class loader for the class. Some implementations may use - * null to represent the bootstrap class loader. This method will return - * null in such implementations if this class was loaded by the bootstrap - * class loader. - * - * <p> If a security manager is present, and the caller's class loader is - * not null and the caller's class loader is not the same as or an ancestor of - * the class loader for the class whose class loader is requested, then - * this method calls the security manager's {@code checkPermission} - * method with a {@code RuntimePermission("getClassLoader")} - * permission to ensure it's ok to access the class loader for the class. - * - * <p>If this object - * represents a primitive type or void, null is returned. - * - * @return the class loader that loaded the class or interface - * represented by this object. - * @throws SecurityException - * if a security manager exists and its - * {@code checkPermission} method denies - * access to the class loader for the class. - * @see java.lang.ClassLoader - * @see SecurityManager#checkPermission - * @see java.lang.RuntimePermission - */ - @CallerSensitive - public ClassLoader getClassLoader() { - ClassLoader cl = getClassLoader0(); - if (cl == null) - return null; - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - ClassLoader.checkClassLoaderPermission(cl, Reflection.getCallerClass()); - } - return cl; - } - - // Package-private to allow ClassLoader access - native ClassLoader getClassLoader0(); - - - /** - * 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 java.lang.reflect.GenericSignatureFormatError if the generic - * signature of this generic declaration does not conform to - * the format specified in - * <cite>The Java™ Virtual Machine Specification</cite> - * @since 1.5 - */ - @SuppressWarnings("unchecked") - public TypeVariable<Class<T>>[] getTypeParameters() { - ClassRepository info = getGenericInfo(); - if (info != null) - return (TypeVariable<Class<T>>[])info.getTypeParameters(); - else - return (TypeVariable<Class<T>>[])new TypeVariable<?>[0]; - } - - - /** - * Returns the {@code Class} representing the superclass of the entity - * (class, interface, primitive type or void) represented by this - * {@code Class}. If this {@code Class} represents either the - * {@code Object} class, an interface, a primitive type, or void, then - * null is returned. If this object represents an array class then the - * {@code Class} object representing the {@code Object} class is - * returned. - * - * @return the superclass of the class represented by this object. - */ - public native Class<? super T> getSuperclass(); - - - /** - * Returns the {@code Type} representing the direct superclass of - * the entity (class, interface, primitive type or void) represented by - * this {@code Class}. - * - * <p>If the superclass is a parameterized type, the {@code Type} - * object returned must accurately reflect the actual type - * parameters used in the source code. The parameterized type - * representing the superclass is created if it had not been - * created before. See the declaration of {@link - * java.lang.reflect.ParameterizedType ParameterizedType} for the - * semantics of the creation process for parameterized types. If - * this {@code Class} represents either the {@code Object} - * class, an interface, a primitive type, or void, then null is - * returned. If this object represents an array class then the - * {@code Class} object representing the {@code Object} class is - * returned. - * - * @throws java.lang.reflect.GenericSignatureFormatError if the generic - * class signature does not conform to the format specified in - * <cite>The Java™ Virtual Machine Specification</cite> - * @throws TypeNotPresentException if the generic superclass - * refers to a non-existent type declaration - * @throws java.lang.reflect.MalformedParameterizedTypeException if the - * generic superclass refers to a parameterized type that cannot be - * instantiated for any reason - * @return the superclass of the class represented by this object - * @since 1.5 - */ - public Type getGenericSuperclass() { - ClassRepository info = getGenericInfo(); - if (info == null) { - return getSuperclass(); - } - - // Historical irregularity: - // Generic signature marks interfaces with superclass = Object - // but this API returns null for interfaces - if (isInterface()) { - return null; - } - - return info.getSuperclass(); - } - - /** - * Gets the package for this class. The class loader of this class is used - * to find the package. If the class was loaded by the bootstrap class - * loader the set of packages loaded from CLASSPATH is searched to find the - * package of the class. Null is returned if no package object was created - * by the class loader of this class. - * - * <p> Packages have attributes for versions and specifications only if the - * information was defined in the manifests that accompany the classes, and - * if the class loader created the package instance with the attributes - * from the manifest. - * - * @return the package of the class, or null if no package - * information is available from the archive or codebase. - */ - public Package getPackage() { - return Package.getPackage(this); - } - - - /** - * Determines the interfaces implemented by the class or interface - * represented by this object. - * - * <p> If this object represents a class, the return value is an array - * containing objects representing all interfaces implemented by the - * class. The order of the interface objects in the array corresponds to - * the order of the interface names in the {@code implements} clause - * of the declaration of the class represented by this object. For - * example, given the declaration: - * <blockquote> - * {@code class Shimmer implements FloorWax, DessertTopping { ... }} - * </blockquote> - * suppose the value of {@code s} is an instance of - * {@code Shimmer}; the value of the expression: - * <blockquote> - * {@code s.getClass().getInterfaces()[0]} - * </blockquote> - * is the {@code Class} object that represents interface - * {@code FloorWax}; and the value of: - * <blockquote> - * {@code s.getClass().getInterfaces()[1]} - * </blockquote> - * is the {@code Class} object that represents interface - * {@code DessertTopping}. - * - * <p> If this object represents an interface, the array contains objects - * representing all interfaces extended by the interface. The order of the - * interface objects in the array corresponds to the order of the interface - * names in the {@code extends} clause of the declaration of the - * interface represented by this object. - * - * <p> If this object represents a class or interface that implements no - * interfaces, the method returns an array of length 0. - * - * <p> If this object represents a primitive type or void, the method - * returns an array of length 0. - * - * <p> If this {@code Class} object represents an array type, the - * interfaces {@code Cloneable} and {@code java.io.Serializable} are - * returned in that order. - * - * @return an array of interfaces implemented by this class. - */ - public Class<?>[] getInterfaces() { - ReflectionData<T> rd = reflectionData(); - if (rd == null) { - // no cloning required - return getInterfaces0(); - } else { - Class<?>[] interfaces = rd.interfaces; - if (interfaces == null) { - interfaces = getInterfaces0(); - rd.interfaces = interfaces; - } - // defensively copy before handing over to user code - return interfaces.clone(); - } - } - - private native Class<?>[] getInterfaces0(); - - /** - * Returns the {@code Type}s representing the interfaces - * directly implemented by the class or interface represented by - * this object. - * - * <p>If a superinterface is a parameterized type, the - * {@code Type} object returned for it must accurately reflect - * the actual type parameters used in the source code. The - * parameterized type representing each superinterface is created - * if it had not been created before. See the declaration of - * {@link java.lang.reflect.ParameterizedType ParameterizedType} - * for the semantics of the creation process for parameterized - * types. - * - * <p> If this object represents a class, the return value is an - * array containing objects representing all interfaces - * implemented by the class. The order of the interface objects in - * the array corresponds to the order of the interface names in - * the {@code implements} clause of the declaration of the class - * represented by this object. In the case of an array class, the - * interfaces {@code Cloneable} and {@code Serializable} are - * returned in that order. - * - * <p>If this object represents an interface, the array contains - * objects representing all interfaces directly extended by the - * interface. The order of the interface objects in the array - * corresponds to the order of the interface names in the - * {@code extends} clause of the declaration of the interface - * represented by this object. - * - * <p>If this object represents a class or interface that - * implements no interfaces, the method returns an array of length - * 0. - * - * <p>If this object represents a primitive type or void, the - * method returns an array of length 0. - * - * @throws java.lang.reflect.GenericSignatureFormatError - * if the generic class signature does not conform to the format - * specified in - * <cite>The Java™ Virtual Machine Specification</cite> - * @throws TypeNotPresentException if any of the generic - * superinterfaces refers to a non-existent type declaration - * @throws java.lang.reflect.MalformedParameterizedTypeException - * if any of the generic superinterfaces refer to a parameterized - * type that cannot be instantiated for any reason - * @return an array of interfaces implemented by this class - * @since 1.5 - */ - public Type[] getGenericInterfaces() { - ClassRepository info = getGenericInfo(); - return (info == null) ? getInterfaces() : info.getSuperInterfaces(); - } - - - /** - * Returns the {@code Class} representing the component type of an - * array. If this class does not represent an array class this method - * returns null. - * - * @return the {@code Class} representing the component type of this - * class if this class is an array - * @see java.lang.reflect.Array - * @since JDK1.1 - */ - public native Class<?> getComponentType(); - - - /** - * Returns the Java language modifiers for this class or interface, encoded - * in an integer. The modifiers consist of the Java Virtual Machine's - * constants for {@code public}, {@code protected}, - * {@code private}, {@code final}, {@code static}, - * {@code abstract} and {@code interface}; they should be decoded - * using the methods of class {@code Modifier}. - * - * <p> If the underlying class is an array class, then its - * {@code public}, {@code private} and {@code protected} - * modifiers are the same as those of its component type. If this - * {@code Class} represents a primitive type or void, its - * {@code public} modifier is always {@code true}, and its - * {@code protected} and {@code private} modifiers are always - * {@code false}. If this object represents an array class, a - * primitive type or void, then its {@code final} modifier is always - * {@code true} and its interface modifier is always - * {@code false}. The values of its other modifiers are not determined - * by this specification. - * - * <p> The modifier encodings are defined in <em>The Java Virtual Machine - * Specification</em>, table 4.1. - * - * @return the {@code int} representing the modifiers for this class - * @see java.lang.reflect.Modifier - * @since JDK1.1 - */ - public native int getModifiers(); - - - /** - * Gets the signers of this class. - * - * @return the signers of this class, or null if there are no signers. In - * particular, this method returns null if this object represents - * a primitive type or void. - * @since JDK1.1 - */ - public native Object[] getSigners(); - - - /** - * Set the signers of this class. - */ - native void setSigners(Object[] signers); - - - /** - * If this {@code Class} object represents a local or anonymous - * class within a method, returns a {@link - * java.lang.reflect.Method Method} object representing the - * immediately enclosing method of the underlying class. Returns - * {@code null} otherwise. - * - * In particular, this method returns {@code null} if the underlying - * class is a local or anonymous class immediately enclosed by a type - * declaration, instance initializer or static initializer. - * - * @return the immediately enclosing method of the underlying class, if - * that class is a local or anonymous class; otherwise {@code null}. - * - * @throws SecurityException - * If a security manager, <i>s</i>, is present and any of the - * following conditions is met: - * - * <ul> - * - * <li> the caller's class loader is not the same as the - * class loader of the enclosing class and invocation of - * {@link SecurityManager#checkPermission - * s.checkPermission} method with - * {@code RuntimePermission("accessDeclaredMembers")} - * denies access to the methods within the enclosing class - * - * <li> the caller's class loader is not the same as or an - * ancestor of the class loader for the enclosing class and - * invocation of {@link SecurityManager#checkPackageAccess - * s.checkPackageAccess()} denies access to the package - * of the enclosing class - * - * </ul> - * @since 1.5 - */ - @CallerSensitive - public Method getEnclosingMethod() throws SecurityException { - EnclosingMethodInfo enclosingInfo = getEnclosingMethodInfo(); - - if (enclosingInfo == null) - return null; - else { - if (!enclosingInfo.isMethod()) - return null; - - MethodRepository typeInfo = MethodRepository.make(enclosingInfo.getDescriptor(), - getFactory()); - Class<?> returnType = toClass(typeInfo.getReturnType()); - Type [] parameterTypes = typeInfo.getParameterTypes(); - Class<?>[] parameterClasses = new Class<?>[parameterTypes.length]; - - // Convert Types to Classes; returned types *should* - // be class objects since the methodDescriptor's used - // don't have generics information - for(int i = 0; i < parameterClasses.length; i++) - parameterClasses[i] = toClass(parameterTypes[i]); - - // Perform access check - Class<?> enclosingCandidate = enclosingInfo.getEnclosingClass(); - enclosingCandidate.checkMemberAccess(Member.DECLARED, - Reflection.getCallerClass(), true); - /* - * Loop over all declared methods; match method name, - * number of and type of parameters, *and* return - * type. Matching return type is also necessary - * because of covariant returns, etc. - */ - for(Method m: enclosingCandidate.getDeclaredMethods()) { - if (m.getName().equals(enclosingInfo.getName()) ) { - Class<?>[] candidateParamClasses = m.getParameterTypes(); - if (candidateParamClasses.length == parameterClasses.length) { - boolean matches = true; - for(int i = 0; i < candidateParamClasses.length; i++) { - if (!candidateParamClasses[i].equals(parameterClasses[i])) { - matches = false; - break; - } - } - - if (matches) { // finally, check return type - if (m.getReturnType().equals(returnType) ) - return m; - } - } - } - } - - throw new InternalError("Enclosing method not found"); - } - } - - private native Object[] getEnclosingMethod0(); - - private EnclosingMethodInfo getEnclosingMethodInfo() { - Object[] enclosingInfo = getEnclosingMethod0(); - if (enclosingInfo == null) - return null; - else { - return new EnclosingMethodInfo(enclosingInfo); - } - } - - private final static class EnclosingMethodInfo { - private Class<?> enclosingClass; - private String name; - private String descriptor; - - private EnclosingMethodInfo(Object[] enclosingInfo) { - if (enclosingInfo.length != 3) - throw new InternalError("Malformed enclosing method information"); - try { - // The array is expected to have three elements: - - // the immediately enclosing class - enclosingClass = (Class<?>) enclosingInfo[0]; - assert(enclosingClass != null); - - // the immediately enclosing method or constructor's - // name (can be null). - name = (String) enclosingInfo[1]; - - // the immediately enclosing method or constructor's - // descriptor (null iff name is). - descriptor = (String) enclosingInfo[2]; - assert((name != null && descriptor != null) || name == descriptor); - } catch (ClassCastException cce) { - throw new InternalError("Invalid type in enclosing method information", cce); - } - } - - boolean isPartial() { - return enclosingClass == null || name == null || descriptor == null; - } - - boolean isConstructor() { return !isPartial() && "<init>".equals(name); } - - boolean isMethod() { return !isPartial() && !isConstructor() && !"<clinit>".equals(name); } - - Class<?> getEnclosingClass() { return enclosingClass; } - - String getName() { return name; } - - String getDescriptor() { return descriptor; } - - } - - private static Class<?> toClass(Type o) { - if (o instanceof GenericArrayType) - return Array.newInstance(toClass(((GenericArrayType)o).getGenericComponentType()), - 0) - .getClass(); - return (Class<?>)o; - } - - /** - * If this {@code Class} object represents a local or anonymous - * class within a constructor, returns a {@link - * java.lang.reflect.Constructor Constructor} object representing - * the immediately enclosing constructor of the underlying - * class. Returns {@code null} otherwise. In particular, this - * method returns {@code null} if the underlying class is a local - * or anonymous class immediately enclosed by a type declaration, - * instance initializer or static initializer. - * - * @return the immediately enclosing constructor of the underlying class, if - * that class is a local or anonymous class; otherwise {@code null}. - * @throws SecurityException - * If a security manager, <i>s</i>, is present and any of the - * following conditions is met: - * - * <ul> - * - * <li> the caller's class loader is not the same as the - * class loader of the enclosing class and invocation of - * {@link SecurityManager#checkPermission - * s.checkPermission} method with - * {@code RuntimePermission("accessDeclaredMembers")} - * denies access to the constructors within the enclosing class - * - * <li> the caller's class loader is not the same as or an - * ancestor of the class loader for the enclosing class and - * invocation of {@link SecurityManager#checkPackageAccess - * s.checkPackageAccess()} denies access to the package - * of the enclosing class - * - * </ul> - * @since 1.5 - */ - @CallerSensitive - public Constructor<?> getEnclosingConstructor() throws SecurityException { - EnclosingMethodInfo enclosingInfo = getEnclosingMethodInfo(); - - if (enclosingInfo == null) - return null; - else { - if (!enclosingInfo.isConstructor()) - return null; - - ConstructorRepository typeInfo = ConstructorRepository.make(enclosingInfo.getDescriptor(), - getFactory()); - Type [] parameterTypes = typeInfo.getParameterTypes(); - Class<?>[] parameterClasses = new Class<?>[parameterTypes.length]; - - // Convert Types to Classes; returned types *should* - // be class objects since the methodDescriptor's used - // don't have generics information - for(int i = 0; i < parameterClasses.length; i++) - parameterClasses[i] = toClass(parameterTypes[i]); - - // Perform access check - Class<?> enclosingCandidate = enclosingInfo.getEnclosingClass(); - enclosingCandidate.checkMemberAccess(Member.DECLARED, - Reflection.getCallerClass(), true); - /* - * Loop over all declared constructors; match number - * of and type of parameters. - */ - for(Constructor<?> c: enclosingCandidate.getDeclaredConstructors()) { - Class<?>[] candidateParamClasses = c.getParameterTypes(); - if (candidateParamClasses.length == parameterClasses.length) { - boolean matches = true; - for(int i = 0; i < candidateParamClasses.length; i++) { - if (!candidateParamClasses[i].equals(parameterClasses[i])) { - matches = false; - break; - } - } - - if (matches) - return c; - } - } - - throw new InternalError("Enclosing constructor not found"); - } - } - - - /** - * If the class or interface represented by this {@code Class} object - * is a member of another class, returns the {@code Class} object - * representing the class in which it was declared. This method returns - * null if this class or interface is not a member of any other class. If - * this {@code Class} object represents an array class, a primitive - * type, or void,then this method returns null. - * - * @return the declaring class for this class - * @throws SecurityException - * If a security manager, <i>s</i>, is present and the caller's - * class loader is not the same as or an ancestor of the class - * loader for the declaring class and invocation of {@link - * SecurityManager#checkPackageAccess s.checkPackageAccess()} - * denies access to the package of the declaring class - * @since JDK1.1 - */ - @CallerSensitive - public Class<?> getDeclaringClass() throws SecurityException { - final Class<?> candidate = getDeclaringClass0(); - - if (candidate != null) - candidate.checkPackageAccess( - ClassLoader.getClassLoader(Reflection.getCallerClass()), true); - return candidate; - } - - private native Class<?> getDeclaringClass0(); - - - /** - * Returns the immediately enclosing class of the underlying - * class. If the underlying class is a top level class this - * method returns {@code null}. - * @return the immediately enclosing class of the underlying class - * @exception SecurityException - * If a security manager, <i>s</i>, is present and the caller's - * class loader is not the same as or an ancestor of the class - * loader for the enclosing class and invocation of {@link - * SecurityManager#checkPackageAccess s.checkPackageAccess()} - * denies access to the package of the enclosing class - * @since 1.5 - */ - @CallerSensitive - public Class<?> getEnclosingClass() throws SecurityException { - // There are five kinds of classes (or interfaces): - // a) Top level classes - // b) Nested classes (static member classes) - // c) Inner classes (non-static member classes) - // d) Local classes (named classes declared within a method) - // e) Anonymous classes - - - // JVM Spec 4.8.6: A class must have an EnclosingMethod - // attribute if and only if it is a local class or an - // anonymous class. - EnclosingMethodInfo enclosingInfo = getEnclosingMethodInfo(); - Class<?> enclosingCandidate; - - if (enclosingInfo == null) { - // This is a top level or a nested class or an inner class (a, b, or c) - enclosingCandidate = getDeclaringClass(); - } else { - Class<?> enclosingClass = enclosingInfo.getEnclosingClass(); - // This is a local class or an anonymous class (d or e) - if (enclosingClass == this || enclosingClass == null) - throw new InternalError("Malformed enclosing method information"); - else - enclosingCandidate = enclosingClass; - } - - if (enclosingCandidate != null) - enclosingCandidate.checkPackageAccess( - ClassLoader.getClassLoader(Reflection.getCallerClass()), true); - return enclosingCandidate; - } - - /** - * Returns the simple name of the underlying class as given in the - * source code. Returns an empty string if the underlying class is - * anonymous. - * - * <p>The simple name of an array is the simple name of the - * component type with "[]" appended. In particular the simple - * name of an array whose component type is anonymous is "[]". - * - * @return the simple name of the underlying class - * @since 1.5 - */ - public String getSimpleName() { - if (isArray()) - return getComponentType().getSimpleName()+"[]"; - - String simpleName = getSimpleBinaryName(); - if (simpleName == null) { // top level class - simpleName = getName(); - return simpleName.substring(simpleName.lastIndexOf(".")+1); // strip the package name - } - // According to JLS3 "Binary Compatibility" (13.1) the binary - // name of non-package classes (not top level) is the binary - // name of the immediately enclosing class followed by a '$' followed by: - // (for nested and inner classes): the simple name. - // (for local classes): 1 or more digits followed by the simple name. - // (for anonymous classes): 1 or more digits. - - // Since getSimpleBinaryName() will strip the binary name of - // the immediatly enclosing class, we are now looking at a - // string that matches the regular expression "\$[0-9]*" - // followed by a simple name (considering the simple of an - // anonymous class to be the empty string). - - // Remove leading "\$[0-9]*" from the name - int length = simpleName.length(); - if (length < 1 || simpleName.charAt(0) != '$') - throw new InternalError("Malformed class name"); - int index = 1; - while (index < length && isAsciiDigit(simpleName.charAt(index))) - index++; - // Eventually, this is the empty string iff this is an anonymous class - return simpleName.substring(index); - } - - /** - * Return an informative string for the name of this type. - * - * @return an informative string for the name of this type - * @since 1.8 - */ - public String getTypeName() { - if (isArray()) { - try { - Class<?> cl = this; - int dimensions = 0; - while (cl.isArray()) { - dimensions++; - cl = cl.getComponentType(); - } - StringBuilder sb = new StringBuilder(); - sb.append(cl.getName()); - for (int i = 0; i < dimensions; i++) { - sb.append("[]"); - } - return sb.toString(); - } catch (Throwable e) { /*FALLTHRU*/ } - } - return getName(); - } - - /** - * Character.isDigit answers {@code true} to some non-ascii - * digits. This one does not. - */ - private static boolean isAsciiDigit(char c) { - return '0' <= c && c <= '9'; - } - - /** - * Returns the canonical name of the underlying class as - * defined by the Java Language Specification. Returns null if - * the underlying class does not have a canonical name (i.e., if - * it is a local or anonymous class or an array whose component - * type does not have a canonical name). - * @return the canonical name of the underlying class if it exists, and - * {@code null} otherwise. - * @since 1.5 - */ - public String getCanonicalName() { - if (isArray()) { - String canonicalName = getComponentType().getCanonicalName(); - if (canonicalName != null) - return canonicalName + "[]"; - else - return null; - } - if (isLocalOrAnonymousClass()) - return null; - Class<?> enclosingClass = getEnclosingClass(); - if (enclosingClass == null) { // top level class - return getName(); - } else { - String enclosingName = enclosingClass.getCanonicalName(); - if (enclosingName == null) - return null; - return enclosingName + "." + getSimpleName(); - } - } - - /** - * Returns {@code true} if and only if the underlying class - * is an anonymous class. - * - * @return {@code true} if and only if this class is an anonymous class. - * @since 1.5 - */ - public boolean isAnonymousClass() { - return "".equals(getSimpleName()); - } - - /** - * Returns {@code true} if and only if the underlying class - * is a local class. - * - * @return {@code true} if and only if this class is a local class. - * @since 1.5 - */ - public boolean isLocalClass() { - return isLocalOrAnonymousClass() && !isAnonymousClass(); - } - - /** - * Returns {@code true} if and only if the underlying class - * is a member class. - * - * @return {@code true} if and only if this class is a member class. - * @since 1.5 - */ - public boolean isMemberClass() { - return getSimpleBinaryName() != null && !isLocalOrAnonymousClass(); - } - - /** - * Returns the "simple binary name" of the underlying class, i.e., - * the binary name without the leading enclosing class name. - * Returns {@code null} if the underlying class is a top level - * class. - */ - private String getSimpleBinaryName() { - Class<?> enclosingClass = getEnclosingClass(); - if (enclosingClass == null) // top level class - return null; - // Otherwise, strip the enclosing class' name - try { - return getName().substring(enclosingClass.getName().length()); - } catch (IndexOutOfBoundsException ex) { - throw new InternalError("Malformed class name", ex); - } - } - - /** - * Returns {@code true} if this is a local class or an anonymous - * class. Returns {@code false} otherwise. - */ - private boolean isLocalOrAnonymousClass() { - // JVM Spec 4.8.6: A class must have an EnclosingMethod - // attribute if and only if it is a local class or an - // anonymous class. - return getEnclosingMethodInfo() != null; - } - - /** - * Returns an array containing {@code Class} objects representing all - * the public classes and interfaces that are members of the class - * represented by this {@code Class} object. This includes public - * class and interface members inherited from superclasses and public class - * and interface members declared by the class. This method returns an - * array of length 0 if this {@code Class} object has no public member - * classes or interfaces. This method also returns an array of length 0 if - * this {@code Class} object represents a primitive type, an array - * class, or void. - * - * @return the array of {@code Class} objects representing the public - * members of this class - * @throws SecurityException - * If a security manager, <i>s</i>, is present and - * the caller's class loader is not the same as or an - * ancestor of the class loader for the current class and - * invocation of {@link SecurityManager#checkPackageAccess - * s.checkPackageAccess()} denies access to the package - * of this class. - * - * @since JDK1.1 - */ - @CallerSensitive - public Class<?>[] getClasses() { - checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false); - - // Privileged so this implementation can look at DECLARED classes, - // something the caller might not have privilege to do. The code here - // is allowed to look at DECLARED classes because (1) it does not hand - // out anything other than public members and (2) public member access - // has already been ok'd by the SecurityManager. - - return java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction<Class<?>[]>() { - public Class<?>[] run() { - List<Class<?>> list = new ArrayList<>(); - Class<?> currentClass = Class.this; - while (currentClass != null) { - Class<?>[] members = currentClass.getDeclaredClasses(); - for (int i = 0; i < members.length; i++) { - if (Modifier.isPublic(members[i].getModifiers())) { - list.add(members[i]); - } - } - currentClass = currentClass.getSuperclass(); - } - return list.toArray(new Class<?>[0]); - } - }); - } - - - /** - * Returns an array containing {@code Field} objects reflecting all - * the accessible public fields of the class or interface represented by - * this {@code Class} object. - * - * <p> If this {@code Class} object represents a class or interface with no - * no accessible public fields, then this method returns an array of length - * 0. - * - * <p> If this {@code Class} object represents a class, then this method - * returns the public fields of the class and of all its superclasses. - * - * <p> If this {@code Class} object represents an interface, then this - * method returns the fields of the interface and of all its - * superinterfaces. - * - * <p> If this {@code Class} object represents an array type, a primitive - * type, or void, then this method returns an array of length 0. - * - * <p> The elements in the returned array are not sorted and are not in any - * particular order. - * - * @return the array of {@code Field} objects representing the - * public fields - * @throws SecurityException - * If a security manager, <i>s</i>, is present and - * the caller's class loader is not the same as or an - * ancestor of the class loader for the current class and - * invocation of {@link SecurityManager#checkPackageAccess - * s.checkPackageAccess()} denies access to the package - * of this class. - * - * @since JDK1.1 - * @jls 8.2 Class Members - * @jls 8.3 Field Declarations - */ - @CallerSensitive - public Field[] getFields() throws SecurityException { - checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); - return copyFields(privateGetPublicFields(null)); - } - - - /** - * Returns an array containing {@code Method} objects reflecting all the - * public methods of the class or interface represented by this {@code - * Class} object, including those declared by the class or interface and - * those inherited from superclasses and superinterfaces. - * - * <p> If this {@code Class} object represents a type that has multiple - * public methods with the same name and parameter types, but different - * return types, then the returned array has a {@code Method} object for - * each such method. - * - * <p> If this {@code Class} object represents a type with a class - * initialization method {@code <clinit>}, then the returned array does - * <em>not</em> have a corresponding {@code Method} object. - * - * <p> If this {@code Class} object represents an array type, then the - * returned array has a {@code Method} object for each of the public - * methods inherited by the array type from {@code Object}. It does not - * contain a {@code Method} object for {@code clone()}. - * - * <p> If this {@code Class} object represents an interface then the - * returned array does not contain any implicitly declared methods from - * {@code Object}. Therefore, if no methods are explicitly declared in - * this interface or any of its superinterfaces then the returned array - * has length 0. (Note that a {@code Class} object which represents a class - * always has public methods, inherited from {@code Object}.) - * - * <p> If this {@code Class} object represents a primitive type or void, - * then the returned array has length 0. - * - * <p> Static methods declared in superinterfaces of the class or interface - * represented by this {@code Class} object are not considered members of - * the class or interface. - * - * <p> The elements in the returned array are not sorted and are not in any - * particular order. - * - * @return the array of {@code Method} objects representing the - * public methods of this class - * @throws SecurityException - * If a security manager, <i>s</i>, is present and - * the caller's class loader is not the same as or an - * ancestor of the class loader for the current class and - * invocation of {@link SecurityManager#checkPackageAccess - * s.checkPackageAccess()} denies access to the package - * of this class. - * - * @jls 8.2 Class Members - * @jls 8.4 Method Declarations - * @since JDK1.1 - */ - @CallerSensitive - public Method[] getMethods() throws SecurityException { - checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); - return copyMethods(privateGetPublicMethods()); - } - - - /** - * Returns an array containing {@code Constructor} objects reflecting - * all the public constructors of the class represented by this - * {@code Class} object. An array of length 0 is returned if the - * class has no public constructors, or if the class is an array class, or - * if the class reflects a primitive type or void. - * - * Note that while this method returns an array of {@code - * Constructor<T>} objects (that is an array of constructors from - * this class), the return type of this method is {@code - * Constructor<?>[]} and <em>not</em> {@code Constructor<T>[]} as - * might be expected. This less informative return type is - * necessary since after being returned from this method, the - * array could be modified to hold {@code Constructor} objects for - * different classes, which would violate the type guarantees of - * {@code Constructor<T>[]}. - * - * @return the array of {@code Constructor} objects representing the - * public constructors of this class - * @throws SecurityException - * If a security manager, <i>s</i>, is present and - * the caller's class loader is not the same as or an - * ancestor of the class loader for the current class and - * invocation of {@link SecurityManager#checkPackageAccess - * s.checkPackageAccess()} denies access to the package - * of this class. - * - * @since JDK1.1 - */ - @CallerSensitive - public Constructor<?>[] getConstructors() throws SecurityException { - checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); - return copyConstructors(privateGetDeclaredConstructors(true)); - } - - - /** - * Returns a {@code Field} object that reflects the specified public member - * field of the class or interface represented by this {@code Class} - * object. The {@code name} parameter is a {@code String} specifying the - * simple name of the desired field. - * - * <p> The field to be reflected is determined by the algorithm that - * follows. Let C be the class or interface represented by this object: - * - * <OL> - * <LI> If C declares a public field with the name specified, that is the - * field to be reflected.</LI> - * <LI> If no field was found in step 1 above, this algorithm is applied - * recursively to each direct superinterface of C. The direct - * superinterfaces are searched in the order they were declared.</LI> - * <LI> If no field was found in steps 1 and 2 above, and C has a - * superclass S, then this algorithm is invoked recursively upon S. - * If C has no superclass, then a {@code NoSuchFieldException} - * is thrown.</LI> - * </OL> - * - * <p> If this {@code Class} object represents an array type, then this - * method does not find the {@code length} field of the array type. - * - * @param name the field name - * @return the {@code Field} object of this class specified by - * {@code name} - * @throws NoSuchFieldException if a field with the specified name is - * not found. - * @throws NullPointerException if {@code name} is {@code null} - * @throws SecurityException - * If a security manager, <i>s</i>, is present and - * the caller's class loader is not the same as or an - * ancestor of the class loader for the current class and - * invocation of {@link SecurityManager#checkPackageAccess - * s.checkPackageAccess()} denies access to the package - * of this class. - * - * @since JDK1.1 - * @jls 8.2 Class Members - * @jls 8.3 Field Declarations - */ - @CallerSensitive - public Field getField(String name) - throws NoSuchFieldException, SecurityException { - checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); - Field field = getField0(name); - if (field == null) { - throw new NoSuchFieldException(name); - } - return field; - } - - - /** - * Returns a {@code Method} object that reflects the specified public - * member method of the class or interface represented by this - * {@code Class} object. The {@code name} parameter is a - * {@code String} specifying the simple name of the desired method. The - * {@code parameterTypes} parameter is an array of {@code Class} - * objects that identify the method's formal parameter types, in declared - * order. If {@code parameterTypes} is {@code null}, it is - * treated as if it were an empty array. - * - * <p> If the {@code name} is "{@code <init>}" or "{@code <clinit>}" a - * {@code NoSuchMethodException} is raised. Otherwise, the method to - * be reflected is determined by the algorithm that follows. Let C be the - * class or interface represented by this object: - * <OL> - * <LI> C is searched for a <I>matching method</I>, as defined below. If a - * matching method is found, it is reflected.</LI> - * <LI> If no matching method is found by step 1 then: - * <OL TYPE="a"> - * <LI> If C is a class other than {@code Object}, then this algorithm is - * invoked recursively on the superclass of C.</LI> - * <LI> If C is the class {@code Object}, or if C is an interface, then - * the superinterfaces of C (if any) are searched for a matching - * method. If any such method is found, it is reflected.</LI> - * </OL></LI> - * </OL> - * - * <p> To find a matching method in a class or interface C: If C - * declares exactly one public method with the specified name and exactly - * the same formal parameter types, that is the method reflected. If more - * than one such method is found in C, and one of these methods has a - * return type that is more specific than any of the others, that method is - * reflected; otherwise one of the methods is chosen arbitrarily. - * - * <p>Note that there may be more than one matching method in a - * class because while the Java language forbids a class to - * declare multiple methods with the same signature but different - * return types, the Java virtual machine does not. This - * increased flexibility in the virtual machine can be used to - * implement various language features. For example, covariant - * returns can be implemented with {@linkplain - * java.lang.reflect.Method#isBridge bridge methods}; the bridge - * method and the method being overridden would have the same - * signature but different return types. - * - * <p> If this {@code Class} object represents an array type, then this - * method does not find the {@code clone()} method. - * - * <p> Static methods declared in superinterfaces of the class or interface - * represented by this {@code Class} object are not considered members of - * the class or interface. - * - * @param name the name of the method - * @param parameterTypes the list of parameters - * @return the {@code Method} object that matches the specified - * {@code name} and {@code parameterTypes} - * @throws NoSuchMethodException if a matching method is not found - * or if the name is "<init>"or "<clinit>". - * @throws NullPointerException if {@code name} is {@code null} - * @throws SecurityException - * If a security manager, <i>s</i>, is present and - * the caller's class loader is not the same as or an - * ancestor of the class loader for the current class and - * invocation of {@link SecurityManager#checkPackageAccess - * s.checkPackageAccess()} denies access to the package - * of this class. - * - * @jls 8.2 Class Members - * @jls 8.4 Method Declarations - * @since JDK1.1 - */ - @CallerSensitive - public Method getMethod(String name, Class<?>... parameterTypes) - throws NoSuchMethodException, SecurityException { - checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); - Method method = getMethod0(name, parameterTypes, true); - if (method == null) { - throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes)); - } - return method; - } - - - /** - * Returns a {@code Constructor} object that reflects the specified - * public constructor of the class represented by this {@code Class} - * object. The {@code parameterTypes} parameter is an array of - * {@code Class} objects that identify the constructor's formal - * parameter types, in declared order. - * - * If this {@code Class} object represents an inner class - * declared in a non-static context, the formal parameter types - * include the explicit enclosing instance as the first parameter. - * - * <p> The constructor to reflect is the public constructor of the class - * represented by this {@code Class} object whose formal parameter - * types match those specified by {@code parameterTypes}. - * - * @param parameterTypes the parameter array - * @return the {@code Constructor} object of the public constructor that - * matches the specified {@code parameterTypes} - * @throws NoSuchMethodException if a matching method is not found. - * @throws SecurityException - * If a security manager, <i>s</i>, is present and - * the caller's class loader is not the same as or an - * ancestor of the class loader for the current class and - * invocation of {@link SecurityManager#checkPackageAccess - * s.checkPackageAccess()} denies access to the package - * of this class. - * - * @since JDK1.1 - */ - @CallerSensitive - public Constructor<T> getConstructor(Class<?>... parameterTypes) - throws NoSuchMethodException, SecurityException { - checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); - return getConstructor0(parameterTypes, Member.PUBLIC); - } - - - /** - * Returns an array of {@code Class} objects reflecting all the - * classes and interfaces declared as members of the class represented by - * this {@code Class} object. This includes public, protected, default - * (package) access, and private classes and interfaces declared by the - * class, but excludes inherited classes and interfaces. This method - * returns an array of length 0 if the class declares no classes or - * interfaces as members, or if this {@code Class} object represents a - * primitive type, an array class, or void. - * - * @return the array of {@code Class} objects representing all the - * declared members of this class - * @throws SecurityException - * If a security manager, <i>s</i>, is present and any of the - * following conditions is met: - * - * <ul> - * - * <li> the caller's class loader is not the same as the - * class loader of this class and invocation of - * {@link SecurityManager#checkPermission - * s.checkPermission} method with - * {@code RuntimePermission("accessDeclaredMembers")} - * denies access to the declared classes within this class - * - * <li> the caller's class loader is not the same as or an - * ancestor of the class loader for the current class and - * invocation of {@link SecurityManager#checkPackageAccess - * s.checkPackageAccess()} denies access to the package - * of this class - * - * </ul> - * - * @since JDK1.1 - */ - @CallerSensitive - public Class<?>[] getDeclaredClasses() throws SecurityException { - checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), false); - return getDeclaredClasses0(); - } - - - /** - * Returns an array of {@code Field} objects reflecting all the fields - * declared by the class or interface represented by this - * {@code Class} object. This includes public, protected, default - * (package) access, and private fields, but excludes inherited fields. - * - * <p> If this {@code Class} object represents a class or interface with no - * declared fields, then this method returns an array of length 0. - * - * <p> If this {@code Class} object represents an array type, a primitive - * type, or void, then this method returns an array of length 0. - * - * <p> The elements in the returned array are not sorted and are not in any - * particular order. - * - * @return the array of {@code Field} objects representing all the - * declared fields of this class - * @throws SecurityException - * If a security manager, <i>s</i>, is present and any of the - * following conditions is met: - * - * <ul> - * - * <li> the caller's class loader is not the same as the - * class loader of this class and invocation of - * {@link SecurityManager#checkPermission - * s.checkPermission} method with - * {@code RuntimePermission("accessDeclaredMembers")} - * denies access to the declared fields within this class - * - * <li> the caller's class loader is not the same as or an - * ancestor of the class loader for the current class and - * invocation of {@link SecurityManager#checkPackageAccess - * s.checkPackageAccess()} denies access to the package - * of this class - * - * </ul> - * - * @since JDK1.1 - * @jls 8.2 Class Members - * @jls 8.3 Field Declarations - */ - @CallerSensitive - public Field[] getDeclaredFields() throws SecurityException { - checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); - return copyFields(privateGetDeclaredFields(false)); - } - - - /** - * - * Returns an array containing {@code Method} objects reflecting all the - * declared methods of the class or interface represented by this {@code - * Class} object, including public, protected, default (package) - * access, and private methods, but excluding inherited methods. - * - * <p> If this {@code Class} object represents a type that has multiple - * declared methods with the same name and parameter types, but different - * return types, then the returned array has a {@code Method} object for - * each such method. - * - * <p> If this {@code Class} object represents a type that has a class - * initialization method {@code <clinit>}, then the returned array does - * <em>not</em> have a corresponding {@code Method} object. - * - * <p> If this {@code Class} object represents a class or interface with no - * declared methods, then the returned array has length 0. - * - * <p> If this {@code Class} object represents an array type, a primitive - * type, or void, then the returned array has length 0. - * - * <p> The elements in the returned array are not sorted and are not in any - * particular order. - * - * @return the array of {@code Method} objects representing all the - * declared methods of this class - * @throws SecurityException - * If a security manager, <i>s</i>, is present and any of the - * following conditions is met: - * - * <ul> - * - * <li> the caller's class loader is not the same as the - * class loader of this class and invocation of - * {@link SecurityManager#checkPermission - * s.checkPermission} method with - * {@code RuntimePermission("accessDeclaredMembers")} - * denies access to the declared methods within this class - * - * <li> the caller's class loader is not the same as or an - * ancestor of the class loader for the current class and - * invocation of {@link SecurityManager#checkPackageAccess - * s.checkPackageAccess()} denies access to the package - * of this class - * - * </ul> - * - * @jls 8.2 Class Members - * @jls 8.4 Method Declarations - * @since JDK1.1 - */ - @CallerSensitive - public Method[] getDeclaredMethods() throws SecurityException { - checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); - return copyMethods(privateGetDeclaredMethods(false)); - } - - - /** - * Returns an array of {@code Constructor} objects reflecting all the - * constructors declared by the class represented by this - * {@code Class} object. These are public, protected, default - * (package) access, and private constructors. The elements in the array - * returned are not sorted and are not in any particular order. If the - * class has a default constructor, it is included in the returned array. - * This method returns an array of length 0 if this {@code Class} - * object represents an interface, a primitive type, an array class, or - * void. - * - * <p> See <em>The Java Language Specification</em>, section 8.2. - * - * @return the array of {@code Constructor} objects representing all the - * declared constructors of this class - * @throws SecurityException - * If a security manager, <i>s</i>, is present and any of the - * following conditions is met: - * - * <ul> - * - * <li> the caller's class loader is not the same as the - * class loader of this class and invocation of - * {@link SecurityManager#checkPermission - * s.checkPermission} method with - * {@code RuntimePermission("accessDeclaredMembers")} - * denies access to the declared constructors within this class - * - * <li> the caller's class loader is not the same as or an - * ancestor of the class loader for the current class and - * invocation of {@link SecurityManager#checkPackageAccess - * s.checkPackageAccess()} denies access to the package - * of this class - * - * </ul> - * - * @since JDK1.1 - */ - @CallerSensitive - public Constructor<?>[] getDeclaredConstructors() throws SecurityException { - checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); - return copyConstructors(privateGetDeclaredConstructors(false)); - } - - - /** - * Returns a {@code Field} object that reflects the specified declared - * field of the class or interface represented by this {@code Class} - * object. The {@code name} parameter is a {@code String} that specifies - * the simple name of the desired field. - * - * <p> If this {@code Class} object represents an array type, then this - * method does not find the {@code length} field of the array type. - * - * @param name the name of the field - * @return the {@code Field} object for the specified field in this - * class - * @throws NoSuchFieldException if a field with the specified name is - * not found. - * @throws NullPointerException if {@code name} is {@code null} - * @throws SecurityException - * If a security manager, <i>s</i>, is present and any of the - * following conditions is met: - * - * <ul> - * - * <li> the caller's class loader is not the same as the - * class loader of this class and invocation of - * {@link SecurityManager#checkPermission - * s.checkPermission} method with - * {@code RuntimePermission("accessDeclaredMembers")} - * denies access to the declared field - * - * <li> the caller's class loader is not the same as or an - * ancestor of the class loader for the current class and - * invocation of {@link SecurityManager#checkPackageAccess - * s.checkPackageAccess()} denies access to the package - * of this class - * - * </ul> - * - * @since JDK1.1 - * @jls 8.2 Class Members - * @jls 8.3 Field Declarations - */ - @CallerSensitive - public Field getDeclaredField(String name) - throws NoSuchFieldException, SecurityException { - checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); - Field field = searchFields(privateGetDeclaredFields(false), name); - if (field == null) { - throw new NoSuchFieldException(name); - } - return field; - } - - - /** - * Returns a {@code Method} object that reflects the specified - * declared method of the class or interface represented by this - * {@code Class} object. The {@code name} parameter is a - * {@code String} that specifies the simple name of the desired - * method, and the {@code parameterTypes} parameter is an array of - * {@code Class} objects that identify the method's formal parameter - * types, in declared order. If more than one method with the same - * parameter types is declared in a class, and one of these methods has a - * return type that is more specific than any of the others, that method is - * returned; otherwise one of the methods is chosen arbitrarily. If the - * name is "<init>"or "<clinit>" a {@code NoSuchMethodException} - * is raised. - * - * <p> If this {@code Class} object represents an array type, then this - * method does not find the {@code clone()} method. - * - * @param name the name of the method - * @param parameterTypes the parameter array - * @return the {@code Method} object for the method of this class - * matching the specified name and parameters - * @throws NoSuchMethodException if a matching method is not found. - * @throws NullPointerException if {@code name} is {@code null} - * @throws SecurityException - * If a security manager, <i>s</i>, is present and any of the - * following conditions is met: - * - * <ul> - * - * <li> the caller's class loader is not the same as the - * class loader of this class and invocation of - * {@link SecurityManager#checkPermission - * s.checkPermission} method with - * {@code RuntimePermission("accessDeclaredMembers")} - * denies access to the declared method - * - * <li> the caller's class loader is not the same as or an - * ancestor of the class loader for the current class and - * invocation of {@link SecurityManager#checkPackageAccess - * s.checkPackageAccess()} denies access to the package - * of this class - * - * </ul> - * - * @jls 8.2 Class Members - * @jls 8.4 Method Declarations - * @since JDK1.1 - */ - @CallerSensitive - public Method getDeclaredMethod(String name, Class<?>... parameterTypes) - throws NoSuchMethodException, SecurityException { - checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); - Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes); - if (method == null) { - throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes)); - } - return method; - } - - - /** - * Returns a {@code Constructor} object that reflects the specified - * constructor of the class or interface represented by this - * {@code Class} object. The {@code parameterTypes} parameter is - * an array of {@code Class} objects that identify the constructor's - * formal parameter types, in declared order. - * - * If this {@code Class} object represents an inner class - * declared in a non-static context, the formal parameter types - * include the explicit enclosing instance as the first parameter. - * - * @param parameterTypes the parameter array - * @return The {@code Constructor} object for the constructor with the - * specified parameter list - * @throws NoSuchMethodException if a matching method is not found. - * @throws SecurityException - * If a security manager, <i>s</i>, is present and any of the - * following conditions is met: - * - * <ul> - * - * <li> the caller's class loader is not the same as the - * class loader of this class and invocation of - * {@link SecurityManager#checkPermission - * s.checkPermission} method with - * {@code RuntimePermission("accessDeclaredMembers")} - * denies access to the declared constructor - * - * <li> the caller's class loader is not the same as or an - * ancestor of the class loader for the current class and - * invocation of {@link SecurityManager#checkPackageAccess - * s.checkPackageAccess()} denies access to the package - * of this class - * - * </ul> - * - * @since JDK1.1 - */ - @CallerSensitive - public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) - throws NoSuchMethodException, SecurityException { - checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); - return getConstructor0(parameterTypes, Member.DECLARED); - } - - /** - * Finds a resource with a given name. The rules for searching resources - * associated with a given class are implemented by the defining - * {@linkplain ClassLoader class loader} of the class. This method - * delegates to this object's class loader. If this object was loaded by - * the bootstrap class loader, the method delegates to {@link - * ClassLoader#getSystemResourceAsStream}. - * - * <p> Before delegation, an absolute resource name is constructed from the - * given resource name using this algorithm: - * - * <ul> - * - * <li> If the {@code name} begins with a {@code '/'} - * (<tt>'\u002f'</tt>), then the absolute name of the resource is the - * portion of the {@code name} following the {@code '/'}. - * - * <li> Otherwise, the absolute name is of the following form: - * - * <blockquote> - * {@code modified_package_name/name} - * </blockquote> - * - * <p> Where the {@code modified_package_name} is the package name of this - * object with {@code '/'} substituted for {@code '.'} - * (<tt>'\u002e'</tt>). - * - * </ul> - * - * @param name name of the desired resource - * @return A {@link java.io.InputStream} object or {@code null} if - * no resource with this name is found - * @throws NullPointerException If {@code name} is {@code null} - * @since JDK1.1 - */ - public InputStream getResourceAsStream(String name) { - name = resolveName(name); - ClassLoader cl = getClassLoader0(); - if (cl==null) { - // A system class. - return ClassLoader.getSystemResourceAsStream(name); - } - return cl.getResourceAsStream(name); - } - - /** - * Finds a resource with a given name. The rules for searching resources - * associated with a given class are implemented by the defining - * {@linkplain ClassLoader class loader} of the class. This method - * delegates to this object's class loader. If this object was loaded by - * the bootstrap class loader, the method delegates to {@link - * ClassLoader#getSystemResource}. - * - * <p> Before delegation, an absolute resource name is constructed from the - * given resource name using this algorithm: - * - * <ul> - * - * <li> If the {@code name} begins with a {@code '/'} - * (<tt>'\u002f'</tt>), then the absolute name of the resource is the - * portion of the {@code name} following the {@code '/'}. - * - * <li> Otherwise, the absolute name is of the following form: - * - * <blockquote> - * {@code modified_package_name/name} - * </blockquote> - * - * <p> Where the {@code modified_package_name} is the package name of this - * object with {@code '/'} substituted for {@code '.'} - * (<tt>'\u002e'</tt>). - * - * </ul> - * - * @param name name of the desired resource - * @return A {@link java.net.URL} object or {@code null} if no - * resource with this name is found - * @since JDK1.1 - */ - public java.net.URL getResource(String name) { - name = resolveName(name); - ClassLoader cl = getClassLoader0(); - if (cl==null) { - // A system class. - return ClassLoader.getSystemResource(name); - } - return cl.getResource(name); - } - - - - /** protection domain returned when the internal domain is null */ - private static java.security.ProtectionDomain allPermDomain; - - - /** - * Returns the {@code ProtectionDomain} of this class. If there is a - * security manager installed, this method first calls the security - * manager's {@code checkPermission} method with a - * {@code RuntimePermission("getProtectionDomain")} permission to - * ensure it's ok to get the - * {@code ProtectionDomain}. - * - * @return the ProtectionDomain of this class - * - * @throws SecurityException - * if a security manager exists and its - * {@code checkPermission} method doesn't allow - * getting the ProtectionDomain. - * - * @see java.security.ProtectionDomain - * @see SecurityManager#checkPermission - * @see java.lang.RuntimePermission - * @since 1.2 - */ - public java.security.ProtectionDomain getProtectionDomain() { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(SecurityConstants.GET_PD_PERMISSION); - } - java.security.ProtectionDomain pd = getProtectionDomain0(); - if (pd == null) { - if (allPermDomain == null) { - java.security.Permissions perms = - new java.security.Permissions(); - perms.add(SecurityConstants.ALL_PERMISSION); - allPermDomain = - new java.security.ProtectionDomain(null, perms); - } - pd = allPermDomain; - } - return pd; - } - - - /** - * Returns the ProtectionDomain of this class. - */ - private native java.security.ProtectionDomain getProtectionDomain0(); - - /* - * Return the Virtual Machine's Class object for the named - * primitive type. - */ - static native Class<?> getPrimitiveClass(String name); - - /* - * Check if client is allowed to access members. If access is denied, - * throw a SecurityException. - * - * This method also enforces package access. - * - * <p> Default policy: allow all clients access with normal Java access - * control. - */ - private void checkMemberAccess(int which, Class<?> caller, boolean checkProxyInterfaces) { - final SecurityManager s = System.getSecurityManager(); - if (s != null) { - /* Default policy allows access to all {@link Member#PUBLIC} members, - * as well as access to classes that have the same class loader as the caller. - * In all other cases, it requires RuntimePermission("accessDeclaredMembers") - * permission. - */ - final ClassLoader ccl = ClassLoader.getClassLoader(caller); - final ClassLoader cl = getClassLoader0(); - if (which != Member.PUBLIC) { - if (ccl != cl) { - s.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION); - } - } - this.checkPackageAccess(ccl, checkProxyInterfaces); - } - } - - /* - * Checks if a client loaded in ClassLoader ccl is allowed to access this - * class under the current package access policy. If access is denied, - * throw a SecurityException. - */ - private void checkPackageAccess(final ClassLoader ccl, boolean checkProxyInterfaces) { - final SecurityManager s = System.getSecurityManager(); - if (s != null) { - final ClassLoader cl = getClassLoader0(); - - if (ReflectUtil.needsPackageAccessCheck(ccl, cl)) { - String name = this.getName(); - int i = name.lastIndexOf('.'); - if (i != -1) { - // skip the package access check on a proxy class in default proxy package - String pkg = name.substring(0, i); - if (!Proxy.isProxyClass(this) || ReflectUtil.isNonPublicProxyClass(this)) { - s.checkPackageAccess(pkg); - } - } - } - // check package access on the proxy interfaces - if (checkProxyInterfaces && Proxy.isProxyClass(this)) { - ReflectUtil.checkProxyPackageAccess(ccl, this.getInterfaces()); - } - } - } - - /** - * Add a package name prefix if the name is not absolute Remove leading "/" - * if name is absolute - */ - private String resolveName(String name) { - if (name == null) { - return name; - } - if (!name.startsWith("/")) { - Class<?> c = this; - while (c.isArray()) { - c = c.getComponentType(); - } - String baseName = c.getName(); - int index = baseName.lastIndexOf('.'); - if (index != -1) { - name = baseName.substring(0, index).replace('.', '/') - +"/"+name; - } - } else { - name = name.substring(1); - } - return name; - } - - /** - * Atomic operations support. - */ - private static class Atomic { - @ikvm.internal.InterlockedCompareAndSet("reflectionData") - static native <T> boolean casReflectionData(Class<?> clazz, - SoftReference<ReflectionData<T>> oldData, - SoftReference<ReflectionData<T>> newData); - - @ikvm.internal.InterlockedCompareAndSet("annotationType") - static native <T> boolean casAnnotationType(Class<?> clazz, - AnnotationType oldType, - AnnotationType newType); - - @ikvm.internal.InterlockedCompareAndSet("annotationData") - static native <T> boolean casAnnotationData(Class<?> clazz, - AnnotationData oldData, - AnnotationData newData); - } - - /** - * Reflection support. - */ - - // Caches for certain reflective results - private static boolean useCaches; - - // reflection data that might get invalidated when JVM TI RedefineClasses() is called - private static class ReflectionData<T> { - volatile Field[] declaredFields; - volatile Field[] publicFields; - volatile Method[] declaredMethods; - volatile Method[] publicMethods; - volatile Constructor<T>[] declaredConstructors; - volatile Constructor<T>[] publicConstructors; - // Intermediate results for getFields and getMethods - volatile Field[] declaredPublicFields; - volatile Method[] declaredPublicMethods; - volatile Class<?>[] interfaces; - - // Value of classRedefinedCount when we created this ReflectionData instance - final int redefinedCount; - - ReflectionData(int redefinedCount) { - this.redefinedCount = redefinedCount; - } - } - - private volatile transient SoftReference<ReflectionData<T>> reflectionData; - - // Incremented by the VM on each call to JVM TI RedefineClasses() - // that redefines this class or a superclass. - private volatile transient int classRedefinedCount; - - // Lazily create and cache ReflectionData - private ReflectionData<T> reflectionData() { - SoftReference<ReflectionData<T>> reflectionData = this.reflectionData; - int classRedefinedCount = this.classRedefinedCount; - ReflectionData<T> rd; - if (useCaches && - reflectionData != null && - (rd = reflectionData.get()) != null && - rd.redefinedCount == classRedefinedCount) { - return rd; - } - // else no SoftReference or cleared SoftReference or stale ReflectionData - // -> create and replace new instance - return newReflectionData(reflectionData, classRedefinedCount); - } - - private ReflectionData<T> newReflectionData(SoftReference<ReflectionData<T>> oldReflectionData, - int classRedefinedCount) { - if (!useCaches) return null; - - while (true) { - ReflectionData<T> rd = new ReflectionData<>(classRedefinedCount); - // try to CAS it... - if (Atomic.casReflectionData(this, oldReflectionData, new SoftReference<>(rd))) { - return rd; - } - // else retry - oldReflectionData = this.reflectionData; - classRedefinedCount = this.classRedefinedCount; - if (oldReflectionData != null && - (rd = oldReflectionData.get()) != null && - rd.redefinedCount == classRedefinedCount) { - return rd; - } - } - } - - // Generic signature handling - private native String getGenericSignature0(); - - // Generic info repository; lazily initialized - private volatile transient ClassRepository genericInfo; - - // accessor for factory - private GenericsFactory getFactory() { - // create scope and factory - return CoreReflectionFactory.make(this, ClassScope.make(this)); - } - - // accessor for generic info repository; - // generic info is lazily initialized - private ClassRepository getGenericInfo() { - ClassRepository genericInfo = this.genericInfo; - if (genericInfo == null) { - String signature = getGenericSignature0(); - if (signature == null) { - genericInfo = ClassRepository.NONE; - } else { - genericInfo = ClassRepository.make(signature, getFactory()); - } - this.genericInfo = genericInfo; - } - return (genericInfo != ClassRepository.NONE) ? genericInfo : null; - } - - // Annotations handling - private native Map<Class<? extends Annotation>, Annotation> getDeclaredAnnotationsImpl(); - // Since 1.8 - native byte[] getRawTypeAnnotations(); - static byte[] getExecutableTypeAnnotationBytes(Executable ex) { - return getReflectionFactory().getExecutableTypeAnnotationBytes(ex); - } - - native ConstantPool getConstantPool(); - - // - // - // java.lang.reflect.Field handling - // - // - - // Returns an array of "root" fields. These Field objects must NOT - // be propagated to the outside world, but must instead be copied - // via ReflectionFactory.copyField. - private Field[] privateGetDeclaredFields(boolean publicOnly) { - checkInitted(); - Field[] res; - ReflectionData<T> rd = reflectionData(); - if (rd != null) { - res = publicOnly ? rd.declaredPublicFields : rd.declaredFields; - if (res != null) return res; - } - // No cached value available; request value from VM - res = Reflection.filterFields(this, getDeclaredFields0(publicOnly)); - if (rd != null) { - if (publicOnly) { - rd.declaredPublicFields = res; - } else { - rd.declaredFields = res; - } - } - return res; - } - - // Returns an array of "root" fields. These Field objects must NOT - // be propagated to the outside world, but must instead be copied - // via ReflectionFactory.copyField. - private Field[] privateGetPublicFields(Set<Class<?>> traversedInterfaces) { - checkInitted(); - Field[] res; - ReflectionData<T> rd = reflectionData(); - if (rd != null) { - res = rd.publicFields; - if (res != null) return res; - } - - // No cached value available; compute value recursively. - // Traverse in correct order for getField(). - List<Field> fields = new ArrayList<>(); - if (traversedInterfaces == null) { - traversedInterfaces = new HashSet<>(); - } - - // Local fields - Field[] tmp = privateGetDeclaredFields(true); - addAll(fields, tmp); - - // Direct superinterfaces, recursively - for (Class<?> c : getInterfaces()) { - if (!traversedInterfaces.contains(c)) { - traversedInterfaces.add(c); - addAll(fields, c.privateGetPublicFields(traversedInterfaces)); - } - } - - // Direct superclass, recursively - if (!isInterface()) { - Class<?> c = getSuperclass(); - if (c != null) { - addAll(fields, c.privateGetPublicFields(traversedInterfaces)); - } - } - - res = new Field[fields.size()]; - fields.toArray(res); - if (rd != null) { - rd.publicFields = res; - } - return res; - } - - private static void addAll(Collection<Field> c, Field[] o) { - for (int i = 0; i < o.length; i++) { - c.add(o[i]); - } - } - - - // - // - // java.lang.reflect.Constructor handling - // - // - - // Returns an array of "root" constructors. These Constructor - // objects must NOT be propagated to the outside world, but must - // instead be copied via ReflectionFactory.copyConstructor. - private Constructor<T>[] privateGetDeclaredConstructors(boolean publicOnly) { - checkInitted(); - Constructor<T>[] res; - ReflectionData<T> rd = reflectionData(); - if (rd != null) { - res = publicOnly ? rd.publicConstructors : rd.declaredConstructors; - if (res != null) return res; - } - // No cached value available; request value from VM - if (isInterface()) { - @SuppressWarnings("unchecked") - Constructor<T>[] temporaryRes = (Constructor<T>[]) new Constructor<?>[0]; - res = temporaryRes; - } else { - res = getDeclaredConstructors0(publicOnly); - } - if (rd != null) { - if (publicOnly) { - rd.publicConstructors = res; - } else { - rd.declaredConstructors = res; - } - } - return res; - } - - // - // - // java.lang.reflect.Method handling - // - // - - // Returns an array of "root" methods. These Method objects must NOT - // be propagated to the outside world, but must instead be copied - // via ReflectionFactory.copyMethod. - private Method[] privateGetDeclaredMethods(boolean publicOnly) { - checkInitted(); - Method[] res; - ReflectionData<T> rd = reflectionData(); - if (rd != null) { - res = publicOnly ? rd.declaredPublicMethods : rd.declaredMethods; - if (res != null) return res; - } - // No cached value available; request value from VM - res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly)); - if (rd != null) { - if (publicOnly) { - rd.declaredPublicMethods = res; - } else { - rd.declaredMethods = res; - } - } - return res; - } - - static class MethodArray { - private Method[] methods; - private int length; - - MethodArray() { - methods = new Method[20]; - length = 0; - } - - void add(Method m) { - if (length == methods.length) { - methods = Arrays.copyOf(methods, 2 * methods.length); - } - methods[length++] = m; - } - - void addAll(Method[] ma) { - for (int i = 0; i < ma.length; i++) { - add(ma[i]); - } - } - - void addAll(MethodArray ma) { - for (int i = 0; i < ma.length(); i++) { - add(ma.get(i)); - } - } - - void addIfNotPresent(Method newMethod) { - for (int i = 0; i < length; i++) { - Method m = methods[i]; - if (m == newMethod || (m != null && m.equals(newMethod))) { - return; - } - } - add(newMethod); - } - - void addAllIfNotPresent(MethodArray newMethods) { - for (int i = 0; i < newMethods.length(); i++) { - Method m = newMethods.get(i); - if (m != null) { - addIfNotPresent(m); - } - } - } - - void addAllNonStatic(Method[] methods) { - for (Method candidate : methods) { - if (!Modifier.isStatic(candidate.getModifiers())) { - add(candidate); - } - } - } - - int length() { - return length; - } - - Method get(int i) { - return methods[i]; - } - - void removeByNameAndSignature(Method toRemove) { - for (int i = 0; i < length; i++) { - Method m = methods[i]; - if (m != null && - m.getReturnType() == toRemove.getReturnType() && - m.getName() == toRemove.getName() && - arrayContentsEq(m.getParameterTypes(), - toRemove.getParameterTypes())) { - methods[i] = null; - } - } - } - - void compactAndTrim() { - int newPos = 0; - // Get rid of null slots - for (int pos = 0; pos < length; pos++) { - Method m = methods[pos]; - if (m != null) { - if (pos != newPos) { - methods[newPos] = m; - } - newPos++; - } - } - if (newPos != methods.length) { - methods = Arrays.copyOf(methods, newPos); - } - } - - Method[] getArray() { - return methods; - } - } - - - // Returns an array of "root" methods. These Method objects must NOT - // be propagated to the outside world, but must instead be copied - // via ReflectionFactory.copyMethod. - private Method[] privateGetPublicMethods() { - checkInitted(); - Method[] res; - ReflectionData<T> rd = reflectionData(); - if (rd != null) { - res = rd.publicMethods; - if (res != null) return res; - } - - // No cached value available; compute value recursively. - // Start by fetching public declared methods - MethodArray methods = new MethodArray(); - { - Method[] tmp = privateGetDeclaredMethods(true); - methods.addAll(tmp); - } - // Now recur over superclass and direct superinterfaces. - // Go over superinterfaces first so we can more easily filter - // out concrete implementations inherited from superclasses at - // the end. - MethodArray inheritedMethods = new MethodArray(); - Class<?>[] interfaces = getInterfaces(); - for (int i = 0; i < interfaces.length; i++) { - inheritedMethods.addAllNonStatic(interfaces[i].privateGetPublicMethods()); - } - if (!isInterface()) { - Class<?> c = getSuperclass(); - if (c != null) { - MethodArray supers = new MethodArray(); - supers.addAll(c.privateGetPublicMethods()); - // Filter out concrete implementations of any - // interface methods - for (int i = 0; i < supers.length(); i++) { - Method m = supers.get(i); - if (m != null && !Modifier.isAbstract(m.getModifiers())) { - inheritedMethods.removeByNameAndSignature(m); - } - } - // Insert superclass's inherited methods before - // superinterfaces' to satisfy getMethod's search - // order - supers.addAll(inheritedMethods); - inheritedMethods = supers; - } - } - // Filter out all local methods from inherited ones - for (int i = 0; i < methods.length(); i++) { - Method m = methods.get(i); - inheritedMethods.removeByNameAndSignature(m); - } - methods.addAllIfNotPresent(inheritedMethods); - methods.compactAndTrim(); - res = methods.getArray(); - if (rd != null) { - rd.publicMethods = res; - } - return res; - } - - - // - // Helpers for fetchers of one field, method, or constructor - // - - private static Field searchFields(Field[] fields, String name) { - String internedName = name.intern(); - for (int i = 0; i < fields.length; i++) { - if (fields[i].getName() == internedName) { - return getReflectionFactory().copyField(fields[i]); - } - } - return null; - } - - private Field getField0(String name) throws NoSuchFieldException { - // Note: the intent is that the search algorithm this routine - // uses be equivalent to the ordering imposed by - // privateGetPublicFields(). It fetches only the declared - // public fields for each class, however, to reduce the number - // of Field objects which have to be created for the common - // case where the field being requested is declared in the - // class which is being queried. - Field res; - // Search declared public fields - if ((res = searchFields(privateGetDeclaredFields(true), name)) != null) { - return res; - } - // Direct superinterfaces, recursively - Class<?>[] interfaces = getInterfaces(); - for (int i = 0; i < interfaces.length; i++) { - Class<?> c = interfaces[i]; - if ((res = c.getField0(name)) != null) { - return res; - } - } - // Direct superclass, recursively - if (!isInterface()) { - Class<?> c = getSuperclass(); - if (c != null) { - if ((res = c.getField0(name)) != null) { - return res; - } - } - } - return null; - } - - private static Method searchMethods(Method[] methods, - String name, - Class<?>[] parameterTypes) - { - Method res = null; - String internedName = name.intern(); - for (int i = 0; i < methods.length; i++) { - Method m = methods[i]; - if (m.getName() == internedName - && arrayContentsEq(parameterTypes, m.getParameterTypes()) - && (res == null - || res.getReturnType().isAssignableFrom(m.getReturnType()))) - res = m; - } - - return (res == null ? res : getReflectionFactory().copyMethod(res)); - } - - - private Method getMethod0(String name, Class<?>[] parameterTypes, boolean includeStaticMethods) { - // Note: the intent is that the search algorithm this routine - // uses be equivalent to the ordering imposed by - // privateGetPublicMethods(). It fetches only the declared - // public methods for each class, however, to reduce the - // number of Method objects which have to be created for the - // common case where the method being requested is declared in - // the class which is being queried. - Method res; - // Search declared public methods - if ((res = searchMethods(privateGetDeclaredMethods(true), - name, - parameterTypes)) != null) { - if (includeStaticMethods || !Modifier.isStatic(res.getModifiers())) - return res; - } - // Search superclass's methods - if (!isInterface()) { - Class<? super T> c = getSuperclass(); - if (c != null) { - if ((res = c.getMethod0(name, parameterTypes, true)) != null) { - return res; - } - } - } - // Search superinterfaces' methods - Class<?>[] interfaces = getInterfaces(); - for (Class<?> c : interfaces) - if ((res = c.getMethod0(name, parameterTypes, false)) != null) - return res; - // Not found - return null; - } - - private Constructor<T> getConstructor0(Class<?>[] parameterTypes, - int which) throws NoSuchMethodException - { - Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC)); - for (Constructor<T> constructor : constructors) { - if (arrayContentsEq(parameterTypes, - constructor.getParameterTypes())) { - return getReflectionFactory().copyConstructor(constructor); - } - } - throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes)); - } - - // - // Other helpers and base implementation - // - - private static boolean arrayContentsEq(Object[] a1, Object[] a2) { - if (a1 == null) { - return a2 == null || a2.length == 0; - } - - if (a2 == null) { - return a1.length == 0; - } - - if (a1.length != a2.length) { - return false; - } - - for (int i = 0; i < a1.length; i++) { - if (a1[i] != a2[i]) { - return false; - } - } - - return true; - } - - private static Field[] copyFields(Field[] arg) { - Field[] out = new Field[arg.length]; - ReflectionFactory fact = getReflectionFactory(); - for (int i = 0; i < arg.length; i++) { - out[i] = fact.copyField(arg[i]); - } - return out; - } - - private static Method[] copyMethods(Method[] arg) { - Method[] out = new Method[arg.length]; - ReflectionFactory fact = getReflectionFactory(); - for (int i = 0; i < arg.length; i++) { - out[i] = fact.copyMethod(arg[i]); - } - return out; - } - - private static <U> Constructor<U>[] copyConstructors(Constructor<U>[] arg) { - Constructor<U>[] out = arg.clone(); - ReflectionFactory fact = getReflectionFactory(); - for (int i = 0; i < out.length; i++) { - out[i] = fact.copyConstructor(out[i]); - } - return out; - } - - private native Field[] getDeclaredFields0(boolean publicOnly); - private native Method[] getDeclaredMethods0(boolean publicOnly); - private native Constructor<T>[] getDeclaredConstructors0(boolean publicOnly); - private native Class<?>[] getDeclaredClasses0(); - - private static String argumentTypesToString(Class<?>[] argTypes) { - StringBuilder buf = new StringBuilder(); - buf.append("("); - if (argTypes != null) { - for (int i = 0; i < argTypes.length; i++) { - if (i > 0) { - buf.append(", "); - } - Class<?> c = argTypes[i]; - buf.append((c == null) ? "null" : c.getName()); - } - } - buf.append(")"); - return buf.toString(); - } - - /** use serialVersionUID from JDK 1.1 for interoperability */ - private static final long serialVersionUID = 3206093459760846163L; - - - /** - * Class Class is special cased within the Serialization Stream Protocol. - * - * A Class instance is written initially into an ObjectOutputStream in the - * following format: - * <pre> - * {@code TC_CLASS} ClassDescriptor - * A ClassDescriptor is a special cased serialization of - * a {@code java.io.ObjectStreamClass} instance. - * </pre> - * A new handle is generated for the initial time the class descriptor - * is written into the stream. Future references to the class descriptor - * are written as references to the initial class descriptor instance. - * - * @see java.io.ObjectStreamClass - */ - - @ikvm.lang.Property(get="get_spf") - private static final ObjectStreamField[] serialPersistentFields = null; - - private static ObjectStreamField[] get_spf() { - return java.io.ObjectStreamClass.NO_FIELDS; - } - - - /** - * Returns the assertion status that would be assigned to this - * class if it were to be initialized at the time this method is invoked. - * If this class has had its assertion status set, the most recent - * setting will be returned; otherwise, if any package default assertion - * status pertains to this class, the most recent setting for the most - * specific pertinent package default assertion status is returned; - * otherwise, if this class is not a system class (i.e., it has a - * class loader) its class loader's default assertion status is returned; - * otherwise, the system class default assertion status is returned. - * <p> - * Few programmers will have any need for this method; it is provided - * for the benefit of the JRE itself. (It allows a class to determine at - * the time that it is initialized whether assertions should be enabled.) - * Note that this method is not guaranteed to return the actual - * assertion status that was (or will be) associated with the specified - * class when it was (or will be) initialized. - * - * @return the desired assertion status of the specified class. - * @see java.lang.ClassLoader#setClassAssertionStatus - * @see java.lang.ClassLoader#setPackageAssertionStatus - * @see java.lang.ClassLoader#setDefaultAssertionStatus - * @since 1.4 - */ - public boolean desiredAssertionStatus() { - ClassLoader loader = getClassLoader(); - // If the loader is null this is a system class, so ask the VM - if (loader == null) - return desiredAssertionStatus0(this); - - // If the classloader has been initialized with the assertion - // directives, ask it. Otherwise, ask the VM. - synchronized(loader.assertionLock) { - if (loader.classAssertionStatus != null) { - return loader.desiredAssertionStatus(getName()); - } - } - return desiredAssertionStatus0(this); - } - - // Retrieves the desired assertion status of this class from the VM - private static native boolean desiredAssertionStatus0(Class<?> clazz); - - /** - * Returns true if and only if this class was declared as an enum in the - * source code. - * - * @return true if and only if this class was declared as an enum in the - * source code - * @since 1.5 - */ - public boolean isEnum() { - // An enum must both directly extend java.lang.Enum and have - // the ENUM bit set; classes for specialized enum constants - // don't do the former. - return (this.getModifiers() & ENUM) != 0 && - this.getSuperclass() == java.lang.Enum.class; - } - - // Fetches the factory for reflective objects - private static ReflectionFactory getReflectionFactory() { - if (reflectionFactory == null) { - reflectionFactory = - java.security.AccessController.doPrivileged - (new sun.reflect.ReflectionFactory.GetReflectionFactoryAction()); - } - return reflectionFactory; - } - private static ReflectionFactory reflectionFactory; - - // To be able to query system properties as soon as they're available - private static boolean initted; - private static void checkInitted() { - if (initted) return; - useCaches = true; - AccessController.doPrivileged(new PrivilegedAction<Void>() { - public Void run() { - // Tests to ensure the system properties table is fully - // initialized. This is needed because reflection code is - // called very early in the initialization process (before - // command-line arguments have been parsed and therefore - // these user-settable properties installed.) - - if (!sun.misc.VM.isBooted()) { - return null; - } - - // Doesn't use Boolean.getBoolean to avoid class init. - String val = - System.getProperty("sun.reflect.noCaches"); - if (val != null && val.equals("true")) { - useCaches = false; - } - - initted = true; - return null; - } - }); - } - - /** - * Returns the elements of this enum class or null if this - * Class object does not represent an enum type. - * - * @return an array containing the values comprising the enum class - * represented by this Class object in the order they're - * declared, or null if this Class object does not - * represent an enum type - * @since 1.5 - */ - public T[] getEnumConstants() { - T[] values = getEnumConstantsShared(); - return (values != null) ? values.clone() : null; - } - - /** - * Returns the elements of this enum class or null if this - * Class object does not represent an enum type; - * identical to getEnumConstants except that the result is - * uncloned, cached, and shared by all callers. - */ - T[] getEnumConstantsShared() { - if (enumConstants == null) { - if (!isEnum()) return null; - try { - final Method values = getMethod("values"); - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction<Void>() { - public Void run() { - values.setAccessible(true); - return null; - } - }); - @SuppressWarnings("unchecked") - T[] temporaryConstants = (T[])values.invoke(null); - enumConstants = temporaryConstants; - } - // These can happen when users concoct enum-like classes - // that don't comply with the enum spec. - catch (InvocationTargetException | NoSuchMethodException | - IllegalAccessException ex) { return null; } - } - return enumConstants; - } - private volatile transient T[] enumConstants; - - /** - * Returns a map from simple name to enum constant. This package-private - * method is used internally by Enum to implement - * {@code public static <T extends Enum<T>> T valueOf(Class<T>, String)} - * efficiently. Note that the map is returned by this method is - * created lazily on first use. Typically it won't ever get created. - */ - Map<String, T> enumConstantDirectory() { - if (enumConstantDirectory == null) { - T[] universe = getEnumConstantsShared(); - if (universe == null) - throw new IllegalArgumentException( - getName() + " is not an enum type"); - Map<String, T> m = new HashMap<>(2 * universe.length); - for (T constant : universe) - m.put(((Enum<?>)constant).name(), constant); - enumConstantDirectory = m; - } - return enumConstantDirectory; - } - private volatile transient Map<String, T> enumConstantDirectory; - - /** - * Casts an object to the class or interface represented - * by this {@code Class} object. - * - * @param obj the object to be cast - * @return the object after casting, or null if obj is null - * - * @throws ClassCastException if the object is not - * null and is not assignable to the type T. - * - * @since 1.5 - */ - @SuppressWarnings("unchecked") - public T cast(Object obj) { - if (obj != null && !isInstance(obj)) - throw new ClassCastException(cannotCastMsg(obj)); - return (T) obj; - } - - private String cannotCastMsg(Object obj) { - return "Cannot cast " + obj.getClass().getName() + " to " + getName(); - } - - /** - * Casts this {@code Class} object to represent a subclass of the class - * represented by the specified class object. Checks that the cast - * is valid, and throws a {@code ClassCastException} if it is not. If - * this method succeeds, it always returns a reference to this class object. - * - * <p>This method is useful when a client needs to "narrow" the type of - * a {@code Class} object to pass it to an API that restricts the - * {@code Class} objects that it is willing to accept. A cast would - * generate a compile-time warning, as the correctness of the cast - * could not be checked at runtime (because generic types are implemented - * by erasure). - * - * @param <U> the type to cast this class object to - * @param clazz the class of the type to cast this class object to - * @return this {@code Class} object, cast to represent a subclass of - * the specified class object. - * @throws ClassCastException if this {@code Class} object does not - * represent a subclass of the specified class (here "subclass" includes - * the class itself). - * @since 1.5 - */ - @SuppressWarnings("unchecked") - public <U> Class<? extends U> asSubclass(Class<U> clazz) { - if (clazz.isAssignableFrom(this)) - return (Class<? extends U>) this; - else - throw new ClassCastException(this.toString()); - } - - /** - * @throws NullPointerException {@inheritDoc} - * @since 1.5 - */ - @SuppressWarnings("unchecked") - public <A extends Annotation> A getAnnotation(Class<A> annotationClass) { - Objects.requireNonNull(annotationClass); - - return (A) annotationData().annotations.get(annotationClass); - } - - /** - * {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - * @since 1.5 - */ - @Override - public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) { - return GenericDeclaration.super.isAnnotationPresent(annotationClass); - } - - /** - * @throws NullPointerException {@inheritDoc} - * @since 1.8 - */ - @Override - public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationClass) { - Objects.requireNonNull(annotationClass); - - AnnotationData annotationData = annotationData(); - return AnnotationSupport.getAssociatedAnnotations(annotationData.declaredAnnotations, - this, - annotationClass); - } - - /** - * @since 1.5 - */ - public Annotation[] getAnnotations() { - return AnnotationParser.toArray(annotationData().annotations); - } - - /** - * @throws NullPointerException {@inheritDoc} - * @since 1.8 - */ - @Override - @SuppressWarnings("unchecked") - public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass) { - Objects.requireNonNull(annotationClass); - - return (A) annotationData().declaredAnnotations.get(annotationClass); - } - - /** - * @throws NullPointerException {@inheritDoc} - * @since 1.8 - */ - @Override - public <A extends Annotation> A[] getDeclaredAnnotationsByType(Class<A> annotationClass) { - Objects.requireNonNull(annotationClass); - - return AnnotationSupport.getDirectlyAndIndirectlyPresent(annotationData().declaredAnnotations, - annotationClass); - } - - /** - * @since 1.5 - */ - public Annotation[] getDeclaredAnnotations() { - return AnnotationParser.toArray(annotationData().declaredAnnotations); - } - - // annotation data that might get invalidated when JVM TI RedefineClasses() is called - private static class AnnotationData { - final Map<Class<? extends Annotation>, Annotation> annotations; - final Map<Class<? extends Annotation>, Annotation> declaredAnnotations; - - // Value of classRedefinedCount when we created this AnnotationData instance - final int redefinedCount; - - AnnotationData(Map<Class<? extends Annotation>, Annotation> annotations, - Map<Class<? extends Annotation>, Annotation> declaredAnnotations, - int redefinedCount) { - this.annotations = annotations; - this.declaredAnnotations = declaredAnnotations; - this.redefinedCount = redefinedCount; - } - } - - // Annotations cache - @SuppressWarnings("UnusedDeclaration") - private volatile transient AnnotationData annotationData; - - private AnnotationData annotationData() { - while (true) { // retry loop - AnnotationData annotationData = this.annotationData; - int classRedefinedCount = this.classRedefinedCount; - if (annotationData != null && - annotationData.redefinedCount == classRedefinedCount) { - return annotationData; - } - // null or stale annotationData -> optimistically create new instance - AnnotationData newAnnotationData = createAnnotationData(classRedefinedCount); - // try to install it - if (Atomic.casAnnotationData(this, annotationData, newAnnotationData)) { - // successfully installed new AnnotationData - return newAnnotationData; - } - } - } - - private AnnotationData createAnnotationData(int classRedefinedCount) { - Map<Class<? extends Annotation>, Annotation> declaredAnnotations = - getDeclaredAnnotationsImpl(); - Class<?> superClass = getSuperclass(); - Map<Class<? extends Annotation>, Annotation> annotations = null; - if (superClass != null) { - Map<Class<? extends Annotation>, Annotation> superAnnotations = - superClass.annotationData().annotations; - for (Map.Entry<Class<? extends Annotation>, Annotation> e : superAnnotations.entrySet()) { - Class<? extends Annotation> annotationClass = e.getKey(); - if (AnnotationType.getInstance(annotationClass).isInherited()) { - if (annotations == null) { // lazy construction - annotations = new LinkedHashMap<>((Math.max( - declaredAnnotations.size(), - Math.min(12, declaredAnnotations.size() + superAnnotations.size()) - ) * 4 + 2) / 3 - ); - } - annotations.put(annotationClass, e.getValue()); - } - } - } - if (annotations == null) { - // no inherited annotations -> share the Map with declaredAnnotations - annotations = declaredAnnotations; - } else { - // at least one inherited annotation -> declared may override inherited - annotations.putAll(declaredAnnotations); - } - return new AnnotationData(annotations, declaredAnnotations, classRedefinedCount); - } - - // Annotation types cache their internal (AnnotationType) form - - @SuppressWarnings("UnusedDeclaration") - private volatile transient AnnotationType annotationType; - - boolean casAnnotationType(AnnotationType oldType, AnnotationType newType) { - return Atomic.casAnnotationType(this, oldType, newType); - } - - AnnotationType getAnnotationType() { - return annotationType; - } - - Map<Class<? extends Annotation>, Annotation> getDeclaredAnnotationMap() { - return annotationData().declaredAnnotations; - } - - /* Backing store of user-defined values pertaining to this class. - * Maintained by the ClassValue class. - */ - transient ClassValue.ClassValueMap classValueMap; - - /** - * Returns an {@code AnnotatedType} object that represents the use of a - * type to specify the superclass of the entity represented by this {@code - * Class} object. (The <em>use</em> of type Foo to specify the superclass - * in '... extends Foo' is distinct from the <em>declaration</em> of type - * Foo.) - * - * <p> If this {@code Class} object represents a type whose declaration - * does not explicitly indicate an annotated superclass, then the return - * value is an {@code AnnotatedType} object representing an element with no - * annotations. - * - * <p> If this {@code Class} represents either the {@code Object} class, an - * interface type, an array type, a primitive type, or void, the return - * value is {@code null}. - * - * @return an object representing the superclass - * @since 1.8 - */ - public AnnotatedType getAnnotatedSuperclass() { - if (this == Object.class || - isInterface() || - isArray() || - isPrimitive() || - this == Void.TYPE) { - return null; - } - - return TypeAnnotationParser.buildAnnotatedSuperclass(getRawTypeAnnotations(), getConstantPool(), this); - } - - /** - * Returns an array of {@code AnnotatedType} objects that represent the use - * of types to specify superinterfaces of the entity represented by this - * {@code Class} object. (The <em>use</em> of type Foo to specify a - * superinterface in '... implements Foo' is distinct from the - * <em>declaration</em> of type Foo.) - * - * <p> If this {@code Class} object represents a class, the return value is - * an array containing objects representing the uses of interface types to - * specify interfaces implemented by the class. The order of the objects in - * the array corresponds to the order of the interface types used in the - * 'implements' clause of the declaration of this {@code Class} object. - * - * <p> If this {@code Class} object represents an interface, the return - * value is an array containing objects representing the uses of interface - * types to specify interfaces directly extended by the interface. The - * order of the objects in the array corresponds to the order of the - * interface types used in the 'extends' clause of the declaration of this - * {@code Class} object. - * - * <p> If this {@code Class} object represents a class or interface whose - * declaration does not explicitly indicate any annotated superinterfaces, - * the return value is an array of length 0. - * - * <p> If this {@code Class} object represents either the {@code Object} - * class, an array type, a primitive type, or void, the return value is an - * array of length 0. - * - * @return an array representing the superinterfaces - * @since 1.8 - */ - public AnnotatedType[] getAnnotatedInterfaces() { - return TypeAnnotationParser.buildAnnotatedInterfaces(getRawTypeAnnotations(), getConstantPool(), this); - } -} diff --git a/openjdk/java/lang/ClassLoader.java b/openjdk/java/lang/ClassLoader.java deleted file mode 100644 index 57c1ee3e..00000000 --- a/openjdk/java/lang/ClassLoader.java +++ /dev/null @@ -1,2261 +0,0 @@ -/* - * Copyright (c) 1994, 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 java.lang; - -import java.io.InputStream; -import java.io.IOException; -import java.io.File; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.net.MalformedURLException; -import java.net.URL; -import java.security.AccessController; -import java.security.AccessControlContext; -import java.security.CodeSource; -import java.security.Policy; -import java.security.PrivilegedAction; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.security.ProtectionDomain; -import java.security.cert.Certificate; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; -import java.util.Stack; -import java.util.Map; -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.security.util.SecurityConstants; - -/** - * A class loader is an object that is responsible for loading classes. The - * class <tt>ClassLoader</tt> is an abstract class. Given the <a - * href="#name">binary name</a> of a class, a class loader should attempt to - * locate or generate data that constitutes a definition for the class. A - * typical strategy is to transform the name into a file name and then read a - * "class file" of that name from a file system. - * - * <p> Every {@link Class <tt>Class</tt>} object contains a {@link - * Class#getClassLoader() reference} to the <tt>ClassLoader</tt> that defined - * it. - * - * <p> <tt>Class</tt> objects for array classes are not created by class - * loaders, but are created automatically as required by the Java runtime. - * The class loader for an array class, as returned by {@link - * Class#getClassLoader()} is the same as the class loader for its element - * type; if the element type is a primitive type, then the array class has no - * class loader. - * - * <p> Applications implement subclasses of <tt>ClassLoader</tt> in order to - * extend the manner in which the Java virtual machine dynamically loads - * classes. - * - * <p> Class loaders may typically be used by security managers to indicate - * security domains. - * - * <p> The <tt>ClassLoader</tt> class uses a delegation model to search for - * classes and resources. Each instance of <tt>ClassLoader</tt> has an - * associated parent class loader. When requested to find a class or - * resource, a <tt>ClassLoader</tt> instance will delegate the search for the - * class or resource to its parent class loader before attempting to find the - * class or resource itself. The virtual machine's built-in class loader, - * called the "bootstrap class loader", does not itself have a parent but may - * serve as the parent of a <tt>ClassLoader</tt> instance. - * - * <p> Class loaders that support concurrent loading of classes are known as - * <em>parallel capable</em> class loaders and are required to register - * themselves at their class initialization time by invoking the - * {@link - * #registerAsParallelCapable <tt>ClassLoader.registerAsParallelCapable</tt>} - * method. Note that the <tt>ClassLoader</tt> class is registered as parallel - * capable by default. However, its subclasses still need to register themselves - * if they are parallel capable. <br> - * In environments in which the delegation model is not strictly - * hierarchical, class loaders need to be parallel capable, otherwise class - * loading can lead to deadlocks because the loader lock is held for the - * duration of the class loading process (see {@link #loadClass - * <tt>loadClass</tt>} methods). - * - * <p> Normally, the Java virtual machine loads classes from the local file - * system in a platform-dependent manner. For example, on UNIX systems, the - * virtual machine loads classes from the directory defined by the - * <tt>CLASSPATH</tt> environment variable. - * - * <p> However, some classes may not originate from a file; they may originate - * from other sources, such as the network, or they could be constructed by an - * application. The method {@link #defineClass(String, byte[], int, int) - * <tt>defineClass</tt>} converts an array of bytes into an instance of class - * <tt>Class</tt>. Instances of this newly defined class can be created using - * {@link Class#newInstance <tt>Class.newInstance</tt>}. - * - * <p> The methods and constructors of objects created by a class loader may - * reference other classes. To determine the class(es) referred to, the Java - * virtual machine invokes the {@link #loadClass <tt>loadClass</tt>} method of - * the class loader that originally created the class. - * - * <p> For example, an application could create a network class loader to - * download class files from a server. Sample code might look like: - * - * <blockquote><pre> - * ClassLoader loader = new NetworkClassLoader(host, port); - * Object main = loader.loadClass("Main", true).newInstance(); - * . . . - * </pre></blockquote> - * - * <p> The network class loader subclass must define the methods {@link - * #findClass <tt>findClass</tt>} and <tt>loadClassData</tt> to load a class - * from the network. Once it has downloaded the bytes that make up the class, - * it should use the method {@link #defineClass <tt>defineClass</tt>} to - * create a class instance. A sample implementation is: - * - * <blockquote><pre> - * class NetworkClassLoader extends ClassLoader { - * String host; - * int port; - * - * public Class findClass(String name) { - * byte[] b = loadClassData(name); - * return defineClass(name, b, 0, b.length); - * } - * - * private byte[] loadClassData(String name) { - * // load the class data from the connection - * . . . - * } - * } - * </pre></blockquote> - * - * <h4> <a name="name">Binary names</a> </h4> - * - * <p> Any class name provided as a {@link String} parameter to methods in - * <tt>ClassLoader</tt> must be a binary name as defined by - * <cite>The Java™ Language Specification</cite>. - * - * <p> Examples of valid class names include: - * <blockquote><pre> - * "java.lang.String" - * "javax.swing.JSpinner$DefaultEditor" - * "java.security.KeyStore$Builder$FileBuilder$1" - * "java.net.URLClassLoader$3$1" - * </pre></blockquote> - * - * @see #resolveClass(Class) - * @since 1.0 - */ -public abstract class ClassLoader { - - // If initialization succeed this is set to true and security checks will - // succeed. Otherwise the object is not initialized and the object is - // useless. - private final boolean initialized; - - // The parent class loader for delegation - // Note: VM hardcoded the offset of this field, thus all new fields - // must be added *after* it. - private final ClassLoader parent; - - /** - * Encapsulates the set of parallel capable loader types. - */ - private static class ParallelLoaders { - private ParallelLoaders() {} - - // the set of parallel capable loader types - private static final Set<Class<? extends ClassLoader>> loaderTypes = - Collections.newSetFromMap( - new WeakHashMap<Class<? extends ClassLoader>, Boolean>()); - static { - synchronized (loaderTypes) { loaderTypes.add(ClassLoader.class); } - } - - /** - * Registers the given class loader type as parallel capabale. - * Returns {@code true} is successfully registered; {@code false} if - * loader's super class is not registered. - */ - static boolean register(Class<? extends ClassLoader> c) { - synchronized (loaderTypes) { - if (loaderTypes.contains(c.getSuperclass())) { - // register the class loader as parallel capable - // if and only if all of its super classes are. - // Note: given current classloading sequence, if - // the immediate super class is parallel capable, - // all the super classes higher up must be too. - loaderTypes.add(c); - return true; - } else { - return false; - } - } - } - - /** - * Returns {@code true} if the given class loader type is - * registered as parallel capable. - */ - static boolean isRegistered(Class<? extends ClassLoader> c) { - synchronized (loaderTypes) { - return loaderTypes.contains(c); - } - } - } - - // Maps class name to the corresponding lock object when the current - // class loader is parallel capable. - // Note: VM also uses this field to decide if the current class loader - // is parallel capable and the appropriate lock object for class loading. - private final ConcurrentHashMap<String, Object> parallelLockMap; - - // Hashtable that maps packages to certs - private final Map <String, Certificate[]> package2certs; - - // 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 - // is to keep the classes from being GC'ed until the loader is GC'ed. - private final Vector<Class<?>> classes = new Vector<>(); - - // The "default" domain. Set as the default ProtectionDomain on newly - // created classes. - private final ProtectionDomain defaultDomain = - new ProtectionDomain(new CodeSource(null, (Certificate[]) null), - null, this, null); - - // The initiating protection domains for all classes loaded by this loader - private final Set<ProtectionDomain> domains; - - // Invoked by the VM to record every loaded class with this loader. - void addClass(Class c) { - classes.addElement(c); - } - - // The packages defined in this class loader. Each package name is mapped - // to its corresponding Package object. - // @GuardedBy("itself") - private final HashMap<String, Package> packages = new HashMap<>(); - - @ikvm.lang.Internal - public static final ClassLoader DUMMY = new ClassLoader(false) { }; - - ClassLoader(boolean ignored) - { - // [IKVM] This constructor is IKVM specific and only used to construct DUMMY. - // Note that this body is replaced in map.xml with an empty body as - // we don't want to execute any of the instance field initializers. - this((Void)null, (ClassLoader)null); - } - - private static Void checkCreateClassLoader() { - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkCreateClassLoader(); - } - return null; - } - - // [IKVM] this normally private constructor is also used by ikvm.runtime.AssemblyClassLoader - // to construct an assembly class loader without doing a security check - @ikvm.lang.Internal - protected ClassLoader(Void unused, ClassLoader parent) { - if (parent != null) { - parent.check(); - } - this.parent = parent; - if (ParallelLoaders.isRegistered(this.getClass())) { - parallelLockMap = new ConcurrentHashMap<>(); - package2certs = new ConcurrentHashMap<>(); - domains = - Collections.synchronizedSet(new HashSet<ProtectionDomain>()); - assertionLock = new Object(); - } else { - // no finer-grained lock; lock on the classloader instance - parallelLockMap = null; - package2certs = new Hashtable<>(); - domains = new HashSet<>(); - assertionLock = this; - } - initialized = true; - } - - /** - * Creates a new class loader using the specified parent class loader for - * delegation. - * - * <p> If there is a security manager, its {@link - * SecurityManager#checkCreateClassLoader() - * <tt>checkCreateClassLoader</tt>} method is invoked. This may result in - * a security exception. </p> - * - * @param parent - * The parent class loader - * - * @throws SecurityException - * If a security manager exists and its - * <tt>checkCreateClassLoader</tt> method doesn't allow creation - * of a new class loader. - * - * @since 1.2 - */ - protected ClassLoader(ClassLoader parent) { - this(checkCreateClassLoader(), parent); - } - - /** - * Creates a new class loader using the <tt>ClassLoader</tt> returned by - * the method {@link #getSystemClassLoader() - * <tt>getSystemClassLoader()</tt>} as the parent class loader. - * - * <p> If there is a security manager, its {@link - * SecurityManager#checkCreateClassLoader() - * <tt>checkCreateClassLoader</tt>} method is invoked. This may result in - * a security exception. </p> - * - * @throws SecurityException - * If a security manager exists and its - * <tt>checkCreateClassLoader</tt> method doesn't allow creation - * of a new class loader. - */ - protected ClassLoader() { - this(checkCreateClassLoader(), getSystemClassLoader()); - } - - // -- Class -- - - /** - * Loads the class with the specified <a href="#name">binary name</a>. - * This method searches for classes in the same manner as the {@link - * #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) <tt>loadClass(name, - * false)</tt>}. </p> - * - * @param name - * The <a href="#name">binary name</a> of the class - * - * @return The resulting <tt>Class</tt> object - * - * @throws ClassNotFoundException - * If the class was not found - */ - public Class<?> loadClass(String name) throws ClassNotFoundException { - return loadClass(name, false); - } - - /** - * Loads the class with the specified <a href="#name">binary name</a>. The - * default implementation of this method searches for classes in the - * following order: - * - * <p><ol> - * - * <li><p> Invoke {@link #findLoadedClass(String)} to check if the class - * has already been loaded. </p></li> - * - * <li><p> Invoke the {@link #loadClass(String) <tt>loadClass</tt>} method - * on the parent class loader. If the parent is <tt>null</tt> the class - * loader built-in to the virtual machine is used, instead. </p></li> - * - * <li><p> Invoke the {@link #findClass(String)} method to find the - * class. </p></li> - * - * </ol> - * - * <p> If the class was found using the above steps, and the - * <tt>resolve</tt> flag is true, this method will then invoke the {@link - * #resolveClass(Class)} method on the resulting <tt>Class</tt> object. - * - * <p> Subclasses of <tt>ClassLoader</tt> are encouraged to override {@link - * #findClass(String)}, rather than this method. </p> - * - * <p> Unless overridden, this method synchronizes on the result of - * {@link #getClassLoadingLock <tt>getClassLoadingLock</tt>} method - * during the entire class loading process. - * - * @param name - * The <a href="#name">binary name</a> of the class - * - * @param resolve - * If <tt>true</tt> then resolve the class - * - * @return The resulting <tt>Class</tt> object - * - * @throws ClassNotFoundException - * If the class could not be found - */ - protected Class<?> loadClass(String name, boolean resolve) - throws ClassNotFoundException - { - synchronized (getClassLoadingLock(name)) { - // First, check if the class has already been loaded - Class c = findLoadedClass(name); - if (c == null) { - try { - if (parent != null) { - c = parent.loadClass(name, false); - } else { - c = findBootstrapClassOrNull(name); - } - } catch (ClassNotFoundException e) { - // ClassNotFoundException thrown if class not found - // from the non-null parent class loader - } - - if (c == null) { - // If still not found, then invoke findClass in order - // to find the class. - c = findClass(name); - } - } - if (resolve) { - resolveClass(c); - } - return c; - } - } - - /** - * Returns the lock object for class loading operations. - * For backward compatibility, the default implementation of this method - * 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. </p> - * - * @param className - * The name of the to-be-loaded class - * - * @return the lock for class loading operations - * - * @throws NullPointerException - * If registered as parallel capable and <tt>className</tt> is null - * - * @see #loadClass(String, boolean) - * - * @since 1.7 - */ - protected Object getClassLoadingLock(String className) { - Object lock = this; - if (parallelLockMap != null) { - Object newLock = new Object(); - lock = parallelLockMap.putIfAbsent(className, newLock); - if (lock == null) { - lock = newLock; - } - } - return lock; - } - - // This method is invoked by the virtual machine to load a class. - final Class loadClassInternal(String name) - throws ClassNotFoundException - { - // For backward compatibility, explicitly lock on 'this' when - // the current class loader is not parallel capable. - if (parallelLockMap == null) { - synchronized (this) { - return loadClass(name); - } - } else { - return loadClass(name); - } - } - - // Invoked by the VM after loading class with this loader. - final void checkPackageAccess(Class cls, ProtectionDomain pd) { - final SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - final String name = cls.getName(); - final int i = name.lastIndexOf('.'); - if (i != -1) { - AccessController.doPrivileged(new PrivilegedAction<Void>() { - public Void run() { - sm.checkPackageAccess(name.substring(0, i)); - return null; - } - }, new AccessControlContext(new ProtectionDomain[] {pd})); - } - } - domains.add(pd); - } - - /** - * Finds the class with the specified <a href="#name">binary name</a>. - * This method should be overridden by class loader implementations that - * follow the delegation model for loading classes, and will be invoked by - * the {@link #loadClass <tt>loadClass</tt>} method after checking the - * parent class loader for the requested class. The default implementation - * throws a <tt>ClassNotFoundException</tt>. </p> - * - * @param name - * The <a href="#name">binary name</a> of the class - * - * @return The resulting <tt>Class</tt> object - * - * @throws ClassNotFoundException - * If the class could not be found - * - * @since 1.2 - */ - protected Class<?> findClass(String name) throws ClassNotFoundException { - throw new ClassNotFoundException(name); - } - - /** - * Converts an array of bytes into an instance of class <tt>Class</tt>. - * Before the <tt>Class</tt> can be used it must be resolved. This method - * is deprecated in favor of the version that takes a <a - * href="#name">binary name</a> as its first argument, and is more secure. - * - * @param b - * The bytes that make up the class data. The bytes in positions - * <tt>off</tt> through <tt>off+len-1</tt> should have the format - * of a valid class file as defined by - * <cite>The Java™ Virtual Machine Specification</cite>. - * - * @param off - * The start offset in <tt>b</tt> of the class data - * - * @param len - * The length of the class data - * - * @return The <tt>Class</tt> object that was created from the specified - * class data - * - * @throws ClassFormatError - * If the data did not contain a valid class - * - * @throws IndexOutOfBoundsException - * If either <tt>off</tt> or <tt>len</tt> is negative, or if - * <tt>off+len</tt> is greater than <tt>b.length</tt>. - * - * @throws SecurityException - * If an attempt is made to add this class to a package that - * contains classes that were signed by a different set of - * certificates than this class, or if an attempt is made - * to define a class in a package with a fully-qualified name - * that starts with "{@code java.}". - * - * @see #loadClass(String, boolean) - * @see #resolveClass(Class) - * - * @deprecated Replaced by {@link #defineClass(String, byte[], int, int) - * defineClass(String, byte[], int, int)} - */ - @Deprecated - protected final Class<?> defineClass(byte[] b, int off, int len) - throws ClassFormatError - { - return defineClass(null, b, off, len, null); - } - - /** - * Converts an array of bytes into an instance of class <tt>Class</tt>. - * Before the <tt>Class</tt> can be used it must be resolved. - * - * <p> This method assigns a default {@link java.security.ProtectionDomain - * <tt>ProtectionDomain</tt>} to the newly defined class. The - * <tt>ProtectionDomain</tt> is effectively granted the same set of - * permissions returned when {@link - * java.security.Policy#getPermissions(java.security.CodeSource) - * <tt>Policy.getPolicy().getPermissions(new CodeSource(null, null))</tt>} - * is invoked. The default domain is created on the first invocation of - * {@link #defineClass(String, byte[], int, int) <tt>defineClass</tt>}, - * and re-used on subsequent invocations. - * - * <p> To assign a specific <tt>ProtectionDomain</tt> to the class, use - * the {@link #defineClass(String, byte[], int, int, - * java.security.ProtectionDomain) <tt>defineClass</tt>} method that takes a - * <tt>ProtectionDomain</tt> as one of its arguments. </p> - * - * @param name - * The expected <a href="#name">binary name</a> of the class, or - * <tt>null</tt> if not known - * - * @param b - * The bytes that make up the class data. The bytes in positions - * <tt>off</tt> through <tt>off+len-1</tt> should have the format - * of a valid class file as defined by - * <cite>The Java™ Virtual Machine Specification</cite>. - * - * @param off - * The start offset in <tt>b</tt> of the class data - * - * @param len - * The length of the class data - * - * @return The <tt>Class</tt> object that was created from the specified - * class data. - * - * @throws ClassFormatError - * If the data did not contain a valid class - * - * @throws IndexOutOfBoundsException - * If either <tt>off</tt> or <tt>len</tt> is negative, or if - * <tt>off+len</tt> is greater than <tt>b.length</tt>. - * - * @throws SecurityException - * If an attempt is made to add this class to a package that - * contains classes that were signed by a different set of - * certificates than this class (which is unsigned), or if - * <tt>name</tt> begins with "<tt>java.</tt>". - * - * @see #loadClass(String, boolean) - * @see #resolveClass(Class) - * @see java.security.CodeSource - * @see java.security.SecureClassLoader - * - * @since 1.1 - */ - protected final Class<?> defineClass(String name, byte[] b, int off, int len) - throws ClassFormatError - { - return defineClass(name, b, off, len, null); - } - - /* Determine protection domain, and check that: - - not define java.* class, - - signer of this class matches signers for the rest of the classes in - package. - */ - private ProtectionDomain preDefineClass(String name, - ProtectionDomain pd) - { - if (!checkName(name)) - throw new NoClassDefFoundError("IllegalName: " + name); - - if ((name != null) && name.startsWith("java.")) { - throw new SecurityException - ("Prohibited package name: " + - name.substring(0, name.lastIndexOf('.'))); - } - if (pd == null) { - pd = defaultDomain; - } - - if (name != null) checkCerts(name, pd.getCodeSource()); - - return pd; - } - - private String defineClassSourceLocation(ProtectionDomain pd) - { - CodeSource cs = pd.getCodeSource(); - String source = null; - if (cs != null && cs.getLocation() != null) { - source = cs.getLocation().toString(); - } - 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) - { - if (pd.getCodeSource() != null) { - Certificate certs[] = pd.getCodeSource().getCertificates(); - if (certs != null) - setSigners(c, certs); - } - } - - /** - * Converts an array of bytes into an instance of class <tt>Class</tt>, - * with an optional <tt>ProtectionDomain</tt>. If the domain is - * <tt>null</tt>, then a default domain will be assigned to the class as - * specified in the documentation for {@link #defineClass(String, byte[], - * int, int)}. Before the class can be used it must be resolved. - * - * <p> The first class defined in a package determines the exact set of - * certificates that all subsequent classes defined in that package must - * contain. The set of certificates for a class is obtained from the - * {@link java.security.CodeSource <tt>CodeSource</tt>} within the - * <tt>ProtectionDomain</tt> of the class. Any classes added to that - * package must contain the same set of certificates or a - * <tt>SecurityException</tt> will be thrown. Note that if - * <tt>name</tt> is <tt>null</tt>, this check is not performed. - * You should always pass in the <a href="#name">binary name</a> of the - * class you are defining as well as the bytes. This ensures that the - * class you are defining is indeed the class you think it is. - * - * <p> The specified <tt>name</tt> cannot begin with "<tt>java.</tt>", since - * all classes in the "<tt>java.*</tt> packages can only be defined by the - * bootstrap class loader. If <tt>name</tt> is not <tt>null</tt>, it - * must be equal to the <a href="#name">binary name</a> of the class - * specified by the byte array "<tt>b</tt>", otherwise a {@link - * <tt>NoClassDefFoundError</tt>} will be thrown. </p> - * - * @param name - * The expected <a href="#name">binary name</a> of the class, or - * <tt>null</tt> if not known - * - * @param b - * The bytes that make up the class data. The bytes in positions - * <tt>off</tt> through <tt>off+len-1</tt> should have the format - * of a valid class file as defined by - * <cite>The Java™ Virtual Machine Specification</cite>. - * - * @param off - * The start offset in <tt>b</tt> of the class data - * - * @param len - * The length of the class data - * - * @param protectionDomain - * The ProtectionDomain of the class - * - * @return The <tt>Class</tt> object created from the data, - * and optional <tt>ProtectionDomain</tt>. - * - * @throws ClassFormatError - * If the data did not contain a valid class - * - * @throws NoClassDefFoundError - * If <tt>name</tt> is not equal to the <a href="#name">binary - * name</a> of the class specified by <tt>b</tt> - * - * @throws IndexOutOfBoundsException - * If either <tt>off</tt> or <tt>len</tt> is negative, or if - * <tt>off+len</tt> is greater than <tt>b.length</tt>. - * - * @throws SecurityException - * If an attempt is made to add this class to a package that - * contains classes that were signed by a different set of - * certificates than this class, or if <tt>name</tt> begins with - * "<tt>java.</tt>". - */ - protected final Class<?> defineClass(String name, byte[] b, int off, int len, - ProtectionDomain protectionDomain) - throws ClassFormatError - { - 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); - } - - postDefineClass(c, protectionDomain); - return c; - } - - /** - * Converts a {@link java.nio.ByteBuffer <tt>ByteBuffer</tt>} - * into an instance of class <tt>Class</tt>, - * with an optional <tt>ProtectionDomain</tt>. If the domain is - * <tt>null</tt>, then a default domain will be assigned to the class as - * specified in the documentation for {@link #defineClass(String, byte[], - * int, int)}. Before the class can be used it must be resolved. - * - * <p>The rules about the first class defined in a package determining the - * set of certificates for the package, and the restrictions on class names - * are identical to those specified in the documentation for {@link - * #defineClass(String, byte[], int, int, ProtectionDomain)}. - * - * <p> An invocation of this method of the form - * <i>cl</i><tt>.defineClass(</tt><i>name</i><tt>,</tt> - * <i>bBuffer</i><tt>,</tt> <i>pd</i><tt>)</tt> yields exactly the same - * result as the statements - * - * <blockquote><tt> - * ...<br> - * byte[] temp = new byte[</tt><i>bBuffer</i><tt>.{@link - * java.nio.ByteBuffer#remaining remaining}()];<br> - * </tt><i>bBuffer</i><tt>.{@link java.nio.ByteBuffer#get(byte[]) - * get}(temp);<br> - * return {@link #defineClass(String, byte[], int, int, ProtectionDomain) - * </tt><i>cl</i><tt>.defineClass}(</tt><i>name</i><tt>, temp, 0, - * temp.length, </tt><i>pd</i><tt>);<br> - * </tt></blockquote> - * - * @param name - * The expected <a href="#name">binary name</a>. of the class, or - * <tt>null</tt> if not known - * - * @param b - * The bytes that make up the class data. The bytes from positions - * <tt>b.position()</tt> through <tt>b.position() + b.limit() -1 - * </tt> should have the format of a valid class file as defined by - * <cite>The Java™ Virtual Machine Specification</cite>. - * - * @param protectionDomain - * The ProtectionDomain of the class, or <tt>null</tt>. - * - * @return The <tt>Class</tt> object created from the data, - * and optional <tt>ProtectionDomain</tt>. - * - * @throws ClassFormatError - * If the data did not contain a valid class. - * - * @throws NoClassDefFoundError - * If <tt>name</tt> is not equal to the <a href="#name">binary - * name</a> of the class specified by <tt>b</tt> - * - * @throws SecurityException - * If an attempt is made to add this class to a package that - * contains classes that were signed by a different set of - * certificates than this class, or if <tt>name</tt> begins with - * "<tt>java.</tt>". - * - * @see #defineClass(String, byte[], int, int, ProtectionDomain) - * - * @since 1.5 - */ - protected final Class<?> defineClass(String name, java.nio.ByteBuffer b, - ProtectionDomain protectionDomain) - throws ClassFormatError - { - check(); - - int len = b.remaining(); - - // Use byte[] if not a direct ByteBufer: - if (!b.isDirect()) { - if (b.hasArray()) { - return defineClass(name, b.array(), - b.position() + b.arrayOffset(), len, - protectionDomain); - } else { - // no array, or read-only array - byte[] tb = new byte[len]; - b.get(tb); // get bytes out of byte buffer. - return defineClass(name, tb, 0, len, protectionDomain); - } - } - - 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); - } - - postDefineClass(c, protectionDomain); - return c; - } - - 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 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) { - if ((name == null) || (name.length() == 0)) - return true; - if ((name.indexOf('/') != -1) - || (!VM.allowArraySyntax() && (name.charAt(0) == '['))) - return false; - return true; - } - - private void checkCerts(String name, CodeSource cs) { - int i = name.lastIndexOf('.'); - String pname = (i == -1) ? "" : name.substring(0, i); - - Certificate[] certs = null; - if (cs != null) { - certs = cs.getCertificates(); - } - Certificate[] pcerts = null; - if (parallelLockMap == null) { - synchronized (this) { - pcerts = package2certs.get(pname); - if (pcerts == null) { - package2certs.put(pname, (certs == null? nocerts:certs)); - } - } - } else { - pcerts = ((ConcurrentHashMap<String, Certificate[]>)package2certs). - putIfAbsent(pname, (certs == null? nocerts:certs)); - } - if (pcerts != null && !compareCerts(pcerts, certs)) { - throw new SecurityException("class \""+ name + - "\"'s signer information does not match signer information of other classes in the same package"); - } - } - - /** - * check to make sure the certs for the new class (certs) are the same as - * the certs for the first class inserted in the package (pcerts) - */ - private boolean compareCerts(Certificate[] pcerts, - Certificate[] certs) - { - // certs can be null, indicating no certs. - if ((certs == null) || (certs.length == 0)) { - return pcerts.length == 0; - } - - // the length must be the same at this point - if (certs.length != pcerts.length) - return false; - - // go through and make sure all the certs in one array - // are in the other and vice-versa. - boolean match; - for (int i = 0; i < certs.length; i++) { - match = false; - for (int j = 0; j < pcerts.length; j++) { - if (certs[i].equals(pcerts[j])) { - match = true; - break; - } - } - if (!match) return false; - } - - // now do the same for pcerts - for (int i = 0; i < pcerts.length; i++) { - match = false; - for (int j = 0; j < certs.length; j++) { - if (pcerts[i].equals(certs[j])) { - match = true; - break; - } - } - if (!match) return false; - } - - return true; - } - - /** - * Links the specified class. This (misleadingly named) method may be - * used by a class loader to link a class. If the class <tt>c</tt> has - * already been linked, then this method simply returns. Otherwise, the - * class is linked as described in the "Execution" chapter of - * <cite>The Java™ Language Specification</cite>. - * </p> - * - * @param c - * The class to link - * - * @throws NullPointerException - * If <tt>c</tt> is <tt>null</tt>. - * - * @see #defineClass(String, byte[], int, int) - */ - protected final void resolveClass(Class<?> c) { - check(); - resolveClass0(c); - } - - private native void resolveClass0(Class c); - - /** - * Finds a class with the specified <a href="#name">binary name</a>, - * loading it if necessary. - * - * <p> This method loads the class through the system class loader (see - * {@link #getSystemClassLoader()}). The <tt>Class</tt> object returned - * might have more than one <tt>ClassLoader</tt> associated with it. - * Subclasses of <tt>ClassLoader</tt> need not usually invoke this method, - * because most class loaders need to override just {@link - * #findClass(String)}. </p> - * - * @param name - * The <a href="#name">binary name</a> of the class - * - * @return The <tt>Class</tt> object for the specified <tt>name</tt> - * - * @throws ClassNotFoundException - * If the class could not be found - * - * @see #ClassLoader(ClassLoader) - * @see #getParent() - */ - protected final Class<?> findSystemClass(String name) - throws ClassNotFoundException - { - check(); - ClassLoader system = getSystemClassLoader(); - if (system == null) { - if (!checkName(name)) - throw new ClassNotFoundException(name); - Class cls = findBootstrapClass(name); - if (cls == null) { - throw new ClassNotFoundException(name); - } - return cls; - } - return system.loadClass(name); - } - - /** - * Returns a class loaded by the bootstrap class loader; - * or return null if not found. - */ - private Class findBootstrapClassOrNull(String name) - { - check(); - if (!checkName(name)) return null; - - return findBootstrapClass(name); - } - - // return null if not found - private native Class findBootstrapClass(String name); - - // Check to make sure the class loader has been initialized. - private void check() { - if (!initialized) { - throw new SecurityException("ClassLoader object not initialized"); - } - } - - /** - * Returns the class with the given <a href="#name">binary name</a> if this - * loader has been recorded by the Java virtual machine as an initiating - * loader of a class with that <a href="#name">binary name</a>. Otherwise - * <tt>null</tt> is returned. </p> - * - * @param name - * The <a href="#name">binary name</a> of the class - * - * @return The <tt>Class</tt> object, or <tt>null</tt> if the class has - * not been loaded - * - * @since 1.1 - */ - protected final Class<?> findLoadedClass(String name) { - check(); - if (!checkName(name)) - return null; - return findLoadedClass0(name); - } - - private native final Class findLoadedClass0(String name); - - /** - * Sets the signers of a class. This should be invoked after defining a - * class. </p> - * - * @param c - * The <tt>Class</tt> object - * - * @param signers - * The signers for the class - * - * @since 1.1 - */ - protected final void setSigners(Class<?> c, Object[] signers) { - check(); - c.setSigners(signers); - } - - - // -- Resource -- - - /** - * Finds the resource with the given name. A resource is some data - * (images, audio, text, etc) that can be accessed by class code in a way - * that is independent of the location of the code. - * - * <p> The name of a resource is a '<tt>/</tt>'-separated path name that - * identifies the resource. - * - * <p> This method will first search the parent class loader for the - * resource; if the parent is <tt>null</tt> the path of the class loader - * built-in to the virtual machine is searched. That failing, this method - * will invoke {@link #findResource(String)} to find the resource. </p> - * - * @param name - * The resource name - * - * @return A <tt>URL</tt> object for reading the resource, or - * <tt>null</tt> if the resource could not be found or the invoker - * doesn't have adequate privileges to get the resource. - * - * @since 1.1 - */ - public URL getResource(String name) { - URL url; - if (parent != null) { - url = parent.getResource(name); - } else { - url = getBootstrapResource(name); - } - if (url == null) { - url = findResource(name); - } - return url; - } - - /** - * Finds all the resources with the given name. A resource is some data - * (images, audio, text, etc) that can be accessed by class code in a way - * that is independent of the location of the code. - * - * <p>The name of a resource is a <tt>/</tt>-separated path name that - * identifies the resource. - * - * <p> The search order is described in the documentation for {@link - * #getResource(String)}. </p> - * - * @param name - * The resource name - * - * @return An enumeration of {@link java.net.URL <tt>URL</tt>} objects for - * the resource. If no resources could be found, the enumeration - * will be empty. Resources that the class loader doesn't have - * access to will not be in the enumeration. - * - * @throws IOException - * If I/O errors occur - * - * @see #findResources(String) - * - * @since 1.2 - */ - public Enumeration<URL> getResources(String name) throws IOException { - Enumeration[] tmp = new Enumeration[2]; - if (parent != null) { - tmp[0] = parent.getResources(name); - } else { - tmp[0] = getBootstrapResources(name); - } - tmp[1] = findResources(name); - - return new CompoundEnumeration<>(tmp); - } - - /** - * Finds the resource with the given name. Class loader implementations - * should override this method to specify where to find resources. </p> - * - * @param name - * The resource name - * - * @return A <tt>URL</tt> object for reading the resource, or - * <tt>null</tt> if the resource could not be found - * - * @since 1.2 - */ - protected URL findResource(String name) { - return null; - } - - /** - * Returns an enumeration of {@link java.net.URL <tt>URL</tt>} objects - * representing all the resources with the given name. Class loader - * implementations should override this method to specify where to load - * resources from. </p> - * - * @param name - * The resource name - * - * @return An enumeration of {@link java.net.URL <tt>URL</tt>} objects for - * the resources - * - * @throws IOException - * If I/O errors occur - * - * @since 1.2 - */ - protected Enumeration<URL> findResources(String name) throws IOException { - return java.util.Collections.emptyEnumeration(); - } - - /** - * Registers the caller as parallel capable.</p> - * The registration succeeds if and only if all of the following - * conditions are met: <br> - * 1. no instance of the caller has been created</p> - * 2. all of the super classes (except class Object) of the caller are - * registered as parallel capable</p> - * Note that once a class loader is registered as parallel capable, there - * is no way to change it back. </p> - * - * @return true if the caller is successfully registered as - * parallel capable and false if otherwise. - * - * @since 1.7 - */ - @CallerSensitive - protected static boolean registerAsParallelCapable() { - Class<? extends ClassLoader> callerClass = - Reflection.getCallerClass().asSubclass(ClassLoader.class); - return ParallelLoaders.register(callerClass); - } - - /** - * 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()}). </p> - * - * @param name - * The resource name - * - * @return A {@link java.net.URL <tt>URL</tt>} object for reading the - * resource, or <tt>null</tt> if the resource could not be found - * - * @since 1.1 - */ - public static URL getSystemResource(String name) { - ClassLoader system = getSystemClassLoader(); - if (system == null) { - return getBootstrapResource(name); - } - return system.getResource(name); - } - - /** - * Finds all resources of the specified name from the search path used to - * load classes. The resources thus found are returned as an - * {@link java.util.Enumeration <tt>Enumeration</tt>} of {@link - * java.net.URL <tt>URL</tt>} objects. - * - * <p> The search order is described in the documentation for {@link - * #getSystemResource(String)}. </p> - * - * @param name - * The resource name - * - * @return An enumeration of resource {@link java.net.URL <tt>URL</tt>} - * objects - * - * @throws IOException - * If I/O errors occur - - * @since 1.2 - */ - public static Enumeration<URL> getSystemResources(String name) - throws IOException - { - ClassLoader system = getSystemClassLoader(); - if (system == null) { - return getBootstrapResources(name); - } - return system.getResources(name); - } - - /** - * Find resources from the VM's built-in classloader. - */ - private static native URL getBootstrapResource(String name); - - /** - * Find resources from the VM's built-in classloader. - */ - private static native Enumeration<URL> getBootstrapResources(String name) - throws IOException; - - // Returns the URLClassPath that is used for finding system resources. - static URLClassPath getBootstrapClassPath() { - return sun.misc.Launcher.getBootstrapClassPath(); - } - - - /** - * Returns an input stream for reading the specified resource. - * - * <p> The search order is described in the documentation for {@link - * #getResource(String)}. </p> - * - * @param name - * The resource name - * - * @return An input stream for reading the resource, or <tt>null</tt> - * if the resource could not be found - * - * @since 1.1 - */ - public InputStream getResourceAsStream(String name) { - URL url = getResource(name); - try { - return url != null ? url.openStream() : null; - } catch (IOException e) { - return null; - } - } - - /** - * 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()}). </p> - * - * @param name - * The resource name - * - * @return An input stream for reading the resource, or <tt>null</tt> - * if the resource could not be found - * - * @since 1.1 - */ - public static InputStream getSystemResourceAsStream(String name) { - URL url = getSystemResource(name); - try { - return url != null ? url.openStream() : null; - } catch (IOException e) { - return null; - } - } - - - // -- Hierarchy -- - - /** - * Returns the parent class loader for delegation. Some implementations may - * use <tt>null</tt> to represent the bootstrap class loader. This method - * will return <tt>null</tt> in such implementations if this class loader's - * parent is the bootstrap class loader. - * - * <p> If a security manager is present, and the invoker's class loader is - * not <tt>null</tt> and is not an ancestor of this class loader, then this - * method invokes the security manager's {@link - * SecurityManager#checkPermission(java.security.Permission) - * <tt>checkPermission</tt>} method with a {@link - * RuntimePermission#RuntimePermission(String) - * <tt>RuntimePermission("getClassLoader")</tt>} permission to verify - * access to the parent class loader is permitted. If not, a - * <tt>SecurityException</tt> will be thrown. </p> - * - * @return The parent <tt>ClassLoader</tt> - * - * @throws SecurityException - * If a security manager exists and its <tt>checkPermission</tt> - * method doesn't allow access to this class loader's parent class - * loader. - * - * @since 1.2 - */ - @CallerSensitive - public final ClassLoader getParent() { - if (parent == null) - return null; - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - checkClassLoaderPermission(parent, Reflection.getCallerClass()); - } - return parent; - } - - /** - * Returns the system class loader for delegation. This is the default - * delegation parent for new <tt>ClassLoader</tt> instances, and is - * typically the class loader used to start the application. - * - * <p> This method is first invoked early in the runtime's startup - * sequence, at which point it creates the system class loader and sets it - * as the context class loader of the invoking <tt>Thread</tt>. - * - * <p> The default system class loader is an implementation-dependent - * instance of this class. - * - * <p> If the system property "<tt>java.system.class.loader</tt>" is defined - * when this method is first invoked then the value of that property is - * taken to be the name of a class that will be returned as the system - * class loader. The class is loaded using the default system class loader - * and must define a public constructor that takes a single parameter of - * type <tt>ClassLoader</tt> which is used as the delegation parent. An - * instance is then created using this constructor with the default system - * class loader as the parameter. The resulting class loader is defined - * to be the system class loader. - * - * <p> If a security manager is present, and the invoker's class loader is - * not <tt>null</tt> and the invoker's class loader is not the same as or - * an ancestor of the system class loader, then this method invokes the - * security manager's {@link - * SecurityManager#checkPermission(java.security.Permission) - * <tt>checkPermission</tt>} method with a {@link - * RuntimePermission#RuntimePermission(String) - * <tt>RuntimePermission("getClassLoader")</tt>} permission to verify - * access to the system class loader. If not, a - * <tt>SecurityException</tt> will be thrown. </p> - * - * @return The system <tt>ClassLoader</tt> for delegation, or - * <tt>null</tt> if none - * - * @throws SecurityException - * If a security manager exists and its <tt>checkPermission</tt> - * method doesn't allow access to the system class loader. - * - * @throws IllegalStateException - * If invoked recursively during the construction of the class - * loader specified by the "<tt>java.system.class.loader</tt>" - * property. - * - * @throws Error - * If the system property "<tt>java.system.class.loader</tt>" - * is defined but the named class could not be loaded, the - * provider class does not define the required constructor, or an - * exception is thrown by that constructor when it is invoked. The - * underlying cause of the error can be retrieved via the - * {@link Throwable#getCause()} method. - * - * @revised 1.4 - */ - @CallerSensitive - public static ClassLoader getSystemClassLoader() { - initSystemClassLoader(); - if (scl == null) { - return null; - } - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - checkClassLoaderPermission(scl, Reflection.getCallerClass()); - } - return scl; - } - - private static synchronized void initSystemClassLoader() { - if (!sclSet) { - if (scl != null) - throw new IllegalStateException("recursive invocation"); - sun.misc.Launcher l = sun.misc.Launcher.getLauncher(); - if (l != null) { - Throwable oops = null; - scl = l.getClassLoader(); - try { - scl = AccessController.doPrivileged( - new SystemClassLoaderAction(scl)); - } catch (PrivilegedActionException pae) { - oops = pae.getCause(); - if (oops instanceof InvocationTargetException) { - oops = oops.getCause(); - } - } - if (oops != null) { - if (oops instanceof Error) { - throw (Error) oops; - } else { - // wrap the exception - throw new Error(oops); - } - } - } - sclSet = true; - } - } - - // Returns true if the specified class loader can be found in this class - // loader's delegation chain. - boolean isAncestor(ClassLoader cl) { - ClassLoader acl = this; - do { - acl = acl.parent; - if (cl == acl) { - return true; - } - } while (acl != null); - return false; - } - - // Tests if class loader access requires "getClassLoader" permission - // check. A class loader 'from' can access class loader 'to' if - // class loader 'from' is same as class loader 'to' or an ancestor - // of 'to'. The class loader in a system domain can access - // any class loader. - private static boolean needsClassLoaderPermissionCheck(ClassLoader from, - ClassLoader to) - { - if (from == to) - return false; - - if (from == null) - return false; - - return !to.isAncestor(from); - } - - // Returns the class's class loader, or null if none. - static ClassLoader getClassLoader(Class<?> caller) { - // This can be null if the VM is requesting it - if (caller == null) { - return null; - } - // Circumvent security check since this is package-private - return caller.getClassLoader0(); - } - - static void checkClassLoaderPermission(ClassLoader cl, Class<?> caller) { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - // caller can be null if the VM is requesting it - ClassLoader ccl = getClassLoader(caller); - if (needsClassLoaderPermissionCheck(ccl, cl)) { - sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); - } - } - } - - // The class loader for the system - // @GuardedBy("ClassLoader.class") - private static ClassLoader scl; - - // Set to true once the system class loader has been set - // @GuardedBy("ClassLoader.class") - private static boolean sclSet; - - - // -- Package -- - - /** - * Defines a package by name in this <tt>ClassLoader</tt>. This allows - * 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. </p> - * - * @param name - * The package name - * - * @param specTitle - * The specification title - * - * @param specVersion - * The specification version - * - * @param specVendor - * The specification vendor - * - * @param implTitle - * The implementation title - * - * @param implVersion - * The implementation version - * - * @param implVendor - * The implementation vendor - * - * @param sealBase - * If not <tt>null</tt>, then this package is sealed with - * respect to the given code source {@link java.net.URL - * <tt>URL</tt>} object. Otherwise, the package is not sealed. - * - * @return The newly defined <tt>Package</tt> object - * - * @throws IllegalArgumentException - * If package name duplicates an existing package either in this - * class loader or one of its ancestors - * - * @since 1.2 - */ - protected Package definePackage(String name, String specTitle, - String specVersion, String specVendor, - String implTitle, String implVersion, - String implVendor, URL sealBase) - throws IllegalArgumentException - { - synchronized (packages) { - Package pkg = getPackage(name); - if (pkg != null) { - throw new IllegalArgumentException(name); - } - pkg = new Package(name, specTitle, specVersion, specVendor, - implTitle, implVersion, implVendor, - sealBase, this); - packages.put(name, pkg); - return pkg; - } - } - - /** - * Returns a <tt>Package</tt> that has been defined by this class loader - * or any of its ancestors. </p> - * - * @param name - * The package name - * - * @return The <tt>Package</tt> corresponding to the given name, or - * <tt>null</tt> if not found - * - * @since 1.2 - */ - protected Package getPackage(String name) { - Package pkg; - synchronized (packages) { - pkg = packages.get(name); - } - if (pkg == null) { - if (parent != null) { - pkg = parent.getPackage(name); - } else { - pkg = Package.getSystemPackage(name); - } - if (pkg != null) { - synchronized (packages) { - Package pkg2 = packages.get(name); - if (pkg2 == null) { - packages.put(name, pkg); - } else { - pkg = pkg2; - } - } - } - } - return pkg; - } - - /** - * Returns all of the <tt>Packages</tt> defined by this class loader and - * its ancestors. </p> - * - * @return The array of <tt>Package</tt> objects defined by this - * <tt>ClassLoader</tt> - * - * @since 1.2 - */ - protected Package[] getPackages() { - Map<String, Package> map; - synchronized (packages) { - map = new HashMap<>(packages); - } - Package[] pkgs; - if (parent != null) { - pkgs = parent.getPackages(); - } else { - pkgs = Package.getSystemPackages(); - } - if (pkgs != null) { - for (int i = 0; i < pkgs.length; i++) { - String pkgName = pkgs[i].getName(); - if (map.get(pkgName) == null) { - map.put(pkgName, pkgs[i]); - } - } - } - return map.values().toArray(new Package[map.size()]); - } - - - // -- Native library access -- - - /** - * Returns the absolute path name of a native library. The VM invokes this - * method to locate the native libraries that belong to classes loaded with - * this class loader. If this method returns <tt>null</tt>, the VM - * searches the library along the path specified as the - * "<tt>java.library.path</tt>" property. </p> - * - * @param libname - * The library name - * - * @return The absolute path of the native library - * - * @see System#loadLibrary(String) - * @see System#mapLibraryName(String) - * - * @since 1.2 - */ - protected String findLibrary(String libname) { - return null; - } - - /** - * The inner class NativeLibrary denotes a loaded native library instance. - * Every classloader contains a vector of loaded native libraries in the - * private field <tt>nativeLibraries</tt>. The native libraries loaded - * into the system are entered into the <tt>systemNativeLibraries</tt> - * vector. - * - * <p> Every native library requires a particular version of JNI. This is - * denoted by the private <tt>jniVersion</tt> field. This field is set by - * the VM when it loads the library, and used by the VM to pass the correct - * version of JNI to the native methods. </p> - * - * @see ClassLoader - * @since 1.2 - */ - static class NativeLibrary { - // opaque handle to native library, used in native code. - long handle; - // the version of JNI environment the native library requires. - private int jniVersion; - // the class from which the library is loaded, also indicates - // the loader this native library belongs. - Class fromClass; - // the canonicalized name of the native library. - String name; - - native void load(String name); - native long find(String name); - native void unload(); - - public NativeLibrary(Class fromClass, String name) { - this.name = name; - this.fromClass = fromClass; - } - - protected void finalize() { - synchronized (loadedLibraryNames) { - if (fromClass.getClassLoader() != null && handle != 0) { - /* remove the native library name */ - int size = loadedLibraryNames.size(); - for (int i = 0; i < size; i++) { - if (name.equals(loadedLibraryNames.elementAt(i))) { - loadedLibraryNames.removeElementAt(i); - break; - } - } - /* unload the library. */ - ClassLoader.nativeLibraryContext.push(this); - try { - unload(); - } finally { - ClassLoader.nativeLibraryContext.pop(); - } - } - } - } - // Invoked in the VM to determine the context class in - // JNI_Load/JNI_Unload - static Class getFromClass() { - return ClassLoader.nativeLibraryContext.peek().fromClass; - } - } - - // All native library names we've loaded. - private static Vector<String> loadedLibraryNames = new Vector<>(); - - // Native libraries belonging to system classes. - private static Vector<NativeLibrary> systemNativeLibraries - = new Vector<>(); - - // Native libraries associated with the class loader. - private Vector<NativeLibrary> nativeLibraries = new Vector<>(); - - // native libraries being loaded/unloaded. - private static Stack<NativeLibrary> nativeLibraryContext = new Stack<>(); - - // The paths searched for libraries - private static String usr_paths[]; - private static String sys_paths[]; - - private static String[] initializePath(String ldpath) { - String ps = File.pathSeparator; - int ldlen = ldpath.length(); - int i, j, n; - // Count the separators in the path - i = ldpath.indexOf(ps); - n = 0; - while (i >= 0) { - n++; - i = ldpath.indexOf(ps, i + 1); - } - - // allocate the array of paths - n :'s = n + 1 path elements - String[] paths = new String[n + 1]; - - // Fill the array with paths from the ldpath - n = i = 0; - j = ldpath.indexOf(ps); - while (j >= 0) { - if (j - i > 0) { - paths[n++] = ldpath.substring(i, j); - } else if (j - i == 0) { - paths[n++] = "."; - } - i = j + 1; - j = ldpath.indexOf(ps, i); - } - paths[n] = ldpath.substring(i, ldlen); - return paths; - } - - private static String java_library_path; - private static String sun_boot_library_path; - - static void initializeLibraryPaths(java.util.Properties props) - { - java_library_path = props.getProperty("java.library.path", ""); - sun_boot_library_path = props.getProperty("sun.boot.library.path", ""); - } - - // Invoked in the java.lang.Runtime class to implement load and loadLibrary. - static void loadLibrary(Class fromClass, String name, - boolean isAbsolute) { - ClassLoader loader = - (fromClass == null) ? null : fromClass.getClassLoader(); - if (sys_paths == null) { - usr_paths = initializePath(java_library_path); - sys_paths = initializePath(sun_boot_library_path); - } - if (isAbsolute) { - if (loadLibrary0(fromClass, new File(name))) { - return; - } - throw new UnsatisfiedLinkError("Can't load library: " + name); - } - if (loader != null) { - String libfilename = loader.findLibrary(name); - if (libfilename != null) { - File libfile = new File(libfilename); - if (!libfile.isAbsolute()) { - throw new UnsatisfiedLinkError( - "ClassLoader.findLibrary failed to return an absolute path: " + libfilename); - } - if (loadLibrary0(fromClass, libfile)) { - return; - } - throw new UnsatisfiedLinkError("Can't load " + libfilename); - } - } - for (int i = 0 ; i < sys_paths.length ; i++) { - File libfile = new File(sys_paths[i], System.mapLibraryName(name)); - if (loadLibrary0(fromClass, libfile)) { - return; - } - } - if (loader != null) { - for (int i = 0 ; i < usr_paths.length ; i++) { - File libfile = new File(usr_paths[i], - System.mapLibraryName(name)); - if (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<Object>() { - 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; - } - ClassLoader loader = - (fromClass == null) ? null : fromClass.getClassLoader(); - Vector<NativeLibrary> libs = - loader != null ? loader.nativeLibraries : systemNativeLibraries; - synchronized (libs) { - int size = libs.size(); - for (int i = 0; i < size; i++) { - NativeLibrary lib = libs.elementAt(i); - if (name.equals(lib.name)) { - return true; - } - } - - synchronized (loadedLibraryNames) { - if (loadedLibraryNames.contains(name)) { - throw new UnsatisfiedLinkError - ("Native Library " + - name + - " already loaded in another classloader"); - } - /* If the library is being loaded (must be by the same thread, - * because Runtime.load and Runtime.loadLibrary are - * synchronous). The reason is can occur is that the JNI_OnLoad - * function can cause another loadLibrary invocation. - * - * Thus we can use a static stack to hold the list of libraries - * we are loading. - * - * If there is a pending load operation for the library, we - * immediately return success; otherwise, we raise - * UnsatisfiedLinkError. - */ - int n = nativeLibraryContext.size(); - for (int i = 0; i < n; i++) { - NativeLibrary lib = nativeLibraryContext.elementAt(i); - if (name.equals(lib.name)) { - if (loader == lib.fromClass.getClassLoader()) { - return true; - } else { - throw new UnsatisfiedLinkError - ("Native Library " + - name + - " is being loaded in another classloader"); - } - } - } - NativeLibrary lib = new NativeLibrary(fromClass, name); - nativeLibraryContext.push(lib); - try { - lib.load(name); - } finally { - nativeLibraryContext.pop(); - } - if (lib.handle != 0) { - loadedLibraryNames.addElement(name); - libs.addElement(lib); - return true; - } - return false; - } - } - } - - // Invoked in the VM class linking code. - static long findNative(ClassLoader loader, String name) { - Vector<NativeLibrary> libs = - loader != null ? loader.nativeLibraries : systemNativeLibraries; - synchronized (libs) { - int size = libs.size(); - for (int i = 0; i < size; i++) { - NativeLibrary lib = libs.elementAt(i); - long entry = lib.find(name); - if (entry != 0) - return entry; - } - } - return 0; - } - - - // -- Assertion management -- - - final Object assertionLock; - - // The default toggle for assertion checking. - // @GuardedBy("assertionLock") - private boolean defaultAssertionStatus = false; - - // Maps String packageName to Boolean package default assertion status Note - // that the default package is placed under a null map key. If this field - // is null then we are delegating assertion status queries to the VM, i.e., - // none of this ClassLoader's assertion status modification methods have - // been invoked. - // @GuardedBy("assertionLock") - private Map<String, Boolean> packageAssertionStatus = null; - - // Maps String fullyQualifiedClassName to Boolean assertionStatus If this - // field is null then we are delegating assertion status queries to the VM, - // i.e., none of this ClassLoader's assertion status modification methods - // have been invoked. - // @GuardedBy("assertionLock") - Map<String, Boolean> classAssertionStatus = null; - - /** - * Sets the default assertion status for this class loader. This setting - * determines whether classes loaded by this class loader and initialized - * 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)}. </p> - * - * @param enabled - * <tt>true</tt> if classes loaded by this class loader will - * henceforth have assertions enabled by default, <tt>false</tt> - * if they will have assertions disabled by default. - * - * @since 1.4 - */ - public void setDefaultAssertionStatus(boolean enabled) { - synchronized (assertionLock) { - if (classAssertionStatus == null) - initializeJavaAssertionMaps(); - - defaultAssertionStatus = enabled; - } - } - - /** - * Sets the package default assertion status for the named package. The - * package default assertion status determines the assertion status for - * classes initialized in the future that belong to the named package or - * any of its "subpackages". - * - * <p> A subpackage of a package named p is any package whose name begins - * with "<tt>p.</tt>". For example, <tt>javax.swing.text</tt> is a - * subpackage of <tt>javax.swing</tt>, and both <tt>java.util</tt> and - * <tt>java.lang.reflect</tt> are subpackages of <tt>java</tt>. - * - * <p> In the event that multiple package defaults apply to a given class, - * the package default pertaining to the most specific package takes - * precedence over the others. For example, if <tt>javax.lang</tt> and - * <tt>javax.lang.reflect</tt> both have package defaults associated with - * them, the latter package default applies to classes in - * <tt>javax.lang.reflect</tt>. - * - * <p> Package defaults take precedence over the class loader's default - * assertion status, and may be overridden on a per-class basis by invoking - * {@link #setClassAssertionStatus(String, boolean)}. </p> - * - * @param packageName - * The name of the package whose package default assertion status - * is to be set. A <tt>null</tt> value indicates the unnamed - * package that is "current" - * (see section 7.4.2 of - * <cite>The Java™ Language Specification</cite>.) - * - * @param enabled - * <tt>true</tt> if classes loaded by this classloader and - * belonging to the named package or any of its subpackages will - * have assertions enabled by default, <tt>false</tt> if they will - * have assertions disabled by default. - * - * @since 1.4 - */ - public void setPackageAssertionStatus(String packageName, - boolean enabled) { - synchronized (assertionLock) { - if (packageAssertionStatus == null) - initializeJavaAssertionMaps(); - - packageAssertionStatus.put(packageName, enabled); - } - } - - /** - * Sets the desired assertion status for the named top-level class in this - * class loader and any nested classes contained therein. This setting - * takes precedence over the class loader's default assertion status, and - * over any applicable per-package default. This method has no effect if - * the named class has already been initialized. (Once a class is - * initialized, its assertion status cannot change.) - * - * <p> If the named class is not a top-level class, this invocation will - * have no effect on the actual assertion status of any class. </p> - * - * @param className - * The fully qualified class name of the top-level class whose - * assertion status is to be set. - * - * @param enabled - * <tt>true</tt> if the named class is to have assertions - * enabled when (and if) it is initialized, <tt>false</tt> if the - * class is to have assertions disabled. - * - * @since 1.4 - */ - public void setClassAssertionStatus(String className, boolean enabled) { - synchronized (assertionLock) { - if (classAssertionStatus == null) - initializeJavaAssertionMaps(); - - classAssertionStatus.put(className, enabled); - } - } - - /** - * Sets the default assertion status for this class loader to - * <tt>false</tt> and discards any package defaults or class assertion - * 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." - * </p> - * - * @since 1.4 - */ - public void clearAssertionStatus() { - /* - * Whether or not "Java assertion maps" are initialized, set - * them to empty maps, effectively ignoring any present settings. - */ - synchronized (assertionLock) { - classAssertionStatus = new HashMap<>(); - packageAssertionStatus = new HashMap<>(); - defaultAssertionStatus = false; - } - } - - /** - * Returns the assertion status that would be assigned to the specified - * class if it were to be initialized at the time this method is invoked. - * If the named class has had its assertion status set, the most recent - * setting will be returned; otherwise, if any package default assertion - * status pertains to this class, the most recent setting for the most - * specific pertinent package default assertion status is returned; - * otherwise, this class loader's default assertion status is returned. - * </p> - * - * @param className - * The fully qualified class name of the class whose desired - * assertion status is being queried. - * - * @return The desired assertion status of the specified class. - * - * @see #setClassAssertionStatus(String, boolean) - * @see #setPackageAssertionStatus(String, boolean) - * @see #setDefaultAssertionStatus(boolean) - * - * @since 1.4 - */ - boolean desiredAssertionStatus(String className) { - synchronized (assertionLock) { - // assert classAssertionStatus != null; - // assert packageAssertionStatus != null; - - // Check for a class entry - Boolean result = classAssertionStatus.get(className); - if (result != null) - return result.booleanValue(); - - // Check for most specific package entry - int dotIndex = className.lastIndexOf("."); - if (dotIndex < 0) { // default package - result = packageAssertionStatus.get(null); - if (result != null) - return result.booleanValue(); - } - while(dotIndex > 0) { - className = className.substring(0, dotIndex); - result = packageAssertionStatus.get(className); - if (result != null) - return result.booleanValue(); - dotIndex = className.lastIndexOf(".", dotIndex-1); - } - - // Return the classloader default - return defaultAssertionStatus; - } - } - - // Set up the assertions with information provided by the VM. - // Note: Should only be called inside a synchronized block - private void initializeJavaAssertionMaps() { - // assert Thread.holdsLock(assertionLock); - - classAssertionStatus = new HashMap<>(); - packageAssertionStatus = new HashMap<>(); - AssertionStatusDirectives directives = retrieveDirectives(); - - for(int i = 0; i < directives.classes.length; i++) - classAssertionStatus.put(directives.classes[i], - directives.classEnabled[i]); - - for(int i = 0; i < directives.packages.length; i++) - packageAssertionStatus.put(directives.packages[i], - directives.packageEnabled[i]); - - defaultAssertionStatus = directives.deflt; - } - - // Retrieves the assertion directives from the VM. - private static native AssertionStatusDirectives retrieveDirectives(); - - // [IKVM] equivalent of HotSpot's java_lang_ClassLoader::is_trusted_loader() - static boolean isTrustedLoader(ClassLoader loader) { - ClassLoader cl = scl; - while (cl != null) { - if (cl == loader) return true; - cl = cl.parent; - } - return false; - } -} - - -class SystemClassLoaderAction - implements PrivilegedExceptionAction<ClassLoader> { - private ClassLoader parent; - - SystemClassLoaderAction(ClassLoader parent) { - this.parent = parent; - } - - public ClassLoader run() throws Exception { - String cls = System.getProperty("java.system.class.loader"); - if (cls == null) { - return parent; - } - - Constructor ctor = Class.forName(cls, true, parent) - .getDeclaredConstructor(new Class[] { ClassLoader.class }); - ClassLoader sys = (ClassLoader) ctor.newInstance( - new Object[] { parent }); - Thread.currentThread().setContextClassLoader(sys); - return sys; - } -} diff --git a/openjdk/java/lang/ClassLoaderHelper.java b/openjdk/java/lang/ClassLoaderHelper.java deleted file mode 100644 index c37c47e8..00000000 --- a/openjdk/java/lang/ClassLoaderHelper.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2012, 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; - -import java.io.File; - -class ClassLoaderHelper { - - private ClassLoaderHelper() {} - - /** - * Returns an alternate path name for the given file - * such that if the original pathname did not exist, then the - * file may be located at the alternate location. - * For mac, this replaces the final .dylib suffix with .jnilib - */ - static File mapAlternativeName(File lib) { - if (ikvm.internal.Util.MACOSX) { - String name = lib.toString(); - int index = name.toLowerCase().lastIndexOf(".dylib"); - if (index < 0) { - return null; - } - return new File(name.substring(0, index) + ".jnilib"); - } else { - return null; - } - } -} diff --git a/openjdk/java/lang/Enum.java b/openjdk/java/lang/Enum.java deleted file mode 100644 index b29550b4..00000000 --- a/openjdk/java/lang/Enum.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright (c) 2003, 2009, 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; - -import java.io.Serializable; -import java.io.IOException; -import java.io.InvalidObjectException; -import java.io.ObjectInputStream; -import java.io.ObjectStreamException; -import cli.System.Runtime.Serialization.IObjectReference; -import cli.System.Runtime.Serialization.SerializationException; -import cli.System.Runtime.Serialization.SerializationInfo; -import cli.System.Runtime.Serialization.StreamingContext; - -/** - * This is the common base class of all Java language enumeration types. - * - * More information about enums, including descriptions of the - * implicitly declared methods synthesized by the compiler, can be - * found in section 8.9 of - * <cite>The Java™ Language Specification</cite>. - * - * <p> Note that when using an enumeration type as the type of a set - * or as the type of the keys in a map, specialized and efficient - * {@linkplain java.util.EnumSet set} and {@linkplain - * java.util.EnumMap map} implementations are available. - * - * @param <E> The enum type subclass - * @author Josh Bloch - * @author Neal Gafter - * @see Class#getEnumConstants() - * @see java.util.EnumSet - * @see java.util.EnumMap - * @since 1.5 - */ -@cli.System.SerializableAttribute.Annotation -public abstract class Enum<E extends Enum<E>> - implements Comparable<E>, Serializable { - /** - * The name of this enum constant, as declared in the enum declaration. - * Most programmers should use the {@link #toString} method rather than - * accessing this field. - */ - private final String name; - - /** - * Returns the name of this enum constant, exactly as declared in its - * enum declaration. - * - * <b>Most programmers should use the {@link #toString} method in - * preference to this one, as the toString method may return - * a more user-friendly name.</b> This method is designed primarily for - * use in specialized situations where correctness depends on getting the - * exact name, which will not vary from release to release. - * - * @return the name of this enum constant - */ - public final String name() { - return name; - } - - /** - * The ordinal of this enumeration constant (its position - * in the enum declaration, where the initial constant is assigned - * an ordinal of zero). - * - * Most programmers will have no use for this field. It is designed - * for use by sophisticated enum-based data structures, such as - * {@link java.util.EnumSet} and {@link java.util.EnumMap}. - */ - private final int ordinal; - - /** - * Returns the ordinal of this enumeration constant (its position - * in its enum declaration, where the initial constant is assigned - * an ordinal of zero). - * - * Most programmers will have no use for this method. It is - * designed for use by sophisticated enum-based data structures, such - * as {@link java.util.EnumSet} and {@link java.util.EnumMap}. - * - * @return the ordinal of this enumeration constant - */ - public final int ordinal() { - return ordinal; - } - - /** - * Sole constructor. Programmers cannot invoke this constructor. - * It is for use by code emitted by the compiler in response to - * enum type declarations. - * - * @param name - The name of this enum constant, which is the identifier - * used to declare it. - * @param ordinal - The ordinal of this enumeration constant (its position - * in the enum declaration, where the initial constant is assigned - * an ordinal of zero). - */ - protected Enum(String name, int ordinal) { - this.name = name; - this.ordinal = ordinal; - } - - /** - * Returns the name of this enum constant, as contained in the - * declaration. This method may be overridden, though it typically - * isn't necessary or desirable. An enum type should override this - * method when a more "programmer-friendly" string form exists. - * - * @return the name of this enum constant - */ - public String toString() { - return name; - } - - /** - * Returns true if the specified object is equal to this - * enum constant. - * - * @param other the object to be compared for equality with this object. - * @return true if the specified object is equal to this - * enum constant. - */ - public final boolean equals(Object other) { - return this==other; - } - - /** - * Returns a hash code for this enum constant. - * - * @return a hash code for this enum constant. - */ - public final int hashCode() { - return super.hashCode(); - } - - /** - * Throws CloneNotSupportedException. This guarantees that enums - * are never cloned, which is necessary to preserve their "singleton" - * status. - * - * @return (never returns) - */ - protected final Object clone() throws CloneNotSupportedException { - throw new CloneNotSupportedException(); - } - - /** - * Compares this enum with the specified object for order. Returns a - * negative integer, zero, or a positive integer as this object is less - * than, equal to, or greater than the specified object. - * - * Enum constants are only comparable to other enum constants of the - * same enum type. The natural order implemented by this - * method is the order in which the constants are declared. - */ - public final int compareTo(E o) { - Enum other = (Enum)o; - Enum self = this; - if (self.getClass() != other.getClass() && // optimization - self.getDeclaringClass() != other.getDeclaringClass()) - throw new ClassCastException(); - return self.ordinal - other.ordinal; - } - - /** - * Returns the Class object corresponding to this enum constant's - * enum type. Two enum constants e1 and e2 are of the - * same enum type if and only if - * e1.getDeclaringClass() == e2.getDeclaringClass(). - * (The value returned by this method may differ from the one returned - * by the {@link Object#getClass} method for enum constants with - * constant-specific class bodies.) - * - * @return the Class object corresponding to this enum constant's - * enum type - */ - public final Class<E> getDeclaringClass() { - Class clazz = getClass(); - Class zuper = clazz.getSuperclass(); - return (zuper == Enum.class) ? clazz : zuper; - } - - /** - * Returns the enum constant of the specified enum type with the - * specified name. The name must match exactly an identifier used - * to declare an enum constant in this type. (Extraneous whitespace - * characters are not permitted.) - * - * <p>Note that for a particular enum type {@code T}, the - * implicitly declared {@code public static T valueOf(String)} - * method on that enum may be used instead of this method to map - * from a name to the corresponding enum constant. All the - * constants of an enum type can be obtained by calling the - * implicit {@code public static T[] values()} method of that - * type. - * - * @param <T> The enum type whose constant is to be returned - * @param enumType the {@code Class} object of the enum type from which - * to return a constant - * @param name the name of the constant to return - * @return the enum constant of the specified enum type with the - * specified name - * @throws IllegalArgumentException if the specified enum type has - * no constant with the specified name, or the specified - * class object does not represent an enum type - * @throws NullPointerException if {@code enumType} or {@code name} - * is null - * @since 1.5 - */ - public static <T extends Enum<T>> T valueOf(Class<T> enumType, - String name) { - T result = enumType.enumConstantDirectory().get(name); - if (result != null) - return result; - if (name == null) - throw new NullPointerException("Name is null"); - throw new IllegalArgumentException( - "No enum constant " + enumType.getCanonicalName() + "." + name); - } - - /** - * enum classes cannot have finalize methods. - */ - protected final void finalize() { } - - /** - * prevent default deserialization - */ - private void readObject(ObjectInputStream in) throws IOException, - ClassNotFoundException { - throw new InvalidObjectException("can't deserialize enum"); - } - - private void readObjectNoData() throws ObjectStreamException { - throw new InvalidObjectException("can't deserialize enum"); - } - - // [IKVM] .NET serialization support starts here - // Note that we don't have a security demand, because the info is harmless. - @cli.IKVM.Attributes.HideFromJavaAttribute.Annotation - @cli.System.Security.SecurityCriticalAttribute.Annotation - public final void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue("enumType", getDeclaringClass()); - info.AddValue("name", name); - info.SetType(ikvm.runtime.Util.getInstanceTypeFromClass(EnumSerializationProxy.class)); - } -} - -@cli.System.SerializableAttribute.Annotation -final class EnumSerializationProxy implements IObjectReference -{ - private Class enumType; - private String name; - - @cli.System.Security.SecurityCriticalAttribute.Annotation - public Object GetRealObject(StreamingContext context) - { - try - { - return Enum.valueOf(enumType, name); - } - catch (IllegalArgumentException x) - { - ikvm.runtime.Util.throwException(new SerializationException("Enum value " + name + " not found in " + enumType, x)); - return null; - } - } -} diff --git a/openjdk/java/lang/LangHelper.java b/openjdk/java/lang/LangHelper.java deleted file mode 100644 index 8d725d43..00000000 --- a/openjdk/java/lang/LangHelper.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - Copyright (C) 2007-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 - 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 java.lang.annotation.Annotation; -import java.lang.reflect.Executable; -import java.security.AccessControlContext; -import java.util.Map; -import sun.nio.ch.Interruptible; -import sun.reflect.annotation.AnnotationType; - -@ikvm.lang.Internal -public class LangHelper -{ - public static sun.misc.JavaLangAccess getJavaLangAccess() - { - return new sun.misc.JavaLangAccess() { - public sun.reflect.ConstantPool getConstantPool(Class klass) { - return klass.getConstantPool(); - } - public boolean casAnnotationType(Class<?> klass, AnnotationType oldType, AnnotationType newType) { - return klass.casAnnotationType(oldType, newType); - } - public AnnotationType getAnnotationType(Class klass) { - return klass.getAnnotationType(); - } - public Map<Class<? extends Annotation>, Annotation> getDeclaredAnnotationMap(Class<?> klass) { - return klass.getDeclaredAnnotationMap(); - } - public byte[] getRawClassAnnotations(Class<?> klass) { - throw new InternalError(); - } - public byte[] getRawClassTypeAnnotations(Class<?> klass) { - return klass.getRawTypeAnnotations(); - } - public byte[] getRawExecutableTypeAnnotations(Executable executable) { - return Class.getExecutableTypeAnnotationBytes(executable); - } - public <E extends Enum<E>> - E[] getEnumConstantsShared(Class<E> klass) { - return klass.getEnumConstantsShared(); - } - public void blockedOn(Thread t, Interruptible b) { - t.blockedOn(b); - } - public void registerShutdownHook(int slot, boolean registerShutdownInProgress, Runnable hook) { - Shutdown.add(slot, registerShutdownInProgress, hook); - } - public int getStackTraceDepth(Throwable t) { - return t.getStackTraceDepth(); - } - public StackTraceElement getStackTraceElement(Throwable t, int i) { - return t.getStackTraceElement(i); - } - public String newStringUnsafe(char[] chars) { - return String.valueOf(chars); - } - public Thread newThreadWithAcc(Runnable target, AccessControlContext acc) { - return new Thread(target, acc); - } - public void invokeFinalize(Object o) throws Throwable { - // we don't actually support invoking the finalize method explicitly - } - }; - } -} diff --git a/openjdk/java/lang/Package.java b/openjdk/java/lang/Package.java deleted file mode 100644 index 395cf336..00000000 --- a/openjdk/java/lang/Package.java +++ /dev/null @@ -1,615 +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 java.lang; - -import java.io.InputStream; -import java.util.Enumeration; - -import java.util.StringTokenizer; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.URL; -import java.net.MalformedURLException; -import java.security.AccessController; -import java.security.PrivilegedAction; - -import java.util.jar.JarInputStream; -import java.util.jar.Manifest; -import java.util.jar.Attributes; -import java.util.jar.Attributes.Name; -import java.util.jar.JarException; -import java.util.Map; -import java.util.HashMap; -import java.util.Iterator; - -import java.lang.annotation.Annotation; -import sun.net.www.ParseUtil; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; - -/** - * {@code Package} objects contain version information - * about the implementation and specification of a Java package. - * This versioning information is retrieved and made available - * by the {@link ClassLoader} instance that - * loaded the class(es). Typically, it is stored in the manifest that is - * distributed with the classes. - * - * <p>The set of classes that make up the package may implement a - * particular specification and if so the specification title, version number, - * and vendor strings identify that specification. - * An application can ask if the package is - * compatible with a particular version, see the {@link - * #isCompatibleWith isCompatibleWith} - * method for details. - * - * <p>Specification version numbers use a syntax that consists of nonnegative - * decimal integers separated by periods ".", for example "2.0" or - * "1.2.3.4.5.6.7". This allows an extensible number to be used to represent - * major, minor, micro, etc. versions. The version specification is described - * by the following formal grammar: - * <blockquote> - * <dl> - * <dt><i>SpecificationVersion: - * <dd>Digits RefinedVersion<sub>opt</sub></i> - - * <p><dt><i>RefinedVersion:</i> - * <dd>{@code .} <i>Digits</i> - * <dd>{@code .} <i>Digits RefinedVersion</i> - * - * <p><dt><i>Digits: - * <dd>Digit - * <dd>Digits</i> - * - * <p><dt><i>Digit:</i> - * <dd>any character for which {@link Character#isDigit} returns {@code true}, - * e.g. 0, 1, 2, ... - * </dl> - * </blockquote> - * - * <p>The implementation title, version, and vendor strings identify an - * implementation and are made available conveniently to enable accurate - * reporting of the packages involved when a problem occurs. The contents - * all three implementation strings are vendor specific. The - * implementation version strings have no specified syntax and should - * only be compared for equality with desired version identifiers. - * - * <p>Within each {@code ClassLoader} instance all classes from the same - * java package have the same Package object. The static methods allow a package - * to be found by name or the set of all packages known to the current class - * loader to be found. - * - * @see ClassLoader#definePackage - */ -public class Package implements java.lang.reflect.AnnotatedElement { - /** - * Return the name of this package. - * - * @return The fully-qualified name of this package as defined in section 6.5.3 of - * <cite>The Java™ Language Specification</cite>, - * for example, {@code java.lang} - */ - public String getName() { - return pkgName; - } - - - /** - * Return the title of the specification that this package implements. - * @return the specification title, null is returned if it is not known. - */ - public String getSpecificationTitle() { - return specTitle; - } - - /** - * Returns the version number of the specification - * that this package implements. - * This version string must be a sequence of nonnegative decimal - * integers separated by "."'s and may have leading zeros. - * When version strings are compared the most significant - * numbers are compared. - * @return the specification version, null is returned if it is not known. - */ - public String getSpecificationVersion() { - return specVersion; - } - - /** - * Return the name of the organization, vendor, - * or company that owns and maintains the specification - * of the classes that implement this package. - * @return the specification vendor, null is returned if it is not known. - */ - public String getSpecificationVendor() { - return specVendor; - } - - /** - * Return the title of this package. - * @return the title of the implementation, null is returned if it is not known. - */ - public String getImplementationTitle() { - return implTitle; - } - - /** - * Return the version of this implementation. It consists of any string - * assigned by the vendor of this implementation and does - * not have any particular syntax specified or expected by the Java - * runtime. It may be compared for equality with other - * package version strings used for this implementation - * by this vendor for this package. - * @return the version of the implementation, null is returned if it is not known. - */ - public String getImplementationVersion() { - return implVersion; - } - - /** - * Returns the name of the organization, - * vendor or company that provided this implementation. - * @return the vendor that implemented this package.. - */ - public String getImplementationVendor() { - return implVendor; - } - - /** - * Returns true if this package is sealed. - * - * @return true if the package is sealed, false otherwise - */ - public boolean isSealed() { - return sealBase != null; - } - - /** - * Returns true if this package is sealed with respect to the specified - * code source url. - * - * @param url the code source url - * @return true if this package is sealed with respect to url - */ - public boolean isSealed(URL url) { - return url.equals(sealBase); - } - - /** - * Compare this package's specification version with a - * desired version. It returns true if - * this packages specification version number is greater than or equal - * to the desired version number. <p> - * - * Version numbers are compared by sequentially comparing corresponding - * components of the desired and specification strings. - * Each component is converted as a decimal integer and the values - * compared. - * If the specification value is greater than the desired - * value true is returned. If the value is less false is returned. - * If the values are equal the period is skipped and the next pair of - * components is compared. - * - * @param desired the version string of the desired version. - * @return true if this package's version number is greater - * than or equal to the desired version number - * - * @exception NumberFormatException if the desired or current version - * is not of the correct dotted form. - */ - public boolean isCompatibleWith(String desired) - throws NumberFormatException - { - if (specVersion == null || specVersion.length() < 1) { - throw new NumberFormatException("Empty version string"); - } - - String [] sa = specVersion.split("\\.", -1); - int [] si = new int[sa.length]; - for (int i = 0; i < sa.length; i++) { - si[i] = Integer.parseInt(sa[i]); - if (si[i] < 0) - throw NumberFormatException.forInputString("" + si[i]); - } - - String [] da = desired.split("\\.", -1); - int [] di = new int[da.length]; - for (int i = 0; i < da.length; i++) { - di[i] = Integer.parseInt(da[i]); - if (di[i] < 0) - throw NumberFormatException.forInputString("" + di[i]); - } - - int len = Math.max(di.length, si.length); - for (int i = 0; i < len; i++) { - int d = (i < di.length ? di[i] : 0); - int s = (i < si.length ? si[i] : 0); - if (s < d) - return false; - if (s > d) - return true; - } - return true; - } - - /** - * Find a package by name in the callers {@code ClassLoader} instance. - * The callers {@code ClassLoader} instance is used to find the package - * instance corresponding to the named class. If the callers - * {@code ClassLoader} instance is null then the set of packages loaded - * by the system {@code ClassLoader} instance is searched to find the - * named package. <p> - * - * Packages have attributes for versions and specifications only if the class - * loader created the package instance with the appropriate attributes. Typically, - * those attributes are defined in the manifests that accompany the classes. - * - * @param name a package name, for example, java.lang. - * @return the package of the requested name. It may be null if no package - * information is available from the archive or codebase. - */ - @CallerSensitive - public static Package getPackage(String name) { - ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass()); - if (l != null) { - return l.getPackage(name); - } else { - return getSystemPackage(name); - } - } - - /** - * Get all the packages currently known for the caller's {@code ClassLoader} - * instance. Those packages correspond to classes loaded via or accessible by - * name to that {@code ClassLoader} instance. If the caller's - * {@code ClassLoader} instance is the bootstrap {@code ClassLoader} - * instance, which may be represented by {@code null} in some implementations, - * only packages corresponding to classes loaded by the bootstrap - * {@code ClassLoader} instance will be returned. - * - * @return a new array of packages known to the callers {@code ClassLoader} - * instance. An zero length array is returned if none are known. - */ - @CallerSensitive - public static Package[] getPackages() { - ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass()); - if (l != null) { - return l.getPackages(); - } else { - return getSystemPackages(); - } - } - - /** - * Get the package for the specified class. - * The class's class loader is used to find the package instance - * corresponding to the specified class. If the class loader - * is the bootstrap class loader, which may be represented by - * {@code null} in some implementations, then the set of packages - * loaded by the bootstrap class loader is searched to find the package. - * <p> - * Packages have attributes for versions and specifications only - * if the class loader created the package - * instance with the appropriate attributes. Typically those - * attributes are defined in the manifests that accompany - * the classes. - * - * @param class the class to get the package of. - * @return the package of the class. It may be null if no package - * information is available from the archive or codebase. */ - static Package getPackage(Class<?> c) { - String name = c.getName(); - int i = name.lastIndexOf('.'); - if (i != -1) { - name = name.substring(0, i); - ClassLoader cl = c.getClassLoader(); - if (cl != null) { - return cl.getPackage(name); - } else { - return getSystemPackage(name); - } - } else { - return null; - } - } - - /** - * Return the hash code computed from the package name. - * @return the hash code computed from the package name. - */ - public int hashCode(){ - return pkgName.hashCode(); - } - - /** - * Returns the string representation of this Package. - * Its value is the string "package " and the package name. - * If the package title is defined it is appended. - * If the package version is defined it is appended. - * @return the string representation of the package. - */ - public String toString() { - String spec = specTitle; - String ver = specVersion; - if (spec != null && spec.length() > 0) - spec = ", " + spec; - else - spec = ""; - if (ver != null && ver.length() > 0) - ver = ", version " + ver; - else - ver = ""; - return "package " + pkgName + spec + ver; - } - - private Class<?> getPackageInfo() { - if (packageInfo == null) { - try { - packageInfo = Class.forName(pkgName + ".package-info", false, loader); - } catch (ClassNotFoundException ex) { - // store a proxy for the package info that has no annotations - class PackageInfoProxy {} - packageInfo = PackageInfoProxy.class; - } - } - return packageInfo; - } - - /** - * @throws NullPointerException {@inheritDoc} - * @since 1.5 - */ - public <A extends Annotation> A getAnnotation(Class<A> annotationClass) { - return getPackageInfo().getAnnotation(annotationClass); - } - - /** - * @throws NullPointerException {@inheritDoc} - * @since 1.5 - */ - public boolean isAnnotationPresent( - Class<? extends Annotation> annotationClass) { - return getPackageInfo().isAnnotationPresent(annotationClass); - } - - /** - * @since 1.5 - */ - public Annotation[] getAnnotations() { - return getPackageInfo().getAnnotations(); - } - - /** - * @since 1.5 - */ - public Annotation[] getDeclaredAnnotations() { - return getPackageInfo().getDeclaredAnnotations(); - } - - /** - * Construct a package instance with the specified version - * information. - * @param pkgName the name of the package - * @param spectitle the title of the specification - * @param specversion the version of the specification - * @param specvendor the organization that maintains the specification - * @param impltitle the title of the implementation - * @param implversion the version of the implementation - * @param implvendor the organization that maintains the implementation - * @return a new package for containing the specified information. - */ - Package(String name, - String spectitle, String specversion, String specvendor, - String impltitle, String implversion, String implvendor, - URL sealbase, ClassLoader loader) - { - pkgName = name; - implTitle = impltitle; - implVersion = implversion; - implVendor = implvendor; - specTitle = spectitle; - specVersion = specversion; - specVendor = specvendor; - sealBase = sealbase; - this.loader = loader; - } - - /* - * Construct a package using the attributes from the specified manifest. - * - * @param name the package name - * @param man the optional manifest for the package - * @param url the optional code source url for the package - */ - private Package(String name, Manifest man, URL url, ClassLoader loader) { - String path = name.replace('.', '/').concat("/"); - String sealed = null; - String specTitle= null; - String specVersion= null; - String specVendor= null; - String implTitle= null; - String implVersion= null; - String implVendor= null; - URL sealBase= null; - Attributes attr = man.getAttributes(path); - if (attr != null) { - specTitle = attr.getValue(Name.SPECIFICATION_TITLE); - specVersion = attr.getValue(Name.SPECIFICATION_VERSION); - specVendor = attr.getValue(Name.SPECIFICATION_VENDOR); - implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE); - implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION); - implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR); - sealed = attr.getValue(Name.SEALED); - } - attr = man.getMainAttributes(); - if (attr != null) { - if (specTitle == null) { - specTitle = attr.getValue(Name.SPECIFICATION_TITLE); - } - if (specVersion == null) { - specVersion = attr.getValue(Name.SPECIFICATION_VERSION); - } - if (specVendor == null) { - specVendor = attr.getValue(Name.SPECIFICATION_VENDOR); - } - if (implTitle == null) { - implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE); - } - if (implVersion == null) { - implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION); - } - if (implVendor == null) { - implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR); - } - if (sealed == null) { - sealed = attr.getValue(Name.SEALED); - } - } - if ("true".equalsIgnoreCase(sealed)) { - sealBase = url; - } - pkgName = name; - this.specTitle = specTitle; - this.specVersion = specVersion; - this.specVendor = specVendor; - this.implTitle = implTitle; - this.implVersion = implVersion; - this.implVendor = implVendor; - this.sealBase = sealBase; - this.loader = loader; - } - - /* - * Returns the loaded system package for the specified name. - */ - static Package getSystemPackage(String name) { - synchronized (pkgs) { - Package pkg = pkgs.get(name); - if (pkg == null) { - name = name.replace('.', '/').concat("/"); - String fn = getSystemPackage0(name); - if (fn != null) { - pkg = defineSystemPackage(name, fn); - } - } - return pkg; - } - } - - /* - * Return an array of loaded system packages. - */ - static Package[] getSystemPackages() { - // First, update the system package map with new package names - String[] names = getSystemPackages0(); - synchronized (pkgs) { - for (int i = 0; i < names.length; i++) { - defineSystemPackage(names[i], getSystemPackage0(names[i])); - } - return pkgs.values().toArray(new Package[pkgs.size()]); - } - } - - private static Package defineSystemPackage(final String iname, - final String fn) - { - return AccessController.doPrivileged(new PrivilegedAction<Package>() { - public Package run() { - String name = iname; - // Get the cached code source url for the file name - URL url = urls.get(fn); - if (url == null) { - // URL not found, so create one - File file = new File(fn); - try { - url = ParseUtil.fileToEncodedURL(file); - } catch (MalformedURLException e) { - } - if (url != null) { - urls.put(fn, url); - // If loading a JAR file, then also cache the manifest - if (file.isFile()) { - mans.put(fn, loadManifest(fn)); - } - } - } - // Convert to "."-separated package name - name = name.substring(0, name.length() - 1).replace('/', '.'); - Package pkg; - Manifest man = mans.get(fn); - if (man != null) { - pkg = new Package(name, man, url, null); - } else { - pkg = new Package(name, null, null, null, - null, null, null, null, null); - } - pkgs.put(name, pkg); - return pkg; - } - }); - } - - /* - * Returns the Manifest for the specified JAR file name. - */ - private static Manifest loadManifest(String fn) { - try (FileInputStream fis = new FileInputStream(fn); - JarInputStream jis = new JarInputStream(fis, false)) - { - return jis.getManifest(); - } catch (IOException e) { - return null; - } - } - - // The map of loaded system packages - private static Map<String, Package> pkgs = new HashMap<>(31); - - // Maps each directory or zip file name to its corresponding url - private static Map<String, URL> urls = new HashMap<>(10); - - // Maps each code source url for a jar file to its manifest - private static Map<String, Manifest> mans = new HashMap<>(10); - - private static native String getSystemPackage0(String name); - private static native String[] getSystemPackages0(); - - /* - * Private storage for the package name and attributes. - */ - private final String pkgName; - private final String specTitle; - private final String specVersion; - private final String specVendor; - private final String implTitle; - private final String implVersion; - private final String implVendor; - private final URL sealBase; - private transient final ClassLoader loader; - private transient Class packageInfo; -} diff --git a/openjdk/java/lang/ProcessImpl.java b/openjdk/java/lang/ProcessImpl.java deleted file mode 100644 index 0624dc17..00000000 --- a/openjdk/java/lang/ProcessImpl.java +++ /dev/null @@ -1,834 +0,0 @@ -/* - * 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. - */ - -/*IKVM*/ -/* - * Modified for IKVM by Jeroen Frijters - */ - -package java.lang; - -import java.io.IOException; -import java.io.File; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.FileDescriptor; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.lang.ProcessBuilder.Redirect; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import cli.System.AsyncCallback; -import cli.System.IAsyncResult; -import cli.System.Diagnostics.ProcessStartInfo; -import cli.System.EventArgs; -import cli.System.EventHandler; -import cli.System.IO.FileAccess; -import cli.System.IO.FileShare; -import cli.System.IO.FileMode; -import cli.System.IO.FileOptions; -import cli.System.IO.FileStream; -import cli.System.IO.Stream; -import cli.System.Security.AccessControl.FileSystemRights; - -/* This class is for the exclusive use of ProcessBuilder.start() to - * create new processes. - * - * @author Martin Buchholz - * @since 1.5 - */ - -final class ProcessImpl extends Process { - static class fdAccess { - static Stream getHandle(FileDescriptor fd) { - return fd.getStream(); - } - } - - /** - * Open a file for writing. If {@code append} is {@code true} then the file - * is opened for atomic append directly and a FileOutputStream constructed - * with the resulting handle. This is because a FileOutputStream created - * to append to a file does not open the file in a manner that guarantees - * that writes by the child process will be atomic. - */ - private static FileOutputStream newFileOutputStream(File f, boolean append) - throws IOException - { - if (append) { - String path = f.getPath(); - SecurityManager sm = System.getSecurityManager(); - if (sm != null) - sm.checkWrite(path); - final FileDescriptor fd = openForAtomicAppend(path); - return AccessController.doPrivileged( - new PrivilegedAction<FileOutputStream>() { - public FileOutputStream run() { - return new FileOutputStream(fd); - } - } - ); - } else { - return new FileOutputStream(f); - } - } - - // System-dependent portion of ProcessBuilder.start() - static Process start(String cmdarray[], - java.util.Map<String,String> environment, - String dir, - ProcessBuilder.Redirect[] redirects, - boolean redirectErrorStream) - throws IOException - { - FileInputStream f0 = null; - FileOutputStream f1 = null; - FileOutputStream f2 = null; - - try { - Stream[] stdHandles; - if (redirects == null) { - stdHandles = new Stream[3]; - } else { - stdHandles = new Stream[3]; - - if (redirects[0] == Redirect.PIPE) - stdHandles[0] = null; - else if (redirects[0] == Redirect.INHERIT) - stdHandles[0] = fdAccess.getHandle(FileDescriptor.in); - else { - f0 = new FileInputStream(redirects[0].file()); - stdHandles[0] = fdAccess.getHandle(f0.getFD()); - } - - if (redirects[1] == Redirect.PIPE) - stdHandles[1] = null; - else if (redirects[1] == Redirect.INHERIT) - stdHandles[1] = fdAccess.getHandle(FileDescriptor.out); - else { - f1 = newFileOutputStream(redirects[1].file(), - redirects[1].append()); - stdHandles[1] = fdAccess.getHandle(f1.getFD()); - } - - if (redirects[2] == Redirect.PIPE) - stdHandles[2] = null; - else if (redirects[2] == Redirect.INHERIT) - stdHandles[2] = fdAccess.getHandle(FileDescriptor.err); - else { - f2 = newFileOutputStream(redirects[2].file(), - redirects[2].append()); - stdHandles[2] = fdAccess.getHandle(f2.getFD()); - } - } - - return new ProcessImpl(cmdarray, environment, dir, - stdHandles, redirectErrorStream); - } catch (Throwable t) { - if (f0 != null) - f0.close(); - if (f1 != null) - f1.close(); - if (f2 != null) - f2.close(); - throw t; - } finally { - // HACK prevent the File[In|Out]putStream objects from closing the streams - // (the System.IO.FileStream will eventually be closed explicitly or by its finalizer) - if (f0 != null) - cli.System.GC.SuppressFinalize(f0); - if (f1 != null) - cli.System.GC.SuppressFinalize(f1); - if (f2 != null) - cli.System.GC.SuppressFinalize(f2); - } - - } - - private static class LazyPattern { - // Escape-support version: - // "(\")((?:\\\\\\1|.)+?)\\1|([^\\s\"]+)"; - private static final Pattern PATTERN = - Pattern.compile("[^\\s\"]+|\"[^\"]*\""); - }; - - /* Parses the command string parameter into the executable name and - * program arguments. - * - * The command string is broken into tokens. The token separator is a space - * or quota character. The space inside quotation is not a token separator. - * There are no escape sequences. - */ - private static String[] getTokensFromCommand(String command) { - ArrayList<String> matchList = new ArrayList<>(8); - Matcher regexMatcher = LazyPattern.PATTERN.matcher(command); - while (regexMatcher.find()) - matchList.add(regexMatcher.group()); - return matchList.toArray(new String[matchList.size()]); - } - - private static final int VERIFICATION_CMD_BAT = 0; - private static final int VERIFICATION_WIN32 = 1; - private static final int VERIFICATION_LEGACY = 2; - private static final char ESCAPE_VERIFICATION[][] = { - // We guarantee the only command file execution for implicit [cmd.exe] run. - // http://technet.microsoft.com/en-us/library/bb490954.aspx - {' ', '\t', '<', '>', '&', '|', '^'}, - - {' ', '\t', '<', '>'}, - {' ', '\t'} - }; - - private static String createCommandLine(int verificationType, - final String executablePath, - final String cmd[]) - { - StringBuilder cmdbuf = new StringBuilder(80); - - cmdbuf.append(executablePath); - - for (int i = 1; i < cmd.length; ++i) { - cmdbuf.append(' '); - String s = cmd[i]; - if (needsEscaping(verificationType, s)) { - cmdbuf.append('"').append(s); - - // The code protects the [java.exe] and console command line - // parser, that interprets the [\"] combination as an escape - // sequence for the ["] char. - // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx - // - // If the argument is an FS path, doubling of the tail [\] - // char is not a problem for non-console applications. - // - // The [\"] sequence is not an escape sequence for the [cmd.exe] - // command line parser. The case of the [""] tail escape - // sequence could not be realized due to the argument validation - // procedure. - if ((verificationType != VERIFICATION_CMD_BAT) && s.endsWith("\\")) { - cmdbuf.append('\\'); - } - cmdbuf.append('"'); - } else { - cmdbuf.append(s); - } - } - return cmdbuf.toString(); - } - - private static boolean isQuoted(boolean noQuotesInside, String arg, - String errorMessage) { - int lastPos = arg.length() - 1; - if (lastPos >=1 && arg.charAt(0) == '"' && arg.charAt(lastPos) == '"') { - // The argument has already been quoted. - if (noQuotesInside) { - if (arg.indexOf('"', 1) != lastPos) { - // There is ["] inside. - throw new IllegalArgumentException(errorMessage); - } - } - return true; - } - if (noQuotesInside) { - if (arg.indexOf('"') >= 0) { - // There is ["] inside. - throw new IllegalArgumentException(errorMessage); - } - } - return false; - } - - private static boolean needsEscaping(int verificationType, String arg) { - // Switch off MS heuristic for internal ["]. - // Please, use the explicit [cmd.exe] call - // if you need the internal ["]. - // Example: "cmd.exe", "/C", "Extended_MS_Syntax" - - // For [.exe] or [.com] file the unpaired/internal ["] - // in the argument is not a problem. - boolean argIsQuoted = isQuoted( - (verificationType == VERIFICATION_CMD_BAT), - arg, "Argument has embedded quote, use the explicit CMD.EXE call."); - - if (!argIsQuoted) { - char testEscape[] = ESCAPE_VERIFICATION[verificationType]; - for (int i = 0; i < testEscape.length; ++i) { - if (arg.indexOf(testEscape[i]) >= 0) { - return true; - } - } - } - return false; - } - - private static String getExecutablePath(String path) - throws IOException - { - boolean pathIsQuoted = isQuoted(true, path, - "Executable name has embedded quote, split the arguments"); - - // Win32 CreateProcess requires path to be normalized - File fileToRun = new File(pathIsQuoted - ? path.substring(1, path.length() - 1) - : path); - - // From the [CreateProcess] function documentation: - // - // "If the file name does not contain an extension, .exe is appended. - // Therefore, if the file name extension is .com, this parameter - // must include the .com extension. If the file name ends in - // a period (.) with no extension, or if the file name contains a path, - // .exe is not appended." - // - // "If the file name !does not contain a directory path!, - // the system searches for the executable file in the following - // sequence:..." - // - // In practice ANY non-existent path is extended by [.exe] extension - // in the [CreateProcess] funcion with the only exception: - // the path ends by (.) - - return fileToRun.getPath(); - } - - - private boolean isShellFile(String executablePath) { - String upPath = executablePath.toUpperCase(); - return (upPath.endsWith(".CMD") || upPath.endsWith(".BAT")); - } - - private String quoteString(String arg) { - StringBuilder argbuf = new StringBuilder(arg.length() + 2); - return argbuf.append('"').append(arg).append('"').toString(); - } - - - private cli.System.Diagnostics.Process handle; - private OutputStream stdin_stream; - private InputStream stdout_stream; - private InputStream stderr_stream; - - private ProcessImpl(String cmd[], - final java.util.Map<String,String> envblock, - final String path, - final Stream[] stdHandles, - final boolean redirectErrorStream) - throws IOException - { - String cmdstr; - SecurityManager security = System.getSecurityManager(); - boolean allowAmbiguousCommands = false; - if (security == null) { - allowAmbiguousCommands = true; - String value = System.getProperty("jdk.lang.Process.allowAmbiguousCommands"); - if (value != null) - allowAmbiguousCommands = !"false".equalsIgnoreCase(value); - } - if (allowAmbiguousCommands) { - // Legacy mode. - - // Normalize path if possible. - String executablePath = new File(cmd[0]).getPath(); - - // No worry about internal, unpaired ["], and redirection/piping. - if (needsEscaping(VERIFICATION_LEGACY, executablePath) ) - executablePath = quoteString(executablePath); - - cmdstr = createCommandLine( - //legacy mode doesn't worry about extended verification - VERIFICATION_LEGACY, - executablePath, - cmd); - } else { - String executablePath; - try { - executablePath = getExecutablePath(cmd[0]); - } catch (IllegalArgumentException e) { - // Workaround for the calls like - // Runtime.getRuntime().exec("\"C:\\Program Files\\foo\" bar") - - // No chance to avoid CMD/BAT injection, except to do the work - // right from the beginning. Otherwise we have too many corner - // cases from - // Runtime.getRuntime().exec(String[] cmd [, ...]) - // calls with internal ["] and escape sequences. - - // Restore original command line. - StringBuilder join = new StringBuilder(); - // terminal space in command line is ok - for (String s : cmd) - join.append(s).append(' '); - - // Parse the command line again. - cmd = getTokensFromCommand(join.toString()); - executablePath = getExecutablePath(cmd[0]); - - // Check new executable name once more - if (security != null) - security.checkExec(executablePath); - } - - // Quotation protects from interpretation of the [path] argument as - // start of longer path with spaces. Quotation has no influence to - // [.exe] extension heuristic. - cmdstr = createCommandLine( - // We need the extended verification procedure for CMD files. - isShellFile(executablePath) - ? VERIFICATION_CMD_BAT - : VERIFICATION_WIN32, - quoteString(executablePath), - cmd); - } - - handle = create(cmdstr, envblock, path, - stdHandles, redirectErrorStream); - - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction<Void>() { - public Void run() { - if (stdHandles[0] == null) - stdin_stream = ProcessBuilder.NullOutputStream.INSTANCE; - else { - FileDescriptor stdin_fd = FileDescriptor.fromStream(stdHandles[0]); - stdin_stream = new BufferedOutputStream( - new FileOutputStream(stdin_fd)); - } - - if (stdHandles[1] == null) - stdout_stream = ProcessBuilder.NullInputStream.INSTANCE; - else { - FileDescriptor stdout_fd = FileDescriptor.fromStream(stdHandles[1]); - stdout_stream = new BufferedInputStream( - new FileInputStream(stdout_fd)); - } - - if (stdHandles[2] == null) - stderr_stream = ProcessBuilder.NullInputStream.INSTANCE; - else { - FileDescriptor stderr_fd = FileDescriptor.fromStream(stdHandles[2]); - stderr_stream = new FileInputStream(stderr_fd); - } - - return null; }}); - } - - private static native String mapVfsExecutable(String path); - - public OutputStream getOutputStream() { - return stdin_stream; - } - - public InputStream getInputStream() { - return stdout_stream; - } - - public InputStream getErrorStream() { - return stderr_stream; - } - - public int exitValue() { - if (!handle.get_HasExited()) - throw new IllegalThreadStateException("process has not exited"); - return handle.get_ExitCode(); - } - - public int waitFor() throws InterruptedException { - waitForInterruptibly(handle); - if (Thread.interrupted()) - throw new InterruptedException(); - return exitValue(); - } - - private static void waitForInterruptibly(cli.System.Diagnostics.Process handle) throws InterruptedException { - // to be interruptable we have to use polling - // (on .NET 2.0 WaitForExit is actually interruptible, but this isn't documented) - Thread current = Thread.currentThread(); - while (!current.isInterrupted() && !handle.WaitForExit(100)) - ; - } - - @Override - public boolean waitFor(long timeout, TimeUnit unit) - throws InterruptedException - { - if (handle.get_HasExited()) return true; - if (timeout <= 0) return false; - - long msTimeout = unit.toMillis(timeout); - - waitForTimeoutInterruptibly(handle, msTimeout); - if (Thread.interrupted()) - throw new InterruptedException(); - return handle.get_HasExited(); - } - - private static void waitForTimeoutInterruptibly( - cli.System.Diagnostics.Process handle, long timeout) { - long now = System.currentTimeMillis(); - long exp = now + timeout; - if (exp < now) { - // if we overflowed, just wait for a really long time - exp = Long.MAX_VALUE; - } - Thread current = Thread.currentThread(); - for (;;) { - if (current.isInterrupted()) { - return; - } - // wait for a maximum of 100 ms to be interruptible - if (handle.WaitForExit((int)Math.min(100, exp - now))) { - return; - } - now = System.currentTimeMillis(); - if (now >= exp) { - return; - } - } - } - - public void destroy() { terminateProcess(handle); } - - @Override - public Process destroyForcibly() { - destroy(); - return this; - } - - private static void terminateProcess(cli.System.Diagnostics.Process handle) { - try { - if (false) throw new cli.System.ComponentModel.Win32Exception(); - if (false) throw new cli.System.InvalidOperationException(); - handle.Kill(); - } catch (cli.System.ComponentModel.Win32Exception _) { - } catch (cli.System.InvalidOperationException _) { - } - } - - @Override - public boolean isAlive() { - return isProcessAlive(handle); - } - - private static boolean isProcessAlive(cli.System.Diagnostics.Process handle) { - return !handle.get_HasExited(); - } - - /** - * Create a process using the win32 function CreateProcess. - * The method is synchronized due to MS kb315939 problem. - * All native handles should restore the inherit flag at the end of call. - * - * @param cmdstr the Windows command line - * @param envblock NUL-separated, double-NUL-terminated list of - * environment strings in VAR=VALUE form - * @param dir the working directory of the process, or null if - * inheriting the current directory from the parent process - * @param stdHandles array of windows HANDLEs. Indexes 0, 1, and - * 2 correspond to standard input, standard output and - * standard error, respectively. On input, a value of -1 - * means to create a pipe to connect child and parent - * processes. On output, a value which is not -1 is the - * parent pipe handle corresponding to the pipe which has - * been created. An element of this array is -1 on input - * if and only if it is <em>not</em> -1 on output. - * @param redirectErrorStream redirectErrorStream attribute - * @return the native subprocess HANDLE returned by CreateProcess - */ - private static cli.System.Diagnostics.Process create(String cmdstr, - java.util.Map<String,String> envblock, - String dir, - Stream[] stdHandles, - boolean redirectErrorStream) - throws IOException { - - int programEnd = parseCommandString(cmdstr); - int argumentsStart = programEnd; - if (cmdstr.length() > argumentsStart && cmdstr.charAt(argumentsStart) == ' ') { - argumentsStart++; - } - - String fileName = cmdstr.substring(0, programEnd); - ProcessStartInfo si = new ProcessStartInfo(mapVfsExecutable(fileName), cmdstr.substring(argumentsStart)); - si.set_UseShellExecute(false); - si.set_RedirectStandardError(true); - si.set_RedirectStandardOutput(true); - si.set_RedirectStandardInput(true); - si.set_CreateNoWindow(true); - if (dir != null) { - si.set_WorkingDirectory(dir); - } - if (envblock != null) { - si.get_EnvironmentVariables().Clear(); - for (String key : envblock.keySet()) { - si.get_EnvironmentVariables().set_Item(key, envblock.get(key)); - } - } - - cli.System.Diagnostics.Process proc; - try { - if (false) throw new cli.System.ComponentModel.Win32Exception(); - if (false) throw new cli.System.InvalidOperationException(); - proc = cli.System.Diagnostics.Process.Start(si); - } catch (cli.System.ComponentModel.Win32Exception x1) { - throw new IOException(x1.getMessage()); - } catch (cli.System.InvalidOperationException x2) { - throw new IOException(x2.getMessage()); - } - - // if any of the handles is redirected to/from a file, - // we need to close the files as soon as the process exits - if (stdHandles[0] instanceof FileStream - || stdHandles[1] instanceof FileStream - || stdHandles[2] instanceof FileStream) { - final Stream s0 = stdHandles[0]; - final Stream s1 = stdHandles[1]; - final Stream s2 = stdHandles[2]; - proc.set_EnableRaisingEvents(true); - proc.add_Exited(new EventHandler(new EventHandler.Method() { - public void Invoke(Object sender, EventArgs e) { - if (s0 instanceof FileStream) - s0.Close(); - if (s1 instanceof FileStream) - s1.Close(); - if (s2 instanceof FileStream) - s2.Close(); - } - })); - } - - Stream stdin = proc.get_StandardInput().get_BaseStream(); - Stream stdout = proc.get_StandardOutput().get_BaseStream(); - Stream stderr = proc.get_StandardError().get_BaseStream(); - - if (stdHandles[0] != null) { - connectPipe(stdHandles[0], stdin); - stdHandles[0] = null; - } else { - stdHandles[0] = stdin; - } - - Stream stdoutDrain = null; - if (stdHandles[1] != null) { - stdoutDrain = stdHandles[1]; - connectPipe(stdout, stdoutDrain); - stdHandles[1] = null; - } else if (redirectErrorStream) { - PipeStream pipe = new PipeStream(); - connectPipe(stdout, pipe); - connectPipe(stderr, pipe); - stdHandles[1] = pipe; - } else { - stdHandles[1] = stdout; - } - - if (redirectErrorStream) { - if (stdoutDrain != null) { - connectPipe(stderr, stdoutDrain); - } - stdHandles[2] = null; - } else if (stdHandles[2] != null) { - connectPipe(stderr, stdHandles[2]); - stdHandles[2] = null; - } else { - stdHandles[2] = stderr; - } - - return proc; - } - - private static final class PipeStream extends Stream - { - private final byte[] buf = new byte[4096]; - private int pos; - private int users = 2; - - @Override - public synchronized int Read(byte[] buffer, int offset, int count) - { - if (count == 0) - { - return 0; - } - while (pos == 0) - { - try - { - wait(); - } - catch (InterruptedException _) { } - } - if (pos == -1) - { - return 0; - } - count = Math.min(count, pos); - System.arraycopy(buf, 0, buffer, offset, count); - pos -= count; - System.arraycopy(buf, count, buf, 0, pos); - notifyAll(); - return count; - } - - @Override - public synchronized void Write(byte[] buffer, int offset, int count) - { - while (buf.length - pos < count) - { - try - { - wait(); - } - catch (InterruptedException _) { } - } - System.arraycopy(buffer, offset, buf, pos, count); - pos += count; - notifyAll(); - } - - @Override - public synchronized void Close() - { - if (--users == 0) - { - pos = -1; - notifyAll(); - } - } - - @Override - public boolean get_CanRead() - { - return true; - } - - @Override - public boolean get_CanSeek() - { - return false; - } - - @Override - public boolean get_CanWrite() - { - return true; - } - - @Override - public void Flush() - { - } - - @Override - public long get_Length() - { - ikvm.runtime.Util.throwException(new cli.System.NotSupportedException()); - return 0; - } - - @Override - public long get_Position() - { - ikvm.runtime.Util.throwException(new cli.System.NotSupportedException()); - return 0; - } - - @Override - public long Seek(long offset, cli.System.IO.SeekOrigin origin) - { - ikvm.runtime.Util.throwException(new cli.System.NotSupportedException()); - return 0; - } - - @Override - public void SetLength(long value) - { - ikvm.runtime.Util.throwException(new cli.System.NotSupportedException()); - } - - @Override - public void set_Position(long position) - { - ikvm.runtime.Util.throwException(new cli.System.NotSupportedException()); - } - } - - private static native int parseCommandString(String cmdstr); - - /** - * Opens a file for atomic append. The file is created if it doesn't - * already exist. - * - * @param file the file to open or create - * @return the native HANDLE - */ - private static FileDescriptor openForAtomicAppend(String path) - throws IOException { - try { - if (false) throw new cli.System.ArgumentException(); - if (false) throw new cli.System.IO.IOException(); - if (false) throw new cli.System.Security.SecurityException(); - if (false) throw new cli.System.UnauthorizedAccessException(); - return FileDescriptor.fromStream(new FileStream(path, FileMode.wrap(FileMode.Append), FileSystemRights.wrap(FileSystemRights.AppendData), FileShare.wrap(FileShare.ReadWrite), 1, FileOptions.wrap(FileOptions.None))); - } catch (cli.System.ArgumentException x) { - throw new IOException(x.getMessage()); - } catch (cli.System.IO.IOException x) { - throw new IOException(x.getMessage()); - } catch (cli.System.Security.SecurityException x) { - throw new IOException(x.getMessage()); - } catch (cli.System.UnauthorizedAccessException x) { - throw new IOException(x.getMessage()); - } - } - - private static void connectPipe(final Stream in, final Stream out) { - final byte[] buf = new byte[4096]; - final AsyncCallback[] callback = new AsyncCallback[1]; - callback[0] = new AsyncCallback(new AsyncCallback.Method() { - public void Invoke(IAsyncResult ar) { - try { - int count = in.EndRead(ar); - if (count > 0) { - out.Write(buf, 0, count); - out.Flush(); - in.BeginRead(buf, 0, buf.length, callback[0], null); - } else { - out.Close(); - } - } catch (Throwable _) { - } - } - }); - try { - in.BeginRead(buf, 0, buf.length, callback[0], null); - } catch (Throwable _) { - } - } -} diff --git a/openjdk/java/lang/PropertyConstants.java.in b/openjdk/java/lang/PropertyConstants.java.in deleted file mode 100644 index 69e7796f..00000000 --- a/openjdk/java/lang/PropertyConstants.java.in +++ /dev/null @@ -1,33 +0,0 @@ -/* - Copyright (C) 2007, 2009 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; - -interface PropertyConstants -{ - String awt_toolkit = "ikvm.awt.NetToolkit, @AWTASSEMBLY@"; - String java_awt_graphicsenv = "ikvm.awt.NetGraphicsEnvironment, @AWTASSEMBLY@"; - String java_vm_version = "@VERSION@"; - String java_runtime_version = "@VERSION@"; - String openjdk_version = "@OPENJDK_VERSION@"; -} diff --git a/openjdk/java/lang/Shutdown.java b/openjdk/java/lang/Shutdown.java deleted file mode 100644 index 947f0e39..00000000 --- a/openjdk/java/lang/Shutdown.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright (c) 1999, 2005, 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; - -import cli.System.AppDomain; -import cli.System.EventArgs; -import cli.System.EventHandler; -import cli.System.Threading.Monitor; - -/** - * Package-private utility class containing data structures and logic - * governing the virtual-machine shutdown sequence. - * - * @author Mark Reinhold - * @since 1.3 - */ - -class Shutdown { - - /* Shutdown state */ - private static final int RUNNING = 0; - private static final int HOOKS = 1; - private static final int FINALIZERS = 2; - private static int state = RUNNING; - - /* Should we run all finalizers upon exit? */ - static volatile boolean runFinalizersOnExit = false; - - // The system shutdown hooks are registered with a predefined slot. - // The list of shutdown hooks is as follows: - // (0) Console restore hook - // (1) Application hooks - // (2) DeleteOnExit hook - private static final int MAX_SYSTEM_HOOKS = 10; - private static final Runnable[] hooks = new Runnable[MAX_SYSTEM_HOOKS]; - - // the index of the currently running shutdown hook to the hooks array - private static int currentRunningHook = 0; - - // [IKVM] have we registered the AppDomain.ProcessExit event handler? - private static boolean registeredProcessExit; - - /* The preceding static fields are protected by this lock */ - private static class Lock { }; - private static Object lock = new Lock(); - - /* Lock object for the native halt method */ - private static Object haltLock = new Lock(); - - /* Invoked by Runtime.runFinalizersOnExit */ - static void setRunFinalizersOnExit(boolean run) { - synchronized (lock) { - runFinalizersOnExit = run; - } - } - - private static void registerProcessExit() { - try { - // MONOBUG Mono doesn't support starting a new thread during ProcessExit - // (and application shutdown hooks are based on threads) - // see https://bugzilla.xamarin.com/show_bug.cgi?id=5650 - if (!ikvm.internal.Util.MONO) { - // AppDomain.ProcessExit has a LinkDemand, so we have to have a separate method - registerShutdownHook(); - if (false) throw new cli.System.Security.SecurityException(); - } - } - catch (cli.System.Security.SecurityException _) { - } - } - - private static void registerShutdownHook() - { - AppDomain.get_CurrentDomain().add_ProcessExit(new EventHandler(new EventHandler.Method() { - public void Invoke(Object sender, EventArgs e) { - shutdown(); - } - })); - } - - /** - * Add a new shutdown hook. Checks the shutdown state and the hook itself, - * but does not do any security checks. - * - * The registerShutdownInProgress parameter should be false except - * registering the DeleteOnExitHook since the first file may - * be added to the delete on exit list by the application shutdown - * hooks. - * - * @params slot the slot in the shutdown hook array, whose element - * will be invoked in order during shutdown - * @params registerShutdownInProgress true to allow the hook - * to be registered even if the shutdown is in progress. - * @params hook the hook to be registered - * - * @throw IllegalStateException - * if registerShutdownInProgress is false and shutdown is in progress; or - * if registerShutdownInProgress is true and the shutdown process - * already passes the given slot - */ - static void add(int slot, boolean registerShutdownInProgress, Runnable hook) { - synchronized (lock) { - if (hooks[slot] != null) - throw new InternalError("Shutdown hook at slot " + slot + " already registered"); - - if (!registerShutdownInProgress) { - if (state > RUNNING) - throw new IllegalStateException("Shutdown in progress"); - } else { - if (state > HOOKS || (state == HOOKS && slot <= currentRunningHook)) - throw new IllegalStateException("Shutdown in progress"); - } - - if (!registeredProcessExit) { - registeredProcessExit = true; - registerProcessExit(); - } - - hooks[slot] = hook; - } - } - - /* Run all registered shutdown hooks - */ - private static void runHooks() { - for (int i=0; i < MAX_SYSTEM_HOOKS; i++) { - try { - Runnable hook; - synchronized (lock) { - // acquire the lock to make sure the hook registered during - // shutdown is visible here. - currentRunningHook = i; - hook = hooks[i]; - } - if (hook != null) hook.run(); - } catch(Throwable t) { - if (t instanceof ThreadDeath) { - ThreadDeath td = (ThreadDeath)t; - throw td; - } - } - } - } - - /* The halt method is synchronized on the halt lock - * to avoid corruption of the delete-on-shutdown file list. - * It invokes the true native halt method. - */ - static void halt(int status) { - synchronized (haltLock) { - halt0(status); - } - } - - static void halt0(int status) { - cli.System.Environment.Exit(status); - } - - /* Wormhole for invoking java.lang.ref.Finalizer.runAllFinalizers */ - private static void runAllFinalizers() { /* [IKVM] Don't need to do anything here */ } - - - /* The actual shutdown sequence is defined here. - * - * If it weren't for runFinalizersOnExit, this would be simple -- we'd just - * run the hooks and then halt. Instead we need to keep track of whether - * we're running hooks or finalizers. In the latter case a finalizer could - * invoke exit(1) to cause immediate termination, while in the former case - * any further invocations of exit(n), for any n, simply stall. Note that - * if on-exit finalizers are enabled they're run iff the shutdown is - * initiated by an exit(0); they're never run on exit(n) for n != 0 or in - * response to SIGINT, SIGTERM, etc. - */ - private static void sequence() { - synchronized (lock) { - /* Guard against the possibility of a daemon thread invoking exit - * after DestroyJavaVM initiates the shutdown sequence - */ - if (state != HOOKS) return; - } - runHooks(); - boolean rfoe; - synchronized (lock) { - state = FINALIZERS; - rfoe = runFinalizersOnExit; - } - if (rfoe) runAllFinalizers(); - } - - - /* Invoked by Runtime.exit, which does all the security checks. - * Also invoked by handlers for system-provided termination events, - * which should pass a nonzero status code. - */ - static void exit(int status) { - boolean runMoreFinalizers = false; - synchronized (lock) { - if (status != 0) runFinalizersOnExit = false; - switch (state) { - case RUNNING: /* Initiate shutdown */ - state = HOOKS; - break; - case HOOKS: /* Stall and halt */ - break; - case FINALIZERS: - if (status != 0) { - /* Halt immediately on nonzero status */ - halt(status); - } else { - /* Compatibility with old behavior: - * Run more finalizers and then halt - */ - runMoreFinalizers = runFinalizersOnExit; - } - break; - } - } - if (runMoreFinalizers) { - runAllFinalizers(); - halt(status); - } - synchronized (Shutdown.class) { - /* Synchronize on the class object, causing any other thread - * that attempts to initiate shutdown to stall indefinitely - */ - sequence(); - halt(status); - } - } - - - /* Invoked by the JNI DestroyJavaVM procedure when the last non-daemon - * thread has finished. Unlike the exit method, this method does not - * actually halt the VM. - */ - static void shutdown() { - synchronized (lock) { - switch (state) { - case RUNNING: /* Initiate shutdown */ - state = HOOKS; - break; - case HOOKS: /* Stall and then return */ - case FINALIZERS: - break; - } - } - // [IKVM] We don't block here, because we're being called - // from the AppDomain.ProcessExit event and we don't want to - // deadlock with the thread that called exit. - // Note that our JNI DestroyJavaVM implementation doesn't - // call this method. - if (Monitor.TryEnter(Shutdown.class)) { - try { - sequence(); - } finally { - Monitor.Exit(Shutdown.class); - } - } - } - -} diff --git a/openjdk/java/lang/StringHelper.java b/openjdk/java/lang/StringHelper.java deleted file mode 100644 index 98f7816c..00000000 --- a/openjdk/java/lang/StringHelper.java +++ /dev/null @@ -1,2592 +0,0 @@ -/* - * Copyright (c) 1994, 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.lang; - -import java.io.ObjectStreamField; -import java.io.UnsupportedEncodingException; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.Formatter; -import java.util.Locale; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -/** - * The <code>String</code> class represents character strings. All - * string literals in Java programs, such as <code>"abc"</code>, are - * implemented as instances of this class. - * <p> - * Strings are constant; their values cannot be changed after they - * are created. String buffers support mutable strings. - * Because String objects are immutable they can be shared. For example: - * <p><blockquote><pre> - * String str = "abc"; - * </pre></blockquote><p> - * is equivalent to: - * <p><blockquote><pre> - * char data[] = {'a', 'b', 'c'}; - * String str = new String(data); - * </pre></blockquote><p> - * Here are some more examples of how strings can be used: - * <p><blockquote><pre> - * System.out.println("abc"); - * String cde = "cde"; - * System.out.println("abc" + cde); - * String c = "abc".substring(2,3); - * String d = cde.substring(1, 2); - * </pre></blockquote> - * <p> - * The class <code>String</code> includes methods for examining - * individual characters of the sequence, for comparing strings, for - * searching strings, for extracting substrings, and for creating a - * copy of a string with all characters translated to uppercase or to - * lowercase. Case mapping is based on the Unicode Standard version - * specified by the {@link java.lang.Character Character} class. - * <p> - * The Java language provides special support for the string - * concatenation operator ( + ), and for conversion of - * other objects to strings. String concatenation is implemented - * through the <code>StringBuilder</code>(or <code>StringBuffer</code>) - * class and its <code>append</code> method. - * String conversions are implemented through the method - * <code>toString</code>, defined by <code>Object</code> and - * inherited by all classes in Java. For additional information on - * string concatenation and conversion, see Gosling, Joy, and Steele, - * <i>The Java Language Specification</i>. - * - * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor - * or method in this class will cause a {@link NullPointerException} to be - * thrown. - * - * <p>A <code>String</code> represents a string in the UTF-16 format - * in which <em>supplementary characters</em> are represented by <em>surrogate - * pairs</em> (see the section <a href="Character.html#unicode">Unicode - * Character Representations</a> in the <code>Character</code> class for - * more information). - * Index values refer to <code>char</code> code units, so a supplementary - * character uses two positions in a <code>String</code>. - * <p>The <code>String</code> class provides methods for dealing with - * Unicode code points (i.e., characters), in addition to those for - * dealing with Unicode code units (i.e., <code>char</code> values). - * - * @author Lee Boynton - * @author Arthur van Hoff - * @author Martin Buchholz - * @author Ulf Zibis - * @see java.lang.Object#toString() - * @see java.lang.StringBuffer - * @see java.lang.StringBuilder - * @see java.nio.charset.Charset - * @since JDK1.0 - */ - -final class StringHelper -{ - /** - * Allocates a new {@code String} that contains characters from a subarray - * of the <a href="Character.html#unicode">Unicode code point</a> array - * argument. The {@code offset} argument is the index of the first code - * point of the subarray and the {@code count} argument specifies the - * length of the subarray. The contents of the subarray are converted to - * {@code char}s; subsequent modification of the {@code int} array does not - * affect the newly created string. - * - * @param codePoints - * Array that is the source of Unicode code points - * - * @param offset - * The initial offset - * - * @param count - * The length - * - * @throws IllegalArgumentException - * If any invalid Unicode code point is found in {@code - * codePoints} - * - * @throws IndexOutOfBoundsException - * If the {@code offset} and {@code count} arguments index - * characters outside the bounds of the {@code codePoints} array - * - * @since 1.5 - */ - static String NewString(int[] codePoints, int offset, int count) { - if (offset < 0) { - throw new StringIndexOutOfBoundsException(offset); - } - if (count < 0) { - throw new StringIndexOutOfBoundsException(count); - } - // Note: offset or count might be near -1>>>1. - if (offset > codePoints.length - count) { - throw new StringIndexOutOfBoundsException(offset + count); - } - - final int end = offset + count; - - // Pass 1: Compute precise size of char[] - int n = count; - for (int i = offset; i < end; i++) { - int c = codePoints[i]; - if (Character.isBmpCodePoint(c)) - continue; - else if (Character.isValidCodePoint(c)) - n++; - else throw new IllegalArgumentException(Integer.toString(c)); - } - - // Pass 2: Allocate and fill in char[] - final char[] v = new char[n]; - - for (int i = offset, j = 0; i < end; i++, j++) { - int c = codePoints[i]; - if (Character.isBmpCodePoint(c)) - v[j] = (char)c; - else - Character.toSurrogates(c, v, j++); - } - - return new String(v); - } - - /** - * Allocates a new {@code String} constructed from a subarray of an array - * of 8-bit integer values. - * - * <p> The {@code offset} argument is the index of the first byte of the - * subarray, and the {@code count} argument specifies the length of the - * subarray. - * - * <p> Each {@code byte} in the subarray is converted to a {@code char} as - * specified in the method above. - * - * @deprecated This method does not properly convert bytes into characters. - * As of JDK 1.1, the preferred way to do this is via the - * {@code String} constructors that take a {@link - * java.nio.charset.Charset}, charset name, or that use the platform's - * default charset. - * - * @param ascii - * The bytes to be converted to characters - * - * @param hibyte - * The top 8 bits of each 16-bit Unicode code unit - * - * @param offset - * The initial offset - * @param count - * The length - * - * @throws IndexOutOfBoundsException - * If the {@code offset} or {@code count} argument is invalid - * - * @see #String(byte[], int) - * @see #String(byte[], int, int, java.lang.String) - * @see #String(byte[], int, int, java.nio.charset.Charset) - * @see #String(byte[], int, int) - * @see #String(byte[], java.lang.String) - * @see #String(byte[], java.nio.charset.Charset) - * @see #String(byte[]) - */ - @Deprecated - static String NewString(byte ascii[], int hibyte, int offset, int count) { - checkBounds(ascii, offset, count); - char value[] = new char[count]; - - if (hibyte == 0) { - for (int i = count; i-- > 0;) { - value[i] = (char)(ascii[i + offset] & 0xff); - } - } else { - hibyte <<= 8; - for (int i = count; i-- > 0;) { - value[i] = (char)(hibyte | (ascii[i + offset] & 0xff)); - } - } - return new String(value, 0, count); - } - - /** - * Allocates a new {@code String} containing characters constructed from - * an array of 8-bit integer values. Each character <i>c</i>in the - * resulting string is constructed from the corresponding component - * <i>b</i> in the byte array such that: - * - * <blockquote><pre> - * <b><i>c</i></b> == (char)(((hibyte & 0xff) << 8) - * | (<b><i>b</i></b> & 0xff)) - * </pre></blockquote> - * - * @deprecated This method does not properly convert bytes into - * characters. As of JDK 1.1, the preferred way to do this is via the - * {@code String} constructors that take a {@link - * java.nio.charset.Charset}, charset name, or that use the platform's - * default charset. - * - * @param ascii - * The bytes to be converted to characters - * - * @param hibyte - * The top 8 bits of each 16-bit Unicode code unit - * - * @see #String(byte[], int, int, java.lang.String) - * @see #String(byte[], int, int, java.nio.charset.Charset) - * @see #String(byte[], int, int) - * @see #String(byte[], java.lang.String) - * @see #String(byte[], java.nio.charset.Charset) - * @see #String(byte[]) - */ - @Deprecated - static String NewString(byte ascii[], int hibyte) { - return NewString(ascii, hibyte, 0, ascii.length); - } - - /* Common private utility method used to bounds check the byte array - * and requested offset & length values used by the String(byte[],..) - * constructors. - */ - private static void checkBounds(byte[] bytes, int offset, int length) { - if (length < 0) - throw new StringIndexOutOfBoundsException(length); - if (offset < 0) - throw new StringIndexOutOfBoundsException(offset); - if (offset > bytes.length - length) - throw new StringIndexOutOfBoundsException(offset + length); - } - - /** - * Constructs a new {@code String} by decoding the specified subarray of - * bytes using the specified charset. The length of the new {@code String} - * is a function of the charset, and hence may not be equal to the length - * of the subarray. - * - * <p> The behavior of this constructor when the given bytes are not valid - * in the given charset is unspecified. The {@link - * java.nio.charset.CharsetDecoder} class should be used when more control - * over the decoding process is required. - * - * @param bytes - * The bytes to be decoded into characters - * - * @param offset - * The index of the first byte to decode - * - * @param length - * The number of bytes to decode - - * @param charsetName - * The name of a supported {@linkplain java.nio.charset.Charset - * charset} - * - * @throws UnsupportedEncodingException - * If the named charset is not supported - * - * @throws IndexOutOfBoundsException - * If the {@code offset} and {@code length} arguments index - * characters outside the bounds of the {@code bytes} array - * - * @since JDK1.1 - */ - static String NewString(byte bytes[], int offset, int length, String charsetName) - throws UnsupportedEncodingException { - if (charsetName == null) - throw new NullPointerException("charsetName"); - checkBounds(bytes, offset, length); - char[] v = StringCoding.decode(charsetName, bytes, offset, length); - return new String(v); - } - - /** - * Constructs a new {@code String} by decoding the specified subarray of - * bytes using the specified {@linkplain java.nio.charset.Charset charset}. - * The length of the new {@code String} is a function of the charset, and - * hence may not be equal to the length of the subarray. - * - * <p> This method always replaces malformed-input and unmappable-character - * sequences with this charset's default replacement string. The {@link - * java.nio.charset.CharsetDecoder} class should be used when more control - * over the decoding process is required. - * - * @param bytes - * The bytes to be decoded into characters - * - * @param offset - * The index of the first byte to decode - * - * @param length - * The number of bytes to decode - * - * @param charset - * The {@linkplain java.nio.charset.Charset charset} to be used to - * decode the {@code bytes} - * - * @throws IndexOutOfBoundsException - * If the {@code offset} and {@code length} arguments index - * characters outside the bounds of the {@code bytes} array - * - * @since 1.6 - */ - static String NewString(byte bytes[], int offset, int length, Charset charset) { - if (charset == null) - throw new NullPointerException("charset"); - checkBounds(bytes, offset, length); - char[] v = StringCoding.decode(charset, bytes, offset, length); - return new String(v); - } - - /** - * Constructs a new {@code String} by decoding the specified array of bytes - * using the specified {@linkplain java.nio.charset.Charset charset}. The - * length of the new {@code String} is a function of the charset, and hence - * may not be equal to the length of the byte array. - * - * <p> The behavior of this constructor when the given bytes are not valid - * in the given charset is unspecified. The {@link - * java.nio.charset.CharsetDecoder} class should be used when more control - * over the decoding process is required. - * - * @param bytes - * The bytes to be decoded into characters - * - * @param charsetName - * The name of a supported {@linkplain java.nio.charset.Charset - * charset} - * - * @throws UnsupportedEncodingException - * If the named charset is not supported - * - * @since JDK1.1 - */ - static String NewString(byte bytes[], String charsetName) - throws UnsupportedEncodingException { - return NewString(bytes, 0, bytes.length, charsetName); - } - - /** - * Constructs a new {@code String} by decoding the specified array of - * bytes using the specified {@linkplain java.nio.charset.Charset charset}. - * The length of the new {@code String} is a function of the charset, and - * hence may not be equal to the length of the byte array. - * - * <p> This method always replaces malformed-input and unmappable-character - * sequences with this charset's default replacement string. The {@link - * java.nio.charset.CharsetDecoder} class should be used when more control - * over the decoding process is required. - * - * @param bytes - * The bytes to be decoded into characters - * - * @param charset - * The {@linkplain java.nio.charset.Charset charset} to be used to - * decode the {@code bytes} - * - * @since 1.6 - */ - static String NewString(byte bytes[], Charset charset) { - return NewString(bytes, 0, bytes.length, charset); - } - - /** - * Constructs a new {@code String} by decoding the specified subarray of - * bytes using the platform's default charset. The length of the new - * {@code String} is a function of the charset, and hence may not be equal - * to the length of the subarray. - * - * <p> The behavior of this constructor when the given bytes are not valid - * in the default charset is unspecified. The {@link - * java.nio.charset.CharsetDecoder} class should be used when more control - * over the decoding process is required. - * - * @param bytes - * The bytes to be decoded into characters - * - * @param offset - * The index of the first byte to decode - * - * @param length - * The number of bytes to decode - * - * @throws IndexOutOfBoundsException - * If the {@code offset} and the {@code length} arguments index - * characters outside the bounds of the {@code bytes} array - * - * @since JDK1.1 - */ - static String NewString(byte bytes[], int offset, int length) { - checkBounds(bytes, offset, length); - char[] v = StringCoding.decode(bytes, offset, length); - return new String(v); - } - - /** - * Constructs a new {@code String} by decoding the specified array of bytes - * using the platform's default charset. The length of the new {@code - * String} is a function of the charset, and hence may not be equal to the - * length of the byte array. - * - * <p> The behavior of this constructor when the given bytes are not valid - * in the default charset is unspecified. The {@link - * java.nio.charset.CharsetDecoder} class should be used when more control - * over the decoding process is required. - * - * @param bytes - * The bytes to be decoded into characters - * - * @since JDK1.1 - */ - static String NewString(byte bytes[]) { - return NewString(bytes, 0, bytes.length); - } - - /** - * Allocates a new string that contains the sequence of characters - * currently contained in the string buffer argument. The contents of the - * string buffer are copied; subsequent modification of the string buffer - * does not affect the newly created string. - * - * @param buffer - * A {@code StringBuffer} - */ - static String NewString(StringBuffer buffer) { - return buffer.toString(); - } - - /** - * Allocates a new string that contains the sequence of characters - * currently contained in the string builder argument. The contents of the - * string builder are copied; subsequent modification of the string builder - * does not affect the newly created string. - * - * <p> This constructor is provided to ease migration to {@code - * StringBuilder}. Obtaining a string from a string builder via the {@code - * toString} method is likely to run faster and is generally preferred. - * - * @param builder - * A {@code StringBuilder} - * - * @since 1.5 - */ - static String NewString(StringBuilder builder) { - return builder.toString(); - } - - - // Package private constructor which shares value array for speed. - static String NewString(int offset, int count, char value[]) { - return new String(value, offset, count); - } - - /** - * Returns the character (Unicode code point) at the specified - * index. The index refers to <code>char</code> values - * (Unicode code units) and ranges from <code>0</code> to - * {@link #length()}<code> - 1</code>. - * - * <p> If the <code>char</code> value specified at the given index - * is in the high-surrogate range, the following index is less - * than the length of this <code>String</code>, and the - * <code>char</code> value at the following index is in the - * low-surrogate range, then the supplementary code point - * corresponding to this surrogate pair is returned. Otherwise, - * the <code>char</code> value at the given index is returned. - * - * @param index the index to the <code>char</code> values - * @return the code point value of the character at the - * <code>index</code> - * @exception IndexOutOfBoundsException if the <code>index</code> - * argument is negative or not less than the length of this - * string. - * @since 1.5 - */ - static int codePointAt(String _this, int index) { - if ((index < 0) || (index >= _this.length())) { - throw new StringIndexOutOfBoundsException(index); - } - char c1 = _this.charAt(index++); - if (Character.isHighSurrogate(c1)) { - if (index < _this.length()) { - char c2 = _this.charAt(index); - if (Character.isLowSurrogate(c2)) { - return Character.toCodePoint(c1, c2); - } - } - } - return c1; - } - - /** - * Returns the character (Unicode code point) before the specified - * index. The index refers to <code>char</code> values - * (Unicode code units) and ranges from <code>1</code> to {@link - * CharSequence#length() length}. - * - * <p> If the <code>char</code> value at <code>(index - 1)</code> - * is in the low-surrogate range, <code>(index - 2)</code> is not - * negative, and the <code>char</code> value at <code>(index - - * 2)</code> is in the high-surrogate range, then the - * supplementary code point value of the surrogate pair is - * returned. If the <code>char</code> value at <code>index - - * 1</code> is an unpaired low-surrogate or a high-surrogate, the - * surrogate value is returned. - * - * @param index the index following the code point that should be returned - * @return the Unicode code point value before the given index. - * @exception IndexOutOfBoundsException if the <code>index</code> - * argument is less than 1 or greater than the length - * of this string. - * @since 1.5 - */ - static int codePointBefore(String _this, int index) { - int i = index - 1; - if ((i < 0) || (i >= _this.length())) { - throw new StringIndexOutOfBoundsException(index); - } - char c2 = _this.charAt(--index); - if (Character.isLowSurrogate(c2)) { - if (index > 0) { - char c1 = _this.charAt(--index); - if (Character.isHighSurrogate(c1)) { - return Character.toCodePoint(c1, c2); - } - } - } - return c2; - } - - /** - * Returns the number of Unicode code points in the specified text - * range of this <code>String</code>. The text range begins at the - * specified <code>beginIndex</code> and extends to the - * <code>char</code> at index <code>endIndex - 1</code>. Thus the - * length (in <code>char</code>s) of the text range is - * <code>endIndex-beginIndex</code>. Unpaired surrogates within - * the text range count as one code point each. - * - * @param beginIndex the index to the first <code>char</code> of - * the text range. - * @param endIndex the index after the last <code>char</code> of - * the text range. - * @return the number of Unicode code points in the specified text - * range - * @exception IndexOutOfBoundsException if the - * <code>beginIndex</code> is negative, or <code>endIndex</code> - * is larger than the length of this <code>String</code>, or - * <code>beginIndex</code> is larger than <code>endIndex</code>. - * @since 1.5 - */ - static int codePointCount(String _this, int beginIndex, int endIndex) { - if (beginIndex < 0 || endIndex > _this.length() || beginIndex > endIndex) { - throw new IndexOutOfBoundsException(); - } - int n = 0; - for (int i = beginIndex; i < endIndex; ) { - n++; - if (Character.isHighSurrogate(_this.charAt(i++))) { - if (i < endIndex && Character.isLowSurrogate(_this.charAt(i))) { - i++; - } - } - } - return n; - } - - /** - * Returns the index within this <code>String</code> that is - * offset from the given <code>index</code> by - * <code>codePointOffset</code> code points. Unpaired surrogates - * within the text range given by <code>index</code> and - * <code>codePointOffset</code> count as one code point each. - * - * @param index the index to be offset - * @param codePointOffset the offset in code points - * @return the index within this <code>String</code> - * @exception IndexOutOfBoundsException if <code>index</code> - * is negative or larger then the length of this - * <code>String</code>, or if <code>codePointOffset</code> is positive - * and the substring starting with <code>index</code> has fewer - * than <code>codePointOffset</code> code points, - * or if <code>codePointOffset</code> is negative and the substring - * before <code>index</code> has fewer than the absolute value - * of <code>codePointOffset</code> code points. - * @since 1.5 - */ - static int offsetByCodePoints(String _this, int index, int codePointOffset) { - int count = _this.length(); - if (index < 0 || index > count) { - throw new IndexOutOfBoundsException(); - } - int x = index; - if (codePointOffset >= 0) { - int limit = count; - int i; - for (i = 0; x < limit && i < codePointOffset; i++) { - if (Character.isHighSurrogate(_this.charAt(x++))) { - if (x < limit && Character.isLowSurrogate(_this.charAt(x))) { - x++; - } - } - } - if (i < codePointOffset) { - throw new IndexOutOfBoundsException(); - } - } else { - int i; - for (i = codePointOffset; x > 0 && i < 0; i++) { - if (Character.isLowSurrogate(_this.charAt(--x))) { - if (x > 0 && Character.isHighSurrogate(_this.charAt(x-1))) { - x--; - } - } - } - if (i < 0) { - throw new IndexOutOfBoundsException(); - } - } - return x; - } - - /** - * Copy characters from this string into dst starting at dstBegin. - * This method doesn't perform any range checking. - */ - static void getChars(String _this, char dst[], int dstBegin) { - _this.getChars(0, _this.length(), dst, dstBegin); - } - - /** - * Copies characters from this string into the destination character - * array. - * <p> - * The first character to be copied is at index <code>srcBegin</code>; - * the last character to be copied is at index <code>srcEnd-1</code> - * (thus the total number of characters to be copied is - * <code>srcEnd-srcBegin</code>). The characters are copied into the - * subarray of <code>dst</code> starting at index <code>dstBegin</code> - * and ending at index: - * <p><blockquote><pre> - * dstbegin + (srcEnd-srcBegin) - 1 - * </pre></blockquote> - * - * @param srcBegin index of the first character in the string - * to copy. - * @param srcEnd index after the last character in the string - * to copy. - * @param dst the destination array. - * @param dstBegin the start offset in the destination array. - * @exception IndexOutOfBoundsException If any of the following - * is true: - * <ul><li><code>srcBegin</code> is negative. - * <li><code>srcBegin</code> is greater than <code>srcEnd</code> - * <li><code>srcEnd</code> is greater than the length of this - * string - * <li><code>dstBegin</code> is negative - * <li><code>dstBegin+(srcEnd-srcBegin)</code> is larger than - * <code>dst.length</code></ul> - */ - static void getChars(cli.System.String _this, int srcBegin, int srcEnd, char dst[], int dstBegin) { - if (srcBegin < 0) { - throw new StringIndexOutOfBoundsException(srcBegin); - } - if (srcEnd > _this.get_Length()) { - throw new StringIndexOutOfBoundsException(srcEnd); - } - if (srcBegin > srcEnd) { - throw new StringIndexOutOfBoundsException(srcEnd - srcBegin); - } - _this.CopyTo(srcBegin, dst, dstBegin, srcEnd - srcBegin); - } - - /** - * Copies characters from this string into the destination byte array. Each - * byte receives the 8 low-order bits of the corresponding character. The - * eight high-order bits of each character are not copied and do not - * participate in the transfer in any way. - * - * <p> The first character to be copied is at index {@code srcBegin}; the - * last character to be copied is at index {@code srcEnd-1}. The total - * number of characters to be copied is {@code srcEnd-srcBegin}. The - * characters, converted to bytes, are copied into the subarray of {@code - * dst} starting at index {@code dstBegin} and ending at index: - * - * <blockquote><pre> - * dstbegin + (srcEnd-srcBegin) - 1 - * </pre></blockquote> - * - * @deprecated This method does not properly convert characters into - * bytes. As of JDK 1.1, the preferred way to do this is via the - * {@link #getBytes()} method, which uses the platform's default charset. - * - * @param srcBegin - * Index of the first character in the string to copy - * - * @param srcEnd - * Index after the last character in the string to copy - * - * @param dst - * The destination array - * - * @param dstBegin - * The start offset in the destination array - * - * @throws IndexOutOfBoundsException - * If any of the following is true: - * <ul> - * <li> {@code srcBegin} is negative - * <li> {@code srcBegin} is greater than {@code srcEnd} - * <li> {@code srcEnd} is greater than the length of this String - * <li> {@code dstBegin} is negative - * <li> {@code dstBegin+(srcEnd-srcBegin)} is larger than {@code - * dst.length} - * </ul> - */ - @Deprecated - static void getBytes(String _this, int srcBegin, int srcEnd, byte dst[], int dstBegin) { - if (srcBegin < 0) { - throw new StringIndexOutOfBoundsException(srcBegin); - } - if (srcEnd > _this.length()) { - throw new StringIndexOutOfBoundsException(srcEnd); - } - if (srcBegin > srcEnd) { - throw new StringIndexOutOfBoundsException(srcEnd - srcBegin); - } - int j = dstBegin; - int n = srcEnd; - int i = srcBegin; - - while (i < n) { - dst[j++] = (byte)_this.charAt(i++); - } - } - - /** - * Encodes this {@code String} into a sequence of bytes using the named - * charset, storing the result into a new byte array. - * - * <p> The behavior of this method when this string cannot be encoded in - * the given charset is unspecified. The {@link - * java.nio.charset.CharsetEncoder} class should be used when more control - * over the encoding process is required. - * - * @param charsetName - * The name of a supported {@linkplain java.nio.charset.Charset - * charset} - * - * @return The resultant byte array - * - * @throws UnsupportedEncodingException - * If the named charset is not supported - * - * @since JDK1.1 - */ - static byte[] getBytes(String _this, String charsetName) - throws UnsupportedEncodingException { - if (charsetName == null) throw new NullPointerException(); - char[] value = _this.toCharArray(); - return StringCoding.encode(charsetName, value, 0, value.length); - } - - /** - * Encodes this {@code String} into a sequence of bytes using the given - * {@linkplain java.nio.charset.Charset charset}, storing the result into a - * new byte array. - * - * <p> This method always replaces malformed-input and unmappable-character - * sequences with this charset's default replacement byte array. The - * {@link java.nio.charset.CharsetEncoder} class should be used when more - * control over the encoding process is required. - * - * @param charset - * The {@linkplain java.nio.charset.Charset} to be used to encode - * the {@code String} - * - * @return The resultant byte array - * - * @since 1.6 - */ - static byte[] getBytes(String _this, Charset charset) { - if (charset == null) throw new NullPointerException(); - char[] value = _this.toCharArray(); - return StringCoding.encode(charset, value, 0, value.length); - } - - /** - * Encodes this {@code String} into a sequence of bytes using the - * platform's default charset, storing the result into a new byte array. - * - * <p> The behavior of this method when this string cannot be encoded in - * the default charset is unspecified. The {@link - * java.nio.charset.CharsetEncoder} class should be used when more control - * over the encoding process is required. - * - * @return The resultant byte array - * - * @since JDK1.1 - */ - static byte[] getBytes(String _this) { - char[] value = _this.toCharArray(); - return StringCoding.encode(value, 0, value.length); - } - - /** - * Compares this string to the specified {@code StringBuffer}. The result - * is {@code true} if and only if this {@code String} represents the same - * sequence of characters as the specified {@code StringBuffer}. - * - * @param sb - * The {@code StringBuffer} to compare this {@code String} against - * - * @return {@code true} if this {@code String} represents the same - * sequence of characters as the specified {@code StringBuffer}, - * {@code false} otherwise - * - * @since 1.4 - */ - static boolean contentEquals(String _this, StringBuffer sb) { - synchronized (sb) { - return contentEquals(_this, (CharSequence) sb); - } - } - - /** - * Compares this string to the specified {@code CharSequence}. The result - * is {@code true} if and only if this {@code String} represents the same - * sequence of char values as the specified sequence. - * - * @param cs - * The sequence to compare this {@code String} against - * - * @return {@code true} if this {@code String} represents the same - * sequence of char values as the specified sequence, {@code - * false} otherwise - * - * @since 1.5 - */ - static boolean contentEquals(String _this, CharSequence cs) { - if (_this.length() != cs.length()) - return false; - // Argument is a StringBuffer, StringBuilder - if (cs instanceof AbstractStringBuilder) { - char v2[] = ((AbstractStringBuilder) cs).getValue(); - int i = 0; - int n = _this.length(); - while (n-- != 0) { - if (_this.charAt(i) != v2[i]) - return false; - i++; - } - return true; - } - // Argument is a String - if (cs.equals(_this)) - return true; - // Argument is a generic CharSequence - int i = 0; - int n = _this.length(); - while (n-- != 0) { - if (_this.charAt(i) != cs.charAt(i)) - return false; - i++; - } - return true; - } - - /** - * Compares this {@code String} to another {@code String}, ignoring case - * considerations. Two strings are considered equal ignoring case if they - * are of the same length and corresponding characters in the two strings - * are equal ignoring case. - * - * <p> Two characters {@code c1} and {@code c2} are considered the same - * ignoring case if at least one of the following is true: - * <ul> - * <li> The two characters are the same (as compared by the - * {@code ==} operator) - * <li> Applying the method {@link - * java.lang.Character#toUpperCase(char)} to each character - * produces the same result - * <li> Applying the method {@link - * java.lang.Character#toLowerCase(char)} to each character - * produces the same result - * </ul> - * - * @param anotherString - * The {@code String} to compare this {@code String} against - * - * @return {@code true} if the argument is not {@code null} and it - * represents an equivalent {@code String} ignoring case; {@code - * false} otherwise - * - * @see #equals(Object) - */ - static boolean equalsIgnoreCase(String _this, String anotherString) { - return (_this == anotherString) ? true - : (anotherString != null) - && (anotherString.length() == _this.length()) - && regionMatches(_this, true, 0, anotherString, 0, _this.length()); - } - - /** - * Compares two strings lexicographically. - * The comparison is based on the Unicode value of each character in - * the strings. The character sequence represented by this - * <code>String</code> object is compared lexicographically to the - * character sequence represented by the argument string. The result is - * a negative integer if this <code>String</code> object - * lexicographically precedes the argument string. The result is a - * positive integer if this <code>String</code> object lexicographically - * follows the argument string. The result is zero if the strings - * are equal; <code>compareTo</code> returns <code>0</code> exactly when - * the {@link #equals(Object)} method would return <code>true</code>. - * <p> - * This is the definition of lexicographic ordering. If two strings are - * different, then either they have different characters at some index - * that is a valid index for both strings, or their lengths are different, - * or both. If they have different characters at one or more index - * positions, let <i>k</i> be the smallest such index; then the string - * whose character at position <i>k</i> has the smaller value, as - * determined by using the < operator, lexicographically precedes the - * other string. In this case, <code>compareTo</code> returns the - * difference of the two character values at position <code>k</code> in - * the two string -- that is, the value: - * <blockquote><pre> - * this.charAt(k)-anotherString.charAt(k) - * </pre></blockquote> - * If there is no index position at which they differ, then the shorter - * string lexicographically precedes the longer string. In this case, - * <code>compareTo</code> returns the difference of the lengths of the - * strings -- that is, the value: - * <blockquote><pre> - * this.length()-anotherString.length() - * </pre></blockquote> - * - * @param anotherString the <code>String</code> to be compared. - * @return the value <code>0</code> if the argument string is equal to - * this string; a value less than <code>0</code> if this string - * is lexicographically less than the string argument; and a - * value greater than <code>0</code> if this string is - * lexicographically greater than the string argument. - */ - static int compareTo(String _this, String anotherString) { - int len = Math.min(_this.length(), anotherString.length()); - for (int i = 0; i < len; i++) - { - int diff = _this.charAt(i) - anotherString.charAt(i); - if (diff != 0) - { - return diff; - } - } - return _this.length() - anotherString.length(); - } - - /** - * Compares two strings lexicographically, ignoring case - * differences. This method returns an integer whose sign is that of - * calling <code>compareTo</code> with normalized versions of the strings - * where case differences have been eliminated by calling - * <code>Character.toLowerCase(Character.toUpperCase(character))</code> on - * each character. - * <p> - * Note that this method does <em>not</em> take locale into account, - * and will result in an unsatisfactory ordering for certain locales. - * The java.text package provides <em>collators</em> to allow - * locale-sensitive ordering. - * - * @param str the <code>String</code> to be compared. - * @return a negative integer, zero, or a positive integer as the - * specified String is greater than, equal to, or less - * than this String, ignoring case considerations. - * @see java.text.Collator#compare(String, String) - * @since 1.2 - */ - static int compareToIgnoreCase(String _this, String str) { - return String.CASE_INSENSITIVE_ORDER.compare(_this, str); - } - - /** - * Tests if two string regions are equal. - * <p> - * A substring of this <tt>String</tt> object is compared to a substring - * of the argument other. The result is true if these substrings - * represent identical character sequences. The substring of this - * <tt>String</tt> object to be compared begins at index <tt>toffset</tt> - * and has length <tt>len</tt>. The substring of other to be compared - * begins at index <tt>ooffset</tt> and has length <tt>len</tt>. The - * result is <tt>false</tt> if and only if at least one of the following - * is true: - * <ul><li><tt>toffset</tt> is negative. - * <li><tt>ooffset</tt> is negative. - * <li><tt>toffset+len</tt> is greater than the length of this - * <tt>String</tt> object. - * <li><tt>ooffset+len</tt> is greater than the length of the other - * argument. - * <li>There is some nonnegative integer <i>k</i> less than <tt>len</tt> - * such that: - * <tt>this.charAt(toffset+<i>k</i>) != other.charAt(ooffset+<i>k</i>)</tt> - * </ul> - * - * @param toffset the starting offset of the subregion in this string. - * @param other the string argument. - * @param ooffset the starting offset of the subregion in the string - * argument. - * @param len the number of characters to compare. - * @return <code>true</code> if the specified subregion of this string - * exactly matches the specified subregion of the string argument; - * <code>false</code> otherwise. - */ - static boolean regionMatches(String _this, int toffset, String other, int ooffset, - int len) { - int to = toffset; - int po = ooffset; - // Note: toffset, ooffset, or len might be near -1>>>1. - if ((ooffset < 0) || (toffset < 0) - || (toffset > (long)_this.length() - len) - || (ooffset > (long)other.length() - len)) { - return false; - } - while (len-- > 0) { - if (_this.charAt(to++) != other.charAt(po++)) { - return false; - } - } - return true; - } - - /** - * Tests if two string regions are equal. - * <p> - * A substring of this <tt>String</tt> object is compared to a substring - * of the argument <tt>other</tt>. The result is <tt>true</tt> if these - * substrings represent character sequences that are the same, ignoring - * case if and only if <tt>ignoreCase</tt> is true. The substring of - * this <tt>String</tt> object to be compared begins at index - * <tt>toffset</tt> and has length <tt>len</tt>. The substring of - * <tt>other</tt> to be compared begins at index <tt>ooffset</tt> and - * has length <tt>len</tt>. The result is <tt>false</tt> if and only if - * at least one of the following is true: - * <ul><li><tt>toffset</tt> is negative. - * <li><tt>ooffset</tt> is negative. - * <li><tt>toffset+len</tt> is greater than the length of this - * <tt>String</tt> object. - * <li><tt>ooffset+len</tt> is greater than the length of the other - * argument. - * <li><tt>ignoreCase</tt> is <tt>false</tt> and there is some nonnegative - * integer <i>k</i> less than <tt>len</tt> such that: - * <blockquote><pre> - * this.charAt(toffset+k) != other.charAt(ooffset+k) - * </pre></blockquote> - * <li><tt>ignoreCase</tt> is <tt>true</tt> and there is some nonnegative - * integer <i>k</i> less than <tt>len</tt> such that: - * <blockquote><pre> - * Character.toLowerCase(this.charAt(toffset+k)) != - Character.toLowerCase(other.charAt(ooffset+k)) - * </pre></blockquote> - * and: - * <blockquote><pre> - * Character.toUpperCase(this.charAt(toffset+k)) != - * Character.toUpperCase(other.charAt(ooffset+k)) - * </pre></blockquote> - * </ul> - * - * @param ignoreCase if <code>true</code>, ignore case when comparing - * characters. - * @param toffset the starting offset of the subregion in this - * string. - * @param other the string argument. - * @param ooffset the starting offset of the subregion in the string - * argument. - * @param len the number of characters to compare. - * @return <code>true</code> if the specified subregion of this string - * matches the specified subregion of the string argument; - * <code>false</code> otherwise. Whether the matching is exact - * or case insensitive depends on the <code>ignoreCase</code> - * argument. - */ - static boolean regionMatches(String _this, boolean ignoreCase, int toffset, - String other, int ooffset, int len) { - int to = toffset; - int po = ooffset; - // Note: toffset, ooffset, or len might be near -1>>>1. - if ((ooffset < 0) || (toffset < 0) - || (toffset > (long)_this.length() - len) - || (ooffset > (long)other.length() - len)) { - return false; - } - while (len-- > 0) { - char c1 = _this.charAt(to++); - char c2 = other.charAt(po++); - if (c1 == c2) { - continue; - } - if (ignoreCase) { - // If characters don't match but case may be ignored, - // try converting both characters to uppercase. - // If the results match, then the comparison scan should - // continue. - char u1 = Character.toUpperCase(c1); - char u2 = Character.toUpperCase(c2); - if (u1 == u2) { - continue; - } - // Unfortunately, conversion to uppercase does not work properly - // for the Georgian alphabet, which has strange rules about case - // conversion. So we need to make one last check before - // exiting. - if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) { - continue; - } - } - return false; - } - return true; - } - - /** - * Returns a hash code for this string. The hash code for a - * <code>String</code> object is computed as - * <blockquote><pre> - * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] - * </pre></blockquote> - * using <code>int</code> arithmetic, where <code>s[i]</code> is the - * <i>i</i>th character of the string, <code>n</code> is the length of - * the string, and <code>^</code> indicates exponentiation. - * (The hash value of the empty string is zero.) - * - * @return a hash code value for this object. - */ - static int hashCode(cli.System.String _this) { - int h = 0; - // NOTE having the get_Length in the for condition is actually faster than hoisting it, - // the CLR JIT recognizes this pattern and optimizes the array bounds check in get_Chars. - for (int i = 0; i < _this.get_Length(); i++) - { - h = h * 31 + _this.get_Chars(i); - } - return h; - } - - /** - * Returns the index within this string of the first occurrence of - * the specified character. If a character with value - * <code>ch</code> occurs in the character sequence represented by - * this <code>String</code> object, then the index (in Unicode - * code units) of the first such occurrence is returned. For - * values of <code>ch</code> in the range from 0 to 0xFFFF - * (inclusive), this is the smallest value <i>k</i> such that: - * <blockquote><pre> - * this.charAt(<i>k</i>) == ch - * </pre></blockquote> - * is true. For other values of <code>ch</code>, it is the - * smallest value <i>k</i> such that: - * <blockquote><pre> - * this.codePointAt(<i>k</i>) == ch - * </pre></blockquote> - * is true. In either case, if no such character occurs in this - * string, then <code>-1</code> is returned. - * - * @param ch a character (Unicode code point). - * @return the index of the first occurrence of the character in the - * character sequence represented by this object, or - * <code>-1</code> if the character does not occur. - */ - static int indexOf(cli.System.String _this, int ch) { - return indexOf(_this, ch, 0); - } - - /** - * Returns the index within this string of the first occurrence of the - * specified character, starting the search at the specified index. - * <p> - * If a character with value <code>ch</code> occurs in the - * character sequence represented by this <code>String</code> - * object at an index no smaller than <code>fromIndex</code>, then - * the index of the first such occurrence is returned. For values - * of <code>ch</code> in the range from 0 to 0xFFFF (inclusive), - * this is the smallest value <i>k</i> such that: - * <blockquote><pre> - * (this.charAt(<i>k</i>) == ch) && (<i>k</i> >= fromIndex) - * </pre></blockquote> - * is true. For other values of <code>ch</code>, it is the - * smallest value <i>k</i> such that: - * <blockquote><pre> - * (this.codePointAt(<i>k</i>) == ch) && (<i>k</i> >= fromIndex) - * </pre></blockquote> - * is true. In either case, if no such character occurs in this - * string at or after position <code>fromIndex</code>, then - * <code>-1</code> is returned. - * - * <p> - * There is no restriction on the value of <code>fromIndex</code>. If it - * is negative, it has the same effect as if it were zero: this entire - * string may be searched. If it is greater than the length of this - * string, it has the same effect as if it were equal to the length of - * this string: <code>-1</code> is returned. - * - * <p>All indices are specified in <code>char</code> values - * (Unicode code units). - * - * @param ch a character (Unicode code point). - * @param fromIndex the index to start the search from. - * @return the index of the first occurrence of the character in the - * character sequence represented by this object that is greater - * than or equal to <code>fromIndex</code>, or <code>-1</code> - * if the character does not occur. - */ - static int indexOf(cli.System.String _this, int ch, int fromIndex) { - int max = _this.get_Length(); - - if (fromIndex < 0) { - fromIndex = 0; - } else if (fromIndex >= max) { - // Note: fromIndex might be near -1>>>1. - return -1; - } - - int i = fromIndex; - if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { - // handle most cases here (ch is a BMP code point or a - // negative value (invalid code point)) - for (; i < max ; i++) { - if (_this.get_Chars(i) == ch) { - return i; - } - } - return -1; - } else { - return indexOfSupplementary(_this, ch, fromIndex); - } - } - - /** - * Handles (rare) calls of indexOf with a supplementary character. - */ - private static int indexOfSupplementary(cli.System.String _this, int ch, int fromIndex) { - if (Character.isValidCodePoint(ch)) { - final char hi = Character.highSurrogate(ch); - final char lo = Character.lowSurrogate(ch); - final int max = _this.get_Length() - 1; - for (int i = fromIndex; i < max; i++) { - if (_this.get_Chars(i) == hi && _this.get_Chars(i+1) == lo) { - return i; - } - } - } - return -1; - } - - /** - * Returns the index within this string of the last occurrence of - * the specified character. For values of <code>ch</code> in the - * range from 0 to 0xFFFF (inclusive), the index (in Unicode code - * units) returned is the largest value <i>k</i> such that: - * <blockquote><pre> - * this.charAt(<i>k</i>) == ch - * </pre></blockquote> - * is true. For other values of <code>ch</code>, it is the - * largest value <i>k</i> such that: - * <blockquote><pre> - * this.codePointAt(<i>k</i>) == ch - * </pre></blockquote> - * is true. In either case, if no such character occurs in this - * string, then <code>-1</code> is returned. The - * <code>String</code> is searched backwards starting at the last - * character. - * - * @param ch a character (Unicode code point). - * @return the index of the last occurrence of the character in the - * character sequence represented by this object, or - * <code>-1</code> if the character does not occur. - */ - static int lastIndexOf(cli.System.String _this, int ch) { - return lastIndexOf(_this, ch, _this.get_Length() - 1); - } - - /** - * Returns the index within this string of the last occurrence of - * the specified character, searching backward starting at the - * specified index. For values of <code>ch</code> in the range - * from 0 to 0xFFFF (inclusive), the index returned is the largest - * value <i>k</i> such that: - * <blockquote><pre> - * (this.charAt(<i>k</i>) == ch) && (<i>k</i> <= fromIndex) - * </pre></blockquote> - * is true. For other values of <code>ch</code>, it is the - * largest value <i>k</i> such that: - * <blockquote><pre> - * (this.codePointAt(<i>k</i>) == ch) && (<i>k</i> <= fromIndex) - * </pre></blockquote> - * is true. In either case, if no such character occurs in this - * string at or before position <code>fromIndex</code>, then - * <code>-1</code> is returned. - * - * <p>All indices are specified in <code>char</code> values - * (Unicode code units). - * - * @param ch a character (Unicode code point). - * @param fromIndex the index to start the search from. There is no - * restriction on the value of <code>fromIndex</code>. If it is - * greater than or equal to the length of this string, it has - * the same effect as if it were equal to one less than the - * length of this string: this entire string may be searched. - * If it is negative, it has the same effect as if it were -1: - * -1 is returned. - * @return the index of the last occurrence of the character in the - * character sequence represented by this object that is less - * than or equal to <code>fromIndex</code>, or <code>-1</code> - * if the character does not occur before that point. - */ - static int lastIndexOf(cli.System.String _this, int ch, int fromIndex) { - if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { - // handle most cases here (ch is a BMP code point or a - // negative value (invalid code point)) - int i = Math.min(fromIndex, _this.get_Length() - 1); - for (; i >= 0; i--) { - if (_this.get_Chars(i) == ch) { - return i; - } - } - return -1; - } else { - return lastIndexOfSupplementary(_this, ch, fromIndex); - } - } - - /** - * Handles (rare) calls of lastIndexOf with a supplementary character. - */ - private static int lastIndexOfSupplementary(cli.System.String _this, int ch, int fromIndex) { - if (Character.isValidCodePoint(ch)) { - char hi = Character.highSurrogate(ch); - char lo = Character.lowSurrogate(ch); - int i = Math.min(fromIndex, _this.get_Length() - 2); - for (; i >= 0; i--) { - if (_this.get_Chars(i) == hi && _this.get_Chars(i+1) == lo) { - return i; - } - } - } - return -1; - } - - /** - * Returns the index within this string of the first occurrence of the - * specified substring. - * - * <p>The returned index is the smallest value <i>k</i> for which: - * <blockquote><pre> - * this.startsWith(str, <i>k</i>) - * </pre></blockquote> - * If no such value of <i>k</i> exists, then {@code -1} is returned. - * - * @param str the substring to search for. - * @return the index of the first occurrence of the specified substring, - * or {@code -1} if there is no such occurrence. - */ - static int indexOf(String _this, String str) { - return indexOf(_this, str, 0); - } - - /** - * Returns the index within this string of the first occurrence of the - * specified substring, starting at the specified index. - * - * <p>The returned index is the smallest value <i>k</i> for which: - * <blockquote><pre> - * <i>k</i> >= fromIndex && this.startsWith(str, <i>k</i>) - * </pre></blockquote> - * If no such value of <i>k</i> exists, then {@code -1} is returned. - * - * @param str the substring to search for. - * @param fromIndex the index from which to start the search. - * @return the index of the first occurrence of the specified substring, - * starting at the specified index, - * or {@code -1} if there is no such occurrence. - */ - static int indexOf(String _this, String str, int fromIndex) { - // start by dereferencing _this, to make sure we throw a NullPointerException if _this is null - int slen = _this.length(); - int olen = str.length(); - if (olen == 0) - { - return Math.max(0, Math.min(fromIndex, slen)); - } - if (olen > slen) - { - return -1; - } - char firstChar = str.charAt(0); - // Java allows fromIndex to both below zero or above the length of the string, .NET doesn't - int index = Math.max(0, Math.min(slen, fromIndex)); - int end = slen - olen; - while (index >= 0 && index <= end) - { - if (cli.System.String.CompareOrdinal(_this, index, str, 0, olen) == 0) - { - return index; - } - index = _this.indexOf(firstChar, index + 1); - } - return -1; - } - - /** - * Code shared by String and StringBuffer to do searches. The - * source is the character array being searched, and the target - * is the string being searched for. - * - * @param source the characters being searched. - * @param sourceOffset offset of the source string. - * @param sourceCount count of the source string. - * @param target the characters being searched for. - * @param targetOffset offset of the target string. - * @param targetCount count of the target string. - * @param fromIndex the index to begin searching from. - */ - static int indexOf(char[] source, int sourceOffset, int sourceCount, - char[] target, int targetOffset, int targetCount, - int fromIndex) { - if (fromIndex >= sourceCount) { - return (targetCount == 0 ? sourceCount : -1); - } - if (fromIndex < 0) { - fromIndex = 0; - } - if (targetCount == 0) { - return fromIndex; - } - - char first = target[targetOffset]; - int max = sourceOffset + (sourceCount - targetCount); - - for (int i = sourceOffset + fromIndex; i <= max; i++) { - /* Look for first character. */ - if (source[i] != first) { - while (++i <= max && source[i] != first); - } - - /* Found first character, now look at the rest of v2 */ - if (i <= max) { - int j = i + 1; - int end = j + targetCount - 1; - for (int k = targetOffset + 1; j < end && source[j] - == target[k]; j++, k++); - - if (j == end) { - /* Found whole string. */ - return i - sourceOffset; - } - } - } - return -1; - } - - /** - * Returns the index within this string of the last occurrence of the - * specified substring. The last occurrence of the empty string "" - * is considered to occur at the index value {@code this.length()}. - * - * <p>The returned index is the largest value <i>k</i> for which: - * <blockquote><pre> - * this.startsWith(str, <i>k</i>) - * </pre></blockquote> - * If no such value of <i>k</i> exists, then {@code -1} is returned. - * - * @param str the substring to search for. - * @return the index of the last occurrence of the specified substring, - * or {@code -1} if there is no such occurrence. - */ - static int lastIndexOf(String _this, String str) { - return lastIndexOf(_this, str, _this.length()); - } - - /** - * Returns the index within this string of the last occurrence of the - * specified substring, searching backward starting at the specified index. - * - * <p>The returned index is the largest value <i>k</i> for which: - * <blockquote><pre> - * <i>k</i> <= fromIndex && this.startsWith(str, <i>k</i>) - * </pre></blockquote> - * If no such value of <i>k</i> exists, then {@code -1} is returned. - * - * @param str the substring to search for. - * @param fromIndex the index to start the search from. - * @return the index of the last occurrence of the specified substring, - * searching backward from the specified index, - * or {@code -1} if there is no such occurrence. - */ - static int lastIndexOf(String _this, String str, int fromIndex) { - // start by dereferencing s, to make sure we throw a NullPointerException if s is null - int slen = _this.length(); - if (fromIndex < 0) - { - return -1; - } - int olen = str.length(); - if (olen == 0) - { - return Math.min(slen, fromIndex); - } - if (olen > slen) - { - return -1; - } - cli.System.String cliStr = (cli.System.String)(Object)_this; - char firstChar = str.charAt(0); - // Java allows fromIndex to both below zero or above the length of the string, .NET doesn't - int index = Math.max(0, Math.min(slen - olen, fromIndex)); - while (index > 0) - { - if (cli.System.String.CompareOrdinal(_this, index, str, 0, olen) == 0) - { - return index; - } - index = cliStr.LastIndexOf(firstChar, index - 1); - } - return cli.System.String.CompareOrdinal(_this, 0, str, 0, olen) == 0 ? 0 : -1; - } - - /** - * Code shared by String and StringBuffer to do searches. The - * source is the character array being searched, and the target - * is the string being searched for. - * - * @param source the characters being searched. - * @param sourceOffset offset of the source string. - * @param sourceCount count of the source string. - * @param target the characters being searched for. - * @param targetOffset offset of the target string. - * @param targetCount count of the target string. - * @param fromIndex the index to begin searching from. - */ - static int lastIndexOf(char[] source, int sourceOffset, int sourceCount, - char[] target, int targetOffset, int targetCount, - int fromIndex) { - /* - * Check arguments; return immediately where possible. For - * consistency, don't check for null str. - */ - int rightIndex = sourceCount - targetCount; - if (fromIndex < 0) { - return -1; - } - if (fromIndex > rightIndex) { - fromIndex = rightIndex; - } - /* Empty string always matches. */ - if (targetCount == 0) { - return fromIndex; - } - - int strLastIndex = targetOffset + targetCount - 1; - char strLastChar = target[strLastIndex]; - int min = sourceOffset + targetCount - 1; - int i = min + fromIndex; - - startSearchForLastChar: - while (true) { - while (i >= min && source[i] != strLastChar) { - i--; - } - if (i < min) { - return -1; - } - int j = i - 1; - int start = j - (targetCount - 1); - int k = strLastIndex - 1; - - while (j > start) { - if (source[j--] != target[k--]) { - i--; - continue startSearchForLastChar; - } - } - return start - sourceOffset + 1; - } - } - - /** - * Returns a new string that is a substring of this string. The - * substring begins at the specified <code>beginIndex</code> and - * extends to the character at index <code>endIndex - 1</code>. - * Thus the length of the substring is <code>endIndex-beginIndex</code>. - * <p> - * Examples: - * <blockquote><pre> - * "hamburger".substring(4, 8) returns "urge" - * "smiles".substring(1, 5) returns "mile" - * </pre></blockquote> - * - * @param beginIndex the beginning index, inclusive. - * @param endIndex the ending index, exclusive. - * @return the specified substring. - * @exception IndexOutOfBoundsException if the - * <code>beginIndex</code> is negative, or - * <code>endIndex</code> is larger than the length of - * this <code>String</code> object, or - * <code>beginIndex</code> is larger than - * <code>endIndex</code>. - */ - static String substring(cli.System.String _this, int beginIndex, int endIndex) { - if (beginIndex < 0) { - throw new StringIndexOutOfBoundsException(beginIndex); - } - if (endIndex > _this.get_Length()) { - throw new StringIndexOutOfBoundsException(endIndex); - } - int subLen = endIndex - beginIndex; - if (subLen < 0) { - throw new StringIndexOutOfBoundsException(subLen); - } - return ((beginIndex == 0) && (endIndex == _this.get_Length())) ? (String)(Object)_this - : _this.Substring(beginIndex, subLen); - } - - /** - * Concatenates the specified string to the end of this string. - * <p> - * If the length of the argument string is <code>0</code>, then this - * <code>String</code> object is returned. Otherwise, a new - * <code>String</code> object is created, representing a character - * sequence that is the concatenation of the character sequence - * represented by this <code>String</code> object and the character - * sequence represented by the argument string.<p> - * Examples: - * <blockquote><pre> - * "cares".concat("s") returns "caress" - * "to".concat("get").concat("her") returns "together" - * </pre></blockquote> - * - * @param str the <code>String</code> that is concatenated to the end - * of this <code>String</code>. - * @return a string that represents the concatenation of this object's - * characters followed by the string argument's characters. - */ - static String concat(String _this, String str) { - int otherLen = str.length(); - if (otherLen == 0) { - return _this; - } - return cli.System.String.Concat(_this, str); - } - - /** - * Returns a new string resulting from replacing all occurrences of - * <code>oldChar</code> in this string with <code>newChar</code>. - * <p> - * If the character <code>oldChar</code> does not occur in the - * character sequence represented by this <code>String</code> object, - * then a reference to this <code>String</code> object is returned. - * Otherwise, a new <code>String</code> object is created that - * represents a character sequence identical to the character sequence - * represented by this <code>String</code> object, except that every - * occurrence of <code>oldChar</code> is replaced by an occurrence - * of <code>newChar</code>. - * <p> - * Examples: - * <blockquote><pre> - * "mesquite in your cellar".replace('e', 'o') - * returns "mosquito in your collar" - * "the war of baronets".replace('r', 'y') - * returns "the way of bayonets" - * "sparring with a purple porpoise".replace('p', 't') - * returns "starring with a turtle tortoise" - * "JonL".replace('q', 'x') returns "JonL" (no change) - * </pre></blockquote> - * - * @param oldChar the old character. - * @param newChar the new character. - * @return a string derived from this string by replacing every - * occurrence of <code>oldChar</code> with <code>newChar</code>. - */ - static String replace(String _this, char oldChar, char newChar) { - if (oldChar != newChar) { - int len = _this.length(); - int i = -1; - - while (++i < len) { - if (_this.charAt(i) == oldChar) { - break; - } - } - if (i < len) { - char buf[] = new char[len]; - for (int j = 0 ; j < i ; j++) { - buf[j] = _this.charAt(j); - } - while (i < len) { - char c = _this.charAt(i); - buf[i] = (c == oldChar) ? newChar : c; - i++; - } - return new String(buf, true); - } - } - return _this; - } - - /** - * Returns true if and only if this string contains the specified - * sequence of char values. - * - * @param s the sequence to search for - * @return true if this string contains <code>s</code>, false otherwise - * @throws NullPointerException if <code>s</code> is <code>null</code> - * @since 1.5 - */ - static boolean contains(String _this, CharSequence s) { - return indexOf(_this, s.toString()) > -1; - } - - /** - * Replaces each substring of this string that matches the literal target - * sequence with the specified literal replacement sequence. The - * replacement proceeds from the beginning of the string to the end, for - * example, replacing "aa" with "b" in the string "aaa" will result in - * "ba" rather than "ab". - * - * @param target The sequence of char values to be replaced - * @param replacement The replacement sequence of char values - * @return The resulting string - * @throws NullPointerException if <code>target</code> or - * <code>replacement</code> is <code>null</code>. - * @since 1.5 - */ - static String replace(String _this, CharSequence target, CharSequence replacement) { - return Pattern.compile(target.toString(), Pattern.LITERAL).matcher( - _this).replaceAll(Matcher.quoteReplacement(replacement.toString())); - } - - /** - * Splits this string around matches of the given - * <a href="../util/regex/Pattern.html#sum">regular expression</a>. - * - * <p> The array returned by this method contains each substring of this - * string that is terminated by another substring that matches the given - * expression or is terminated by the end of the string. The substrings in - * the array are in the order in which they occur in this string. If the - * expression does not match any part of the input then the resulting array - * has just one element, namely this string. - * - * <p> The <tt>limit</tt> parameter controls the number of times the - * pattern is applied and therefore affects the length of the resulting - * array. If the limit <i>n</i> is greater than zero then the pattern - * will be applied at most <i>n</i> - 1 times, the array's - * length will be no greater than <i>n</i>, and the array's last entry - * will contain all input beyond the last matched delimiter. If <i>n</i> - * is non-positive then the pattern will be applied as many times as - * possible and the array can have any length. If <i>n</i> is zero then - * the pattern will be applied as many times as possible, the array can - * have any length, and trailing empty strings will be discarded. - * - * <p> The string <tt>"boo:and:foo"</tt>, for example, yields the - * following results with these parameters: - * - * <blockquote><table cellpadding=1 cellspacing=0 summary="Split example showing regex, limit, and result"> - * <tr> - * <th>Regex</th> - * <th>Limit</th> - * <th>Result</th> - * </tr> - * <tr><td align=center>:</td> - * <td align=center>2</td> - * <td><tt>{ "boo", "and:foo" }</tt></td></tr> - * <tr><td align=center>:</td> - * <td align=center>5</td> - * <td><tt>{ "boo", "and", "foo" }</tt></td></tr> - * <tr><td align=center>:</td> - * <td align=center>-2</td> - * <td><tt>{ "boo", "and", "foo" }</tt></td></tr> - * <tr><td align=center>o</td> - * <td align=center>5</td> - * <td><tt>{ "b", "", ":and:f", "", "" }</tt></td></tr> - * <tr><td align=center>o</td> - * <td align=center>-2</td> - * <td><tt>{ "b", "", ":and:f", "", "" }</tt></td></tr> - * <tr><td align=center>o</td> - * <td align=center>0</td> - * <td><tt>{ "b", "", ":and:f" }</tt></td></tr> - * </table></blockquote> - * - * <p> An invocation of this method of the form - * <i>str.</i><tt>split(</tt><i>regex</i><tt>,</tt> <i>n</i><tt>)</tt> - * yields the same result as the expression - * - * <blockquote> - * {@link java.util.regex.Pattern}.{@link java.util.regex.Pattern#compile - * compile}<tt>(</tt><i>regex</i><tt>)</tt>.{@link - * java.util.regex.Pattern#split(java.lang.CharSequence,int) - * split}<tt>(</tt><i>str</i><tt>,</tt> <i>n</i><tt>)</tt> - * </blockquote> - * - * - * @param regex - * the delimiting regular expression - * - * @param limit - * the result threshold, as described above - * - * @return the array of strings computed by splitting this string - * around matches of the given regular expression - * - * @throws PatternSyntaxException - * if the regular expression's syntax is invalid - * - * @see java.util.regex.Pattern - * - * @since 1.4 - * @spec JSR-51 - */ - static String[] split(String _this, String regex, int limit) { - /* fastpath if the regex is a - (1)one-char String and this character is not one of the - RegEx's meta characters ".$|()[{^?*+\\", or - (2)two-char String and the first char is the backslash and - the second is not the ascii digit or ascii letter. - */ - char ch = 0; - if (((regex.length() == 1 && - ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) || - (regex.length() == 2 && - regex.charAt(0) == '\\' && - (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 && - ((ch-'a')|('z'-ch)) < 0 && - ((ch-'A')|('Z'-ch)) < 0)) && - (ch < Character.MIN_HIGH_SURROGATE || - ch > Character.MAX_LOW_SURROGATE)) - { - int off = 0; - int next = 0; - boolean limited = limit > 0; - ArrayList<String> list = new ArrayList<>(); - while ((next = _this.indexOf(ch, off)) != -1) { - if (!limited || list.size() < limit - 1) { - list.add(_this.substring(off, next)); - off = next + 1; - } else { // last one - //assert (list.size() == limit - 1); - list.add(_this.substring(off, _this.length())); - off = _this.length(); - break; - } - } - // If no match was found, return this - if (off == 0) - return new String[]{_this}; - - // Add remaining segment - if (!limited || list.size() < limit) - list.add(_this.substring(off, _this.length())); - - // Construct result - int resultSize = list.size(); - if (limit == 0) - while (resultSize > 0 && list.get(resultSize - 1).length() == 0) - resultSize--; - String[] result = new String[resultSize]; - return list.subList(0, resultSize).toArray(result); - } - return Pattern.compile(regex).split(_this, limit); - } - - /** - * Converts all of the characters in this <code>String</code> to lower - * case using the rules of the given <code>Locale</code>. Case mapping is based - * on the Unicode Standard version specified by the {@link java.lang.Character Character} - * class. Since case mappings are not always 1:1 char mappings, the resulting - * <code>String</code> may be a different length than the original <code>String</code>. - * <p> - * Examples of lowercase mappings are in the following table: - * <table border="1" summary="Lowercase mapping examples showing language code of locale, upper case, lower case, and description"> - * <tr> - * <th>Language Code of Locale</th> - * <th>Upper Case</th> - * <th>Lower Case</th> - * <th>Description</th> - * </tr> - * <tr> - * <td>tr (Turkish)</td> - * <td>\u0130</td> - * <td>\u0069</td> - * <td>capital letter I with dot above -> small letter i</td> - * </tr> - * <tr> - * <td>tr (Turkish)</td> - * <td>\u0049</td> - * <td>\u0131</td> - * <td>capital letter I -> small letter dotless i </td> - * </tr> - * <tr> - * <td>(all)</td> - * <td>French Fries</td> - * <td>french fries</td> - * <td>lowercased all chars in String</td> - * </tr> - * <tr> - * <td>(all)</td> - * <td><img src="doc-files/capiota.gif" alt="capiota"><img src="doc-files/capchi.gif" alt="capchi"> - * <img src="doc-files/captheta.gif" alt="captheta"><img src="doc-files/capupsil.gif" alt="capupsil"> - * <img src="doc-files/capsigma.gif" alt="capsigma"></td> - * <td><img src="doc-files/iota.gif" alt="iota"><img src="doc-files/chi.gif" alt="chi"> - * <img src="doc-files/theta.gif" alt="theta"><img src="doc-files/upsilon.gif" alt="upsilon"> - * <img src="doc-files/sigma1.gif" alt="sigma"></td> - * <td>lowercased all chars in String</td> - * </tr> - * </table> - * - * @param locale use the case transformation rules for this locale - * @return the <code>String</code>, converted to lowercase. - * @see java.lang.String#toLowerCase() - * @see java.lang.String#toUpperCase() - * @see java.lang.String#toUpperCase(Locale) - * @since 1.1 - */ - static String toLowerCase(String _this, Locale locale) { - if (locale == null) { - throw new NullPointerException(); - } - - int firstUpper; - final int len = _this.length(); - - /* Now check if there are any characters that need to be changed. */ - scan: { - for (firstUpper = 0 ; firstUpper < len; ) { - char c = _this.charAt(firstUpper); - if ((c >= Character.MIN_HIGH_SURROGATE) - && (c <= Character.MAX_HIGH_SURROGATE)) { - int supplChar = _this.codePointAt(firstUpper); - if (supplChar != Character.toLowerCase(supplChar)) { - break scan; - } - firstUpper += Character.charCount(supplChar); - } else { - if (c != Character.toLowerCase(c)) { - break scan; - } - firstUpper++; - } - } - return _this; - } - - char[] result = new char[len]; - int resultOffset = 0; /* result may grow, so i+resultOffset - * is the write location in result */ - - /* Just copy the first few lowerCase characters. */ - _this.getChars(0, firstUpper, result, 0); - - String lang = locale.getLanguage(); - boolean localeDependent = - (lang == "tr" || lang == "az" || lang == "lt"); - char[] lowerCharArray; - int lowerChar; - int srcChar; - int srcCount; - for (int i = firstUpper; i < len; i += srcCount) { - srcChar = (int)_this.charAt(i); - if ((char)srcChar >= Character.MIN_HIGH_SURROGATE - && (char)srcChar <= Character.MAX_HIGH_SURROGATE) { - srcChar = _this.codePointAt(i); - srcCount = Character.charCount(srcChar); - } else { - srcCount = 1; - } - if (localeDependent || srcChar == '\u03A3') { // GREEK CAPITAL LETTER SIGMA - lowerChar = ConditionalSpecialCasing.toLowerCaseEx(_this, i, locale); - } else if (srcChar == '\u0130') { // LATIN CAPITAL LETTER I DOT - lowerChar = Character.ERROR; - } else { - lowerChar = Character.toLowerCase(srcChar); - } - if ((lowerChar == Character.ERROR) - || (lowerChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) { - if (lowerChar == Character.ERROR) { - if (!localeDependent && srcChar == '\u0130') { - lowerCharArray = - ConditionalSpecialCasing.toLowerCaseCharArray(_this, i, Locale.ENGLISH); - } else { - lowerCharArray = - ConditionalSpecialCasing.toLowerCaseCharArray(_this, i, locale); - } - } else if (srcCount == 2) { - resultOffset += Character.toChars(lowerChar, result, i + resultOffset) - srcCount; - continue; - } else { - lowerCharArray = Character.toChars(lowerChar); - } - - /* Grow result if needed */ - int mapLen = lowerCharArray.length; - if (mapLen > srcCount) { - char[] result2 = new char[result.length + mapLen - srcCount]; - System.arraycopy(result, 0, result2, 0, i + resultOffset); - result = result2; - } - for (int x = 0; x < mapLen; ++x) { - result[i + resultOffset + x] = lowerCharArray[x]; - } - resultOffset += (mapLen - srcCount); - } else { - result[i + resultOffset] = (char)lowerChar; - } - } - return new String(result, 0, len + resultOffset); - } - - /** - * Converts all of the characters in this <code>String</code> to lower - * case using the rules of the default locale. This is equivalent to calling - * <code>toLowerCase(Locale.getDefault())</code>. - * <p> - * <b>Note:</b> This method is locale sensitive, and may produce unexpected - * results if used for strings that are intended to be interpreted locale - * independently. - * Examples are programming language identifiers, protocol keys, and HTML - * tags. - * For instance, <code>"TITLE".toLowerCase()</code> in a Turkish locale - * returns <code>"t\u005Cu0131tle"</code>, where '\u005Cu0131' is the - * LATIN SMALL LETTER DOTLESS I character. - * To obtain correct results for locale insensitive strings, use - * <code>toLowerCase(Locale.ENGLISH)</code>. - * <p> - * @return the <code>String</code>, converted to lowercase. - * @see java.lang.String#toLowerCase(Locale) - */ - static String toLowerCase(String _this) { - return toLowerCase(_this, Locale.getDefault()); - } - - /** - * Converts all of the characters in this <code>String</code> to upper - * case using the rules of the given <code>Locale</code>. Case mapping is based - * on the Unicode Standard version specified by the {@link java.lang.Character Character} - * class. Since case mappings are not always 1:1 char mappings, the resulting - * <code>String</code> may be a different length than the original <code>String</code>. - * <p> - * Examples of locale-sensitive and 1:M case mappings are in the following table. - * <p> - * <table border="1" summary="Examples of locale-sensitive and 1:M case mappings. Shows Language code of locale, lower case, upper case, and description."> - * <tr> - * <th>Language Code of Locale</th> - * <th>Lower Case</th> - * <th>Upper Case</th> - * <th>Description</th> - * </tr> - * <tr> - * <td>tr (Turkish)</td> - * <td>\u0069</td> - * <td>\u0130</td> - * <td>small letter i -> capital letter I with dot above</td> - * </tr> - * <tr> - * <td>tr (Turkish)</td> - * <td>\u0131</td> - * <td>\u0049</td> - * <td>small letter dotless i -> capital letter I</td> - * </tr> - * <tr> - * <td>(all)</td> - * <td>\u00df</td> - * <td>\u0053 \u0053</td> - * <td>small letter sharp s -> two letters: SS</td> - * </tr> - * <tr> - * <td>(all)</td> - * <td>Fahrvergnügen</td> - * <td>FAHRVERGNÜGEN</td> - * <td></td> - * </tr> - * </table> - * @param locale use the case transformation rules for this locale - * @return the <code>String</code>, converted to uppercase. - * @see java.lang.String#toUpperCase() - * @see java.lang.String#toLowerCase() - * @see java.lang.String#toLowerCase(Locale) - * @since 1.1 - */ - static String toUpperCase(String _this, Locale locale) { - if (locale == null) { - throw new NullPointerException(); - } - - int firstLower; - final int len = _this.length(); - - /* Now check if there are any characters that need to be changed. */ - scan: { - for (firstLower = 0 ; firstLower < len; ) { - int c = (int)_this.charAt(firstLower); - int srcCount; - if ((c >= Character.MIN_HIGH_SURROGATE) - && (c <= Character.MAX_HIGH_SURROGATE)) { - c = _this.codePointAt(firstLower); - srcCount = Character.charCount(c); - } else { - srcCount = 1; - } - int upperCaseChar = Character.toUpperCaseEx(c); - if ((upperCaseChar == Character.ERROR) - || (c != upperCaseChar)) { - break scan; - } - firstLower += srcCount; - } - return _this; - } - - char[] result = new char[len]; /* may grow */ - int resultOffset = 0; /* result may grow, so i+resultOffset - * is the write location in result */ - - /* Just copy the first few upperCase characters. */ - _this.getChars(0, firstLower, result, 0); - - String lang = locale.getLanguage(); - boolean localeDependent = - (lang == "tr" || lang == "az" || lang == "lt"); - char[] upperCharArray; - int upperChar; - int srcChar; - int srcCount; - for (int i = firstLower; i < len; i += srcCount) { - srcChar = (int)_this.charAt(i); - if ((char)srcChar >= Character.MIN_HIGH_SURROGATE && - (char)srcChar <= Character.MAX_HIGH_SURROGATE) { - srcChar = _this.codePointAt(i); - srcCount = Character.charCount(srcChar); - } else { - srcCount = 1; - } - if (localeDependent) { - upperChar = ConditionalSpecialCasing.toUpperCaseEx(_this, i, locale); - } else { - upperChar = Character.toUpperCaseEx(srcChar); - } - if ((upperChar == Character.ERROR) - || (upperChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) { - if (upperChar == Character.ERROR) { - if (localeDependent) { - upperCharArray = - ConditionalSpecialCasing.toUpperCaseCharArray(_this, i, locale); - } else { - upperCharArray = Character.toUpperCaseCharArray(srcChar); - } - } else if (srcCount == 2) { - resultOffset += Character.toChars(upperChar, result, i + resultOffset) - srcCount; - continue; - } else { - upperCharArray = Character.toChars(upperChar); - } - - /* Grow result if needed */ - int mapLen = upperCharArray.length; - if (mapLen > srcCount) { - char[] result2 = new char[result.length + mapLen - srcCount]; - System.arraycopy(result, 0, result2, 0, i + resultOffset); - result = result2; - } - for (int x = 0; x < mapLen; ++x) { - result[i + resultOffset + x] = upperCharArray[x]; - } - resultOffset += (mapLen - srcCount); - } else { - result[i + resultOffset] = (char)upperChar; - } - } - return new String(result, 0, len + resultOffset); - } - - /** - * Converts all of the characters in this <code>String</code> to upper - * case using the rules of the default locale. This method is equivalent to - * <code>toUpperCase(Locale.getDefault())</code>. - * <p> - * <b>Note:</b> This method is locale sensitive, and may produce unexpected - * results if used for strings that are intended to be interpreted locale - * independently. - * Examples are programming language identifiers, protocol keys, and HTML - * tags. - * For instance, <code>"title".toUpperCase()</code> in a Turkish locale - * returns <code>"T\u005Cu0130TLE"</code>, where '\u005Cu0130' is the - * LATIN CAPITAL LETTER I WITH DOT ABOVE character. - * To obtain correct results for locale insensitive strings, use - * <code>toUpperCase(Locale.ENGLISH)</code>. - * <p> - * @return the <code>String</code>, converted to uppercase. - * @see java.lang.String#toUpperCase(Locale) - */ - static String toUpperCase(String _this) { - return toUpperCase(_this, Locale.getDefault()); - } - - /** - * Returns a copy of the string, with leading and trailing whitespace - * omitted. - * <p> - * If this <code>String</code> object represents an empty character - * sequence, or the first and last characters of character sequence - * represented by this <code>String</code> object both have codes - * greater than <code>'\u0020'</code> (the space character), then a - * reference to this <code>String</code> object is returned. - * <p> - * Otherwise, if there is no character with a code greater than - * <code>'\u0020'</code> in the string, then a new - * <code>String</code> object representing an empty string is created - * and returned. - * <p> - * Otherwise, let <i>k</i> be the index of the first character in the - * string whose code is greater than <code>'\u0020'</code>, and let - * <i>m</i> be the index of the last character in the string whose code - * is greater than <code>'\u0020'</code>. A new <code>String</code> - * object is created, representing the substring of this string that - * begins with the character at index <i>k</i> and ends with the - * character at index <i>m</i>-that is, the result of - * <code>this.substring(<i>k</i>, <i>m</i>+1)</code>. - * <p> - * This method may be used to trim whitespace (as defined above) from - * the beginning and end of a string. - * - * @return A copy of this string with leading and trailing white - * space removed, or this string if it has no leading or - * trailing white space. - */ - static String trim(String _this) { - int len = _this.length(); - int st = 0; - - while ((st < len) && (_this.charAt(st) <= ' ')) { - st++; - } - while ((st < len) && (_this.charAt(len - 1) <= ' ')) { - len--; - } - return ((st > 0) || (len < _this.length())) ? _this.substring(st, len) : _this; - } - - /** - * Returns a formatted string using the specified format string and - * arguments. - * - * <p> The locale always used is the one returned by {@link - * java.util.Locale#getDefault() Locale.getDefault()}. - * - * @param format - * A <a href="../util/Formatter.html#syntax">format string</a> - * - * @param args - * Arguments referenced by the format specifiers in the format - * string. If there are more arguments than format specifiers, the - * extra arguments are ignored. The number of arguments is - * variable and may be zero. The maximum number of arguments is - * limited by the maximum dimension of a Java array as defined by - * <cite>The Java™ Virtual Machine Specification</cite>. - * The behaviour on a - * <tt>null</tt> argument depends on the <a - * href="../util/Formatter.html#syntax">conversion</a>. - * - * @throws IllegalFormatException - * If a format string contains an illegal syntax, a format - * specifier that is incompatible with the given arguments, - * insufficient arguments given the format string, or other - * illegal conditions. For specification of all possible - * formatting errors, see the <a - * href="../util/Formatter.html#detail">Details</a> section of the - * formatter class specification. - * - * @throws NullPointerException - * If the <tt>format</tt> is <tt>null</tt> - * - * @return A formatted string - * - * @see java.util.Formatter - * @since 1.5 - */ - public static String format(String format, Object... args) { - return new Formatter().format(format, args).toString(); - } - - /** - * Returns a formatted string using the specified locale, format string, - * and arguments. - * - * @param l - * The {@linkplain java.util.Locale locale} to apply during - * formatting. If <tt>l</tt> is <tt>null</tt> then no localization - * is applied. - * - * @param format - * A <a href="../util/Formatter.html#syntax">format string</a> - * - * @param args - * Arguments referenced by the format specifiers in the format - * string. If there are more arguments than format specifiers, the - * extra arguments are ignored. The number of arguments is - * variable and may be zero. The maximum number of arguments is - * limited by the maximum dimension of a Java array as defined by - * <cite>The Java™ Virtual Machine Specification</cite>. - * The behaviour on a - * <tt>null</tt> argument depends on the <a - * href="../util/Formatter.html#syntax">conversion</a>. - * - * @throws IllegalFormatException - * If a format string contains an illegal syntax, a format - * specifier that is incompatible with the given arguments, - * insufficient arguments given the format string, or other - * illegal conditions. For specification of all possible - * formatting errors, see the <a - * href="../util/Formatter.html#detail">Details</a> section of the - * formatter class specification - * - * @throws NullPointerException - * If the <tt>format</tt> is <tt>null</tt> - * - * @return A formatted string - * - * @see java.util.Formatter - * @since 1.5 - */ - public static String format(Locale l, String format, Object... args) { - return new Formatter(l).format(format, args).toString(); - } - - /** - * Returns the string representation of the <code>Object</code> argument. - * - * @param obj an <code>Object</code>. - * @return if the argument is <code>null</code>, then a string equal to - * <code>"null"</code>; otherwise, the value of - * <code>obj.toString()</code> is returned. - * @see java.lang.Object#toString() - */ - public static String valueOf(Object obj) { - return (obj == null) ? "null" : obj.toString(); - } - - /** - * Returns the string representation of the <code>char</code> array - * argument. The contents of the character array are copied; subsequent - * modification of the character array does not affect the newly - * created string. - * - * @param data a <code>char</code> array. - * @return a newly allocated string representing the same sequence of - * characters contained in the character array argument. - */ - public static String valueOf(char data[]) { - return new String(data); - } - - /** - * Returns the string representation of a specific subarray of the - * <code>char</code> array argument. - * <p> - * The <code>offset</code> argument is the index of the first - * character of the subarray. The <code>count</code> argument - * specifies the length of the subarray. The contents of the subarray - * are copied; subsequent modification of the character array does not - * affect the newly created string. - * - * @param data the character array. - * @param offset the initial offset into the value of the - * <code>String</code>. - * @param count the length of the value of the <code>String</code>. - * @return a string representing the sequence of characters contained - * in the subarray of the character array argument. - * @exception IndexOutOfBoundsException if <code>offset</code> is - * negative, or <code>count</code> is negative, or - * <code>offset+count</code> is larger than - * <code>data.length</code>. - */ - public static String valueOf(char data[], int offset, int count) { - return new String(data, offset, count); - } - - /** - * Returns a String that represents the character sequence in the - * array specified. - * - * @param data the character array. - * @param offset initial offset of the subarray. - * @param count length of the subarray. - * @return a <code>String</code> that contains the characters of the - * specified subarray of the character array. - */ - public static String copyValueOf(char data[], int offset, int count) { - // All public String constructors now copy the data. - return new String(data, offset, count); - } - - /** - * Returns a String that represents the character sequence in the - * array specified. - * - * @param data the character array. - * @return a <code>String</code> that contains the characters of the - * character array. - */ - public static String copyValueOf(char data[]) { - return new String(data); - } - - /** - * Returns the string representation of the <code>boolean</code> argument. - * - * @param b a <code>boolean</code>. - * @return if the argument is <code>true</code>, a string equal to - * <code>"true"</code> is returned; otherwise, a string equal to - * <code>"false"</code> is returned. - */ - public static String valueOf(boolean b) { - return b ? "true" : "false"; - } - - /** - * Returns the string representation of the <code>int</code> argument. - * <p> - * The representation is exactly the one returned by the - * <code>Integer.toString</code> method of one argument. - * - * @param i an <code>int</code>. - * @return a string representation of the <code>int</code> argument. - * @see java.lang.Integer#toString(int, int) - */ - public static String valueOf(int i) { - return Integer.toString(i); - } - - /** - * Returns the string representation of the <code>long</code> argument. - * <p> - * The representation is exactly the one returned by the - * <code>Long.toString</code> method of one argument. - * - * @param l a <code>long</code>. - * @return a string representation of the <code>long</code> argument. - * @see java.lang.Long#toString(long) - */ - public static String valueOf(long l) { - return Long.toString(l); - } - - /** - * Returns the string representation of the <code>float</code> argument. - * <p> - * The representation is exactly the one returned by the - * <code>Float.toString</code> method of one argument. - * - * @param f a <code>float</code>. - * @return a string representation of the <code>float</code> argument. - * @see java.lang.Float#toString(float) - */ - public static String valueOf(float f) { - return Float.toString(f); - } - - /** - * Returns the string representation of the <code>double</code> argument. - * <p> - * The representation is exactly the one returned by the - * <code>Double.toString</code> method of one argument. - * - * @param d a <code>double</code>. - * @return a string representation of the <code>double</code> argument. - * @see java.lang.Double#toString(double) - */ - public static String valueOf(double d) { - return Double.toString(d); - } - - /** - * Seed value used for each alternative hash calculated. - */ - private static final int HASHING_SEED; - - static { - long nanos = System.nanoTime(); - long now = System.currentTimeMillis(); - int SEED_MATERIAL[] = { - System.identityHashCode(String.class), - System.identityHashCode(System.class), - (int) (nanos >>> 32), - (int) nanos, - (int) (now >>> 32), - (int) now, - (int) (System.nanoTime() >>> 2) - }; - - // Use murmur3 to scramble the seeding material. - // Inline implementation to avoid loading classes - int h1 = 0; - - // body - for (int k1 : SEED_MATERIAL) { - k1 *= 0xcc9e2d51; - k1 = (k1 << 15) | (k1 >>> 17); - k1 *= 0x1b873593; - - h1 ^= k1; - h1 = (h1 << 13) | (h1 >>> 19); - h1 = h1 * 5 + 0xe6546b64; - } - - // tail (always empty, as body is always 32-bit chunks) - - // finalization - - h1 ^= SEED_MATERIAL.length * 4; - - // finalization mix force all bits of a hash block to avalanche - h1 ^= h1 >>> 16; - h1 *= 0x85ebca6b; - h1 ^= h1 >>> 13; - h1 *= 0xc2b2ae35; - h1 ^= h1 >>> 16; - - HASHING_SEED = h1; - } - - /** - * Calculates a 32-bit hash value for this string. - * - * @return a 32-bit hash value for this string. - */ - static int hash32(String _this) { - // [IKVM] We don't bother with murmur32 and just use the .NET hash code - // and hope that it is good enough. We xor with HASHING_SEED to avoid - // returning predictable values (this does not help against DoS attacks, - // but it will surface constant hash code dependencies). - // If truly randomized string hashes are required (to protect against - // DoS) the .NET 4.5 <UseRandomizedStringHashAlgorithm enabled="1" /> - // app.config setting can be used. - return HASHING_SEED ^ ((cli.System.String)(Object)_this).GetHashCode(); - } - -} diff --git a/openjdk/java/lang/System.java b/openjdk/java/lang/System.java deleted file mode 100644 index e74187b9..00000000 --- a/openjdk/java/lang/System.java +++ /dev/null @@ -1,1168 +0,0 @@ -/* - * Copyright (c) 1994, 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 java.lang; - -import java.io.*; -import java.util.Properties; -import java.util.PropertyPermission; -import java.util.StringTokenizer; -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.reflect.CallerSensitive; -import sun.reflect.Reflection; -import sun.security.util.SecurityConstants; - -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); -} - -final class Props -{ - private Props() { } - - static Properties props; - static String lineSeparator; - - static - { - props = new Properties(); - VMSystemProperties.initProperties(props); - lineSeparator = props.getProperty("line.separator"); - - // after we've initialized the system properties, we need to fixate certain - // results that depend on system properties, because we don't want Java code to - // be able to change the behavior by setting these system properties. - ClassLoader.initializeLibraryPaths(props); - sun.misc.VM.saveAndRemoveProperties(props); - - // now that we've initialized the system properties (which are our only - // notion of "booting" the VM) we set the booted flag. - sun.misc.VM.booted(); - } -} - -/** - * The <code>System</code> class contains several useful class fields - * and methods. It cannot be instantiated. - * - * <p>Among the facilities provided by the <code>System</code> class - * are standard input, standard output, and error output streams; - * access to externally defined properties and environment - * variables; a means of loading files and libraries; and a utility - * method for quickly copying a portion of an array. - * - * @author unascribed - * @since JDK1.0 - */ -public final class System { - - /** Don't let anyone instantiate this class */ - private System() { - } - - /** - * The "standard" input stream. This stream is already - * open and ready to supply input data. Typically this stream - * corresponds to keyboard input or another input source specified by - * the host environment or user. - */ - @ikvm.lang.Property(get="get_in") - public final static InputStream in; - - static { in = null; } - - private static InputStream get_in() - { - return StdIO.in; - } - - /** - * The "standard" output stream. This stream is already - * open and ready to accept output data. Typically this stream - * corresponds to display output or another output destination - * specified by the host environment or user. - * <p> - * For simple stand-alone Java applications, a typical way to write - * a line of output data is: - * <blockquote><pre> - * System.out.println(data) - * </pre></blockquote> - * <p> - * See the <code>println</code> methods in class <code>PrintStream</code>. - * - * @see java.io.PrintStream#println() - * @see java.io.PrintStream#println(boolean) - * @see java.io.PrintStream#println(char) - * @see java.io.PrintStream#println(char[]) - * @see java.io.PrintStream#println(double) - * @see java.io.PrintStream#println(float) - * @see java.io.PrintStream#println(int) - * @see java.io.PrintStream#println(long) - * @see java.io.PrintStream#println(java.lang.Object) - * @see java.io.PrintStream#println(java.lang.String) - */ - @ikvm.lang.Property(get="get_out") - public final static PrintStream out; - - static { out = null; } - - private static PrintStream get_out() - { - return StdIO.out; - } - - /** - * The "standard" error output stream. This stream is already - * open and ready to accept output data. - * <p> - * Typically this stream corresponds to display output or another - * output destination specified by the host environment or user. By - * convention, this output stream is used to display error messages - * or other information that should come to the immediate attention - * of a user even if the principal output stream, the value of the - * variable <code>out</code>, has been redirected to a file or other - * destination that is typically not continuously monitored. - */ - @ikvm.lang.Property(get="get_err") - public final static PrintStream err; - - static { err = null ; } - - private static PrintStream get_err() - { - return StdIO.err; - } - - /* The security manager for the system. - */ - private static volatile SecurityManager security; - - /** - * Reassigns the "standard" input stream. - * - * <p>First, if there is a security manager, its <code>checkPermission</code> - * method is called with a <code>RuntimePermission("setIO")</code> permission - * to see if it's ok to reassign the "standard" input stream. - * <p> - * - * @param in the new standard input stream. - * - * @throws SecurityException - * if a security manager exists and its - * <code>checkPermission</code> method doesn't allow - * reassigning of the standard input stream. - * - * @see SecurityManager#checkPermission - * @see java.lang.RuntimePermission - * - * @since JDK1.1 - */ - public static void setIn(InputStream in) { - checkIO(); - StdIO.in = in; - } - - /** - * Reassigns the "standard" output stream. - * - * <p>First, if there is a security manager, its <code>checkPermission</code> - * method is called with a <code>RuntimePermission("setIO")</code> permission - * to see if it's ok to reassign the "standard" output stream. - * - * @param out the new standard output stream - * - * @throws SecurityException - * if a security manager exists and its - * <code>checkPermission</code> method doesn't allow - * reassigning of the standard output stream. - * - * @see SecurityManager#checkPermission - * @see java.lang.RuntimePermission - * - * @since JDK1.1 - */ - public static void setOut(PrintStream out) { - checkIO(); - StdIO.out = out; - } - - /** - * Reassigns the "standard" error output stream. - * - * <p>First, if there is a security manager, its <code>checkPermission</code> - * method is called with a <code>RuntimePermission("setIO")</code> permission - * to see if it's ok to reassign the "standard" error output stream. - * - * @param err the new standard error output stream. - * - * @throws SecurityException - * if a security manager exists and its - * <code>checkPermission</code> method doesn't allow - * reassigning of the standard error output stream. - * - * @see SecurityManager#checkPermission - * @see java.lang.RuntimePermission - * - * @since JDK1.1 - */ - public static void setErr(PrintStream err) { - checkIO(); - StdIO.err = err; - } - - private static volatile Console cons; - /** - * Returns the unique {@link java.io.Console Console} object associated - * with the current Java virtual machine, if any. - * - * @return The system console, if any, otherwise <tt>null</tt>. - * - * @since 1.6 - */ - public static Console console() { - if (cons == null) { - synchronized (System.class) { - cons = sun.misc.SharedSecrets.getJavaIOAccess().console(); - } - } - return cons; - } - - /** - * Returns the channel inherited from the entity that created this - * Java virtual machine. - * - * <p> This method returns the channel obtained by invoking the - * {@link java.nio.channels.spi.SelectorProvider#inheritedChannel - * inheritedChannel} method of the system-wide default - * {@link java.nio.channels.spi.SelectorProvider} object. </p> - * - * <p> In addition to the network-oriented channels described in - * {@link java.nio.channels.spi.SelectorProvider#inheritedChannel - * inheritedChannel}, this method may return other kinds of - * channels in the future. - * - * @return The inherited channel, if any, otherwise <tt>null</tt>. - * - * @throws IOException - * If an I/O error occurs - * - * @throws SecurityException - * If a security manager is present and it does not - * permit access to the channel. - * - * @since 1.5 - */ - public static Channel inheritedChannel() throws IOException { - return SelectorProvider.provider().inheritedChannel(); - } - - private static void checkIO() { - SecurityManager sm = getSecurityManager(); - if (sm != null) { - sm.checkPermission(new RuntimePermission("setIO")); - } - } - - /** - * Sets the System security. - * - * <p> If there is a security manager already installed, this method first - * calls the security manager's <code>checkPermission</code> method - * with a <code>RuntimePermission("setSecurityManager")</code> - * permission to ensure it's ok to replace the existing - * security manager. - * This may result in throwing a <code>SecurityException</code>. - * - * <p> Otherwise, the argument is established as the current - * security manager. If the argument is <code>null</code> and no - * security manager has been established, then no action is taken and - * the method simply returns. - * - * @param s the security manager. - * @exception SecurityException if the security manager has already - * been set and its <code>checkPermission</code> method - * doesn't allow it to be replaced. - * @see #getSecurityManager - * @see SecurityManager#checkPermission - * @see java.lang.RuntimePermission - */ - public static - void setSecurityManager(final SecurityManager s) { - try { - s.checkPackageAccess("java.lang"); - } catch (Exception e) { - // no-op - } - setSecurityManager0(s); - } - - private static synchronized - void setSecurityManager0(final SecurityManager s) { - // [IKVM] force sun.misc.Launcher to initialize, because it assumes that it runs without a SecurityManager - sun.misc.Launcher.getLauncher(); - - SecurityManager sm = getSecurityManager(); - if (sm != null) { - // ask the currently installed security manager if we - // can replace it. - sm.checkPermission(new RuntimePermission - ("setSecurityManager")); - } - - if ((s != null) && (s.getClass().getClassLoader() != null)) { - // New security manager class is not on bootstrap classpath. - // Cause policy to get initialized before we install the new - // security manager, in order to prevent infinite loops when - // trying to initialize the policy (which usually involves - // accessing some security and/or system properties, which in turn - // calls the installed security manager's checkPermission method - // which will loop infinitely if there is a non-system class - // (in this case: the new security manager class) on the stack). - AccessController.doPrivileged(new PrivilegedAction<Object>() { - public Object run() { - s.getClass().getProtectionDomain().implies - (SecurityConstants.ALL_PERMISSION); - return null; - } - }); - } - - security = s; - } - - /** - * Gets the system security interface. - * - * @return if a security manager has already been established for the - * current application, then that security manager is returned; - * otherwise, <code>null</code> is returned. - * @see #setSecurityManager - */ - public static SecurityManager getSecurityManager() { - return security; - } - - /** - * Returns the current time in milliseconds. Note that - * while the unit of time of the return value is a millisecond, - * the granularity of the value depends on the underlying - * operating system and may be larger. For example, many - * operating systems measure time in units of tens of - * milliseconds. - * - * <p> See the description of the class <code>Date</code> for - * a discussion of slight discrepancies that may arise between - * "computer time" and coordinated universal time (UTC). - * - * @return the difference, measured in milliseconds, between - * the current time and midnight, January 1, 1970 UTC. - * @see java.util.Date - */ - public static long currentTimeMillis() { - long january_1st_1970 = 62135596800000L; - return cli.System.DateTime.get_UtcNow().get_Ticks() / 10000L - january_1st_1970; - } - - /** - * Returns the current value of the running Java Virtual Machine's - * high-resolution time source, in nanoseconds. - * - * <p>This method can only be used to measure elapsed time and is - * not related to any other notion of system or wall-clock time. - * The value returned represents nanoseconds since some fixed but - * arbitrary <i>origin</i> time (perhaps in the future, so values - * may be negative). The same origin is used by all invocations of - * this method in an instance of a Java virtual machine; other - * virtual machine instances are likely to use a different origin. - * - * <p>This method provides nanosecond precision, but not necessarily - * nanosecond resolution (that is, how frequently the value changes) - * - no guarantees are made except that the resolution is at least as - * good as that of {@link #currentTimeMillis()}. - * - * <p>Differences in successive calls that span greater than - * approximately 292 years (2<sup>63</sup> nanoseconds) will not - * correctly compute elapsed time due to numerical overflow. - * - * <p>The values returned by this method become meaningful only when - * the difference between two such values, obtained within the same - * instance of a Java virtual machine, is computed. - * - * <p> For example, to measure how long some code takes to execute: - * <pre> {@code - * long startTime = System.nanoTime(); - * // ... the code being measured ... - * long estimatedTime = System.nanoTime() - startTime;}</pre> - * - * <p>To compare two nanoTime values - * <pre> {@code - * long t0 = System.nanoTime(); - * ... - * long t1 = System.nanoTime();}</pre> - * - * one should use {@code t1 - t0 < 0}, not {@code t1 < t0}, - * because of the possibility of numerical overflow. - * - * @return the current value of the running Java Virtual Machine's - * high-resolution time source, in nanoseconds - * @since 1.5 - */ - public static long nanoTime() { - long NANOS_PER_SEC = 1000000000; - double current = cli.System.Diagnostics.Stopwatch.GetTimestamp(); - double freq = cli.System.Diagnostics.Stopwatch.Frequency; - return (long)((current / freq) * NANOS_PER_SEC); - } - - /** - * Copies an array from the specified source array, beginning at the - * specified position, to the specified position of the destination array. - * A subsequence of array components are copied from the source - * array referenced by <code>src</code> to the destination array - * referenced by <code>dest</code>. The number of components copied is - * equal to the <code>length</code> argument. The components at - * positions <code>srcPos</code> through - * <code>srcPos+length-1</code> in the source array are copied into - * positions <code>destPos</code> through - * <code>destPos+length-1</code>, respectively, of the destination - * array. - * <p> - * If the <code>src</code> and <code>dest</code> arguments refer to the - * same array object, then the copying is performed as if the - * components at positions <code>srcPos</code> through - * <code>srcPos+length-1</code> were first copied to a temporary - * array with <code>length</code> components and then the contents of - * the temporary array were copied into positions - * <code>destPos</code> through <code>destPos+length-1</code> of the - * destination array. - * <p> - * If <code>dest</code> is <code>null</code>, then a - * <code>NullPointerException</code> is thrown. - * <p> - * If <code>src</code> is <code>null</code>, then a - * <code>NullPointerException</code> is thrown and the destination - * array is not modified. - * <p> - * Otherwise, if any of the following is true, an - * <code>ArrayStoreException</code> is thrown and the destination is - * not modified: - * <ul> - * <li>The <code>src</code> argument refers to an object that is not an - * array. - * <li>The <code>dest</code> argument refers to an object that is not an - * array. - * <li>The <code>src</code> argument and <code>dest</code> argument refer - * to arrays whose component types are different primitive types. - * <li>The <code>src</code> argument refers to an array with a primitive - * component type and the <code>dest</code> argument refers to an array - * with a reference component type. - * <li>The <code>src</code> argument refers to an array with a reference - * component type and the <code>dest</code> argument refers to an array - * with a primitive component type. - * </ul> - * <p> - * Otherwise, if any of the following is true, an - * <code>IndexOutOfBoundsException</code> is - * thrown and the destination is not modified: - * <ul> - * <li>The <code>srcPos</code> argument is negative. - * <li>The <code>destPos</code> argument is negative. - * <li>The <code>length</code> argument is negative. - * <li><code>srcPos+length</code> is greater than - * <code>src.length</code>, the length of the source array. - * <li><code>destPos+length</code> is greater than - * <code>dest.length</code>, the length of the destination array. - * </ul> - * <p> - * Otherwise, if any actual component of the source array from - * position <code>srcPos</code> through - * <code>srcPos+length-1</code> cannot be converted to the component - * type of the destination array by assignment conversion, an - * <code>ArrayStoreException</code> is thrown. In this case, let - * <b><i>k</i></b> be the smallest nonnegative integer less than - * length such that <code>src[srcPos+</code><i>k</i><code>]</code> - * cannot be converted to the component type of the destination - * array; when the exception is thrown, source array components from - * positions <code>srcPos</code> through - * <code>srcPos+</code><i>k</i><code>-1</code> - * will already have been copied to destination array positions - * <code>destPos</code> through - * <code>destPos+</code><i>k</I><code>-1</code> and no other - * positions of the destination array will have been modified. - * (Because of the restrictions already itemized, this - * paragraph effectively applies only to the situation where both - * arrays have component types that are reference types.) - * - * @param src the source array. - * @param srcPos starting position in the source array. - * @param dest the destination array. - * @param destPos starting position in the destination data. - * @param length the number of array elements to be copied. - * @exception IndexOutOfBoundsException if copying would cause - * access of data outside array bounds. - * @exception ArrayStoreException if an element in the <code>src</code> - * array could not be stored into the <code>dest</code> array - * because of a type mismatch. - * @exception NullPointerException if either <code>src</code> or - * <code>dest</code> is <code>null</code>. - */ - public static native void arraycopy(Object src, int srcPos, - Object dest, int destPos, - int length); - - /** - * Returns the same hash code for the given object as - * would be returned by the default method hashCode(), - * whether or not the given object's class overrides - * hashCode(). - * The hash code for the null reference is zero. - * - * @param x object for which the hashCode is to be calculated - * @return the hashCode - * @since JDK1.1 - */ - public static int identityHashCode(Object x) { - return cli.System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(x); - } - - /** - * System properties. The following properties are guaranteed to be defined: - * <dl> - * <dt>java.version <dd>Java version number - * <dt>java.vendor <dd>Java vendor specific string - * <dt>java.vendor.url <dd>Java vendor URL - * <dt>java.home <dd>Java installation directory - * <dt>java.class.version <dd>Java class version number - * <dt>java.class.path <dd>Java classpath - * <dt>os.name <dd>Operating System Name - * <dt>os.arch <dd>Operating System Architecture - * <dt>os.version <dd>Operating System Version - * <dt>file.separator <dd>File separator ("/" on Unix) - * <dt>path.separator <dd>Path separator (":" on Unix) - * <dt>line.separator <dd>Line separator ("\n" on Unix) - * <dt>user.name <dd>User account name - * <dt>user.home <dd>User home directory - * <dt>user.dir <dd>User's current working directory - * </dl> - */ - - //private static native Properties initProperties(Properties props); - - /** - * Determines the current system properties. - * <p> - * First, if there is a security manager, its - * <code>checkPropertiesAccess</code> method is called with no - * arguments. This may result in a security exception. - * <p> - * The current set of system properties for use by the - * {@link #getProperty(String)} method is returned as a - * <code>Properties</code> object. If there is no current set of - * system properties, a set of system properties is first created and - * initialized. This set of system properties always includes values - * for the following keys: - * <table summary="Shows property keys and associated values"> - * <tr><th>Key</th> - * <th>Description of Associated Value</th></tr> - * <tr><td><code>java.version</code></td> - * <td>Java Runtime Environment version</td></tr> - * <tr><td><code>java.vendor</code></td> - * <td>Java Runtime Environment vendor</td></tr - * <tr><td><code>java.vendor.url</code></td> - * <td>Java vendor URL</td></tr> - * <tr><td><code>java.home</code></td> - * <td>Java installation directory</td></tr> - * <tr><td><code>java.vm.specification.version</code></td> - * <td>Java Virtual Machine specification version</td></tr> - * <tr><td><code>java.vm.specification.vendor</code></td> - * <td>Java Virtual Machine specification vendor</td></tr> - * <tr><td><code>java.vm.specification.name</code></td> - * <td>Java Virtual Machine specification name</td></tr> - * <tr><td><code>java.vm.version</code></td> - * <td>Java Virtual Machine implementation version</td></tr> - * <tr><td><code>java.vm.vendor</code></td> - * <td>Java Virtual Machine implementation vendor</td></tr> - * <tr><td><code>java.vm.name</code></td> - * <td>Java Virtual Machine implementation name</td></tr> - * <tr><td><code>java.specification.version</code></td> - * <td>Java Runtime Environment specification version</td></tr> - * <tr><td><code>java.specification.vendor</code></td> - * <td>Java Runtime Environment specification vendor</td></tr> - * <tr><td><code>java.specification.name</code></td> - * <td>Java Runtime Environment specification name</td></tr> - * <tr><td><code>java.class.version</code></td> - * <td>Java class format version number</td></tr> - * <tr><td><code>java.class.path</code></td> - * <td>Java class path</td></tr> - * <tr><td><code>java.library.path</code></td> - * <td>List of paths to search when loading libraries</td></tr> - * <tr><td><code>java.io.tmpdir</code></td> - * <td>Default temp file path</td></tr> - * <tr><td><code>java.compiler</code></td> - * <td>Name of JIT compiler to use</td></tr> - * <tr><td><code>java.ext.dirs</code></td> - * <td>Path of extension directory or directories</td></tr> - * <tr><td><code>os.name</code></td> - * <td>Operating system name</td></tr> - * <tr><td><code>os.arch</code></td> - * <td>Operating system architecture</td></tr> - * <tr><td><code>os.version</code></td> - * <td>Operating system version</td></tr> - * <tr><td><code>file.separator</code></td> - * <td>File separator ("/" on UNIX)</td></tr> - * <tr><td><code>path.separator</code></td> - * <td>Path separator (":" on UNIX)</td></tr> - * <tr><td><code>line.separator</code></td> - * <td>Line separator ("\n" on UNIX)</td></tr> - * <tr><td><code>user.name</code></td> - * <td>User's account name</td></tr> - * <tr><td><code>user.home</code></td> - * <td>User's home directory</td></tr> - * <tr><td><code>user.dir</code></td> - * <td>User's current working directory</td></tr> - * </table> - * <p> - * Multiple paths in a system property value are separated by the path - * separator character of the platform. - * <p> - * Note that even if the security manager does not permit the - * <code>getProperties</code> operation, it may choose to permit the - * {@link #getProperty(String)} operation. - * - * @return the system properties - * @exception SecurityException if a security manager exists and its - * <code>checkPropertiesAccess</code> method doesn't allow access - * to the system properties. - * @see #setProperties - * @see java.lang.SecurityException - * @see java.lang.SecurityManager#checkPropertiesAccess() - * @see java.util.Properties - */ - public static Properties getProperties() { - SecurityManager sm = getSecurityManager(); - if (sm != null) { - sm.checkPropertiesAccess(); - } - - return Props.props; - } - - /** - * Returns the system-dependent line separator string. It always - * returns the same value - the initial value of the {@linkplain - * #getProperty(String) system property} {@code line.separator}. - * - * <p>On UNIX systems, it returns {@code "\n"}; on Microsoft - * Windows systems it returns {@code "\r\n"}. - */ - public static String lineSeparator() { - return Props.lineSeparator; - } - - /** - * Sets the system properties to the <code>Properties</code> - * argument. - * <p> - * First, if there is a security manager, its - * <code>checkPropertiesAccess</code> method is called with no - * arguments. This may result in a security exception. - * <p> - * The argument becomes the current set of system properties for use - * by the {@link #getProperty(String)} method. If the argument is - * <code>null</code>, then the current set of system properties is - * forgotten. - * - * @param props the new system properties. - * @exception SecurityException if a security manager exists and its - * <code>checkPropertiesAccess</code> method doesn't allow access - * to the system properties. - * @see #getProperties - * @see java.util.Properties - * @see java.lang.SecurityException - * @see java.lang.SecurityManager#checkPropertiesAccess() - */ - public static void setProperties(Properties props) { - SecurityManager sm = getSecurityManager(); - if (sm != null) { - sm.checkPropertiesAccess(); - } - if (props == null) { - props = new Properties(); - VMSystemProperties.initProperties(props); - } - Props.props = props; - } - - /** - * Gets the system property indicated by the specified key. - * <p> - * First, if there is a security manager, its - * <code>checkPropertyAccess</code> method is called with the key as - * its argument. This may result in a SecurityException. - * <p> - * If there is no current set of system properties, a set of system - * properties is first created and initialized in the same manner as - * for the <code>getProperties</code> method. - * - * @param key the name of the system property. - * @return the string value of the system property, - * or <code>null</code> if there is no property with that key. - * - * @exception SecurityException if a security manager exists and its - * <code>checkPropertyAccess</code> method doesn't allow - * access to the specified system property. - * @exception NullPointerException if <code>key</code> is - * <code>null</code>. - * @exception IllegalArgumentException if <code>key</code> is empty. - * @see #setProperty - * @see java.lang.SecurityException - * @see java.lang.SecurityManager#checkPropertyAccess(java.lang.String) - * @see java.lang.System#getProperties() - */ - public static String getProperty(String key) { - checkKey(key); - SecurityManager sm = getSecurityManager(); - if (sm != null) { - sm.checkPropertyAccess(key); - } - - return Props.props.getProperty(key); - } - - /** - * Gets the system property indicated by the specified key. - * <p> - * First, if there is a security manager, its - * <code>checkPropertyAccess</code> method is called with the - * <code>key</code> as its argument. - * <p> - * If there is no current set of system properties, a set of system - * properties is first created and initialized in the same manner as - * for the <code>getProperties</code> method. - * - * @param key the name of the system property. - * @param def a default value. - * @return the string value of the system property, - * or the default value if there is no property with that key. - * - * @exception SecurityException if a security manager exists and its - * <code>checkPropertyAccess</code> method doesn't allow - * access to the specified system property. - * @exception NullPointerException if <code>key</code> is - * <code>null</code>. - * @exception IllegalArgumentException if <code>key</code> is empty. - * @see #setProperty - * @see java.lang.SecurityManager#checkPropertyAccess(java.lang.String) - * @see java.lang.System#getProperties() - */ - public static String getProperty(String key, String def) { - checkKey(key); - SecurityManager sm = getSecurityManager(); - if (sm != null) { - sm.checkPropertyAccess(key); - } - - return Props.props.getProperty(key, def); - } - - /** - * Sets the system property indicated by the specified key. - * <p> - * First, if a security manager exists, its - * <code>SecurityManager.checkPermission</code> method - * is called with a <code>PropertyPermission(key, "write")</code> - * permission. This may result in a SecurityException being thrown. - * If no exception is thrown, the specified property is set to the given - * value. - * <p> - * - * @param key the name of the system property. - * @param value the value of the system property. - * @return the previous value of the system property, - * or <code>null</code> if it did not have one. - * - * @exception SecurityException if a security manager exists and its - * <code>checkPermission</code> method doesn't allow - * setting of the specified property. - * @exception NullPointerException if <code>key</code> or - * <code>value</code> is <code>null</code>. - * @exception IllegalArgumentException if <code>key</code> is empty. - * @see #getProperty - * @see java.lang.System#getProperty(java.lang.String) - * @see java.lang.System#getProperty(java.lang.String, java.lang.String) - * @see java.util.PropertyPermission - * @see SecurityManager#checkPermission - * @since 1.2 - */ - public static String setProperty(String key, String value) { - checkKey(key); - SecurityManager sm = getSecurityManager(); - if (sm != null) { - sm.checkPermission(new PropertyPermission(key, - SecurityConstants.PROPERTY_WRITE_ACTION)); - } - - return (String) Props.props.setProperty(key, value); - } - - /** - * Removes the system property indicated by the specified key. - * <p> - * First, if a security manager exists, its - * <code>SecurityManager.checkPermission</code> method - * is called with a <code>PropertyPermission(key, "write")</code> - * permission. This may result in a SecurityException being thrown. - * If no exception is thrown, the specified property is removed. - * <p> - * - * @param key the name of the system property to be removed. - * @return the previous string value of the system property, - * or <code>null</code> if there was no property with that key. - * - * @exception SecurityException if a security manager exists and its - * <code>checkPropertyAccess</code> method doesn't allow - * access to the specified system property. - * @exception NullPointerException if <code>key</code> is - * <code>null</code>. - * @exception IllegalArgumentException if <code>key</code> is empty. - * @see #getProperty - * @see #setProperty - * @see java.util.Properties - * @see java.lang.SecurityException - * @see java.lang.SecurityManager#checkPropertiesAccess() - * @since 1.5 - */ - public static String clearProperty(String key) { - checkKey(key); - SecurityManager sm = getSecurityManager(); - if (sm != null) { - sm.checkPermission(new PropertyPermission(key, "write")); - } - - return (String) Props.props.remove(key); - } - - private static void checkKey(String key) { - if (key == null) { - throw new NullPointerException("key can't be null"); - } - if (key.equals("")) { - throw new IllegalArgumentException("key can't be empty"); - } - } - - /** - * Gets the value of the specified environment variable. An - * environment variable is a system-dependent external named - * value. - * - * <p>If a security manager exists, its - * {@link SecurityManager#checkPermission checkPermission} - * method is called with a - * <code>{@link RuntimePermission}("getenv."+name)</code> - * permission. This may result in a {@link SecurityException} - * being thrown. If no exception is thrown the value of the - * variable <code>name</code> is returned. - * - * <p><a name="EnvironmentVSSystemProperties"><i>System - * properties</i> and <i>environment variables</i></a> are both - * conceptually mappings between names and values. Both - * mechanisms can be used to pass user-defined information to a - * Java process. Environment variables have a more global effect, - * because they are visible to all descendants of the process - * which defines them, not just the immediate Java subprocess. - * They can have subtly different semantics, such as case - * insensitivity, on different operating systems. For these - * reasons, environment variables are more likely to have - * unintended side effects. It is best to use system properties - * where possible. Environment variables should be used when a - * global effect is desired, or when an external system interface - * requires an environment variable (such as <code>PATH</code>). - * - * <p>On UNIX systems the alphabetic case of <code>name</code> is - * typically significant, while on Microsoft Windows systems it is - * typically not. For example, the expression - * <code>System.getenv("FOO").equals(System.getenv("foo"))</code> - * is likely to be true on Microsoft Windows. - * - * @param name the name of the environment variable - * @return the string value of the variable, or <code>null</code> - * if the variable is not defined in the system environment - * @throws NullPointerException if <code>name</code> is <code>null</code> - * @throws SecurityException - * if a security manager exists and its - * {@link SecurityManager#checkPermission checkPermission} - * method doesn't allow access to the environment variable - * <code>name</code> - * @see #getenv() - * @see ProcessBuilder#environment() - */ - public static String getenv(String name) { - SecurityManager sm = getSecurityManager(); - if (sm != null) { - sm.checkPermission(new RuntimePermission("getenv."+name)); - } - - return ProcessEnvironment.getenv(name); - } - - - /** - * Returns an unmodifiable string map view of the current system environment. - * The environment is a system-dependent mapping from names to - * values which is passed from parent to child processes. - * - * <p>If the system does not support environment variables, an - * empty map is returned. - * - * <p>The returned map will never contain null keys or values. - * Attempting to query the presence of a null key or value will - * throw a {@link NullPointerException}. Attempting to query - * the presence of a key or value which is not of type - * {@link String} will throw a {@link ClassCastException}. - * - * <p>The returned map and its collection views may not obey the - * general contract of the {@link Object#equals} and - * {@link Object#hashCode} methods. - * - * <p>The returned map is typically case-sensitive on all platforms. - * - * <p>If a security manager exists, its - * {@link SecurityManager#checkPermission checkPermission} - * method is called with a - * <code>{@link RuntimePermission}("getenv.*")</code> - * permission. This may result in a {@link SecurityException} being - * thrown. - * - * <p>When passing information to a Java subprocess, - * <a href=#EnvironmentVSSystemProperties>system properties</a> - * are generally preferred over environment variables. - * - * @return the environment as a map of variable names to values - * @throws SecurityException - * if a security manager exists and its - * {@link SecurityManager#checkPermission checkPermission} - * method doesn't allow access to the process environment - * @see #getenv(String) - * @see ProcessBuilder#environment() - * @since 1.5 - */ - public static java.util.Map<String,String> getenv() { - SecurityManager sm = getSecurityManager(); - if (sm != null) { - sm.checkPermission(new RuntimePermission("getenv.*")); - } - - return ProcessEnvironment.getenv(); - } - - /** - * Terminates the currently running Java Virtual Machine. The - * argument serves as a status code; by convention, a nonzero status - * code indicates abnormal termination. - * <p> - * This method calls the <code>exit</code> method in class - * <code>Runtime</code>. This method never returns normally. - * <p> - * The call <code>System.exit(n)</code> is effectively equivalent to - * the call: - * <blockquote><pre> - * Runtime.getRuntime().exit(n) - * </pre></blockquote> - * - * @param status exit status. - * @throws SecurityException - * if a security manager exists and its <code>checkExit</code> - * method doesn't allow exit with the specified status. - * @see java.lang.Runtime#exit(int) - */ - public static void exit(int status) { - Runtime.getRuntime().exit(status); - } - - /** - * Runs the garbage collector. - * <p> - * Calling the <code>gc</code> method suggests that the Java Virtual - * Machine expend effort toward recycling unused objects in order to - * make the memory they currently occupy available for quick reuse. - * When control returns from the method call, the Java Virtual - * Machine has made a best effort to reclaim space from all discarded - * objects. - * <p> - * The call <code>System.gc()</code> is effectively equivalent to the - * call: - * <blockquote><pre> - * Runtime.getRuntime().gc() - * </pre></blockquote> - * - * @see java.lang.Runtime#gc() - */ - public static void gc() { - Runtime.getRuntime().gc(); - } - - /** - * Runs the finalization methods of any objects pending finalization. - * <p> - * Calling this method suggests that the Java Virtual Machine expend - * effort toward running the <code>finalize</code> methods of objects - * that have been found to be discarded but whose <code>finalize</code> - * methods have not yet been run. When control returns from the - * method call, the Java Virtual Machine has made a best effort to - * complete all outstanding finalizations. - * <p> - * The call <code>System.runFinalization()</code> is effectively - * equivalent to the call: - * <blockquote><pre> - * Runtime.getRuntime().runFinalization() - * </pre></blockquote> - * - * @see java.lang.Runtime#runFinalization() - */ - public static void runFinalization() { - Runtime.getRuntime().runFinalization(); - } - - /** - * Enable or disable finalization on exit; doing so specifies that the - * finalizers of all objects that have finalizers that have not yet been - * automatically invoked are to be run before the Java runtime exits. - * By default, finalization on exit is disabled. - * - * <p>If there is a security manager, - * its <code>checkExit</code> method is first called - * with 0 as its argument to ensure the exit is allowed. - * This could result in a SecurityException. - * - * @deprecated This method is inherently unsafe. It may result in - * finalizers being called on live objects while other threads are - * concurrently manipulating those objects, resulting in erratic - * behavior or deadlock. - * @param value indicating enabling or disabling of finalization - * @throws SecurityException - * if a security manager exists and its <code>checkExit</code> - * method doesn't allow the exit. - * - * @see java.lang.Runtime#exit(int) - * @see java.lang.Runtime#gc() - * @see java.lang.SecurityManager#checkExit(int) - * @since JDK1.1 - */ - @Deprecated - public static void runFinalizersOnExit(boolean value) { - Runtime.getRuntime().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. - * <p> - * The call <code>System.load(name)</code> is effectively equivalent - * to the call: - * <blockquote><pre> - * Runtime.getRuntime().load(name) - * </pre></blockquote> - * - * @param filename the file to load. - * @exception SecurityException if a security manager exists and its - * <code>checkLink</code> method doesn't allow - * loading of the specified dynamic library - * @exception UnsatisfiedLinkError if the file does not exist. - * @exception NullPointerException if <code>filename</code> is - * <code>null</code> - * @see java.lang.Runtime#load(java.lang.String) - * @see java.lang.SecurityManager#checkLink(java.lang.String) - */ - @CallerSensitive - public static void load(String filename) { - Runtime.getRuntime().load0(Reflection.getCallerClass(), filename); - } - - /** - * Loads the system library specified by the <code>libname</code> - * argument. The manner in which a library name is mapped to the - * actual system library is system dependent. - * <p> - * The call <code>System.loadLibrary(name)</code> is effectively - * equivalent to the call - * <blockquote><pre> - * Runtime.getRuntime().loadLibrary(name) - * </pre></blockquote> - * - * @param libname the name of the library. - * @exception SecurityException if a security manager exists and its - * <code>checkLink</code> method doesn't allow - * loading of the specified dynamic library - * @exception UnsatisfiedLinkError if the library does not exist. - * @exception NullPointerException if <code>libname</code> is - * <code>null</code> - * @see java.lang.Runtime#loadLibrary(java.lang.String) - * @see java.lang.SecurityManager#checkLink(java.lang.String) - */ - @CallerSensitive - public static void loadLibrary(String libname) { - Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname); - } - - /** - * Maps a library name into a platform-specific string representing - * a native library. - * - * @param libname the name of the library. - * @return a platform-dependent native library name. - * @exception NullPointerException if <code>libname</code> is - * <code>null</code> - * @see java.lang.System#loadLibrary(java.lang.String) - * @see java.lang.ClassLoader#findLibrary(java.lang.String) - * @since 1.2 - */ - public static String mapLibraryName(String libname) { - if (libname == null) { - throw new NullPointerException(); - } - 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); - } -} diff --git a/openjdk/java/lang/Thread.java b/openjdk/java/lang/Thread.java deleted file mode 100644 index 0ed60578..00000000 --- a/openjdk/java/lang/Thread.java +++ /dev/null @@ -1,2598 +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.lang; - -import java.lang.ref.Reference; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.WeakReference; -import java.security.AccessController; -import java.security.AccessControlContext; -import java.security.PrivilegedAction; -import java.util.Map; -import java.util.HashMap; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.locks.LockSupport; -import sun.nio.ch.Interruptible; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; -import sun.security.util.SecurityConstants; - - -/** - * A <i>thread</i> is a thread of execution in a program. The Java - * Virtual Machine allows an application to have multiple threads of - * execution running concurrently. - * <p> - * Every thread has a priority. Threads with higher priority are - * executed in preference to threads with lower priority. Each thread - * may or may not also be marked as a daemon. When code running in - * some thread creates a new <code>Thread</code> object, the new - * thread has its priority initially set equal to the priority of the - * creating thread, and is a daemon thread if and only if the - * creating thread is a daemon. - * <p> - * When a Java Virtual Machine starts up, there is usually a single - * non-daemon thread (which typically calls the method named - * <code>main</code> of some designated class). The Java Virtual - * Machine continues to execute threads until either of the following - * occurs: - * <ul> - * <li>The <code>exit</code> method of class <code>Runtime</code> has been - * called and the security manager has permitted the exit operation - * to take place. - * <li>All threads that are not daemon threads have died, either by - * returning from the call to the <code>run</code> method or by - * throwing an exception that propagates beyond the <code>run</code> - * method. - * </ul> - * <p> - * There are two ways to create a new thread of execution. One is to - * declare a class to be a subclass of <code>Thread</code>. This - * subclass should override the <code>run</code> method of class - * <code>Thread</code>. An instance of the subclass can then be - * allocated and started. For example, a thread that computes primes - * larger than a stated value could be written as follows: - * <hr><blockquote><pre> - * class PrimeThread extends Thread { - * long minPrime; - * PrimeThread(long minPrime) { - * this.minPrime = minPrime; - * } - * - * public void run() { - * // compute primes larger than minPrime - * . . . - * } - * } - * </pre></blockquote><hr> - * <p> - * The following code would then create a thread and start it running: - * <blockquote><pre> - * PrimeThread p = new PrimeThread(143); - * p.start(); - * </pre></blockquote> - * <p> - * The other way to create a thread is to declare a class that - * implements the <code>Runnable</code> interface. That class then - * implements the <code>run</code> method. An instance of the class can - * then be allocated, passed as an argument when creating - * <code>Thread</code>, and started. The same example in this other - * style looks like the following: - * <hr><blockquote><pre> - * class PrimeRun implements Runnable { - * long minPrime; - * PrimeRun(long minPrime) { - * this.minPrime = minPrime; - * } - * - * public void run() { - * // compute primes larger than minPrime - * . . . - * } - * } - * </pre></blockquote><hr> - * <p> - * The following code would then create a thread and start it running: - * <blockquote><pre> - * PrimeRun p = new PrimeRun(143); - * new Thread(p).start(); - * </pre></blockquote> - * <p> - * Every thread has a name for identification purposes. More than - * one thread may have the same name. If a name is not specified when - * a thread is created, a new name is generated for it. - * <p> - * Unless otherwise noted, passing a {@code null} argument to a constructor - * or method in this class will cause a {@link NullPointerException} to be - * thrown. - * - * @author unascribed - * @see Runnable - * @see Runtime#exit(int) - * @see #run() - * @see #stop() - * @since JDK1.0 - */ -public -class Thread implements Runnable { - // [IKVM] - static { - // force the set/getContextClassLoader methods to be JIT compiled, because isCCLOverridden(Thread) depends on it - // (we don't want to use RuntimeHelpers.PrepareMethod() because it requires full trust) - Thread dummy = new Thread((Void)null); - dummy.getContextClassLoader(); - dummy.setContextClassLoader(ClassLoader.DUMMY); - } - private Thread(Void _) { - // body replaced in map.xml - } - final class Cleanup { - private final Thread thread; - - Cleanup(Thread thread) { - this.thread = thread; - } - - protected void finalize() { - thread.die(); - } - } - /* --- start IKVM specific state --- */ - static final int[] nonDaemonCount = new int[1]; - @cli.System.ThreadStaticAttribute.Annotation - static Thread current; - @cli.System.ThreadStaticAttribute.Annotation - private static Cleanup cleanup; - private final Object lock = new Object(); - private cli.System.Threading.Thread nativeThread; - private Throwable stillborn; - private boolean running; // used only for coordination with stop0(), is never set to false - private volatile boolean interruptPending; - private volatile boolean nativeInterruptPending; - private volatile boolean interruptableWait; - private boolean timedWait; - volatile Object parkLock; // used by get/setParkLock in map.xml - int parkState; // used by cmpxchgParkState in map.xml - /* --- end IKVM specific state --- */ - - private volatile char name[]; - private int priority; - private Thread threadQ; - private long eetop; - - /* Whether or not to single_step this thread. */ - private boolean single_step; - - /* Whether or not the thread is a daemon thread. */ - private boolean daemon = false; - - /* What will be run. */ - private Runnable target; - - /* The group of this thread */ - private ThreadGroup group; - - /* The context ClassLoader for this thread */ - private volatile ClassLoader contextClassLoader; - - /* The inherited AccessControlContext of this thread */ - /* [IKVM] this contains either an AccessControlContext or an AccessController.LazyContext */ - Object inheritedAccessControlContext; - - /* For autonumbering anonymous threads. */ - private static int threadInitNumber; - private static synchronized int nextThreadNum() { - return threadInitNumber++; - } - - /* ThreadLocal values pertaining to this thread. This map is maintained - * by the ThreadLocal class. */ - ThreadLocal.ThreadLocalMap threadLocals = null; - - /* - * InheritableThreadLocal values pertaining to this thread. This map is - * maintained by the InheritableThreadLocal class. - */ - ThreadLocal.ThreadLocalMap inheritableThreadLocals = null; - - /* - * The requested stack size for this thread, or 0 if the creator did - * not specify a stack size. It is up to the VM to do whatever it - * likes with this number; some VMs will ignore it. - */ - private long stackSize; - - /* - * JVM-private state that persists after native thread termination. - */ - private long nativeParkEventPointer; - - /* - * Thread ID - */ - private long tid; - - /* For generating thread ID */ - private static long threadSeqNumber; - - /* Java thread status for tools, - * initialized to indicate thread 'not yet started' - */ - - private volatile int threadStatus = 0; - - - private static synchronized long nextThreadID() { - return ++threadSeqNumber; - } - - /** - * The argument supplied to the current call to - * java.util.concurrent.locks.LockSupport.park. - * Set by (private) java.util.concurrent.locks.LockSupport.setBlocker - * Accessed using java.util.concurrent.locks.LockSupport.getBlocker - */ - @ikvm.lang.Internal // [IKVM] accessed from java.util.concurrent - public volatile Object parkBlocker; - - /* The object in which this thread is blocked in an interruptible I/O - * operation, if any. The blocker's interrupt method should be invoked - * after setting this thread's interrupt status. - */ - private volatile Interruptible blocker; - private final Object blockerLock = new Object(); - - /* Set the blocker field; invoked via sun.misc.SharedSecrets from java.nio code - */ - void blockedOn(Interruptible b) { - synchronized (blockerLock) { - blocker = b; - } - } - - /** - * The minimum priority that a thread can have. - */ - public final static int MIN_PRIORITY = 1; - - /** - * The default priority that is assigned to a thread. - */ - public final static int NORM_PRIORITY = 5; - - /** - * The maximum priority that a thread can have. - */ - public final static int MAX_PRIORITY = 10; - - /** - * Returns a reference to the currently executing thread object. - * - * @return the currently executing thread. - */ - public static Thread currentThread() { - Thread c = current; - if (c == null) { - c = new Thread(getMainThreadGroup()); - } - return c; - } - - private static native ThreadGroup getMainThreadGroup(); - - /** - * A hint to the scheduler that the current thread is willing to yield - * its current use of a processor. The scheduler is free to ignore this - * hint. - * - * <p> Yield is a heuristic attempt to improve relative progression - * between threads that would otherwise over-utilise a CPU. Its use - * should be combined with detailed profiling and benchmarking to - * ensure that it actually has the desired effect. - * - * <p> It is rarely appropriate to use this method. It may be useful - * for debugging or testing purposes, where it may help to reproduce - * bugs due to race conditions. It may also be useful when designing - * concurrency control constructs such as the ones in the - * {@link java.util.concurrent.locks} package. - */ - public static void yield() { - cli.System.Threading.Thread.Sleep(0); - } - - private void enterInterruptableWait(boolean timedWait) throws InterruptedException { - synchronized (lock) { - if (interruptPending) { - interruptPending = false; - throw new InterruptedException(); - } - interruptableWait = true; - this.timedWait = timedWait; - } - } - - private void leaveInterruptableWait() throws InterruptedException { - cli.System.Threading.ThreadInterruptedException dotnetInterrupt = null; - interruptableWait = false; - for (; ; ) { - try { - if (false) throw new cli.System.Threading.ThreadInterruptedException(); - synchronized (lock) { - if (nativeInterruptPending) { - nativeInterruptPending = false; - // HACK if there is a pending Interrupt (on the .NET thread), we need to consume that - // (if there was no contention on "lock (this)" above the interrupted state isn't checked) - try { - if (false) throw new cli.System.Threading.ThreadInterruptedException(); - cli.System.Threading.Thread t = cli.System.Threading.Thread.get_CurrentThread(); - // the obvious thing to do would be t.Interrupt() / t.Join(), - // but for some reason that causes a regression in JSR166TestCase (probably a CLR bug) - // so we waste a time slice... sigh. - t.Join(1); - } - catch (cli.System.Threading.ThreadInterruptedException _) { - } - } - if (interruptPending) { - interruptPending = false; - throw new InterruptedException(); - } - } - break; - } - catch (cli.System.Threading.ThreadInterruptedException x) { - dotnetInterrupt = x; - nativeInterruptPending = false; - } - } - if (dotnetInterrupt != null) { - ikvm.runtime.Util.throwException(dotnetInterrupt); - } - } - - /** - * Causes the currently executing thread to sleep (temporarily cease - * execution) for the specified number of milliseconds, subject to - * the precision and accuracy of system timers and schedulers. The thread - * does not lose ownership of any monitors. - * - * @param millis - * the length of time to sleep in milliseconds - * - * @throws IllegalArgumentException - * if the value of {@code millis} is negative - * - * @throws InterruptedException - * if any thread has interrupted the current thread. The - * <i>interrupted status</i> of the current thread is - * cleared when this exception is thrown. - */ - public static void sleep(long millis) throws InterruptedException { - if (millis < 0) { - throw new IllegalArgumentException("timeout value is negative"); - } - Thread c = currentThread(); - c.enterInterruptableWait(true); - try { - if (false) throw new cli.System.Threading.ThreadInterruptedException(); - for (long iter = millis / Integer.MAX_VALUE; iter != 0; iter--) - { - cli.System.Threading.Thread.Sleep(Integer.MAX_VALUE); - } - cli.System.Threading.Thread.Sleep((int)(millis % Integer.MAX_VALUE)); - } - catch (cli.System.Threading.ThreadInterruptedException _) { - } - finally { - c.leaveInterruptableWait(); - } - } - - /** - * Causes the currently executing thread to sleep (temporarily cease - * execution) for the specified number of milliseconds plus the specified - * number of nanoseconds, subject to the precision and accuracy of system - * timers and schedulers. The thread does not lose ownership of any - * monitors. - * - * @param millis - * the length of time to sleep in milliseconds - * - * @param nanos - * {@code 0-999999} additional nanoseconds to sleep - * - * @throws IllegalArgumentException - * if the value of {@code millis} is negative, or the value of - * {@code nanos} is not in the range {@code 0-999999} - * - * @throws InterruptedException - * if any thread has interrupted the current thread. The - * <i>interrupted status</i> of the current thread is - * cleared when this exception is thrown. - */ - public static void sleep(long millis, int nanos) - throws InterruptedException { - if (millis < 0) { - throw new IllegalArgumentException("timeout value is negative"); - } - - if (nanos < 0 || nanos > 999999) { - throw new IllegalArgumentException( - "nanosecond timeout value out of range"); - } - - if (nanos >= 500000 || (nanos != 0 && millis == 0)) { - millis++; - } - - sleep(millis); - } - - /** - * Initializes a Thread with the current AccessControlContext. - * @see #init(ThreadGroup,Runnable,String,long,AccessControlContext) - */ - private void init(ThreadGroup g, Runnable target, String name, - long stackSize) { - init(g, target, name, stackSize, null); - } - - /** - * Initializes a Thread. - * - * @param g the Thread group - * @param target the object whose run() method gets called - * @param name the name of the new Thread - * @param stackSize the desired stack size for the new thread, or - * zero to indicate that this parameter is to be ignored. - * @param acc the AccessControlContext to inherit, or - * AccessController.getContext() if null - */ - private void init(ThreadGroup g, Runnable target, String name, - long stackSize, AccessControlContext acc) { - if (name == null) { - throw new NullPointerException("name cannot be null"); - } - - this.name = name.toCharArray(); - - Thread parent = currentThread(); - SecurityManager security = System.getSecurityManager(); - if (g == null) { - /* Determine if it's an applet or not */ - - /* If there is a security manager, ask the security manager - what to do. */ - if (security != null) { - g = security.getThreadGroup(); - } - - /* If the security doesn't have a strong opinion of the matter - use the parent thread group. */ - if (g == null) { - g = parent.getThreadGroup(); - } - } - - /* checkAccess regardless of whether or not threadgroup is - explicitly passed in. */ - g.checkAccess(); - - /* - * Do we have the required permissions? - */ - if (security != null) { - if (isCCLOverridden(this)) { - security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); - } - } - - g.addUnstarted(); - - this.group = g; - this.daemon = parent.isDaemon(); - this.priority = parent.getPriority(); - if (isCCLOverridden(parent)) - this.contextClassLoader = parent.getContextClassLoader(); - else - this.contextClassLoader = parent.contextClassLoader; - this.inheritedAccessControlContext = - acc != null ? acc : AccessController.getLazyContext(parent.inheritedAccessControlContext); - this.target = target; - setPriority(priority); - if (parent.inheritableThreadLocals != null) - this.inheritableThreadLocals = - ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); - /* Stash the specified stack size in case the VM cares */ - this.stackSize = stackSize; - - /* Set thread ID */ - tid = nextThreadID(); - } - - // [IKVM] constructor for attaching to a .NET thread - Thread(ThreadGroup g) { - this.running = true; - cli.System.Threading.Thread thread = cli.System.Threading.Thread.get_CurrentThread(); - nativeThread = thread; - String name = thread.get_Name(); - if (name == null) { - name = "Thread-" + nextThreadNum(); - } - - this.group = g; - this.daemon = thread.get_IsBackground(); - this.priority = mapClrPriorityToJava(thread.get_Priority().Value); - this.name = name.toCharArray(); - this.contextClassLoader = ClassLoader.DUMMY; - this.threadStatus = 0x0005; /* JVMTI_THREAD_STATE_ALIVE + JVMTI_THREAD_STATE_RUNNABLE */ - - /* Set thread ID */ - tid = nextThreadID(); - - synchronized (g) { - g.addUnstarted(); - g.add(this); - } - - current = this; - cleanup = new Cleanup(this); - - if (!daemon) { - cli.System.Threading.Interlocked.Increment(nonDaemonCount); - } - } - - private static int mapClrPriorityToJava(int priority) { - // TODO consider supporting -XX:JavaPriorityX_To_OSPriority settings - switch (priority) { - case cli.System.Threading.ThreadPriority.Lowest: - return MIN_PRIORITY; - case cli.System.Threading.ThreadPriority.BelowNormal: - return 3; - default: - case cli.System.Threading.ThreadPriority.Normal: - return NORM_PRIORITY; - case cli.System.Threading.ThreadPriority.AboveNormal: - return 7; - case cli.System.Threading.ThreadPriority.Highest: - return MAX_PRIORITY; - } - } - - private static int mapJavaPriorityToClr(int priority) { - // TODO consider supporting -XX:JavaPriorityX_To_OSPriority settings - if (priority == MIN_PRIORITY) { - return cli.System.Threading.ThreadPriority.Lowest; - } - else if (priority > Thread.MIN_PRIORITY && priority < Thread.NORM_PRIORITY) { - return cli.System.Threading.ThreadPriority.BelowNormal; - } - else if (priority == Thread.NORM_PRIORITY) { - return cli.System.Threading.ThreadPriority.Normal; - } - else if (priority > Thread.NORM_PRIORITY && priority < Thread.MAX_PRIORITY) { - return cli.System.Threading.ThreadPriority.AboveNormal; - } - else if (priority == Thread.MAX_PRIORITY) { - return cli.System.Threading.ThreadPriority.Highest; - } - else { - // can't happen - return cli.System.Threading.ThreadPriority.Normal; - } - } - - /** - * Throws CloneNotSupportedException as a Thread can not be meaningfully - * cloned. Construct a new Thread instead. - * - * @throws CloneNotSupportedException - * always - */ - @Override - protected Object clone() throws CloneNotSupportedException { - throw new CloneNotSupportedException(); - } - - /** - * Allocates a new {@code Thread} object. This constructor has the same - * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} - * {@code (null, null, gname)}, where {@code gname} is a newly generated - * name. Automatically generated names are of the form - * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer. - */ - public Thread() { - init(null, null, "Thread-" + nextThreadNum(), 0); - } - - /** - * Allocates a new {@code Thread} object. This constructor has the same - * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} - * {@code (null, target, gname)}, where {@code gname} is a newly generated - * name. Automatically generated names are of the form - * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer. - * - * @param target - * the object whose {@code run} method is invoked when this thread - * is started. If {@code null}, this classes {@code run} method does - * nothing. - */ - public Thread(Runnable target) { - init(null, target, "Thread-" + nextThreadNum(), 0); - } - - /** - * Creates a new Thread that inherits the given AccessControlContext. - * This is not a public constructor. - */ - Thread(Runnable target, AccessControlContext acc) { - init(null, target, "Thread-" + nextThreadNum(), 0, acc); - } - - /** - * Allocates a new {@code Thread} object. This constructor has the same - * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} - * {@code (group, target, gname)} ,where {@code gname} is a newly generated - * name. Automatically generated names are of the form - * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer. - * - * @param group - * the thread group. If {@code null} and there is a security - * manager, the group is determined by {@linkplain - * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}. - * If there is not a security manager or {@code - * SecurityManager.getThreadGroup()} returns {@code null}, the group - * is set to the current thread's thread group. - * - * @param target - * the object whose {@code run} method is invoked when this thread - * is started. If {@code null}, this thread's run method is invoked. - * - * @throws SecurityException - * if the current thread cannot create a thread in the specified - * thread group - */ - public Thread(ThreadGroup group, Runnable target) { - init(group, target, "Thread-" + nextThreadNum(), 0); - } - - /** - * Allocates a new {@code Thread} object. This constructor has the same - * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} - * {@code (null, null, name)}. - * - * @param name - * the name of the new thread - */ - public Thread(String name) { - init(null, null, name, 0); - } - - /** - * Allocates a new {@code Thread} object. This constructor has the same - * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} - * {@code (group, null, name)}. - * - * @param group - * the thread group. If {@code null} and there is a security - * manager, the group is determined by {@linkplain - * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}. - * If there is not a security manager or {@code - * SecurityManager.getThreadGroup()} returns {@code null}, the group - * is set to the current thread's thread group. - * - * @param name - * the name of the new thread - * - * @throws SecurityException - * if the current thread cannot create a thread in the specified - * thread group - */ - public Thread(ThreadGroup group, String name) { - init(group, null, name, 0); - } - - /** - * Allocates a new {@code Thread} object. This constructor has the same - * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} - * {@code (null, target, name)}. - * - * @param target - * the object whose {@code run} method is invoked when this thread - * is started. If {@code null}, this thread's run method is invoked. - * - * @param name - * the name of the new thread - */ - public Thread(Runnable target, String name) { - init(null, target, name, 0); - } - - /** - * Allocates a new {@code Thread} object so that it has {@code target} - * as its run object, has the specified {@code name} as its name, - * and belongs to the thread group referred to by {@code group}. - * - * <p>If there is a security manager, its - * {@link SecurityManager#checkAccess(ThreadGroup) checkAccess} - * method is invoked with the ThreadGroup as its argument. - * - * <p>In addition, its {@code checkPermission} method is invoked with - * the {@code RuntimePermission("enableContextClassLoaderOverride")} - * permission when invoked directly or indirectly by the constructor - * of a subclass which overrides the {@code getContextClassLoader} - * or {@code setContextClassLoader} methods. - * - * <p>The priority of the newly created thread is set equal to the - * priority of the thread creating it, that is, the currently running - * thread. The method {@linkplain #setPriority setPriority} may be - * used to change the priority to a new value. - * - * <p>The newly created thread is initially marked as being a daemon - * thread if and only if the thread creating it is currently marked - * as a daemon thread. The method {@linkplain #setDaemon setDaemon} - * may be used to change whether or not a thread is a daemon. - * - * @param group - * the thread group. If {@code null} and there is a security - * manager, the group is determined by {@linkplain - * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}. - * If there is not a security manager or {@code - * SecurityManager.getThreadGroup()} returns {@code null}, the group - * is set to the current thread's thread group. - * - * @param target - * the object whose {@code run} method is invoked when this thread - * is started. If {@code null}, this thread's run method is invoked. - * - * @param name - * the name of the new thread - * - * @throws SecurityException - * if the current thread cannot create a thread in the specified - * thread group or cannot override the context class loader methods. - */ - public Thread(ThreadGroup group, Runnable target, String name) { - init(group, target, name, 0); - } - - /** - * Allocates a new {@code Thread} object so that it has {@code target} - * as its run object, has the specified {@code name} as its name, - * and belongs to the thread group referred to by {@code group}, and has - * the specified <i>stack size</i>. - * - * <p>This constructor is identical to {@link - * #Thread(ThreadGroup,Runnable,String)} with the exception of the fact - * that it allows the thread stack size to be specified. The stack size - * is the approximate number of bytes of address space that the virtual - * machine is to allocate for this thread's stack. <b>The effect of the - * {@code stackSize} parameter, if any, is highly platform dependent.</b> - * - * <p>On some platforms, specifying a higher value for the - * {@code stackSize} parameter may allow a thread to achieve greater - * recursion depth before throwing a {@link StackOverflowError}. - * Similarly, specifying a lower value may allow a greater number of - * threads to exist concurrently without throwing an {@link - * OutOfMemoryError} (or other internal error). The details of - * the relationship between the value of the <tt>stackSize</tt> parameter - * and the maximum recursion depth and concurrency level are - * platform-dependent. <b>On some platforms, the value of the - * {@code stackSize} parameter may have no effect whatsoever.</b> - * - * <p>The virtual machine is free to treat the {@code stackSize} - * parameter as a suggestion. If the specified value is unreasonably low - * for the platform, the virtual machine may instead use some - * platform-specific minimum value; if the specified value is unreasonably - * high, the virtual machine may instead use some platform-specific - * maximum. Likewise, the virtual machine is free to round the specified - * value up or down as it sees fit (or to ignore it completely). - * - * <p>Specifying a value of zero for the {@code stackSize} parameter will - * cause this constructor to behave exactly like the - * {@code Thread(ThreadGroup, Runnable, String)} constructor. - * - * <p><i>Due to the platform-dependent nature of the behavior of this - * constructor, extreme care should be exercised in its use. - * The thread stack size necessary to perform a given computation will - * likely vary from one JRE implementation to another. In light of this - * variation, careful tuning of the stack size parameter may be required, - * and the tuning may need to be repeated for each JRE implementation on - * which an application is to run.</i> - * - * <p>Implementation note: Java platform implementers are encouraged to - * document their implementation's behavior with respect to the - * {@code stackSize} parameter. - * - * - * @param group - * the thread group. If {@code null} and there is a security - * manager, the group is determined by {@linkplain - * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}. - * If there is not a security manager or {@code - * SecurityManager.getThreadGroup()} returns {@code null}, the group - * is set to the current thread's thread group. - * - * @param target - * the object whose {@code run} method is invoked when this thread - * is started. If {@code null}, this thread's run method is invoked. - * - * @param name - * the name of the new thread - * - * @param stackSize - * the desired stack size for the new thread, or zero to indicate - * that this parameter is to be ignored. - * - * @throws SecurityException - * if the current thread cannot create a thread in the specified - * thread group - * - * @since 1.4 - */ - public Thread(ThreadGroup group, Runnable target, String name, - long stackSize) { - init(group, target, name, stackSize); - } - - /** - * Causes this thread to begin execution; the Java Virtual Machine - * calls the <code>run</code> method of this thread. - * <p> - * The result is that two threads are running concurrently: the - * current thread (which returns from the call to the - * <code>start</code> method) and the other thread (which executes its - * <code>run</code> method). - * <p> - * It is never legal to start a thread more than once. - * In particular, a thread may not be restarted once it has completed - * execution. - * - * @exception IllegalThreadStateException if the thread was already - * started. - * @see #run() - * @see #stop() - */ - public synchronized void start() { - /** - * This method is not invoked for the main method thread or "system" - * group threads created/set up by the VM. Any new functionality added - * to this method in the future may have to also be added to the VM. - * - * A zero status value corresponds to state "NEW". - */ - if (threadStatus != 0) - throw new IllegalThreadStateException(); - - /* Notify the group that this thread is about to be started - * so that it can be added to the group's list of threads - * and the group's unstarted count can be decremented. */ - group.add(this); - - boolean started = false; - try { - start0(); - started = true; - } finally { - try { - if (!started) { - group.threadStartFailed(this); - } - } catch (Throwable ignore) { - /* do nothing. If start0 threw a Throwable then - it will be passed up the call stack */ - } - } - } - - private void start0() { - cli.System.Threading.ThreadStart threadStart = new cli.System.Threading.ThreadStart(new cli.System.Threading.ThreadStart.Method() { - @cli.IKVM.Attributes.HideFromJavaAttribute.Annotation - public void Invoke() { - threadProc(); - } - }); - if (stackSize <= 0) { - nativeThread = new cli.System.Threading.Thread(threadStart); - } - else { - int maxStackSize = (int)Math.min(Math.max(128 * 1024, stackSize), Integer.MAX_VALUE); - nativeThread = new cli.System.Threading.Thread(threadStart, maxStackSize); - } - nativeThread.set_Name(getName()); - nativeThread.set_IsBackground(daemon); - nativeThread.set_Priority(cli.System.Threading.ThreadPriority.wrap(mapJavaPriorityToClr(priority))); - String apartment = Props.props.getProperty("ikvm.apartmentstate", "").toLowerCase(); - if ("mta".equals(apartment)) { - nativeThread.SetApartmentState(cli.System.Threading.ApartmentState.wrap(cli.System.Threading.ApartmentState.MTA)); - } - else if ("sta".equals(apartment)) { - nativeThread.SetApartmentState(cli.System.Threading.ApartmentState.wrap(cli.System.Threading.ApartmentState.STA)); - } - threadStatus = 0x0005; // JVMTI_THREAD_STATE_ALIVE + JVMTI_THREAD_STATE_RUNNABLE - nativeThread.Start(); - if (!daemon) { - cli.System.Threading.Interlocked.Increment(nonDaemonCount); - } - } - - /** - * If this thread was constructed using a separate - * <code>Runnable</code> run object, then that - * <code>Runnable</code> object's <code>run</code> method is called; - * otherwise, this method does nothing and returns. - * <p> - * Subclasses of <code>Thread</code> should override this method. - * - * @see #start() - * @see #stop() - * @see #Thread(ThreadGroup, Runnable, String) - */ - @Override - public void run() { - if (target != null) { - target.run(); - } - } - - // [IKVM] for threads started from Java, this method is called on the thread itself, - // but for .NET threads it will be called by the finalizer of the Cleanup object. - // NOTE there might be a race condition here (when the thread's Cleanup object - // is finalized during AppDomain shutdown while the thread is also exiting on its own), - // but that doesn't matter because Thread.exit() is safe to call multiple times. - void die() { - exit(); - synchronized (lock) { - nativeThread = null; - threadStatus = 0x0002; // JVMTI_THREAD_STATE_TERMINATED - } - wakeupJoinedThreads(); - if (!daemon) { - // TODO there is a race condition in the non-daemon counting - // (setDaemon() isn't synchronized so it may clear/set the daemon flag without the count being affected) - cli.System.Threading.Interlocked.Decrement(nonDaemonCount); - } - if (current == this) { - current = null; - // check if we have a cleanup object, this happens if we attach and subsequently detach from JNI code - if (cleanup != null) { - cli.System.GC.SuppressFinalize(cleanup); - cleanup = null; - } - } - } - - private void wakeupJoinedThreads() { - // HACK locking this here isn't ideal, because we might be invoked from - // the Cleanup object's finalizer and some user code might own the lock and hence - // block the finalizer thread. - // A second scenario is that another thread is currently blocking inside stop() - // (the Thread.Abort() call will block while we are running the finally block) - // and that thread will own the lock on our thread object. - boolean locked = false; - try { - locked = cli.System.Threading.Monitor.TryEnter(this); - if (locked) { - notifyAll(); - } else { - // HACK schedule an asynchronous notification - cli.System.Threading.ThreadPool.QueueUserWorkItem( - new cli.System.Threading.WaitCallback( - new cli.System.Threading.WaitCallback.Method() { - public void Invoke(Object thread) { - synchronized (thread) { - thread.notifyAll(); - } - } - }), this); - } - } - finally { - if (locked) - cli.System.Threading.Monitor.Exit(this); - } - } - - /** - * This method is called by the system to give a Thread - * a chance to clean up before it actually exits. - */ - private void exit() { - if (group != null) { - group.threadTerminated(this); - group = null; - } - /* Aggressively null out all reference fields: see bug 4006245 */ - target = null; - /* Speed the release of some of these resources */ - threadLocals = null; - inheritableThreadLocals = null; - inheritedAccessControlContext = null; - blocker = null; - uncaughtExceptionHandler = null; - } - - /** - * Forces the thread to stop executing. - * <p> - * If there is a security manager installed, its <code>checkAccess</code> - * method is called with <code>this</code> - * as its argument. This may result in a - * <code>SecurityException</code> being raised (in the current thread). - * <p> - * If this thread is different from the current thread (that is, the current - * thread is trying to stop a thread other than itself), the - * security manager's <code>checkPermission</code> method (with a - * <code>RuntimePermission("stopThread")</code> argument) is called in - * addition. - * Again, this may result in throwing a - * <code>SecurityException</code> (in the current thread). - * <p> - * The thread represented by this thread is forced to stop whatever - * it is doing abnormally and to throw a newly created - * <code>ThreadDeath</code> object as an exception. - * <p> - * It is permitted to stop a thread that has not yet been started. - * If the thread is eventually started, it immediately terminates. - * <p> - * An application should not normally try to catch - * <code>ThreadDeath</code> unless it must do some extraordinary - * cleanup operation (note that the throwing of - * <code>ThreadDeath</code> causes <code>finally</code> clauses of - * <code>try</code> statements to be executed before the thread - * officially dies). If a <code>catch</code> clause catches a - * <code>ThreadDeath</code> object, it is important to rethrow the - * object so that the thread actually dies. - * <p> - * The top-level error handler that reacts to otherwise uncaught - * exceptions does not print out a message or otherwise notify the - * application if the uncaught exception is an instance of - * <code>ThreadDeath</code>. - * - * @exception SecurityException if the current thread cannot - * modify this thread. - * @see #interrupt() - * @see #checkAccess() - * @see #run() - * @see #start() - * @see ThreadDeath - * @see ThreadGroup#uncaughtException(Thread,Throwable) - * @see SecurityManager#checkAccess(Thread) - * @see SecurityManager#checkPermission - * @deprecated This method is inherently unsafe. Stopping a thread with - * Thread.stop causes it to unlock all of the monitors that it - * has locked (as a natural consequence of the unchecked - * <code>ThreadDeath</code> exception propagating up the stack). If - * any of the objects previously protected by these monitors were in - * an inconsistent state, the damaged objects become visible to - * other threads, potentially resulting in arbitrary behavior. Many - * uses of <code>stop</code> should be replaced by code that simply - * modifies some variable to indicate that the target thread should - * stop running. The target thread should check this variable - * regularly, and return from its run method in an orderly fashion - * if the variable indicates that it is to stop running. If the - * target thread waits for long periods (on a condition variable, - * for example), the <code>interrupt</code> method should be used to - * interrupt the wait. - * For more information, see - * <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why - * are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>. - */ - @Deprecated - public final void stop() { - SecurityManager security = System.getSecurityManager(); - if (security != null) { - checkAccess(); - if (this != Thread.currentThread()) { - security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION); - } - } - // A zero status value corresponds to "NEW", it can't change to - // not-NEW because we hold the lock. - if (threadStatus != 0) { - resume(); // Wake up thread if it was suspended; no-op otherwise - } - - // The VM can handle all thread states - stop0(new ThreadDeath()); - } - - /** - * Throws {@code UnsupportedOperationException}. - * - * @param obj ignored - * - * @deprecated This method was originally designed to force a thread to stop - * and throw a given {@code Throwable} as an exception. It was - * inherently unsafe (see {@link #stop()} for details), and furthermore - * could be used to generate exceptions that the target thread was - * not prepared to handle. - * For more information, see - * <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why - * are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>. - */ - @Deprecated - public final synchronized void stop(Throwable obj) { - throw new UnsupportedOperationException(); - } - - /** - * Interrupts this thread. - * - * <p> Unless the current thread is interrupting itself, which is - * always permitted, the {@link #checkAccess() checkAccess} method - * of this thread is invoked, which may cause a {@link - * SecurityException} to be thrown. - * - * <p> If this thread is blocked in an invocation of the {@link - * Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link - * Object#wait(long, int) wait(long, int)} methods of the {@link Object} - * class, or of the {@link #join()}, {@link #join(long)}, {@link - * #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)}, - * methods of this class, then its interrupt status will be cleared and it - * will receive an {@link InterruptedException}. - * - * <p> If this thread is blocked in an I/O operation upon an {@link - * java.nio.channels.InterruptibleChannel InterruptibleChannel} - * then the channel will be closed, the thread's interrupt - * status will be set, and the thread will receive a {@link - * java.nio.channels.ClosedByInterruptException}. - * - * <p> If this thread is blocked in a {@link java.nio.channels.Selector} - * then the thread's interrupt status will be set and it will return - * immediately from the selection operation, possibly with a non-zero - * value, just as if the selector's {@link - * java.nio.channels.Selector#wakeup wakeup} method were invoked. - * - * <p> If none of the previous conditions hold then this thread's interrupt - * status will be set. </p> - * - * <p> Interrupting a thread that is not alive need not have any effect. - * - * @throws SecurityException - * if the current thread cannot modify this thread - * - * @revised 6.0 - * @spec JSR-51 - */ - public void interrupt() { - if (this != Thread.currentThread()) - checkAccess(); - - synchronized (blockerLock) { - Interruptible b = blocker; - if (b != null) { - interrupt0(); // Just to set the interrupt flag - b.interrupt(this); - return; - } - } - interrupt0(); - } - - /** - * Tests whether the current thread has been interrupted. The - * <i>interrupted status</i> of the thread is cleared by this method. In - * other words, if this method were to be called twice in succession, the - * second call would return false (unless the current thread were - * interrupted again, after the first call had cleared its interrupted - * status and before the second call had examined it). - * - * <p>A thread interruption ignored because a thread was not alive - * at the time of the interrupt will be reflected by this method - * returning false. - * - * @return <code>true</code> if the current thread has been interrupted; - * <code>false</code> otherwise. - * @see #isInterrupted() - * @revised 6.0 - */ - public static boolean interrupted() { - Thread current = currentThread(); - if (!current.interruptPending) { - return false; - } - current.interruptPending = false; - return true; - } - - /** - * Tests whether this thread has been interrupted. The <i>interrupted - * status</i> of the thread is unaffected by this method. - * - * <p>A thread interruption ignored because a thread was not alive - * at the time of the interrupt will be reflected by this method - * returning false. - * - * @return <code>true</code> if this thread has been interrupted; - * <code>false</code> otherwise. - * @see #interrupted() - * @revised 6.0 - */ - public boolean isInterrupted() { - return interruptPending; - } - - /** - * Throws {@link NoSuchMethodError}. - * - * @deprecated This method was originally designed to destroy this - * thread without any cleanup. Any monitors it held would have - * remained locked. However, the method was never implemented. - * If if were to be implemented, it would be deadlock-prone in - * much the manner of {@link #suspend}. If the target thread held - * a lock protecting a critical system resource when it was - * destroyed, no thread could ever access this resource again. - * If another thread ever attempted to lock this resource, deadlock - * would result. Such deadlocks typically manifest themselves as - * "frozen" processes. For more information, see - * <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html"> - * Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>. - * @throws NoSuchMethodError always - */ - @Deprecated - public void destroy() { - throw new NoSuchMethodError(); - } - - /** - * Tests if this thread is alive. A thread is alive if it has - * been started and has not yet died. - * - * @return <code>true</code> if this thread is alive; - * <code>false</code> otherwise. - */ - public final boolean isAlive() { - return (threadStatus & 0x0001) != 0; - } - - /** - * Suspends this thread. - * <p> - * First, the <code>checkAccess</code> method of this thread is called - * with no arguments. This may result in throwing a - * <code>SecurityException </code>(in the current thread). - * <p> - * If the thread is alive, it is suspended and makes no further - * progress unless and until it is resumed. - * - * @exception SecurityException if the current thread cannot modify - * this thread. - * @see #checkAccess - * @deprecated This method has been deprecated, as it is - * inherently deadlock-prone. If the target thread holds a lock on the - * monitor protecting a critical system resource when it is suspended, no - * thread can access this resource until the target thread is resumed. If - * the thread that would resume the target thread attempts to lock this - * monitor prior to calling <code>resume</code>, deadlock results. Such - * deadlocks typically manifest themselves as "frozen" processes. - * For more information, see - * <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why - * are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>. - */ - @Deprecated - public final void suspend() { - checkAccess(); - suspend0(); - } - - /** - * Resumes a suspended thread. - * <p> - * First, the <code>checkAccess</code> method of this thread is called - * with no arguments. This may result in throwing a - * <code>SecurityException</code> (in the current thread). - * <p> - * If the thread is alive but suspended, it is resumed and is - * permitted to make progress in its execution. - * - * @exception SecurityException if the current thread cannot modify this - * thread. - * @see #checkAccess - * @see #suspend() - * @deprecated This method exists solely for use with {@link #suspend}, - * which has been deprecated because it is deadlock-prone. - * For more information, see - * <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why - * are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>. - */ - @Deprecated - public final void resume() { - checkAccess(); - resume0(); - } - - /** - * Changes the priority of this thread. - * <p> - * First the <code>checkAccess</code> method of this thread is called - * with no arguments. This may result in throwing a - * <code>SecurityException</code>. - * <p> - * Otherwise, the priority of this thread is set to the smaller of - * the specified <code>newPriority</code> and the maximum permitted - * priority of the thread's thread group. - * - * @param newPriority priority to set this thread to - * @exception IllegalArgumentException If the priority is not in the - * range <code>MIN_PRIORITY</code> to - * <code>MAX_PRIORITY</code>. - * @exception SecurityException if the current thread cannot modify - * this thread. - * @see #getPriority - * @see #checkAccess() - * @see #getThreadGroup() - * @see #MAX_PRIORITY - * @see #MIN_PRIORITY - * @see ThreadGroup#getMaxPriority() - */ - public final void setPriority(int newPriority) { - ThreadGroup g; - checkAccess(); - if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) { - throw new IllegalArgumentException(); - } - if((g = getThreadGroup()) != null) { - if (newPriority > g.getMaxPriority()) { - newPriority = g.getMaxPriority(); - } - setPriority0(priority = newPriority); - } - } - - /** - * Returns this thread's priority. - * - * @return this thread's priority. - * @see #setPriority - */ - public final int getPriority() { - return priority; - } - - /** - * Changes the name of this thread to be equal to the argument - * <code>name</code>. - * <p> - * First the <code>checkAccess</code> method of this thread is called - * with no arguments. This may result in throwing a - * <code>SecurityException</code>. - * - * @param name the new name for this thread. - * @exception SecurityException if the current thread cannot modify this - * thread. - * @see #getName - * @see #checkAccess() - */ - public final synchronized void setName(String name) { - checkAccess(); - this.name = name.toCharArray(); - if (threadStatus != 0) { - setNativeName(name); - } - } - - /** - * Returns this thread's name. - * - * @return this thread's name. - * @see #setName(String) - */ - public final String getName() { - return String.valueOf(name); - } - - /** - * Returns the thread group to which this thread belongs. - * This method returns null if this thread has died - * (been stopped). - * - * @return this thread's thread group. - */ - public final ThreadGroup getThreadGroup() { - return group; - } - - /** - * Returns an estimate of the number of active threads in the current - * thread's {@linkplain java.lang.ThreadGroup thread group} and its - * subgroups. Recursively iterates over all subgroups in the current - * thread's thread group. - * - * <p> The value returned is only an estimate because the number of - * threads may change dynamically while this method traverses internal - * data structures, and might be affected by the presence of certain - * system threads. This method is intended primarily for debugging - * and monitoring purposes. - * - * @return an estimate of the number of active threads in the current - * thread's thread group and in any other thread group that - * has the current thread's thread group as an ancestor - */ - public static int activeCount() { - return currentThread().getThreadGroup().activeCount(); - } - - /** - * Copies into the specified array every active thread in the current - * thread's thread group and its subgroups. This method simply - * invokes the {@link java.lang.ThreadGroup#enumerate(Thread[])} - * method of the current thread's thread group. - * - * <p> An application might use the {@linkplain #activeCount activeCount} - * method to get an estimate of how big the array should be, however - * <i>if the array is too short to hold all the threads, the extra threads - * are silently ignored.</i> If it is critical to obtain every active - * thread in the current thread's thread group and its subgroups, the - * invoker should verify that the returned int value is strictly less - * than the length of {@code tarray}. - * - * <p> Due to the inherent race condition in this method, it is recommended - * that the method only be used for debugging and monitoring purposes. - * - * @param tarray - * an array into which to put the list of threads - * - * @return the number of threads put into the array - * - * @throws SecurityException - * if {@link java.lang.ThreadGroup#checkAccess} determines that - * the current thread cannot access its thread group - */ - public static int enumerate(Thread tarray[]) { - return currentThread().getThreadGroup().enumerate(tarray); - } - - /** - * Counts the number of stack frames in this thread. The thread must - * be suspended. - * - * @return the number of stack frames in this thread. - * @exception IllegalThreadStateException if this thread is not - * suspended. - * @deprecated The definition of this call depends on {@link #suspend}, - * which is deprecated. Further, the results of this call - * were never well-defined. - */ - @Deprecated - public int countStackFrames() { - return 0; - } - - /** - * Waits at most {@code millis} milliseconds for this thread to - * die. A timeout of {@code 0} means to wait forever. - * - * <p> This implementation uses a loop of {@code this.wait} calls - * conditioned on {@code this.isAlive}. As a thread terminates the - * {@code this.notifyAll} method is invoked. It is recommended that - * applications not use {@code wait}, {@code notify}, or - * {@code notifyAll} on {@code Thread} instances. - * - * @param millis - * the time to wait in milliseconds - * - * @throws IllegalArgumentException - * if the value of {@code millis} is negative - * - * @throws InterruptedException - * if any thread has interrupted the current thread. The - * <i>interrupted status</i> of the current thread is - * cleared when this exception is thrown. - */ - public final synchronized void join(long millis) - throws InterruptedException { - long base = System.currentTimeMillis(); - long now = 0; - - if (millis < 0) { - throw new IllegalArgumentException("timeout value is negative"); - } - - if (millis == 0) { - while (isAlive()) { - wait(0); - } - } else { - while (isAlive()) { - long delay = millis - now; - if (delay <= 0) { - break; - } - wait(delay); - now = System.currentTimeMillis() - base; - } - } - } - - /** - * Waits at most {@code millis} milliseconds plus - * {@code nanos} nanoseconds for this thread to die. - * - * <p> This implementation uses a loop of {@code this.wait} calls - * conditioned on {@code this.isAlive}. As a thread terminates the - * {@code this.notifyAll} method is invoked. It is recommended that - * applications not use {@code wait}, {@code notify}, or - * {@code notifyAll} on {@code Thread} instances. - * - * @param millis - * the time to wait in milliseconds - * - * @param nanos - * {@code 0-999999} additional nanoseconds to wait - * - * @throws IllegalArgumentException - * if the value of {@code millis} is negative, or the value - * of {@code nanos} is not in the range {@code 0-999999} - * - * @throws InterruptedException - * if any thread has interrupted the current thread. The - * <i>interrupted status</i> of the current thread is - * cleared when this exception is thrown. - */ - public final synchronized void join(long millis, int nanos) - throws InterruptedException { - - if (millis < 0) { - throw new IllegalArgumentException("timeout value is negative"); - } - - if (nanos < 0 || nanos > 999999) { - throw new IllegalArgumentException( - "nanosecond timeout value out of range"); - } - - if (nanos >= 500000 || (nanos != 0 && millis == 0)) { - millis++; - } - - join(millis); - } - - /** - * Waits for this thread to die. - * - * <p> An invocation of this method behaves in exactly the same - * way as the invocation - * - * <blockquote> - * {@linkplain #join(long) join}{@code (0)} - * </blockquote> - * - * @throws InterruptedException - * if any thread has interrupted the current thread. The - * <i>interrupted status</i> of the current thread is - * cleared when this exception is thrown. - */ - public final void join() throws InterruptedException { - join(0); - } - - /** - * Prints a stack trace of the current thread to the standard error stream. - * This method is used only for debugging. - * - * @see Throwable#printStackTrace() - */ - public static void dumpStack() { - new Exception("Stack trace").printStackTrace(); - } - - /** - * Marks this thread as either a {@linkplain #isDaemon daemon} thread - * or a user thread. The Java Virtual Machine exits when the only - * threads running are all daemon threads. - * - * <p> This method must be invoked before the thread is started. - * - * @param on - * if {@code true}, marks this thread as a daemon thread - * - * @throws IllegalThreadStateException - * if this thread is {@linkplain #isAlive alive} - * - * @throws SecurityException - * if {@link #checkAccess} determines that the current - * thread cannot modify this thread - */ - public final void setDaemon(boolean on) { - checkAccess(); - if (isAlive()) { - throw new IllegalThreadStateException(); - } - daemon = on; - } - - /** - * Tests if this thread is a daemon thread. - * - * @return <code>true</code> if this thread is a daemon thread; - * <code>false</code> otherwise. - * @see #setDaemon(boolean) - */ - public final boolean isDaemon() { - return daemon; - } - - /** - * Determines if the currently running thread has permission to - * modify this thread. - * <p> - * If there is a security manager, its <code>checkAccess</code> method - * is called with this thread as its argument. This may result in - * throwing a <code>SecurityException</code>. - * - * @exception SecurityException if the current thread is not allowed to - * access this thread. - * @see SecurityManager#checkAccess(Thread) - */ - public final void checkAccess() { - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkAccess(this); - } - } - - /** - * Returns a string representation of this thread, including the - * thread's name, priority, and thread group. - * - * @return a string representation of this thread. - */ - public String toString() { - ThreadGroup group = getThreadGroup(); - if (group != null) { - return "Thread[" + getName() + "," + getPriority() + "," + - group.getName() + "]"; - } else { - return "Thread[" + getName() + "," + getPriority() + "," + - "" + "]"; - } - } - - /** - * Returns the context ClassLoader for this Thread. The context - * ClassLoader is provided by the creator of the thread for use - * by code running in this thread when loading classes and resources. - * If not {@linkplain #setContextClassLoader set}, the default is the - * ClassLoader context of the parent Thread. The context ClassLoader of the - * primordial thread is typically set to the class loader used to load the - * application. - * - * <p>If a security manager is present, and the invoker's class loader is not - * {@code null} and is not the same as or an ancestor of the context class - * loader, then this method invokes the security manager's {@link - * SecurityManager#checkPermission(java.security.Permission) checkPermission} - * method with a {@link RuntimePermission RuntimePermission}{@code - * ("getClassLoader")} permission to verify that retrieval of the context - * class loader is permitted. - * - * @return the context ClassLoader for this Thread, or {@code null} - * indicating the system class loader (or, failing that, the - * bootstrap class loader) - * - * @throws SecurityException - * if the current thread cannot get the context ClassLoader - * - * @since 1.2 - */ - @CallerSensitive - public ClassLoader getContextClassLoader() { - if (contextClassLoader == ClassLoader.DUMMY) { - contextClassLoader = ClassLoader.getSystemClassLoader(); - } - if (contextClassLoader == null) - return null; - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - ClassLoader.checkClassLoaderPermission(contextClassLoader, - Reflection.getCallerClass()); - } - return contextClassLoader; - } - - /** - * Sets the context ClassLoader for this Thread. The context - * ClassLoader can be set when a thread is created, and allows - * the creator of the thread to provide the appropriate class loader, - * through {@code getContextClassLoader}, to code running in the thread - * when loading classes and resources. - * - * <p>If a security manager is present, its {@link - * SecurityManager#checkPermission(java.security.Permission) checkPermission} - * method is invoked with a {@link RuntimePermission RuntimePermission}{@code - * ("setContextClassLoader")} permission to see if setting the context - * ClassLoader is permitted. - * - * @param cl - * the context ClassLoader for this Thread, or null indicating the - * system class loader (or, failing that, the bootstrap class loader) - * - * @throws SecurityException - * if the current thread cannot set the context ClassLoader - * - * @since 1.2 - */ - public void setContextClassLoader(ClassLoader cl) { - if (cl == ClassLoader.DUMMY) { - // we're being called by Thread.<clinit> to force this method to be JIT compiled - return; - } - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new RuntimePermission("setContextClassLoader")); - } - contextClassLoader = cl; - } - - // [IKVM] called by sun.misc.Launcher (via map.xml patch) to initialize the context class loader - final void initContextClassLoader(ClassLoader cl) { - // we only set contextClassLoader if it hasn't been set (by user code) previously - java.util.concurrent.atomic.AtomicReferenceFieldUpdater - .newUpdater(Thread.class, ClassLoader.class, "contextClassLoader") - .compareAndSet(this, ClassLoader.DUMMY, cl); - } - - /** - * Returns <tt>true</tt> if and only if the current thread holds the - * monitor lock on the specified object. - * - * <p>This method is designed to allow a program to assert that - * the current thread already holds a specified lock: - * <pre> - * assert Thread.holdsLock(obj); - * </pre> - * - * @param obj the object on which to test lock ownership - * @throws NullPointerException if obj is <tt>null</tt> - * @return <tt>true</tt> if the current thread holds the monitor lock on - * the specified object. - * @since 1.4 - */ - public static boolean holdsLock(Object obj) { - if (obj == null) { - throw new NullPointerException(); - } - try { - if (false) throw new cli.System.Threading.SynchronizationLockException(); - // The 1.5 memory model (JSR133) explicitly allows spurious wake-ups from Object.wait, - // so we abuse Pulse to check if we own the monitor. - cli.System.Threading.Monitor.Pulse(obj); - return true; - } - catch (cli.System.Threading.SynchronizationLockException _) { - return false; - } - } - - private static final StackTraceElement[] EMPTY_STACK_TRACE - = new StackTraceElement[0]; - - /** - * Returns an array of stack trace elements representing the stack dump - * of this thread. This method will return a zero-length array if - * this thread has not started, has started but has not yet been - * scheduled to run by the system, or has terminated. - * If the returned array is of non-zero length then the first element of - * the array represents the top of the stack, which is the most recent - * method invocation in the sequence. The last element of the array - * represents the bottom of the stack, which is the least recent method - * invocation in the sequence. - * - * <p>If there is a security manager, and this thread is not - * the current thread, then the security manager's - * <tt>checkPermission</tt> method is called with a - * <tt>RuntimePermission("getStackTrace")</tt> permission - * to see if it's ok to get the stack trace. - * - * <p>Some virtual machines may, under some circumstances, omit one - * or more stack frames from the stack trace. In the extreme case, - * a virtual machine that has no stack trace information concerning - * this thread is permitted to return a zero-length array from this - * method. - * - * @return an array of <tt>StackTraceElement</tt>, - * each represents one stack frame. - * - * @throws SecurityException - * if a security manager exists and its - * <tt>checkPermission</tt> method doesn't allow - * getting the stack trace of thread. - * @see SecurityManager#checkPermission - * @see RuntimePermission - * @see Throwable#getStackTrace - * - * @since 1.5 - */ - public StackTraceElement[] getStackTrace() { - if (this != Thread.currentThread()) { - // check for getStackTrace permission - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkPermission( - SecurityConstants.GET_STACK_TRACE_PERMISSION); - } - // optimization so we do not call into the vm for threads that - // have not yet started or have terminated - if (!isAlive()) { - return EMPTY_STACK_TRACE; - } - StackTraceElement[][] stackTraceArray = dumpThreads(new Thread[] {this}); - StackTraceElement[] stackTrace = stackTraceArray[0]; - // a thread that was alive during the previous isAlive call may have - // since terminated, therefore not having a stacktrace. - if (stackTrace == null) { - stackTrace = EMPTY_STACK_TRACE; - } - return stackTrace; - } else { - // Don't need JVM help for current thread - return (new Exception()).getStackTrace(); - } - } - - /** - * Returns a map of stack traces for all live threads. - * The map keys are threads and each map value is an array of - * <tt>StackTraceElement</tt> that represents the stack dump - * of the corresponding <tt>Thread</tt>. - * The returned stack traces are in the format specified for - * the {@link #getStackTrace getStackTrace} method. - * - * <p>The threads may be executing while this method is called. - * The stack trace of each thread only represents a snapshot and - * each stack trace may be obtained at different time. A zero-length - * array will be returned in the map value if the virtual machine has - * no stack trace information about a thread. - * - * <p>If there is a security manager, then the security manager's - * <tt>checkPermission</tt> method is called with a - * <tt>RuntimePermission("getStackTrace")</tt> permission as well as - * <tt>RuntimePermission("modifyThreadGroup")</tt> permission - * to see if it is ok to get the stack trace of all threads. - * - * @return a <tt>Map</tt> from <tt>Thread</tt> to an array of - * <tt>StackTraceElement</tt> that represents the stack trace of - * the corresponding thread. - * - * @throws SecurityException - * if a security manager exists and its - * <tt>checkPermission</tt> method doesn't allow - * getting the stack trace of thread. - * @see #getStackTrace - * @see SecurityManager#checkPermission - * @see RuntimePermission - * @see Throwable#getStackTrace - * - * @since 1.5 - */ - public static Map<Thread, StackTraceElement[]> getAllStackTraces() { - // check for getStackTrace permission - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkPermission( - SecurityConstants.GET_STACK_TRACE_PERMISSION); - security.checkPermission( - SecurityConstants.MODIFY_THREADGROUP_PERMISSION); - } - - // Get a snapshot of the list of all threads - Thread[] threads = getThreads(); - StackTraceElement[][] traces = dumpThreads(threads); - Map<Thread, StackTraceElement[]> m = new HashMap<>(threads.length); - for (int i = 0; i < threads.length; i++) { - StackTraceElement[] stackTrace = traces[i]; - if (stackTrace != null) { - m.put(threads[i], stackTrace); - } - // else terminated so we don't put it in the map - } - return m; - } - - - private static final RuntimePermission SUBCLASS_IMPLEMENTATION_PERMISSION = - new RuntimePermission("enableContextClassLoaderOverride"); - - /** cache of subclass security audit results */ - /* Replace with ConcurrentReferenceHashMap when/if it appears in a future - * release */ - private static class Caches { - /** cache of subclass security audit results */ - static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits = - new ConcurrentHashMap<>(); - - /** queue for WeakReferences to audited subclasses */ - static final ReferenceQueue<Class<?>> subclassAuditsQueue = - new ReferenceQueue<>(); - } - - /** - * Verifies that this (possibly subclass) instance can be constructed - * without violating security constraints: the subclass must not override - * security-sensitive non-final methods, or else the - * "enableContextClassLoaderOverride" RuntimePermission is checked. - */ - @cli.System.Runtime.CompilerServices.MethodImplAttribute.Annotation(value = cli.System.Runtime.CompilerServices.MethodImplOptions.__Enum.NoInlining) - private static native boolean isCCLOverridden(Thread thread); // [IKVM] implemented in map.xml - - private static boolean isCCLOverridden(Class<?> cl) { - if (cl == Thread.class) - return false; - - processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits); - WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue); - Boolean result = Caches.subclassAudits.get(key); - if (result == null) { - result = Boolean.valueOf(auditSubclass(cl)); - Caches.subclassAudits.putIfAbsent(key, result); - } - - return result.booleanValue(); - } - - /** - * Performs reflective checks on given subclass to verify that it doesn't - * override security-sensitive non-final methods. Returns true if the - * subclass overrides any of the methods, false otherwise. - */ - private static boolean auditSubclass(final Class<?> subcl) { - Boolean result = AccessController.doPrivileged( - new PrivilegedAction<Boolean>() { - public Boolean run() { - for (Class<?> cl = subcl; - cl != Thread.class; - cl = cl.getSuperclass()) - { - try { - cl.getDeclaredMethod("getContextClassLoader", new Class<?>[0]); - return Boolean.TRUE; - } catch (NoSuchMethodException ex) { - } - try { - Class<?>[] params = {ClassLoader.class}; - cl.getDeclaredMethod("setContextClassLoader", params); - return Boolean.TRUE; - } catch (NoSuchMethodException ex) { - } - } - return Boolean.FALSE; - } - } - ); - return result.booleanValue(); - } - - private static StackTraceElement[][] dumpThreads(Thread[] threads) { - StackTraceElement[][] stacks = new StackTraceElement[threads.length][]; - for (int i = 0; i < threads.length; i++) { - cli.System.Threading.Thread nativeThread = threads[i].nativeThread; - if (nativeThread == null) { - stacks[i] = new StackTraceElement[0]; - } else { - try { - if (false) throw new cli.System.Threading.ThreadStateException(); - boolean suspended = false; - if ((nativeThread.get_ThreadState().Value & cli.System.Threading.ThreadState.Suspended) == 0 && nativeThread != cli.System.Threading.Thread.get_CurrentThread()) { - suspended = true; - nativeThread.Suspend(); - } - cli.System.Diagnostics.StackTrace stack; - try { - stack = new cli.System.Diagnostics.StackTrace(nativeThread, true); - } - finally { - if (suspended) { - nativeThread.Resume(); - } - } - stacks[i] = getStackTrace(stack); - } - catch (cli.System.Threading.ThreadStateException _) { - stacks[i] = new StackTraceElement[0]; - } - } - } - return stacks; - } - - private static native StackTraceElement[] getStackTrace(cli.System.Diagnostics.StackTrace stack); - - private static native Thread[] getThreads(); - - /** - * Returns the identifier of this Thread. The thread ID is a positive - * <tt>long</tt> number generated when this thread was created. - * The thread ID is unique and remains unchanged during its lifetime. - * When a thread is terminated, this thread ID may be reused. - * - * @return this thread's ID. - * @since 1.5 - */ - public long getId() { - return tid; - } - - /** - * A thread state. A thread can be in one of the following states: - * <ul> - * <li>{@link #NEW}<br> - * A thread that has not yet started is in this state. - * </li> - * <li>{@link #RUNNABLE}<br> - * A thread executing in the Java virtual machine is in this state. - * </li> - * <li>{@link #BLOCKED}<br> - * A thread that is blocked waiting for a monitor lock - * is in this state. - * </li> - * <li>{@link #WAITING}<br> - * A thread that is waiting indefinitely for another thread to - * perform a particular action is in this state. - * </li> - * <li>{@link #TIMED_WAITING}<br> - * A thread that is waiting for another thread to perform an action - * for up to a specified waiting time is in this state. - * </li> - * <li>{@link #TERMINATED}<br> - * A thread that has exited is in this state. - * </li> - * </ul> - * - * <p> - * A thread can be in only one state at a given point in time. - * These states are virtual machine states which do not reflect - * any operating system thread states. - * - * @since 1.5 - * @see #getState - */ - public enum State { - /** - * Thread state for a thread which has not yet started. - */ - NEW, - - /** - * Thread state for a runnable thread. A thread in the runnable - * state is executing in the Java virtual machine but it may - * be waiting for other resources from the operating system - * such as processor. - */ - RUNNABLE, - - /** - * Thread state for a thread blocked waiting for a monitor lock. - * A thread in the blocked state is waiting for a monitor lock - * to enter a synchronized block/method or - * reenter a synchronized block/method after calling - * {@link Object#wait() Object.wait}. - */ - BLOCKED, - - /** - * Thread state for a waiting thread. - * A thread is in the waiting state due to calling one of the - * following methods: - * <ul> - * <li>{@link Object#wait() Object.wait} with no timeout</li> - * <li>{@link #join() Thread.join} with no timeout</li> - * <li>{@link LockSupport#park() LockSupport.park}</li> - * </ul> - * - * <p>A thread in the waiting state is waiting for another thread to - * perform a particular action. - * - * For example, a thread that has called <tt>Object.wait()</tt> - * on an object is waiting for another thread to call - * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on - * that object. A thread that has called <tt>Thread.join()</tt> - * is waiting for a specified thread to terminate. - */ - WAITING, - - /** - * Thread state for a waiting thread with a specified waiting time. - * A thread is in the timed waiting state due to calling one of - * the following methods with a specified positive waiting time: - * <ul> - * <li>{@link #sleep Thread.sleep}</li> - * <li>{@link Object#wait(long) Object.wait} with timeout</li> - * <li>{@link #join(long) Thread.join} with timeout</li> - * <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li> - * <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li> - * </ul> - */ - TIMED_WAITING, - - /** - * Thread state for a terminated thread. - * The thread has completed execution. - */ - TERMINATED; - } - - /** - * Returns the state of this thread. - * This method is designed for use in monitoring of the system state, - * not for synchronization control. - * - * @return this thread's state. - * @since 1.5 - */ - public State getState() { - // get current thread state - switch (threadStatus) { - case 0: - return State.NEW; - case 0x0002: - return State.TERMINATED; - } - synchronized (lock) { - if (interruptableWait) { - // NOTE if objectWait has satisfied the wait condition (or has been interrupted or has timed-out), - // it can be blocking on the re-acquire of the monitor, but we have no way of detecting that. - return timedWait ? State.TIMED_WAITING : State.WAITING; - } - } - cli.System.Threading.Thread nativeThread = this.nativeThread; - if (nativeThread == null) { - return State.TERMINATED; - } - if ((nativeThread.get_ThreadState().Value & cli.System.Threading.ThreadState.WaitSleepJoin) != 0) { - return State.BLOCKED; - } - return State.RUNNABLE; - } - - // Added in JSR-166 - - /** - * Interface for handlers invoked when a <tt>Thread</tt> abruptly - * terminates due to an uncaught exception. - * <p>When a thread is about to terminate due to an uncaught exception - * the Java Virtual Machine will query the thread for its - * <tt>UncaughtExceptionHandler</tt> using - * {@link #getUncaughtExceptionHandler} and will invoke the handler's - * <tt>uncaughtException</tt> method, passing the thread and the - * exception as arguments. - * If a thread has not had its <tt>UncaughtExceptionHandler</tt> - * explicitly set, then its <tt>ThreadGroup</tt> object acts as its - * <tt>UncaughtExceptionHandler</tt>. If the <tt>ThreadGroup</tt> object - * has no - * special requirements for dealing with the exception, it can forward - * the invocation to the {@linkplain #getDefaultUncaughtExceptionHandler - * default uncaught exception handler}. - * - * @see #setDefaultUncaughtExceptionHandler - * @see #setUncaughtExceptionHandler - * @see ThreadGroup#uncaughtException - * @since 1.5 - */ - @FunctionalInterface - public interface UncaughtExceptionHandler { - /** - * Method invoked when the given thread terminates due to the - * given uncaught exception. - * <p>Any exception thrown by this method will be ignored by the - * Java Virtual Machine. - * @param t the thread - * @param e the exception - */ - void uncaughtException(Thread t, Throwable e); - } - - // null unless explicitly set - private volatile UncaughtExceptionHandler uncaughtExceptionHandler; - - // null unless explicitly set - private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler; - - /** - * Set the default handler invoked when a thread abruptly terminates - * due to an uncaught exception, and no other handler has been defined - * for that thread. - * - * <p>Uncaught exception handling is controlled first by the thread, then - * by the thread's {@link ThreadGroup} object and finally by the default - * uncaught exception handler. If the thread does not have an explicit - * uncaught exception handler set, and the thread's thread group - * (including parent thread groups) does not specialize its - * <tt>uncaughtException</tt> method, then the default handler's - * <tt>uncaughtException</tt> method will be invoked. - * <p>By setting the default uncaught exception handler, an application - * can change the way in which uncaught exceptions are handled (such as - * logging to a specific device, or file) for those threads that would - * already accept whatever "default" behavior the system - * provided. - * - * <p>Note that the default uncaught exception handler should not usually - * defer to the thread's <tt>ThreadGroup</tt> object, as that could cause - * infinite recursion. - * - * @param eh the object to use as the default uncaught exception handler. - * If <tt>null</tt> then there is no default handler. - * - * @throws SecurityException if a security manager is present and it - * denies <tt>{@link RuntimePermission} - * ("setDefaultUncaughtExceptionHandler")</tt> - * - * @see #setUncaughtExceptionHandler - * @see #getUncaughtExceptionHandler - * @see ThreadGroup#uncaughtException - * @since 1.5 - */ - public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission( - new RuntimePermission("setDefaultUncaughtExceptionHandler") - ); - } - - defaultUncaughtExceptionHandler = eh; - } - - /** - * Returns the default handler invoked when a thread abruptly terminates - * due to an uncaught exception. If the returned value is <tt>null</tt>, - * there is no default. - * @since 1.5 - * @see #setDefaultUncaughtExceptionHandler - * @return the default uncaught exception handler for all threads - */ - public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){ - return defaultUncaughtExceptionHandler; - } - - /** - * Returns the handler invoked when this thread abruptly terminates - * due to an uncaught exception. If this thread has not had an - * uncaught exception handler explicitly set then this thread's - * <tt>ThreadGroup</tt> object is returned, unless this thread - * has terminated, in which case <tt>null</tt> is returned. - * @since 1.5 - * @return the uncaught exception handler for this thread - */ - public UncaughtExceptionHandler getUncaughtExceptionHandler() { - return uncaughtExceptionHandler != null ? - uncaughtExceptionHandler : group; - } - - /** - * Set the handler invoked when this thread abruptly terminates - * due to an uncaught exception. - * <p>A thread can take full control of how it responds to uncaught - * exceptions by having its uncaught exception handler explicitly set. - * If no such handler is set then the thread's <tt>ThreadGroup</tt> - * object acts as its handler. - * @param eh the object to use as this thread's uncaught exception - * handler. If <tt>null</tt> then this thread has no explicit handler. - * @throws SecurityException if the current thread is not allowed to - * modify this thread. - * @see #setDefaultUncaughtExceptionHandler - * @see ThreadGroup#uncaughtException - * @since 1.5 - */ - public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) { - checkAccess(); - uncaughtExceptionHandler = eh; - } - - /** - * Dispatch an uncaught exception to the handler. This method is - * intended to be called only by the JVM. - */ - private void dispatchUncaughtException(Throwable e) { - getUncaughtExceptionHandler().uncaughtException(this, e); - } - - /** - * Removes from the specified map any keys that have been enqueued - * on the specified reference queue. - */ - static void processQueue(ReferenceQueue<Class<?>> queue, - ConcurrentMap<? extends - WeakReference<Class<?>>, ?> map) - { - Reference<? extends Class<?>> ref; - while((ref = queue.poll()) != null) { - map.remove(ref); - } - } - - /** - * Weak key for Class objects. - **/ - static class WeakClassKey extends WeakReference<Class<?>> { - /** - * saved value of the referent's identity hash code, to maintain - * a consistent hash code after the referent has been cleared - */ - private final int hash; - - /** - * Create a new WeakClassKey to the given object, registered - * with a queue. - */ - WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) { - super(cl, refQueue); - hash = System.identityHashCode(cl); - } - - /** - * Returns the identity hash code of the original referent. - */ - @Override - public int hashCode() { - return hash; - } - - /** - * Returns true if the given object is this identical - * WeakClassKey instance, or, if this object's referent has not - * been cleared, if the given object is another WeakClassKey - * instance with the identical non-null referent as this one. - */ - @Override - public boolean equals(Object obj) { - if (obj == this) - return true; - - if (obj instanceof WeakClassKey) { - Object referent = get(); - return (referent != null) && - (referent == ((WeakClassKey) obj).get()); - } else { - return false; - } - } - } - - - // The following three initially uninitialized fields are exclusively - // managed by class java.util.concurrent.ThreadLocalRandom. These - // fields are used to build the high-performance PRNGs in the - // concurrent code, and we can not risk accidental false sharing. - // Hence, the fields are isolated with @Contended. - - /** The current seed for a ThreadLocalRandom */ - @sun.misc.Contended("tlr") - long threadLocalRandomSeed; - - /** Probe hash value; nonzero if threadLocalRandomSeed initialized */ - @sun.misc.Contended("tlr") - @ikvm.lang.Internal // [IKVM] accessed from java.util.concurrent.atomic.Striped64 - public int threadLocalRandomProbe; - - /** Secondary seed isolated from public ThreadLocalRandom sequence */ - @sun.misc.Contended("tlr") - @ikvm.lang.Internal // [IKVM] accessed from java.util.concurrent.locks.LockSupport - public int threadLocalRandomSecondarySeed; - - /* Some private helper methods */ - private synchronized void setPriority0(int newPriority) { - cli.System.Threading.Thread nativeThread = this.nativeThread; - if (nativeThread != null) { - try { - if (false) throw new cli.System.Threading.ThreadStateException(); - nativeThread.set_Priority(cli.System.Threading.ThreadPriority.wrap(mapJavaPriorityToClr(newPriority))); - } - catch (cli.System.Threading.ThreadStateException _) { - } - } - } - - private void stop0(Throwable x) { - synchronized (lock) { - if (!running) { - stillborn = x; - x = null; - } - } - if (x != null) { - // NOTE we allow ThreadDeath (and its subclasses) to be thrown on every thread, but any - // other exception is ignored, except if we're throwing it on the current Thread. This - // is done to allow exception handlers to be type specific, otherwise every exception - // handler would have to catch ThreadAbortException and look inside it to see if it - // contains the real exception that we wish to handle. - // I hope we can get away with this behavior, because Thread.stop() is deprecated - // anyway. Note that we do allow arbitrary exceptions to be thrown on the current - // thread, since this is harmless (because they aren't wrapped) and also because it - // provides some real value, because it is one of the ways you can throw arbitrary checked - // exceptions from Java. - if (this == current) { - sun.misc.Unsafe.getUnsafe().throwException(x); - } - else if (x instanceof ThreadDeath) { - cli.System.Threading.Thread nativeThread = this.nativeThread; - if (nativeThread == null) { - return; - } - try { - if (false) throw new cli.System.Threading.ThreadStateException(); - nativeThread.Abort(x); - } - catch (cli.System.Threading.ThreadStateException _) { - // .NET 2.0 throws a ThreadStateException if the target thread is currently suspended - // (but it does record the Abort request) - } - try { - if (false) throw new cli.System.Threading.ThreadStateException(); - int suspend = cli.System.Threading.ThreadState.Suspended | cli.System.Threading.ThreadState.SuspendRequested; - while ((nativeThread.get_ThreadState().Value & suspend) != 0) { - nativeThread.Resume(); - } - } - catch (cli.System.Threading.ThreadStateException _) { - } - } - } - } - - private void suspend0() { - try { - if (false) throw new cli.System.Threading.ThreadStateException(); - cli.System.Threading.Thread nativeThread = this.nativeThread; - if (nativeThread != null) { - nativeThread.Suspend(); - } - } - catch (cli.System.Threading.ThreadStateException _) { - } - } - - private void resume0() { - try { - if (false) throw new cli.System.Threading.ThreadStateException(); - cli.System.Threading.Thread nativeThread = this.nativeThread; - if (nativeThread != null) { - nativeThread.Resume(); - } - } - catch (cli.System.Threading.ThreadStateException _) { - } - } - - private void interrupt0() { - synchronized (lock) { - // if the thread hasn't been started yet or has been terminated, the interrupt is ignored - // (like on the reference implementation) - if (nativeThread == null) { - return; - } - if (!interruptPending) { - interruptPending = true; - if (interruptableWait) { - nativeInterruptPending = true; - nativeThread.Interrupt(); - } - } - } - } - - private void setRunningAndCheckStillborn() throws Throwable { - Throwable x; - synchronized (lock) { - running = true; - x = stillborn; - stillborn = null; - } - if (x != null) { - throw x; - } - } - - // [IKVM] this the entry point of thread started from Java - @cli.IKVM.Attributes.HideFromJavaAttribute.Annotation - void threadProc() { - current = this; - try { - // the body of the try block is in another method to allow the (limited) try/finally optimizer - // to properly recognize the try/finally block, because we want to make sure that die() - // runs in a finally block to prevent it from being asynchronously aborted. - threadProc2(); - } - finally { - die(); - } - } - - @cli.IKVM.Attributes.HideFromJavaAttribute.Annotation - private void threadProc2() { - try { - setRunningAndCheckStillborn(); - run(); - } - catch (Throwable x) { - try { - getUncaughtExceptionHandler().uncaughtException(this, x); - } - catch (Throwable _) { - } - } - } - - // [IKVM] this the implementation of Object.wait(long timeout, int nanos). It is hooked up in map.xml. - static void objectWait(Object o, long timeout, int nanos) throws InterruptedException { - if (o == null) { - throw new NullPointerException(); - } - if (timeout < 0) { - throw new IllegalArgumentException("timeout value is negative"); - } - if (nanos < 0 || nanos > 999999) { - throw new IllegalArgumentException("nanosecond timeout value out of range"); - } - if (nanos >= 500000 || (nanos != 0 && timeout == 0)) { - timeout++; - } - objectWait(o, timeout); - } - - // [IKVM] this the implementation of Object.wait(long timeout). It is hooked up in map.xml. - static void objectWait(Object o, long timeout) throws InterruptedException { - if (o == null) { - throw new NullPointerException(); - } - if (timeout < 0) { - throw new IllegalArgumentException("timeout value is negative"); - } - Thread t = currentThread(); - t.enterInterruptableWait(timeout != 0); - try { - if (false) throw new cli.System.Threading.ThreadInterruptedException(); - if (timeout == 0 || timeout > 922337203685476L) { - cli.System.Threading.Monitor.Wait(o); - } - else { - // We wait a maximum of Integer.MAX_VALUE milliseconds, because that is the maximum that Monitor.Wait will wait. - // Note that the Object.wait() specification allows for spurious wakeups, so this isn't a problem. Trying to - // emulate a longer wait with multiple Monitor.Wait() calls is not allowed, because that would mean that - // we acquire and release the synchronization lock multiple times during the wait. - cli.System.Threading.Monitor.Wait(o, (int)Math.min(timeout, Integer.MAX_VALUE)); - } - } - catch (cli.System.Threading.ThreadInterruptedException _) { - } - finally { - t.leaveInterruptableWait(); - } - } - - private void setNativeName(String name) { - cli.System.Threading.Thread thread = nativeThread; - if (thread != null) { - try { - if (false) throw new cli.System.InvalidOperationException(); - thread.set_Name(name); - } catch (cli.System.InvalidOperationException _) { - } - } - } -} diff --git a/openjdk/java/lang/ThrowableHelper.java b/openjdk/java/lang/ThrowableHelper.java deleted file mode 100644 index 8a08a8fe..00000000 --- a/openjdk/java/lang/ThrowableHelper.java +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright (c) 1994, 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 java.lang; -import java.io.*; -import java.util.*; - -final class ThrowableHelper { - /** - * Holder class to defer initializing sentinel objects only used - * for serialization. - */ - private static class SentinelHolder { - /** - * {@linkplain #setStackTrace(StackTraceElement[]) Setting the - * stack trace} to a one-element array containing this sentinel - * value indicates future attempts to set the stack trace will be - * ignored. The sentinal is equal to the result of calling:<br> - * {@code new StackTraceElement("", "", null, Integer.MIN_VALUE)} - */ - public static final StackTraceElement STACK_TRACE_ELEMENT_SENTINEL = - new StackTraceElement("", "", null, Integer.MIN_VALUE); - - /** - * Sentinel value used in the serial form to indicate an immutable - * stack trace. - */ - public static final StackTraceElement[] STACK_TRACE_SENTINEL = - new StackTraceElement[] {STACK_TRACE_ELEMENT_SENTINEL}; - } - - /** Caption for labeling causative exception stack traces */ - private static final String CAUSE_CAPTION = "Caused by: "; - - /** Caption for labeling suppressed exception stack traces */ - private static final String SUPPRESSED_CAPTION = "Suppressed: "; - - /** - * Prints this throwable and its backtrace to the - * standard error stream. This method prints a stack trace for this - * {@code Throwable} object on the error output stream that is - * the value of the field {@code System.err}. The first line of - * output contains the result of the {@link #toString()} method for - * this object. Remaining lines represent data previously recorded by - * the method {@link #fillInStackTrace()}. The format of this - * information depends on the implementation, but the following - * example may be regarded as typical: - * <blockquote><pre> - * java.lang.NullPointerException - * at MyClass.mash(MyClass.java:9) - * at MyClass.crunch(MyClass.java:6) - * at MyClass.main(MyClass.java:3) - * </pre></blockquote> - * This example was produced by running the program: - * <pre> - * class MyClass { - * public static void main(String[] args) { - * crunch(null); - * } - * static void crunch(int[] a) { - * mash(a); - * } - * static void mash(int[] b) { - * System.out.println(b[0]); - * } - * } - * </pre> - * The backtrace for a throwable with an initialized, non-null cause - * should generally include the backtrace for the cause. The format - * of this information depends on the implementation, but the following - * example may be regarded as typical: - * <pre> - * HighLevelException: MidLevelException: LowLevelException - * at Junk.a(Junk.java:13) - * at Junk.main(Junk.java:4) - * Caused by: MidLevelException: LowLevelException - * at Junk.c(Junk.java:23) - * at Junk.b(Junk.java:17) - * at Junk.a(Junk.java:11) - * ... 1 more - * Caused by: LowLevelException - * at Junk.e(Junk.java:30) - * at Junk.d(Junk.java:27) - * at Junk.c(Junk.java:21) - * ... 3 more - * </pre> - * Note the presence of lines containing the characters {@code "..."}. - * These lines indicate that the remainder of the stack trace for this - * exception matches the indicated number of frames from the bottom of the - * stack trace of the exception that was caused by this exception (the - * "enclosing" exception). This shorthand can greatly reduce the length - * of the output in the common case where a wrapped exception is thrown - * from same method as the "causative exception" is caught. The above - * example was produced by running the program: - * <pre> - * public class Junk { - * public static void main(String args[]) { - * try { - * a(); - * } catch(HighLevelException e) { - * e.printStackTrace(); - * } - * } - * static void a() throws HighLevelException { - * try { - * b(); - * } catch(MidLevelException e) { - * throw new HighLevelException(e); - * } - * } - * static void b() throws MidLevelException { - * c(); - * } - * static void c() throws MidLevelException { - * try { - * d(); - * } catch(LowLevelException e) { - * throw new MidLevelException(e); - * } - * } - * static void d() throws LowLevelException { - * e(); - * } - * static void e() throws LowLevelException { - * throw new LowLevelException(); - * } - * } - * - * class HighLevelException extends Exception { - * HighLevelException(Throwable cause) { super(cause); } - * } - * - * class MidLevelException extends Exception { - * MidLevelException(Throwable cause) { super(cause); } - * } - * - * class LowLevelException extends Exception { - * } - * </pre> - * As of release 7, the platform supports the notion of - * <i>suppressed exceptions</i> (in conjunction with the {@code - * try}-with-resources statement). Any exceptions that were - * suppressed in order to deliver an exception are printed out - * beneath the stack trace. The format of this information - * depends on the implementation, but the following example may be - * regarded as typical: - * - * <pre> - * Exception in thread "main" java.lang.Exception: Something happened - * at Foo.bar(Foo.java:10) - * at Foo.main(Foo.java:5) - * Suppressed: Resource$CloseFailException: Resource ID = 0 - * at Resource.close(Resource.java:26) - * at Foo.bar(Foo.java:9) - * ... 1 more - * </pre> - * Note that the "... n more" notation is used on suppressed exceptions - * just at it is used on causes. Unlike causes, suppressed exceptions are - * indented beyond their "containing exceptions." - * - * <p>An exception can have both a cause and one or more suppressed - * exceptions: - * <pre> - * Exception in thread "main" java.lang.Exception: Main block - * at Foo3.main(Foo3.java:7) - * Suppressed: Resource$CloseFailException: Resource ID = 2 - * at Resource.close(Resource.java:26) - * at Foo3.main(Foo3.java:5) - * Suppressed: Resource$CloseFailException: Resource ID = 1 - * at Resource.close(Resource.java:26) - * at Foo3.main(Foo3.java:5) - * Caused by: java.lang.Exception: I did it - * at Foo3.main(Foo3.java:8) - * </pre> - * Likewise, a suppressed exception can have a cause: - * <pre> - * Exception in thread "main" java.lang.Exception: Main block - * at Foo4.main(Foo4.java:6) - * Suppressed: Resource2$CloseFailException: Resource ID = 1 - * at Resource2.close(Resource2.java:20) - * at Foo4.main(Foo4.java:5) - * Caused by: java.lang.Exception: Rats, you caught me - * at Resource2$CloseFailException.<init>(Resource2.java:45) - * ... 2 more - * </pre> - */ - public static void printStackTrace(Throwable _this) { - _this.printStackTrace(System.err); - } - - /** - * Prints this throwable and its backtrace to the specified print stream. - * - * @param s {@code PrintStream} to use for output - */ - public static void printStackTrace(Throwable _this, PrintStream s) { - printStackTrace(_this, new WrappedPrintStream(s)); - } - - private static void printStackTrace(Throwable _this, PrintStreamOrWriter s) { - // Guard against malicious overrides of Throwable.equals by - // using a Set with identity equality semantics. - Set<Throwable> dejaVu = - Collections.newSetFromMap(new IdentityHashMap<Throwable, Boolean>()); - dejaVu.add(_this); - - synchronized (s.lock()) { - // Print our stack trace - s.println(_this); - StackTraceElement[] trace = getOurStackTrace(_this); - for (StackTraceElement traceElement : trace) - s.println("\tat " + traceElement); - - // Print suppressed exceptions, if any - for (Throwable se : _this.getSuppressed()) - printEnclosedStackTrace(se, s, trace, SUPPRESSED_CAPTION, "\t", dejaVu); - - // Print cause, if any - Throwable ourCause = _this.getCause(); - if (ourCause != null) - printEnclosedStackTrace(ourCause, s, trace, CAUSE_CAPTION, "", dejaVu); - } - } - - /** - * Print our stack trace as an enclosed exception for the specified - * stack trace. - */ - private static void printEnclosedStackTrace(Throwable _this, PrintStreamOrWriter s, - StackTraceElement[] enclosingTrace, - String caption, - String prefix, - Set<Throwable> dejaVu) { - assert Thread.holdsLock(s.lock()); - if (dejaVu.contains(_this)) { - s.println("\t[CIRCULAR REFERENCE:" + _this + "]"); - } else { - dejaVu.add(_this); - // Compute number of frames in common between this and enclosing trace - StackTraceElement[] trace = getOurStackTrace(_this); - int m = trace.length - 1; - int n = enclosingTrace.length - 1; - while (m >= 0 && n >=0 && trace[m].equals(enclosingTrace[n])) { - m--; n--; - } - int framesInCommon = trace.length - 1 - m; - - // Print our stack trace - s.println(prefix + caption + _this); - for (int i = 0; i <= m; i++) - s.println(prefix + "\tat " + trace[i]); - if (framesInCommon != 0) - s.println(prefix + "\t... " + framesInCommon + " more"); - - // Print suppressed exceptions, if any - for (Throwable se : _this.getSuppressed()) - printEnclosedStackTrace(se, s, trace, SUPPRESSED_CAPTION, - prefix +"\t", dejaVu); - - // Print cause, if any - Throwable ourCause = _this.getCause(); - if (ourCause != null) - printEnclosedStackTrace(ourCause, s, trace, CAUSE_CAPTION, prefix, dejaVu); - } - } - - private static native StackTraceElement[] getOurStackTrace(Throwable _this); - - /** - * Prints this throwable and its backtrace to the specified - * print writer. - * - * @param s {@code PrintWriter} to use for output - * @since JDK1.1 - */ - public static void printStackTrace(Throwable _this, PrintWriter s) { - printStackTrace(_this, new WrappedPrintWriter(s)); - } - - /** - * Wrapper class for PrintStream and PrintWriter to enable a single - * implementation of printStackTrace. - */ - private abstract static class PrintStreamOrWriter { - /** Returns the object to be locked when using this StreamOrWriter */ - abstract Object lock(); - - /** Prints the specified string as a line on this StreamOrWriter */ - abstract void println(Object o); - } - - private static class WrappedPrintStream extends PrintStreamOrWriter { - private final PrintStream printStream; - - WrappedPrintStream(PrintStream printStream) { - this.printStream = printStream; - } - - Object lock() { - return printStream; - } - - void println(Object o) { - printStream.println(o); - } - } - - private static class WrappedPrintWriter extends PrintStreamOrWriter { - private final PrintWriter printWriter; - - WrappedPrintWriter(PrintWriter printWriter) { - this.printWriter = printWriter; - } - - Object lock() { - return printWriter; - } - - void println(Object o) { - printWriter.println(o); - } - } -} diff --git a/openjdk/java/lang/VMSystemProperties.java b/openjdk/java/lang/VMSystemProperties.java deleted file mode 100644 index c982e2dd..00000000 --- a/openjdk/java/lang/VMSystemProperties.java +++ /dev/null @@ -1,421 +0,0 @@ -/* - Copyright (C) 2004-2011 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 java.util.Properties; -import static ikvm.internal.Util.SafeGetEnvironmentVariable; - -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_VENDOR = "Oracle Corporation"; - - private static String getLibraryPath() - { - String libraryPath; - if(ikvm.internal.Util.WINDOWS) - { - // see /hotspot/src/os/windows/vm/os_windows.cpp for the comment that describes how we build the path - String windir = SafeGetEnvironmentVariable("SystemRoot"); - if(windir != null) - { - libraryPath = cli.System.IO.Path.PathSeparator + windir + "\\Sun\\Java\\bin"; - } - else - { - libraryPath = null; - } - try - { - if(false) throw new cli.System.Security.SecurityException(); - if (libraryPath == null) - { - libraryPath = cli.System.Environment.get_SystemDirectory(); - } - else - { - libraryPath += cli.System.IO.Path.PathSeparator + cli.System.Environment.get_SystemDirectory(); - } - } - catch(cli.System.Security.SecurityException _) - { - } - if(windir != null) - { - libraryPath += cli.System.IO.Path.PathSeparator + windir; - } - String path = SafeGetEnvironmentVariable("PATH"); - if(path != null) - { - libraryPath += cli.System.IO.Path.PathSeparator + path; - } - } - else if(ikvm.internal.Util.MACOSX) - { - libraryPath = "."; - } - else /* assume Linux, since that's the only other platform we support */ - { - // on Linux we have some hardcoded paths (from /hotspot/src/os/linux/vm/os_linux.cpp) - // and we can only guess the cpu arch based on bitness (that means only x86 and x64) - String cpu_arch = cli.System.IntPtr.get_Size() == 4 ? "i386" : "amd64"; - libraryPath = "/usr/java/packages/lib/" + cpu_arch + ":/lib:/usr/lib"; - String ld_library_path = SafeGetEnvironmentVariable("LD_LIBRARY_PATH"); - if(ld_library_path != null) - { - libraryPath = ld_library_path + ":" + libraryPath; - } - } - try - { - cli.System.Reflection.Assembly entryAsm = cli.System.Reflection.Assembly.GetEntryAssembly(); - // If the CLR was started by a native app (e.g. via COM interop) there is no entry assembly - if (entryAsm != null) - { - // the application (or launcher) directory is prepended to the library path - // (similar to how the JDK prepends its directory to the path) - libraryPath = new cli.System.IO.FileInfo(entryAsm.get_Location()).get_DirectoryName() + cli.System.IO.Path.PathSeparator + libraryPath; - } - } - catch(Throwable _) - { - // ignore - } - if(ikvm.internal.Util.WINDOWS) - { - libraryPath += cli.System.IO.Path.PathSeparator + "."; - } - return libraryPath; - } - - private static void initCommonProperties(Properties p) - { - p.setProperty("java.version", "1.7.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.vendor", "Oracle Corporation"); - p.setProperty("java.vm.specification.name", "Java Virtual Machine Specification"); - p.setProperty("java.vm.version", PropertyConstants.java_vm_version); - p.setProperty("java.vm.vendor", "Jeroen Frijters"); - p.setProperty("java.vm.name", "IKVM.NET"); - p.setProperty("java.runtime.name", "IKVM.NET"); - p.setProperty("java.runtime.version", PropertyConstants.java_runtime_version); - 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.path", ""); - p.setProperty("java.library.path", getLibraryPath()); - try - { - if(false) throw new cli.System.Security.SecurityException(); - p.setProperty("java.io.tmpdir", cli.System.IO.Path.GetTempPath()); - } - catch(cli.System.Security.SecurityException _) - { - // TODO should we set another value? - p.setProperty("java.io.tmpdir", "."); - } - p.setProperty("java.ext.dirs", ""); - // NOTE os.name *must* contain "Windows" when running on Windows, because Classpath tests on that - String osname = null; - String osver = null; - cli.System.OperatingSystem os = cli.System.Environment.get_OSVersion(); - int major = os.get_Version().get_Major(); - int minor = os.get_Version().get_Minor(); - switch(os.get_Platform().Value) - { - case cli.System.PlatformID.Win32NT: - osname = "Windows NT (unknown)"; - switch(major) - { - case 3: - case 4: - osver = major + "." + minor; - osname = "Windows NT"; - break; - case 5: - switch(minor) - { - case 0: - osver = "5.0"; - osname = "Windows 2000"; - break; - case 1: - osver = "5.1"; - osname = "Windows XP"; - break; - case 2: - osver = "5.2"; - osname = "Windows 2003"; - break; - } - break; - case 6: - // since there appears to be no managed way to differentiate between Client/Server, we report client names - switch(minor) - { - case 0: - osver = "6.0"; - osname = "Windows Vista"; - break; - case 1: - osver = "6.1"; - osname = "Windows 7"; - break; - } - break; - } - break; - case cli.System.PlatformID.Win32Windows: - if(major == 4) - { - switch(minor) - { - case 0: - osver = "4.0"; - osname = "Windows 95"; - break; - case 10: - osver = "4.10"; - osname = "Windows 98"; - break; - case 90: - osver = "4.90"; - osname = "Windows Me"; - break; - } - } - break; - case cli.System.PlatformID.Unix: - if(ikvm.internal.Util.MACOSX) - { - // for back compat Mono will return PlatformID.Unix when running on the Mac, - // so we handle that explicitly here - osname = "Mac OS X"; - // HACK this tries to map the Darwin version to the OS X version - // (based on http://en.wikipedia.org/wiki/Darwin_(operating_system)#Releases) - cli.System.Version ver = cli.System.Environment.get_OSVersion().get_Version(); - osver = "10." + (ver.get_Major() - 4) + "." + ver.get_Minor(); - } - break; - } - if(osname == null) - { - osname = cli.System.Environment.get_OSVersion().ToString(); - } - if(osver == null) - { - osver = major + "." + minor; - } - p.setProperty("os.name", osname); - p.setProperty("os.version", osver); - String arch = SafeGetEnvironmentVariable("PROCESSOR_ARCHITECTURE"); - if(arch == null) - { - // we don't know, so we make a guess - if(cli.System.IntPtr.get_Size() == 4) - { - arch = ikvm.internal.Util.WINDOWS ? "x86" : "i386"; - } - else - { - arch = "amd64"; - } - } - if(arch.equals("AMD64")) - { - arch = "amd64"; - } - p.setProperty("os.arch", arch); - p.setProperty("sun.arch.data.model", "" + (cli.System.IntPtr.get_Size() * 8)); - p.setProperty("file.separator", "" + cli.System.IO.Path.DirectorySeparatorChar); - p.setProperty("file.encoding", cli.System.Text.Encoding.get_Default().get_WebName()); - p.setProperty("path.separator", "" + cli.System.IO.Path.PathSeparator); - p.setProperty("line.separator", cli.System.Environment.get_NewLine()); - try - { - if(false) throw new cli.System.Security.SecurityException(); - p.setProperty("user.name", cli.System.Environment.get_UserName()); - } - catch(cli.System.Security.SecurityException _) - { - p.setProperty("user.name", "(unknown)"); - } - String home = SafeGetEnvironmentVariable("USERPROFILE"); - if(home == null) - { - // maybe we're on *nix - home = SafeGetEnvironmentVariable("HOME"); - if(home == null) - { - // TODO maybe there is a better way - // NOTE on MS .NET this doesn't return the correct path - // (it returns "C:\\Documents and Settings\\username\\My Documents", but we really need - // "C:\\Documents and Settings\\username" to be compatible with Sun, that's why we use %USERPROFILE% if it exists) - try - { - if(false) throw new cli.System.Security.SecurityException(); - home = cli.System.Environment.GetFolderPath(cli.System.Environment.SpecialFolder.wrap(cli.System.Environment.SpecialFolder.Personal)); - } - catch(cli.System.Security.SecurityException _) - { - home = "."; - } - } - } - p.setProperty("user.home", home); - try - { - if(false) throw new cli.System.Security.SecurityException(); - p.setProperty("user.dir", cli.System.Environment.get_CurrentDirectory()); - } - catch(cli.System.Security.SecurityException _) - { - p.setProperty("user.dir", "."); - } - p.setProperty("awt.toolkit", PropertyConstants.awt_toolkit); - } - - public static void initProperties(Properties p) - { - p.setProperty("openjdk.version", PropertyConstants.openjdk_version); - String vfsroot = getVirtualFileSystemRoot(); - p.setProperty("java.home", vfsroot.substring(0, vfsroot.length() - 1)); - // the %home%\lib\endorsed directory does not exist, but neither does it on JDK 1.7 - p.setProperty("java.endorsed.dirs", vfsroot + "lib" + cli.System.IO.Path.DirectorySeparatorChar + "endorsed"); - p.setProperty("sun.boot.library.path", vfsroot + "bin"); - p.setProperty("sun.boot.class.path", getBootClassPath()); - initCommonProperties(p); - setupI18N(p); - p.setProperty("sun.cpu.endian", cli.System.BitConverter.IsLittleEndian ? "little" : "big"); - p.setProperty("file.encoding.pkg", "sun.io"); - p.setProperty("user.timezone", ""); - p.setProperty("sun.os.patch.level", cli.System.Environment.get_OSVersion().get_ServicePack()); - p.setProperty("java.vm.info", "compiled mode"); - p.setProperty("sun.nio.MaxDirectMemorySize", "-1"); - p.setProperty("java.awt.graphicsenv", PropertyConstants.java_awt_graphicsenv); - p.setProperty("java.awt.printerjob", "sun.awt.windows.WPrinterJob"); - - // 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 - { - // read properties from app.config - if(false) throw new cli.System.Configuration.ConfigurationException(); - cli.System.Collections.Specialized.NameValueCollection appSettings = cli.System.Configuration.ConfigurationSettings.get_AppSettings(); - cli.System.Collections.IEnumerator keys = appSettings.GetEnumerator(); - while(keys.MoveNext()) - { - String key = (String)keys.get_Current(); - if(key.startsWith("ikvm:")) - { - p.setProperty(key.substring(5), appSettings.get_Item(key)); - } - } - } - catch(cli.System.Configuration.ConfigurationException _) - { - // app.config is invalid, ignore - } - // set the properties that were specified with ikvm.runtime.Startup.setProperties() - cli.System.Collections.IDictionary props = ikvm.runtime.Startup.props; - if(props != null) - { - cli.System.Collections.IDictionaryEnumerator entries = props.GetEnumerator(); - while(entries.MoveNext()) - { - p.setProperty((String)entries.get_Key(), (String)entries.get_Value()); - } - } - } - - private static void setupI18N(Properties p) - { - String[] culture = ((cli.System.String)(Object)cli.System.Globalization.CultureInfo.get_CurrentCulture().get_Name()).Split(new char[] { '-' }); - String language; - String script; - String region; - String variant; - if (culture.length == 2) - { - language = culture[0]; - if (culture[1].length() == 4) - { - script = culture[1]; - region = ""; - } - else - { - script = ""; - region = culture[1]; - } - } - else if (culture.length == 3) - { - language = culture[0]; - script = culture[1]; - region = culture[2]; - } - else - { - language = "en"; - script = ""; - region = "US"; - } - // Norwegian - if (language.equals("nb")) - { - language = "no"; - region = "NO"; - variant = ""; - } - else if (language.equals("nn")) - { - language = "no"; - region = "NO"; - variant = "NY"; - } - else - { - variant = ""; - } - p.setProperty("user.language", language); - p.setProperty("user.country", region); - p.setProperty("user.variant", variant); - p.setProperty("user.script", script); - } - - private static native String getVirtualFileSystemRoot(); - private static native String getBootClassPath(); -} diff --git a/openjdk/java/lang/invoke/AdapterMethodHandle.java b/openjdk/java/lang/invoke/AdapterMethodHandle.java deleted file mode 100644 index b5686afa..00000000 --- a/openjdk/java/lang/invoke/AdapterMethodHandle.java +++ /dev/null @@ -1,477 +0,0 @@ -/* - * Copyright (c) 2008, 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. - */ - -/* - * Extensively modified for IKVM.NET by Jeroen Frijters - * Copyright (C) 2011 Jeroen Frijters - */ - -package java.lang.invoke; - -import sun.invoke.util.VerifyType; -import sun.invoke.util.Wrapper; -import sun.invoke.util.ValueConversions; -import java.util.Arrays; -import java.util.ArrayList; -import java.util.Collections; -import static java.lang.invoke.MethodHandleStatics.*; -import ikvm.internal.NotYetImplementedError; - -/** - * This method handle performs simple conversion or checking of a single argument. - * @author jrose - */ -class AdapterMethodHandle extends BoundMethodHandle { - - AdapterMethodHandle(MethodType type) { - super(type, null, -1); - } - AdapterMethodHandle(MethodType type, Object vmtarget) { - super(type, null, -1); - this.vmtarget = vmtarget; - } - - /** Can a JVM-level adapter directly implement the proposed - * argument conversion, as if by fixed-arity MethodHandle.asType? - */ - static boolean canConvertArgument(Class<?> src, Class<?> dst, int level) { - return true; - } - - /** - * Create a JVM-level adapter method handle to conform the given method - * handle to the similar newType, using only pairwise argument conversions. - * For each argument, convert incoming argument to the exact type needed. - * The argument conversions allowed are casting, boxing and unboxing, - * integral widening or narrowing, and floating point widening or narrowing. - * @param newType required call type - * @param target original method handle - * @param level which strength of conversion is allowed - * @return an adapter to the original handle with the desired new type, - * or the original target if the types are already identical - * or null if the adaptation cannot be made - */ - static native MethodHandle makePairwiseConvert(MethodType newType, MethodHandle target, int level); - - /* Return one plus the position of the first non-trivial difference - * between the given types. This is not a symmetric operation; - * we are considering adapting the targetType to adapterType. - * Trivial differences are those which could be ignored by the JVM - * without subverting the verifier. Otherwise, adaptable differences - * are ones for which we could create an adapter to make the type change. - * Return zero if there are no differences (other than trivial ones). - * Return 1+N if N is the only adaptable argument difference. - * Return the -2-N where N is the first of several adaptable - * argument differences. - * Return -1 if there there are differences which are not adaptable. - */ - private static int diffTypes(MethodType adapterType, - MethodType targetType, - boolean raw) { - int diff; - diff = diffReturnTypes(adapterType, targetType, raw); - if (diff != 0) return diff; - int nargs = adapterType.parameterCount(); - if (nargs != targetType.parameterCount()) - return -1; - diff = diffParamTypes(adapterType, 0, targetType, 0, nargs, raw); - //System.out.println("diff "+adapterType); - //System.out.println(" "+diff+" "+targetType); - return diff; - } - private static int diffReturnTypes(MethodType adapterType, - MethodType targetType, - boolean raw) { - Class<?> src = targetType.returnType(); - Class<?> dst = adapterType.returnType(); - if ((!raw - ? VerifyType.canPassUnchecked(src, dst) - : VerifyType.canPassRaw(src, dst) - ) > 0) - return 0; // no significant difference - if (raw && !src.isPrimitive() && !dst.isPrimitive()) - return 0; // can force a reference return (very carefully!) - //if (false) return 1; // never adaptable! - return -1; // some significant difference - } - private static int diffParamTypes(MethodType adapterType, int astart, - MethodType targetType, int tstart, - int nargs, boolean raw) { - assert(nargs >= 0); - int res = 0; - for (int i = 0; i < nargs; i++) { - Class<?> src = adapterType.parameterType(astart+i); - Class<?> dest = targetType.parameterType(tstart+i); - if ((!raw - ? VerifyType.canPassUnchecked(src, dest) - : VerifyType.canPassRaw(src, dest) - ) <= 0) { - // found a difference; is it the only one so far? - if (res != 0) - return -1-res; // return -2-i for prev. i - res = 1+i; - } - } - return res; - } - - /** Can a retyping adapter (alone) validly convert the target to newType? */ - static boolean canRetypeOnly(MethodType newType, MethodType targetType) { - return canRetype(newType, targetType, false); - } - /** Can a retyping adapter (alone) convert the target to newType? - * It is allowed to widen subword types and void to int, to make bitwise - * conversions between float/int and double/long, and to perform unchecked - * reference conversions on return. This last feature requires that the - * caller be trusted, and perform explicit cast conversions on return values. - */ - static boolean canRetypeRaw(MethodType newType, MethodType targetType) { - return canRetype(newType, targetType, true); - } - static boolean canRetype(MethodType newType, MethodType targetType, boolean raw) { - int diff = diffTypes(newType, targetType, raw); - // %%% This assert is too strong. Factor diff into VerifyType and reconcile. - assert(raw || (diff == 0) == VerifyType.isNullConversion(newType, targetType)); - return diff == 0; - } - - /** Factory method: Performs no conversions; simply retypes the adapter. - * Allows unchecked argument conversions pairwise, if they are safe. - * Returns null if not possible. - */ - static MethodHandle makeRetypeOnly(MethodType newType, MethodHandle target) { - return makeRetype(newType, target, false); - } - static MethodHandle makeRetypeRaw(MethodType newType, MethodHandle target) { - return makeRetype(newType, target, true); - } - static native MethodHandle makeRetype(MethodType newType, MethodHandle target, boolean raw); - - static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) { - MethodType type = target.type(); - int last = type.parameterCount() - 1; - if (type.parameterType(last) != arrayType) - target = target.asType(type.changeParameterType(last, arrayType)); - target = target.asFixedArity(); // make sure this attribute is turned off - return new AsVarargsCollector(target, arrayType); - } - - static class AsVarargsCollector extends AdapterMethodHandle { - final MethodHandle target; - final Class<?> arrayType; - MethodHandle cache; - - AsVarargsCollector(MethodHandle target, Class<?> arrayType) { - super(target.type()); - this.vmtarget = target.vmtarget; - this.target = target; - this.arrayType = arrayType; - this.cache = target.asCollector(arrayType, 0); - } - - @Override - public boolean isVarargsCollector() { - return true; - } - - @Override - public MethodHandle asFixedArity() { - return target; - } - - @Override - public MethodHandle asType(MethodType newType) { - MethodType type = this.type(); - int collectArg = type.parameterCount() - 1; - int newArity = newType.parameterCount(); - if (newArity == collectArg+1 && - type.parameterType(collectArg).isAssignableFrom(newType.parameterType(collectArg))) { - // if arity and trailing parameter are compatible, do normal thing - return super.asType(newType); - } - // check cache - if (cache.type().parameterCount() == newArity) - return cache.asType(newType); - // build and cache a collector - int arrayLength = newArity - collectArg; - MethodHandle collector; - try { - collector = target.asCollector(arrayType, arrayLength); - } catch (IllegalArgumentException ex) { - throw new WrongMethodTypeException("cannot build collector"); - } - cache = collector; - return collector.asType(newType); - } - } - - /** Can a checkcast adapter validly convert the target to newType? - * The JVM supports all kind of reference casts, even silly ones. - */ - static boolean canCheckCast(MethodType newType, MethodType targetType, - int arg, Class<?> castType) { - Class<?> src = newType.parameterType(arg); - Class<?> dst = targetType.parameterType(arg); - if (!canCheckCast(src, castType) - || !VerifyType.isNullConversion(castType, dst)) - return false; - int diff = diffTypes(newType, targetType, false); - return (diff == arg+1) || (diff == 0); // arg is sole non-trivial diff - } - /** Can an primitive conversion adapter validly convert src to dst? */ - static boolean canCheckCast(Class<?> src, Class<?> dst) { - return (!src.isPrimitive() && !dst.isPrimitive()); - } - - /** Factory method: Forces a cast at the given argument. - * The castType is the target of the cast, and can be any type - * with a null conversion to the corresponding target parameter. - * Return null if this cannot be done. - */ - static MethodHandle makeCheckCast(MethodType newType, MethodHandle target, - int arg, Class<?> castType) { - if (!canCheckCast(newType, target.type(), arg, castType)) - return null; - throw new NotYetImplementedError(); - } - - /** Can an adapter simply drop arguments to convert the target to newType? */ - static boolean canDropArguments(MethodType newType, MethodType targetType, - int dropArgPos, int dropArgCount) { - if (dropArgCount == 0) - return canRetypeOnly(newType, targetType); - if (diffReturnTypes(newType, targetType, false) != 0) - return false; - int nptypes = newType.parameterCount(); - // parameter types must be the same up to the drop point - if (dropArgPos != 0 && diffParamTypes(newType, 0, targetType, 0, dropArgPos, false) != 0) - return false; - int afterPos = dropArgPos + dropArgCount; - int afterCount = nptypes - afterPos; - if (dropArgPos < 0 || dropArgPos >= nptypes || - dropArgCount < 1 || afterPos > nptypes || - targetType.parameterCount() != nptypes - dropArgCount) - return false; - // parameter types after the drop point must also be the same - if (afterCount != 0 && diffParamTypes(newType, afterPos, targetType, dropArgPos, afterCount, false) != 0) - return false; - return true; - } - - /** Factory method: Drop selected arguments. - * Allow unchecked retyping of remaining arguments, pairwise. - * Return null if this is not possible. - */ - static MethodHandle makeDropArguments(MethodType newType, MethodHandle target, - int dropArgPos, int dropArgCount) { - if (dropArgCount == 0) - return makeRetypeOnly(newType, target); - if (!canDropArguments(newType, target.type(), dropArgPos, dropArgCount)) - return null; - int[] permute = new int[target.type().parameterCount()]; - for (int i = 0, arg = 0; i < permute.length; i++) { - if (arg == dropArgPos) - arg += dropArgCount; - permute[i] = arg++; - } - return MethodHandleImpl.permuteArguments(target, newType, target.type(), permute); - } - - /** Can an adapter duplicate an argument to convert the target to newType? */ - static boolean canDupArguments(MethodType newType, MethodType targetType, - int dupArgPos, int dupArgCount) { - if (diffReturnTypes(newType, targetType, false) != 0) - return false; - int nptypes = newType.parameterCount(); - if (dupArgCount < 0 || dupArgPos + dupArgCount > nptypes) - return false; - if (targetType.parameterCount() != nptypes + dupArgCount) - return false; - // parameter types must be the same up to the duplicated arguments - if (diffParamTypes(newType, 0, targetType, 0, nptypes, false) != 0) - return false; - // duplicated types must be, well, duplicates - if (diffParamTypes(newType, dupArgPos, targetType, nptypes, dupArgCount, false) != 0) - return false; - return true; - } - - /** Factory method: Duplicate the selected argument. - * Return null if this is not possible. - */ - static MethodHandle makeDupArguments(MethodType newType, MethodHandle target, - int dupArgPos, int dupArgCount) { - if (!canDupArguments(newType, target.type(), dupArgPos, dupArgCount)) - return null; - if (dupArgCount == 0) - return target; - // in arglist: [0: ...keep1 | dpos: dup... | dpos+dcount: keep2... ] - // out arglist: [0: ...keep1 | dpos: dup... | dpos+dcount: keep2... | dup... ] - throw new NotYetImplementedError(); - } - - /** Can an adapter swap two arguments to convert the target to newType? */ - static boolean canSwapArguments(MethodType newType, MethodType targetType, - int swapArg1, int swapArg2) { - if (diffReturnTypes(newType, targetType, false) != 0) - return false; - if (swapArg1 >= swapArg2) return false; // caller resp - int nptypes = newType.parameterCount(); - if (targetType.parameterCount() != nptypes) - return false; - if (swapArg1 < 0 || swapArg2 >= nptypes) - return false; - if (diffParamTypes(newType, 0, targetType, 0, swapArg1, false) != 0) - return false; - if (diffParamTypes(newType, swapArg1, targetType, swapArg2, 1, false) != 0) - return false; - if (diffParamTypes(newType, swapArg1+1, targetType, swapArg1+1, swapArg2-swapArg1-1, false) != 0) - return false; - if (diffParamTypes(newType, swapArg2, targetType, swapArg1, 1, false) != 0) - return false; - if (diffParamTypes(newType, swapArg2+1, targetType, swapArg2+1, nptypes-swapArg2-1, false) != 0) - return false; - return true; - } - - /** Factory method: Swap the selected arguments. - * Return null if this is not possible. - */ - static MethodHandle makeSwapArguments(MethodType newType, MethodHandle target, - int swapArg1, int swapArg2) { - if (swapArg1 == swapArg2) - return target; - if (swapArg1 > swapArg2) { int t = swapArg1; swapArg1 = swapArg2; swapArg2 = t; } - if (!canSwapArguments(newType, target.type(), swapArg1, swapArg2)) - return null; - // in arglist: [0: ...keep1 | pos1: a1 | pos1+1: keep2... | pos2: a2 | pos2+1: keep3... ] - // out arglist: [0: ...keep1 | pos1: a2 | pos1+1: keep2... | pos2: a1 | pos2+1: keep3... ] - throw new NotYetImplementedError(); - } - - static int positiveRotation(int argCount, int rotateBy) { - assert(argCount > 0); - if (rotateBy >= 0) { - if (rotateBy < argCount) - return rotateBy; - return rotateBy % argCount; - } else if (rotateBy >= -argCount) { - return rotateBy + argCount; - } else { - return (-1-((-1-rotateBy) % argCount)) + argCount; - } - } - - final static int MAX_ARG_ROTATION = 1; - - /** Can an adapter rotate arguments to convert the target to newType? */ - static boolean canRotateArguments(MethodType newType, MethodType targetType, - int firstArg, int argCount, int rotateBy) { - rotateBy = positiveRotation(argCount, rotateBy); - if (rotateBy == 0) return false; // no rotation - if (rotateBy > MAX_ARG_ROTATION && rotateBy < argCount - MAX_ARG_ROTATION) - return false; // too many argument positions - // Rotate incoming args right N to the out args, N in 1..(argCouunt-1). - if (diffReturnTypes(newType, targetType, false) != 0) - return false; - int nptypes = newType.parameterCount(); - if (targetType.parameterCount() != nptypes) - return false; - if (firstArg < 0 || firstArg >= nptypes) return false; - int argLimit = firstArg + argCount; - if (argLimit > nptypes) return false; - if (diffParamTypes(newType, 0, targetType, 0, firstArg, false) != 0) - return false; - int newChunk1 = argCount - rotateBy, newChunk2 = rotateBy; - // swap new chunk1 with target chunk2 - if (diffParamTypes(newType, firstArg, targetType, argLimit-newChunk1, newChunk1, false) != 0) - return false; - // swap new chunk2 with target chunk1 - if (diffParamTypes(newType, firstArg+newChunk1, targetType, firstArg, newChunk2, false) != 0) - return false; - return true; - } - - /** Factory method: Rotate the selected argument range. - * Return null if this is not possible. - */ - static MethodHandle makeRotateArguments(MethodType newType, MethodHandle target, - int firstArg, int argCount, int rotateBy) { - rotateBy = positiveRotation(argCount, rotateBy); - if (!canRotateArguments(newType, target.type(), firstArg, argCount, rotateBy)) - return null; - throw new NotYetImplementedError(); - } - - /** Can an adapter spread an argument to convert the target to newType? */ - static boolean canSpreadArguments(MethodType newType, MethodType targetType, - Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) { - if (diffReturnTypes(newType, targetType, false) != 0) - return false; - int nptypes = newType.parameterCount(); - // parameter types must be the same up to the spread point - if (spreadArgPos != 0 && diffParamTypes(newType, 0, targetType, 0, spreadArgPos, false) != 0) - return false; - int afterPos = spreadArgPos + spreadArgCount; - int afterCount = nptypes - (spreadArgPos + 1); - if (spreadArgPos < 0 || spreadArgPos >= nptypes || - spreadArgCount < 0 || - targetType.parameterCount() != afterPos + afterCount) - return false; - // parameter types after the spread point must also be the same - if (afterCount != 0 && diffParamTypes(newType, spreadArgPos+1, targetType, afterPos, afterCount, false) != 0) - return false; - // match the array element type to the spread arg types - Class<?> rawSpreadArgType = newType.parameterType(spreadArgPos); - if (rawSpreadArgType != spreadArgType && !canCheckCast(rawSpreadArgType, spreadArgType)) - return false; - for (int i = 0; i < spreadArgCount; i++) { - Class<?> src = VerifyType.spreadArgElementType(spreadArgType, i); - Class<?> dst = targetType.parameterType(spreadArgPos + i); - if (src == null || !canConvertArgument(src, dst, 1)) - return false; - } - return true; - } - - - /** Factory method: Spread selected argument. */ - static native MethodHandle makeSpreadArguments(MethodType newType, MethodHandle target, Class<?> spreadArgType, int spreadArgPos, int spreadArgCount); - - /** Can an adapter collect a series of arguments, replacing them by zero or one results? */ - static boolean canCollectArguments(MethodType targetType, - MethodType collectorType, int collectArgPos, boolean retainOriginalArgs) { - int collectArgCount = collectorType.parameterCount(); - Class<?> rtype = collectorType.returnType(); - assert(rtype == void.class || targetType.parameterType(collectArgPos) == rtype) - // [(Object)Object[], (Object[])Object[], 0, 1] - : Arrays.asList(targetType, collectorType, collectArgPos, collectArgCount) - ; - return true; - } - - /** Factory method: Collect or filter selected argument(s). */ - static native MethodHandle makeCollectArguments(MethodHandle target, MethodHandle collector, int collectArgPos, boolean retainOriginalArgs); -} diff --git a/openjdk/java/lang/invoke/BoundMethodHandle.java b/openjdk/java/lang/invoke/BoundMethodHandle.java deleted file mode 100644 index 6098ca3f..00000000 --- a/openjdk/java/lang/invoke/BoundMethodHandle.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) 2008, 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. - */ - -/* - * Extensively modified for IKVM.NET by Jeroen Frijters - * Copyright (C) 2011 Jeroen Frijters - */ - -package java.lang.invoke; - -import sun.invoke.util.VerifyType; -import sun.invoke.util.Wrapper; -import static java.lang.invoke.MethodHandleStatics.*; - -/** - * The flavor of method handle which emulates an invoke instruction - * on a predetermined argument. The JVM dispatches to the correct method - * when the handle is created, not when it is invoked. - * @author jrose - */ -class BoundMethodHandle extends MethodHandle { - //MethodHandle vmtarget; // next BMH or final DMH or methodOop - private final Object argument; // argument to insert - private final int vmargslot; // position at which it is inserted - - // Constructors in this class *must* be package scoped or private. - - /** Bind a direct MH to its receiver (or first ref. argument). - * The JVM will pre-dispatch the MH if it is not already static. - */ - /*non-public*/ BoundMethodHandle(DirectMethodHandle mh, Object argument) { - super(mh.type().dropParameterTypes(0, 1)); - // check the type now, once for all: - this.argument = checkReferenceArgument(argument, mh, 0); - this.vmargslot = this.type().parameterSlotCount(); - initTarget(mh, 0); - } - - /** Insert an argument into an arbitrary method handle. - * If argnum is zero, inserts the first argument, etc. - * The argument type must be a reference. - */ - /*non-public*/ BoundMethodHandle(MethodHandle mh, Object argument, int argnum) { - this(mh.type().dropParameterTypes(argnum, argnum+1), - mh, argument, argnum); - } - - /** Insert an argument into an arbitrary method handle. - * If argnum is zero, inserts the first argument, etc. - */ - /*non-public*/ BoundMethodHandle(MethodType type, MethodHandle mh, Object argument, int argnum) { - super(type); - if (mh.type().parameterType(argnum).isPrimitive()) - this.argument = bindPrimitiveArgument(argument, mh, argnum); - else { - this.argument = checkReferenceArgument(argument, mh, argnum); - } - this.vmargslot = type.parameterSlotDepth(argnum); - initTarget(mh, argnum); - } - - private void initTarget(MethodHandle mh, int argnum) { - vmtarget = createDelegate(type(), mh, argnum, argument); - } - - private static native Object createDelegate(MethodType newType, MethodHandle mh, int argnum, Object argument); - - /** For the AdapterMethodHandle subclass. - */ - /*non-public*/ BoundMethodHandle(MethodType type, Object argument, int vmargslot) { - super(type); - this.argument = argument; - this.vmargslot = vmargslot; - assert(this instanceof AdapterMethodHandle); - } - - /** Initialize the current object as a self-bound method handle, binding it - * as the first argument of the method handle {@code entryPoint}. - * The invocation type of the resulting method handle will be the - * same as {@code entryPoint}, except that the first argument - * type will be dropped. - */ - /*non-public*/ BoundMethodHandle(MethodHandle entryPoint) { - super(entryPoint.type().dropParameterTypes(0, 1)); - this.argument = this; // kludge; get rid of - this.vmargslot = this.type().parameterSlotDepth(0); - initTarget(entryPoint, 0); - } - - /** Make sure the given {@code argument} can be used as {@code argnum}-th - * parameter of the given method handle {@code mh}, which must be a reference. - * <p> - * If this fails, throw a suitable {@code WrongMethodTypeException}, - * which will prevent the creation of an illegally typed bound - * method handle. - */ - final static Object checkReferenceArgument(Object argument, MethodHandle mh, int argnum) { - Class<?> ptype = mh.type().parameterType(argnum); - if (ptype.isPrimitive()) { - // fail - } else if (argument == null) { - return null; - } else if (VerifyType.isNullReferenceConversion(argument.getClass(), ptype)) { - return argument; - } - throw badBoundArgumentException(argument, mh, argnum); - } - - /** Make sure the given {@code argument} can be used as {@code argnum}-th - * parameter of the given method handle {@code mh}, which must be a primitive. - * <p> - * If this fails, throw a suitable {@code WrongMethodTypeException}, - * which will prevent the creation of an illegally typed bound - * method handle. - */ - final static Object bindPrimitiveArgument(Object argument, MethodHandle mh, int argnum) { - Class<?> ptype = mh.type().parameterType(argnum); - Wrapper wrap = Wrapper.forPrimitiveType(ptype); - Object zero = wrap.zero(); - if (zero == null) { - // fail - } else if (argument == null) { - if (ptype != int.class && wrap.isSubwordOrInt()) - return Integer.valueOf(0); - else - return zero; - } else if (VerifyType.isNullReferenceConversion(argument.getClass(), zero.getClass())) { - if (ptype != int.class && wrap.isSubwordOrInt()) - return Wrapper.INT.wrap(argument); - else - return argument; - } - throw badBoundArgumentException(argument, mh, argnum); - } - - final static RuntimeException badBoundArgumentException(Object argument, MethodHandle mh, int argnum) { - String atype = (argument == null) ? "null" : argument.getClass().toString(); - return new ClassCastException("cannot bind "+atype+" argument to parameter #"+argnum+" of "+mh.type()); - } -} diff --git a/openjdk/java/lang/invoke/CallSite.java b/openjdk/java/lang/invoke/CallSite.java deleted file mode 100644 index 9b07446a..00000000 --- a/openjdk/java/lang/invoke/CallSite.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (c) 2008, 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. - */ - -/* - * Extensively modified for IKVM.NET by Jeroen Frijters - * Copyright (C) 2011 Jeroen Frijters - */ - -package java.lang.invoke; - -import sun.invoke.empty.Empty; -import sun.misc.Unsafe; -import static java.lang.invoke.MethodHandleStatics.*; -import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; - -/** - * A {@code CallSite} is a holder for a variable {@link MethodHandle}, - * which is called its {@code target}. - * An {@code invokedynamic} instruction linked to a {@code CallSite} delegates - * all calls to the site's current target. - * A {@code CallSite} may be associated with several {@code invokedynamic} - * instructions, or it may be "free floating", associated with none. - * In any case, it may be invoked through an associated method handle - * called its {@linkplain #dynamicInvoker dynamic invoker}. - * <p> - * {@code CallSite} is an abstract class which does not allow - * direct subclassing by users. It has three immediate, - * concrete subclasses that may be either instantiated or subclassed. - * <ul> - * <li>If a mutable target is not required, an {@code invokedynamic} instruction - * may be permanently bound by means of a {@linkplain ConstantCallSite constant call site}. - * <li>If a mutable target is required which has volatile variable semantics, - * because updates to the target must be immediately and reliably witnessed by other threads, - * a {@linkplain VolatileCallSite volatile call site} may be used. - * <li>Otherwise, if a mutable target is required, - * a {@linkplain MutableCallSite mutable call site} may be used. - * </ul> - * <p> - * A non-constant call site may be <em>relinked</em> by changing its target. - * The new target must have the same {@linkplain MethodHandle#type() type} - * as the previous target. - * Thus, though a call site can be relinked to a series of - * successive targets, it cannot change its type. - * <p> - * Here is a sample use of call sites and bootstrap methods which links every - * dynamic call site to print its arguments: -<blockquote><pre><!-- see indy-demo/src/PrintArgsDemo.java --> -static void test() throws Throwable { - // THE FOLLOWING LINE IS PSEUDOCODE FOR A JVM INSTRUCTION - InvokeDynamic[#bootstrapDynamic].baz("baz arg", 2, 3.14); -} -private static void printArgs(Object... args) { - System.out.println(java.util.Arrays.deepToString(args)); -} -private static final MethodHandle printArgs; -static { - MethodHandles.Lookup lookup = MethodHandles.lookup(); - Class thisClass = lookup.lookupClass(); // (who am I?) - printArgs = lookup.findStatic(thisClass, - "printArgs", MethodType.methodType(void.class, Object[].class)); -} -private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String name, MethodType type) { - // ignore caller and name, but match the type: - return new ConstantCallSite(printArgs.asType(type)); -} -</pre></blockquote> - * @author John Rose, JSR 292 EG - */ -abstract -public class CallSite { - - interface IndyCallSite { - void setTarget(Object target); - } - - // The actual payload of this call site: - /*package-private*/ - volatile MethodHandle target; - final IndyCallSite ics; - - /** - * Make a blank call site object with the given method type. - * An initial target method is supplied which will throw - * an {@link IllegalStateException} if called. - * <p> - * Before this {@code CallSite} object is returned from a bootstrap method, - * it is usually provided with a more useful target method, - * via a call to {@link CallSite#setTarget(MethodHandle) setTarget}. - * @throws NullPointerException if the proposed type is null - */ - /*package-private*/ - CallSite(MethodType type) { - this(type.invokers().uninitializedCallSite()); - } - - /** - * Make a call site object equipped with an initial target method handle. - * @param target the method handle which will be the initial target of the call site - * @throws NullPointerException if the proposed target is null - */ - /*package-private*/ - CallSite(MethodHandle target) { - target.getClass(); // null check - ics = createIndyCallSite(target.vmtarget); - setTargetNormal(target); - } - - private static native IndyCallSite createIndyCallSite(Object target); - - final void setTargetNormal(MethodHandle target) { - this.target = target; - ics.setTarget(target.vmtarget); - } - - final void setTargetVolatile(MethodHandle target) { - synchronized(ics) { - setTargetNormal(target); - } - } - - final MethodHandle getTargetVolatile() { - synchronized(ics) { - return target; - } - } - - /** - * Make a call site object equipped with an initial target method handle. - * @param targetType the desired type of the call site - * @param createTargetHook a hook which will bind the call site to the target method handle - * @throws WrongMethodTypeException if the hook cannot be invoked on the required arguments, - * or if the target returned by the hook is not of the given {@code targetType} - * @throws NullPointerException if the hook returns a null value - * @throws ClassCastException if the hook returns something other than a {@code MethodHandle} - * @throws Throwable anything else thrown by the the hook function - */ - /*package-private*/ - CallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable { - this(targetType); - ConstantCallSite selfCCS = (ConstantCallSite) this; - MethodHandle boundTarget = (MethodHandle) createTargetHook.invokeWithArguments(selfCCS); - checkTargetChange(this.target, boundTarget); - setTargetNormal(boundTarget); - } - - /** - * Returns the type of this call site's target. - * Although targets may change, any call site's type is permanent, and can never change to an unequal type. - * The {@code setTarget} method enforces this invariant by refusing any new target that does - * not have the previous target's type. - * @return the type of the current target, which is also the type of any future target - */ - public MethodType type() { - // warning: do not call getTarget here, because CCS.getTarget can throw IllegalStateException - return target.type(); - } - - /** - * Returns the target method of the call site, according to the - * behavior defined by this call site's specific class. - * The immediate subclasses of {@code CallSite} document the - * class-specific behaviors of this method. - * - * @return the current linkage state of the call site, its target method handle - * @see ConstantCallSite - * @see VolatileCallSite - * @see #setTarget - * @see ConstantCallSite#getTarget - * @see MutableCallSite#getTarget - * @see VolatileCallSite#getTarget - */ - public abstract MethodHandle getTarget(); - - /** - * Updates the target method of this call site, according to the - * behavior defined by this call site's specific class. - * The immediate subclasses of {@code CallSite} document the - * class-specific behaviors of this method. - * <p> - * The type of the new target must be {@linkplain MethodType#equals equal to} - * the type of the old target. - * - * @param newTarget the new target - * @throws NullPointerException if the proposed new target is null - * @throws WrongMethodTypeException if the proposed new target - * has a method type that differs from the previous target - * @see CallSite#getTarget - * @see ConstantCallSite#setTarget - * @see MutableCallSite#setTarget - * @see VolatileCallSite#setTarget - */ - public abstract void setTarget(MethodHandle newTarget); - - void checkTargetChange(MethodHandle oldTarget, MethodHandle newTarget) { - MethodType oldType = oldTarget.type(); - MethodType newType = newTarget.type(); // null check! - if (!newType.equals(oldType)) - throw wrongTargetType(newTarget, oldType); - } - - private static WrongMethodTypeException wrongTargetType(MethodHandle target, MethodType type) { - return new WrongMethodTypeException(String.valueOf(target)+" should be of type "+type); - } - - /** - * Produces a method handle equivalent to an invokedynamic instruction - * which has been linked to this call site. - * <p> - * This method is equivalent to the following code: - * <blockquote><pre> - * MethodHandle getTarget, invoker, result; - * getTarget = MethodHandles.publicLookup().bind(this, "getTarget", MethodType.methodType(MethodHandle.class)); - * invoker = MethodHandles.exactInvoker(this.type()); - * result = MethodHandles.foldArguments(invoker, getTarget) - * </pre></blockquote> - * - * @return a method handle which always invokes this call site's current target - */ - public abstract MethodHandle dynamicInvoker(); - - /*non-public*/ MethodHandle makeDynamicInvoker() { - MethodHandle getTarget = MethodHandleImpl.bindReceiver(GET_TARGET, this); - MethodHandle invoker = MethodHandles.exactInvoker(this.type()); - return MethodHandles.foldArguments(invoker, getTarget); - } - - private static final MethodHandle GET_TARGET; - static { - try { - GET_TARGET = IMPL_LOOKUP. - findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class)); - } catch (ReflectiveOperationException ignore) { - throw new InternalError(); - } - } - - /** This guy is rolled into the default target if a MethodType is supplied to the constructor. */ - /*package-private*/ - static Empty uninitializedCallSite() { - throw new IllegalStateException("uninitialized call site"); - } -} diff --git a/openjdk/java/lang/invoke/ConstantCallSite.java b/openjdk/java/lang/invoke/ConstantCallSite.java deleted file mode 100644 index 2d9fedec..00000000 --- a/openjdk/java/lang/invoke/ConstantCallSite.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2010, 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 java.lang.invoke; - -/** - * A {@code ConstantCallSite} is a {@link CallSite} whose target is permanent, and can never be changed. - * An {@code invokedynamic} instruction linked to a {@code ConstantCallSite} is permanently - * bound to the call site's target. - * @author John Rose, JSR 292 EG - */ -public class ConstantCallSite extends CallSite { - private final boolean isFrozen; - - /** - * Creates a call site with a permanent target. - * @param target the target to be permanently associated with this call site - * @throws NullPointerException if the proposed target is null - */ - public ConstantCallSite(MethodHandle target) { - super(target); - isFrozen = true; - } - - /** - * Creates a call site with a permanent target, possibly bound to the call site itself. - * <p> - * During construction of the call site, the {@code createTargetHook} is invoked to - * produce the actual target, as if by a call of the form - * {@code (MethodHandle) createTargetHook.invoke(this)}. - * <p> - * Note that user code cannot perform such an action directly in a subclass constructor, - * since the target must be fixed before the {@code ConstantCallSite} constructor returns. - * <p> - * The hook is said to bind the call site to a target method handle, - * and a typical action would be {@code someTarget.bindTo(this)}. - * However, the hook is free to take any action whatever, - * including ignoring the call site and returning a constant target. - * <p> - * The result returned by the hook must be a method handle of exactly - * the same type as the call site. - * <p> - * While the hook is being called, the new {@code ConstantCallSite} - * object is in a partially constructed state. - * In this state, - * a call to {@code getTarget}, or any other attempt to use the target, - * will result in an {@code IllegalStateException}. - * It is legal at all times to obtain the call site's type using the {@code type} method. - * - * @param targetType the type of the method handle to be permanently associated with this call site - * @param createTargetHook a method handle to invoke (on the call site) to produce the call site's target - * @throws WrongMethodTypeException if the hook cannot be invoked on the required arguments, - * or if the target returned by the hook is not of the given {@code targetType} - * @throws NullPointerException if the hook returns a null value - * @throws ClassCastException if the hook returns something other than a {@code MethodHandle} - * @throws Throwable anything else thrown by the the hook function - */ - protected ConstantCallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable { - super(targetType, createTargetHook); - isFrozen = true; - } - - /** - * Returns the target method of the call site, which behaves - * like a {@code final} field of the {@code ConstantCallSite}. - * That is, the the target is always the original value passed - * to the constructor call which created this instance. - * - * @return the immutable linkage state of this call site, a constant method handle - * @throws IllegalStateException if the {@code ConstantCallSite} constructor has not completed - */ - @Override public final MethodHandle getTarget() { - if (!isFrozen) throw new IllegalStateException(); - return target; - } - - /** - * Always throws an {@link UnsupportedOperationException}. - * This kind of call site cannot change its target. - * @param ignore a new target proposed for the call site, which is ignored - * @throws UnsupportedOperationException because this kind of call site cannot change its target - */ - @Override public final void setTarget(MethodHandle ignore) { - throw new UnsupportedOperationException(); - } - - /** - * Returns this call site's permanent target. - * Since that target will never change, this is a correct implementation - * of {@link CallSite#dynamicInvoker CallSite.dynamicInvoker}. - * @return the immutable linkage state of this call site, a constant method handle - * @throws IllegalStateException if the {@code ConstantCallSite} constructor has not completed - */ - @Override - public final MethodHandle dynamicInvoker() { - return getTarget(); - } -} diff --git a/openjdk/java/lang/invoke/DirectMethodHandle.java b/openjdk/java/lang/invoke/DirectMethodHandle.java deleted file mode 100644 index 23a55dce..00000000 --- a/openjdk/java/lang/invoke/DirectMethodHandle.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2008, 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 java.lang.invoke; - -/** - * The flavor of method handle which emulates invokespecial or invokestatic. - * @author jrose - */ -class DirectMethodHandle extends MethodHandle { - //inherited oop vmtarget; // methodOop or virtual class/interface oop - - // Constructors in this class *must* be package scoped or private. - DirectMethodHandle(MethodType mtype, MemberName m, boolean doDispatch, Class<?> lookupClass) { - super(mtype); - - assert(m.isMethod() || !doDispatch && m.isConstructor()); - if (!m.isResolved()) - throw new InternalError(); - - vmtarget = createDelegate(mtype, m, doDispatch, lookupClass); - } - - private static native Object createDelegate(MethodType type, MemberName m, boolean doDispatch, Class<?> lookupClass); - - boolean isValid() { - return vmtarget != null; - } -} diff --git a/openjdk/java/lang/invoke/MethodHandleImpl.java b/openjdk/java/lang/invoke/MethodHandleImpl.java deleted file mode 100644 index 76c41aa0..00000000 --- a/openjdk/java/lang/invoke/MethodHandleImpl.java +++ /dev/null @@ -1,740 +0,0 @@ -/* - * Copyright (c) 2008, 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. - */ - -/* - * Extensively modified for IKVM.NET by Jeroen Frijters - * Copyright (C) 2011 Jeroen Frijters - */ - -package java.lang.invoke; - -import sun.invoke.util.VerifyType; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import sun.invoke.empty.Empty; -import sun.invoke.util.ValueConversions; -import sun.invoke.util.Wrapper; -import sun.misc.Unsafe; -import static java.lang.invoke.MethodHandleStatics.*; -import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; - -/** - * Trusted implementation code for MethodHandle. - * @author jrose - */ -/*non-public*/ abstract class MethodHandleImpl { - /// Factory methods to create method handles: - - private static final MemberName.Factory LOOKUP = MemberName.Factory.INSTANCE; - - static void initStatics() { - // Trigger preceding sequence. - } - - /** Look up a given method. - * Callable only from sun.invoke and related packages. - * <p> - * The resulting method handle type will be of the given type, - * with a receiver type {@code rcvc} prepended if the member is not static. - * <p> - * Access checks are made as of the given lookup class. - * In particular, if the method is protected and {@code defc} is in a - * different package from the lookup class, then {@code rcvc} must be - * the lookup class or a subclass. - * @param token Proof that the lookup class has access to this package. - * @param member Resolved method or constructor to call. - * @param name Name of the desired method. - * @param rcvc Receiver type of desired non-static method (else null) - * @param doDispatch whether the method handle will test the receiver type - * @param lookupClass access-check relative to this class - * @return a direct handle to the matching method - * @throws IllegalAccessException if the given method cannot be accessed by the lookup class - */ - static - MethodHandle findMethod(MemberName method, - boolean doDispatch, Class<?> lookupClass) throws IllegalAccessException { - MethodType mtype = method.getMethodType(); - if (!method.isStatic()) { - // adjust the advertised receiver type to be exactly the one requested - // (in the case of invokespecial, this will be the calling class) - Class<?> recvType = method.getDeclaringClass(); - mtype = mtype.insertParameterTypes(0, recvType); - } - DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, lookupClass); - if (!mh.isValid()) - throw method.makeAccessException("no direct method handle", lookupClass); - assert(mh.type() == mtype); - if (!method.isVarargs()) - return mh; - int argc = mtype.parameterCount(); - if (argc != 0) { - Class<?> arrayType = mtype.parameterType(argc-1); - if (arrayType.isArray()) - return AdapterMethodHandle.makeVarargsCollector(mh, arrayType); - } - throw method.makeAccessException("cannot make variable arity", null); - } - - static - MethodHandle makeAllocator(MethodHandle rawConstructor) { - MethodType rawConType = rawConstructor.type(); - Class<?> allocateClass = rawConType.parameterType(0); - // Wrap the raw (unsafe) constructor with the allocation of a suitable object. - // allocator(arg...) - // [fold]=> cookedConstructor(obj=allocate(C), arg...) - // [dup,collect]=> identity(obj, void=rawConstructor(obj, arg...)) - MethodHandle returner = MethodHandles.identity(allocateClass); - MethodType ctype = rawConType.insertParameterTypes(0, allocateClass).changeReturnType(allocateClass); - MethodHandle cookedConstructor = AdapterMethodHandle.makeCollectArguments(returner, rawConstructor, 1, false); - assert(cookedConstructor.type().equals(ctype)); - ctype = ctype.dropParameterTypes(0, 1); - cookedConstructor = AdapterMethodHandle.makeCollectArguments(cookedConstructor, returner, 0, true); - MethodHandle allocator = new AllocateObject(allocateClass); - // allocate() => new C(void) - assert(allocator.type().equals(MethodType.methodType(allocateClass))); - ctype = ctype.dropParameterTypes(0, 1); - MethodHandle fold = foldArguments(cookedConstructor, ctype, 0, allocator); - return fold; - } - - static final class AllocateObject<C> extends BoundMethodHandle { - private static final Unsafe unsafe = Unsafe.getUnsafe(); - - private final Class<C> allocateClass; - - // for allocation only: - private AllocateObject(Class<C> allocateClass) { - super(ALLOCATE.asType(MethodType.methodType(allocateClass, AllocateObject.class))); - this.allocateClass = allocateClass; - } - @SuppressWarnings("unchecked") - private C allocate() throws InstantiationException { - return (C) unsafe.allocateInstance(allocateClass); - } - static final MethodHandle ALLOCATE; - static { - try { - ALLOCATE = IMPL_LOOKUP.findVirtual(AllocateObject.class, "allocate", MethodType.genericMethodType(0)); - } catch (ReflectiveOperationException ex) { - throw uncaughtException(ex); - } - } - } - - static - MethodHandle accessField(MemberName member, boolean isSetter, - Class<?> lookupClass) { - // Use sun. misc.Unsafe to dig up the dirt on the field. - MethodHandle mh = new FieldAccessor(member, isSetter); - return mh; - } - - static - MethodHandle accessArrayElement(Class<?> arrayClass, boolean isSetter) { - if (!arrayClass.isArray()) - throw newIllegalArgumentException("not an array: "+arrayClass); - Class<?> elemClass = arrayClass.getComponentType(); - MethodHandle[] mhs = FieldAccessor.ARRAY_CACHE.get(elemClass); - if (mhs == null) { - if (!FieldAccessor.doCache(elemClass)) - return FieldAccessor.ahandle(arrayClass, isSetter); - mhs = new MethodHandle[] { - FieldAccessor.ahandle(arrayClass, false), - FieldAccessor.ahandle(arrayClass, true) - }; - if (mhs[0].type().parameterType(0) == Class.class) { - mhs[0] = mhs[0].bindTo(elemClass); - mhs[1] = mhs[1].bindTo(elemClass); - } - synchronized (FieldAccessor.ARRAY_CACHE) {} // memory barrier - FieldAccessor.ARRAY_CACHE.put(elemClass, mhs); - } - return mhs[isSetter ? 1 : 0]; - } - - static final class FieldAccessor<C,V> extends BoundMethodHandle { - private static final Unsafe unsafe = Unsafe.getUnsafe(); - final Object base; // for static refs only - final long offset; - final String name; - - FieldAccessor(MemberName field, boolean isSetter) { - super(fhandle(field.getDeclaringClass(), field.getFieldType(), isSetter, field.isStatic())); - this.offset = fieldOffset(field); - this.name = field.getName(); - this.base = null; - } - @Override - String debugString() { return addTypeString(name, this); } - - int getFieldI(C obj) { return unsafe.getInt(obj, offset); } - void setFieldI(C obj, int x) { unsafe.putInt(obj, offset, x); } - long getFieldJ(C obj) { return unsafe.getLong(obj, offset); } - void setFieldJ(C obj, long x) { unsafe.putLong(obj, offset, x); } - float getFieldF(C obj) { return unsafe.getFloat(obj, offset); } - void setFieldF(C obj, float x) { unsafe.putFloat(obj, offset, x); } - double getFieldD(C obj) { return unsafe.getDouble(obj, offset); } - void setFieldD(C obj, double x) { unsafe.putDouble(obj, offset, x); } - boolean getFieldZ(C obj) { return unsafe.getBoolean(obj, offset); } - void setFieldZ(C obj, boolean x) { unsafe.putBoolean(obj, offset, x); } - byte getFieldB(C obj) { return unsafe.getByte(obj, offset); } - void setFieldB(C obj, byte x) { unsafe.putByte(obj, offset, x); } - short getFieldS(C obj) { return unsafe.getShort(obj, offset); } - void setFieldS(C obj, short x) { unsafe.putShort(obj, offset, x); } - char getFieldC(C obj) { return unsafe.getChar(obj, offset); } - void setFieldC(C obj, char x) { unsafe.putChar(obj, offset, x); } - @SuppressWarnings("unchecked") - V getFieldL(C obj) { return (V) unsafe.getObject(obj, offset); } - @SuppressWarnings("unchecked") - void setFieldL(C obj, V x) { unsafe.putObject(obj, offset, x); } - // cast (V) is OK here, since we wrap convertArguments around the MH. - - static Integer fieldOffset(final MemberName field) { - return AccessController.doPrivileged(new PrivilegedAction<Integer>() { - public Integer run() { - try { - Class c = field.getDeclaringClass(); - // FIXME: Should not have to create 'f' to get this value. - java.lang.reflect.Field f = c.getDeclaredField(field.getName()); - return unsafe.fieldOffset(f); - } catch (NoSuchFieldException ee) { - throw uncaughtException(ee); - } - } - }); - } - - int getStaticI() { return unsafe.getInt(base, offset); } - void setStaticI(int x) { unsafe.putInt(base, offset, x); } - long getStaticJ() { return unsafe.getLong(base, offset); } - void setStaticJ(long x) { unsafe.putLong(base, offset, x); } - float getStaticF() { return unsafe.getFloat(base, offset); } - void setStaticF(float x) { unsafe.putFloat(base, offset, x); } - double getStaticD() { return unsafe.getDouble(base, offset); } - void setStaticD(double x) { unsafe.putDouble(base, offset, x); } - boolean getStaticZ() { return unsafe.getBoolean(base, offset); } - void setStaticZ(boolean x) { unsafe.putBoolean(base, offset, x); } - byte getStaticB() { return unsafe.getByte(base, offset); } - void setStaticB(byte x) { unsafe.putByte(base, offset, x); } - short getStaticS() { return unsafe.getShort(base, offset); } - void setStaticS(short x) { unsafe.putShort(base, offset, x); } - char getStaticC() { return unsafe.getChar(base, offset); } - void setStaticC(char x) { unsafe.putChar(base, offset, x); } - V getStaticL() { return (V) unsafe.getObject(base, offset); } - void setStaticL(V x) { unsafe.putObject(base, offset, x); } - - static String fname(Class<?> vclass, boolean isSetter, boolean isStatic) { - String stem; - if (!isStatic) - stem = (!isSetter ? "getField" : "setField"); - else - stem = (!isSetter ? "getStatic" : "setStatic"); - return stem + Wrapper.basicTypeChar(vclass); - } - static MethodType ftype(Class<?> cclass, Class<?> vclass, boolean isSetter, boolean isStatic) { - MethodType type; - if (!isStatic) { - if (!isSetter) - return MethodType.methodType(vclass, cclass); - else - return MethodType.methodType(void.class, cclass, vclass); - } else { - if (!isSetter) - return MethodType.methodType(vclass); - else - return MethodType.methodType(void.class, vclass); - } - } - static MethodHandle fhandle(Class<?> cclass, Class<?> vclass, boolean isSetter, boolean isStatic) { - String name = FieldAccessor.fname(vclass, isSetter, isStatic); - if (cclass.isPrimitive()) throw newIllegalArgumentException("primitive "+cclass); - Class<?> ecclass = Object.class; //erase this type - Class<?> evclass = vclass; - if (!evclass.isPrimitive()) evclass = Object.class; - MethodType type = FieldAccessor.ftype(ecclass, evclass, isSetter, isStatic); - MethodHandle mh; - try { - mh = IMPL_LOOKUP.findVirtual(FieldAccessor.class, name, type); - } catch (ReflectiveOperationException ex) { - throw uncaughtException(ex); - } - if (evclass != vclass || (!isStatic && ecclass != cclass)) { - MethodType strongType = FieldAccessor.ftype(cclass, vclass, isSetter, isStatic); - strongType = strongType.insertParameterTypes(0, FieldAccessor.class); - mh = convertArguments(mh, strongType, 0); - } - return mh; - } - - /// Support for array element access - static final HashMap<Class<?>, MethodHandle[]> ARRAY_CACHE = - new HashMap<Class<?>, MethodHandle[]>(); - // FIXME: Cache on the classes themselves, not here. - static boolean doCache(Class<?> elemClass) { - if (elemClass.isPrimitive()) return true; - ClassLoader cl = elemClass.getClassLoader(); - return cl == null || cl == ClassLoader.getSystemClassLoader(); - } - static int getElementI(int[] a, int i) { return a[i]; } - static void setElementI(int[] a, int i, int x) { a[i] = x; } - static long getElementJ(long[] a, int i) { return a[i]; } - static void setElementJ(long[] a, int i, long x) { a[i] = x; } - static float getElementF(float[] a, int i) { return a[i]; } - static void setElementF(float[] a, int i, float x) { a[i] = x; } - static double getElementD(double[] a, int i) { return a[i]; } - static void setElementD(double[] a, int i, double x) { a[i] = x; } - static boolean getElementZ(boolean[] a, int i) { return a[i]; } - static void setElementZ(boolean[] a, int i, boolean x) { a[i] = x; } - static byte getElementB(byte[] a, int i) { return a[i]; } - static void setElementB(byte[] a, int i, byte x) { a[i] = x; } - static short getElementS(short[] a, int i) { return a[i]; } - static void setElementS(short[] a, int i, short x) { a[i] = x; } - static char getElementC(char[] a, int i) { return a[i]; } - static void setElementC(char[] a, int i, char x) { a[i] = x; } - static Object getElementL(Object[] a, int i) { return a[i]; } - static void setElementL(Object[] a, int i, Object x) { a[i] = x; } - static <V> V getElementL(Class<V[]> aclass, V[] a, int i) { return aclass.cast(a)[i]; } - static <V> void setElementL(Class<V[]> aclass, V[] a, int i, V x) { aclass.cast(a)[i] = x; } - - static String aname(Class<?> aclass, boolean isSetter) { - Class<?> vclass = aclass.getComponentType(); - if (vclass == null) throw new IllegalArgumentException(); - return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(vclass); - } - static MethodType atype(Class<?> aclass, boolean isSetter) { - Class<?> vclass = aclass.getComponentType(); - if (!isSetter) - return MethodType.methodType(vclass, aclass, int.class); - else - return MethodType.methodType(void.class, aclass, int.class, vclass); - } - static MethodHandle ahandle(Class<?> aclass, boolean isSetter) { - Class<?> vclass = aclass.getComponentType(); - String name = FieldAccessor.aname(aclass, isSetter); - Class<?> caclass = null; - if (!vclass.isPrimitive() && vclass != Object.class) { - caclass = aclass; - aclass = Object[].class; - vclass = Object.class; - } - MethodType type = FieldAccessor.atype(aclass, isSetter); - if (caclass != null) - type = type.insertParameterTypes(0, Class.class); - MethodHandle mh; - try { - mh = IMPL_LOOKUP.findStatic(FieldAccessor.class, name, type); - } catch (ReflectiveOperationException ex) { - throw uncaughtException(ex); - } - if (caclass != null) { - MethodType strongType = FieldAccessor.atype(caclass, isSetter); - mh = mh.bindTo(caclass); - mh = convertArguments(mh, strongType, 0); - } - return mh; - } - } - - /** Bind a predetermined first argument to the given direct method handle. - * Callable only from MethodHandles. - * @param token Proof that the caller has access to this package. - * @param target Any direct method handle. - * @param receiver Receiver (or first static method argument) to pre-bind. - * @return a BoundMethodHandle for the given DirectMethodHandle, or null if it does not exist - */ - static - MethodHandle bindReceiver(MethodHandle target, Object receiver) { - if (receiver == null) return null; - return new BoundMethodHandle(target, receiver, 0); - } - - /** Bind a predetermined argument to the given arbitrary method handle. - * Callable only from MethodHandles. - * @param token Proof that the caller has access to this package. - * @param target Any method handle. - * @param receiver Argument (which can be a boxed primitive) to pre-bind. - * @return a suitable BoundMethodHandle - */ - static - MethodHandle bindArgument(MethodHandle target, int argnum, Object receiver) { - return new BoundMethodHandle(target, receiver, argnum); - } - - static native MethodHandle permuteArguments(MethodHandle target, - MethodType newType, - MethodType oldType, - int[] permutationOrNull); - - /*non-public*/ static - MethodHandle convertArguments(MethodHandle target, MethodType newType, int level) { - MethodType oldType = target.type(); - if (oldType.equals(newType)) - return target; - assert(level > 1 || oldType.isConvertibleTo(newType)); - MethodHandle retFilter = null; - Class<?> oldRT = oldType.returnType(); - Class<?> newRT = newType.returnType(); - if (!VerifyType.isNullConversion(oldRT, newRT)) { - if (oldRT == void.class) { - Wrapper wrap = newRT.isPrimitive() ? Wrapper.forPrimitiveType(newRT) : Wrapper.OBJECT; - retFilter = ValueConversions.zeroConstantFunction(wrap); - } else { - retFilter = MethodHandles.identity(newRT); - retFilter = convertArguments(retFilter, retFilter.type().changeParameterType(0, oldRT), level); - } - newType = newType.changeReturnType(oldRT); - } - MethodHandle res = null; - Exception ex = null; - try { - res = convertArguments(target, newType, oldType, level); - } catch (IllegalArgumentException ex1) { - ex = ex1; - } - if (res == null) { - WrongMethodTypeException wmt = new WrongMethodTypeException("cannot convert to "+newType+": "+target); - wmt.initCause(ex); - throw wmt; - } - if (retFilter != null) - res = MethodHandles.filterReturnValue(res, retFilter); - return res; - } - - static MethodHandle convertArguments(MethodHandle target, - MethodType newType, - MethodType oldType, - int level) { - assert(oldType.parameterCount() == target.type().parameterCount()); - if (newType == oldType) - return target; - if (oldType.parameterCount() != newType.parameterCount()) - throw newIllegalArgumentException("mismatched parameter count", oldType, newType); - return AdapterMethodHandle.makePairwiseConvert(newType, target, level); - } - - static MethodHandle spreadArguments(MethodHandle target, Class<?> arrayType, int arrayLength) { - MethodType oldType = target.type(); - int nargs = oldType.parameterCount(); - int keepPosArgs = nargs - arrayLength; - MethodType newType = oldType - .dropParameterTypes(keepPosArgs, nargs) - .insertParameterTypes(keepPosArgs, arrayType); - return spreadArguments(target, newType, keepPosArgs, arrayType, arrayLength); - } - // called internally only - static MethodHandle spreadArgumentsFromPos(MethodHandle target, MethodType newType, int spreadArgPos) { - int arrayLength = target.type().parameterCount() - spreadArgPos; - return spreadArguments(target, newType, spreadArgPos, Object[].class, arrayLength); - } - static MethodHandle spreadArguments(MethodHandle target, - MethodType newType, - int spreadArgPos, - Class<?> arrayType, - int arrayLength) { - // TO DO: maybe allow the restarg to be Object and implicitly cast to Object[] - MethodType oldType = target.type(); - // spread the last argument of newType to oldType - assert(arrayLength == oldType.parameterCount() - spreadArgPos); - assert(newType.parameterType(spreadArgPos) == arrayType); - return AdapterMethodHandle.makeSpreadArguments(newType, target, arrayType, spreadArgPos, arrayLength); - } - - static MethodHandle collectArguments(MethodHandle target, - int collectArg, - MethodHandle collector) { - MethodType type = target.type(); - Class<?> collectType = collector.type().returnType(); - assert(collectType != void.class); // else use foldArguments - if (collectType != type.parameterType(collectArg)) - target = target.asType(type.changeParameterType(collectArg, collectType)); - MethodType newType = type - .dropParameterTypes(collectArg, collectArg+1) - .insertParameterTypes(collectArg, collector.type().parameterArray()); - return collectArguments(target, newType, collectArg, collector); - } - static MethodHandle collectArguments(MethodHandle target, - MethodType newType, - int collectArg, - MethodHandle collector) { - MethodType oldType = target.type(); // (a...,c)=>r - // newType // (a..., b...)=>r - MethodType colType = collector.type(); // (b...)=>c - // oldType // (a..., b...)=>r - assert(newType.parameterCount() == collectArg + colType.parameterCount()); - assert(oldType.parameterCount() == collectArg + 1); - return AdapterMethodHandle.makeCollectArguments(target, collector, collectArg, false); - } - - static MethodHandle filterArgument(MethodHandle target, - int pos, - MethodHandle filter) { - MethodType ttype = target.type(); - MethodType ftype = filter.type(); - assert(ftype.parameterCount() == 1); - return AdapterMethodHandle.makeCollectArguments(target, filter, pos, false); - } - - static MethodHandle foldArguments(MethodHandle target, - MethodType newType, - int foldPos, - MethodHandle combiner) { - MethodType oldType = target.type(); - MethodType ctype = combiner.type(); - return AdapterMethodHandle.makeCollectArguments(target, combiner, foldPos, true); - } - - static - MethodHandle dropArguments(MethodHandle target, - MethodType newType, int argnum) { - int drops = newType.parameterCount() - target.type().parameterCount(); - return AdapterMethodHandle.makeDropArguments(newType, target, argnum, drops); - } - - static - MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) { - return testResult ? target : fallback; - } - - static MethodHandle SELECT_ALTERNATIVE; - static MethodHandle selectAlternative() { - if (SELECT_ALTERNATIVE != null) return SELECT_ALTERNATIVE; - try { - SELECT_ALTERNATIVE - = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "selectAlternative", - MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)); - } catch (ReflectiveOperationException ex) { - throw new RuntimeException(ex); - } - return SELECT_ALTERNATIVE; - } - - static - MethodHandle makeGuardWithTest(MethodHandle test, - MethodHandle target, - MethodHandle fallback) { - // gwt(arg...) - // [fold]=> continueAfterTest(z=test(arg...), arg...) - // [filter]=> (tf=select(z))(arg...) - // where select(z) = select(z, t, f).bindTo(t, f) => z ? t f - // [tailcall]=> tf(arg...) - assert(test.type().returnType() == boolean.class); - MethodType targetType = target.type(); - MethodType foldTargetType = targetType.insertParameterTypes(0, boolean.class); - // working backwards, as usual: - assert(target.type().equals(fallback.type())); - MethodHandle tailcall = MethodHandles.exactInvoker(target.type()); - MethodHandle select = selectAlternative(); - select = bindArgument(select, 2, fallback); - select = bindArgument(select, 1, target); - // select(z: boolean) => (z ? target : fallback) - MethodHandle filter = filterArgument(tailcall, 0, select); - assert(filter.type().parameterType(0) == boolean.class); - MethodHandle fold = foldArguments(filter, filter.type().dropParameterTypes(0, 1), 0, test); - return fold; - } - - private static class GuardWithCatch extends BoundMethodHandle { - private final MethodHandle target; - private final Class<? extends Throwable> exType; - private final MethodHandle catcher; - GuardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) { - this(INVOKES[target.type().parameterCount()], target, exType, catcher); - } - // FIXME: Build the control flow out of foldArguments. - GuardWithCatch(MethodHandle invoker, - MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) { - super(invoker); - this.target = target; - this.exType = exType; - this.catcher = catcher; - } - @Override - String debugString() { - return addTypeString(target, this); - } - private Object invoke_V(Object... av) throws Throwable { - try { - return target.invokeExact(av); - } catch (Throwable t) { - if (!exType.isInstance(t)) throw t; - return catcher.invokeExact(t, av); - } - } - private Object invoke_L0() throws Throwable { - try { - return target.invokeExact(); - } catch (Throwable t) { - if (!exType.isInstance(t)) throw t; - return catcher.invokeExact(t); - } - } - private Object invoke_L1(Object a0) throws Throwable { - try { - return target.invokeExact(a0); - } catch (Throwable t) { - if (!exType.isInstance(t)) throw t; - return catcher.invokeExact(t, a0); - } - } - private Object invoke_L2(Object a0, Object a1) throws Throwable { - try { - return target.invokeExact(a0, a1); - } catch (Throwable t) { - if (!exType.isInstance(t)) throw t; - return catcher.invokeExact(t, a0, a1); - } - } - private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable { - try { - return target.invokeExact(a0, a1, a2); - } catch (Throwable t) { - if (!exType.isInstance(t)) throw t; - return catcher.invokeExact(t, a0, a1, a2); - } - } - private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable { - try { - return target.invokeExact(a0, a1, a2, a3); - } catch (Throwable t) { - if (!exType.isInstance(t)) throw t; - return catcher.invokeExact(t, a0, a1, a2, a3); - } - } - private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { - try { - return target.invokeExact(a0, a1, a2, a3, a4); - } catch (Throwable t) { - if (!exType.isInstance(t)) throw t; - return catcher.invokeExact(t, a0, a1, a2, a3, a4); - } - } - private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { - try { - return target.invokeExact(a0, a1, a2, a3, a4, a5); - } catch (Throwable t) { - if (!exType.isInstance(t)) throw t; - return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5); - } - } - private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { - try { - return target.invokeExact(a0, a1, a2, a3, a4, a5, a6); - } catch (Throwable t) { - if (!exType.isInstance(t)) throw t; - return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6); - } - } - private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { - try { - return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7); - } catch (Throwable t) { - if (!exType.isInstance(t)) throw t; - return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6, a7); - } - } - static MethodHandle[] makeInvokes() { - ArrayList<MethodHandle> invokes = new ArrayList<MethodHandle>(); - MethodHandles.Lookup lookup = IMPL_LOOKUP; - for (;;) { - int nargs = invokes.size(); - String name = "invoke_L"+nargs; - MethodHandle invoke = null; - try { - invoke = lookup.findVirtual(GuardWithCatch.class, name, MethodType.genericMethodType(nargs)); - } catch (ReflectiveOperationException ex) { - } - if (invoke == null) break; - invokes.add(invoke); - } - assert(invokes.size() == 9); // current number of methods - return invokes.toArray(new MethodHandle[0]); - }; - static final MethodHandle[] INVOKES = makeInvokes(); - // For testing use this: - //static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2); - static final MethodHandle VARARGS_INVOKE; - static { - try { - VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(GuardWithCatch.class, "invoke_V", MethodType.genericMethodType(0, true)); - } catch (ReflectiveOperationException ex) { - throw uncaughtException(ex); - } - } - } - - - static - MethodHandle makeGuardWithCatch(MethodHandle target, - Class<? extends Throwable> exType, - MethodHandle catcher) { - MethodType type = target.type(); - MethodType ctype = catcher.type(); - int nargs = type.parameterCount(); - if (nargs < GuardWithCatch.INVOKES.length) { - MethodType gtype = type.generic(); - MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class); - // Note: convertArguments(...2) avoids interface casts present in convertArguments(...0) - MethodHandle gtarget = convertArguments(target, gtype, type, 2); - MethodHandle gcatcher = convertArguments(catcher, gcatchType, ctype, 2); - MethodHandle gguard = new GuardWithCatch(gtarget, exType, gcatcher); - if (gtarget == null || gcatcher == null || gguard == null) return null; - return convertArguments(gguard, type, gtype, 2); - } else { - MethodType gtype = MethodType.genericMethodType(0, true); - MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class); - MethodHandle gtarget = spreadArgumentsFromPos(target, gtype, 0); - catcher = catcher.asType(ctype.changeParameterType(0, Throwable.class)); - MethodHandle gcatcher = spreadArgumentsFromPos(catcher, gcatchType, 1); - MethodHandle gguard = new GuardWithCatch(GuardWithCatch.VARARGS_INVOKE, gtarget, exType, gcatcher); - if (gtarget == null || gcatcher == null || gguard == null) return null; - return collectArguments(gguard, type, 0, ValueConversions.varargsArray(nargs)).asType(type); - } - } - - static - MethodHandle throwException(MethodType type) { - return AdapterMethodHandle.makeRetypeRaw(type, throwException()); - } - - static MethodHandle THROW_EXCEPTION; - static MethodHandle throwException() { - if (THROW_EXCEPTION != null) return THROW_EXCEPTION; - try { - THROW_EXCEPTION - = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException", - MethodType.methodType(Empty.class, Throwable.class)); - } catch (ReflectiveOperationException ex) { - throw new RuntimeException(ex); - } - return THROW_EXCEPTION; - } - static <T extends Throwable> Empty throwException(T t) throws T { throw t; } -} diff --git a/openjdk/java/lang/invoke/MethodHandleNatives.java b/openjdk/java/lang/invoke/MethodHandleNatives.java deleted file mode 100644 index 4f7da894..00000000 --- a/openjdk/java/lang/invoke/MethodHandleNatives.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (c) 2008, 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. - */ - -/* - * Extensively modified for IKVM.NET by Jeroen Frijters - * Copyright (C) 2011 Jeroen Frijters - */ - -package java.lang.invoke; - -import java.lang.invoke.MethodHandles.Lookup; -import java.lang.reflect.AccessibleObject; -import java.lang.reflect.Field; -import static java.lang.invoke.MethodHandleNatives.Constants.*; -import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; - -/** - * The JVM interface for the method handles package is all here. - * This is an interface internal and private to an implemetantion of JSR 292. - * <em>This class is not part of the JSR 292 standard.</em> - * @author jrose - */ -class MethodHandleNatives { - - private MethodHandleNatives() { } // static only - - /// MethodName support - - static native void init(MemberName self, Object ref); - static native void expand(MemberName self); - static native void resolve(MemberName self, Class<?> caller); - static native int getMembers(Class<?> defc, String matchName, String matchSig, - int matchFlags, Class<?> caller, int skip, MemberName[] results); - - /** Initialize a method type, once per form. */ - static void init(MethodType self) { } - - /** Fetch the name of the handled method, if available. - * This routine is for debugging and reflection. - */ - static MemberName getMethodName(MethodHandle self) { - throw new ikvm.internal.NotYetImplementedError(); - } - - static Object[] makeTarget(Class<?> defc, String name, String sig, int mods, Class<?> refc) { - return new Object[] { defc, name, sig, mods, refc }; - } - - /** Java copy of MethodHandlePushLimit in range 2..255. */ - static final int JVM_PUSH_LIMIT; - /** JVM stack motion (in words) after one slot is pushed, usually -1. - */ - static final int JVM_STACK_MOVE_UNIT; - - /** Which conv-ops are implemented by the JVM? */ - static final int CONV_OP_IMPLEMENTED_MASK; - /** Derived mode flag. Only false on some old JVM implementations. */ - static final boolean HAVE_RICOCHET_FRAMES; - - static final int OP_ROT_ARGS_DOWN_LIMIT_BIAS; - - static { - int k; - JVM_PUSH_LIMIT = 3; - JVM_STACK_MOVE_UNIT = 1; - k = 0; - CONV_OP_IMPLEMENTED_MASK = (k != 0) ? k : DEFAULT_CONV_OP_IMPLEMENTED_MASK; - k = 0; - OP_ROT_ARGS_DOWN_LIMIT_BIAS = (k != 0) ? (byte)k : -1; - HAVE_RICOCHET_FRAMES = (CONV_OP_IMPLEMENTED_MASK & (1<<OP_COLLECT_ARGS)) != 0; - //sun.reflect.Reflection.registerMethodsToFilter(MethodHandleImpl.class, "init"); - } - - // All compile-time constants go here. - // There is an opportunity to check them against the JVM's idea of them. - static class Constants { - Constants() { } // static only - // MethodHandleImpl - static final int // for getConstant - GC_JVM_PUSH_LIMIT = 0, - GC_JVM_STACK_MOVE_UNIT = 1, - GC_CONV_OP_IMPLEMENTED_MASK = 2, - GC_OP_ROT_ARGS_DOWN_LIMIT_BIAS = 3; - static final int - ETF_HANDLE_OR_METHOD_NAME = 0, // all available data (immediate MH or method) - ETF_DIRECT_HANDLE = 1, // ultimate method handle (will be a DMH, may be self) - ETF_METHOD_NAME = 2, // ultimate method as MemberName - ETF_REFLECT_METHOD = 3; // ultimate method as java.lang.reflect object (sans refClass) - - // MemberName - // The JVM uses values of -2 and above for vtable indexes. - // Field values are simple positive offsets. - // Ref: src/share/vm/oops/methodOop.hpp - // This value is negative enough to avoid such numbers, - // but not too negative. - static final int - MN_IS_METHOD = 0x00010000, // method (not constructor) - MN_IS_CONSTRUCTOR = 0x00020000, // constructor - MN_IS_FIELD = 0x00040000, // field - MN_IS_TYPE = 0x00080000, // nested type - MN_SEARCH_SUPERCLASSES = 0x00100000, // for MHN.getMembers - MN_SEARCH_INTERFACES = 0x00200000, // for MHN.getMembers - VM_INDEX_UNINITIALIZED = -99; - - // BoundMethodHandle - /** Constants for decoding the vmargslot field, which contains 2 values. */ - static final int - ARG_SLOT_PUSH_SHIFT = 16, - ARG_SLOT_MASK = (1<<ARG_SLOT_PUSH_SHIFT)-1; - - // AdapterMethodHandle - /** Conversions recognized by the JVM. - * They must align with the constants in java.lang.invoke.AdapterMethodHandle, - * in the JVM file hotspot/src/share/vm/classfile/javaClasses.hpp. - */ - static final int - OP_RETYPE_ONLY = 0x0, // no argument changes; straight retype - OP_RETYPE_RAW = 0x1, // straight retype, trusted (void->int, Object->T) - OP_CHECK_CAST = 0x2, // ref-to-ref conversion; requires a Class argument - OP_PRIM_TO_PRIM = 0x3, // converts from one primitive to another - OP_REF_TO_PRIM = 0x4, // unboxes a wrapper to produce a primitive - OP_PRIM_TO_REF = 0x5, // boxes a primitive into a wrapper - OP_SWAP_ARGS = 0x6, // swap arguments (vminfo is 2nd arg) - OP_ROT_ARGS = 0x7, // rotate arguments (vminfo is displaced arg) - OP_DUP_ARGS = 0x8, // duplicates one or more arguments (at TOS) - OP_DROP_ARGS = 0x9, // remove one or more argument slots - OP_COLLECT_ARGS = 0xA, // combine arguments using an auxiliary function - OP_SPREAD_ARGS = 0xB, // expand in place a varargs array (of known size) - OP_FOLD_ARGS = 0xC, // combine but do not remove arguments; prepend result - //OP_UNUSED_13 = 0xD, // unused code, perhaps for reified argument lists - CONV_OP_LIMIT = 0xE; // limit of CONV_OP enumeration - /** Shift and mask values for decoding the AMH.conversion field. - * These numbers are shared with the JVM for creating AMHs. - */ - static final int - CONV_OP_MASK = 0xF00, // this nybble contains the conversion op field - CONV_TYPE_MASK = 0x0F, // fits T_ADDRESS and below - CONV_VMINFO_MASK = 0x0FF, // LSB is reserved for JVM use - CONV_VMINFO_SHIFT = 0, // position of bits in CONV_VMINFO_MASK - CONV_OP_SHIFT = 8, // position of bits in CONV_OP_MASK - CONV_DEST_TYPE_SHIFT = 12, // byte 2 has the adapter BasicType (if needed) - CONV_SRC_TYPE_SHIFT = 16, // byte 2 has the source BasicType (if needed) - CONV_STACK_MOVE_SHIFT = 20, // high 12 bits give signed SP change - CONV_STACK_MOVE_MASK = (1 << (32 - CONV_STACK_MOVE_SHIFT)) - 1; - - /** Which conv-ops are implemented by the JVM? */ - static final int DEFAULT_CONV_OP_IMPLEMENTED_MASK = - // Value to use if the corresponding JVM query fails. - ((1<<OP_RETYPE_ONLY) - |(1<<OP_RETYPE_RAW) - |(1<<OP_CHECK_CAST) - |(1<<OP_PRIM_TO_PRIM) - |(1<<OP_REF_TO_PRIM) - |(1<<OP_SWAP_ARGS) - |(1<<OP_ROT_ARGS) - |(1<<OP_DUP_ARGS) - |(1<<OP_DROP_ARGS) - //|(1<<OP_SPREAD_ARGS) - ); - - /** - * Basic types as encoded in the JVM. These code values are not - * intended for use outside this class. They are used as part of - * a private interface between the JVM and this class. - */ - static final int - T_BOOLEAN = 4, - T_CHAR = 5, - T_FLOAT = 6, - T_DOUBLE = 7, - T_BYTE = 8, - T_SHORT = 9, - T_INT = 10, - T_LONG = 11, - T_OBJECT = 12, - //T_ARRAY = 13 - T_VOID = 14, - //T_ADDRESS = 15 - T_ILLEGAL = 99; - - /** - * Constant pool reference-kind codes, as used by CONSTANT_MethodHandle CP entries. - */ - static final int - REF_getField = 1, - REF_getStatic = 2, - REF_putField = 3, - REF_putStatic = 4, - REF_invokeVirtual = 5, - REF_invokeStatic = 6, - REF_invokeSpecial = 7, - REF_newInvokeSpecial = 8, - REF_invokeInterface = 9; - } - - /** - * This assertion marks code which was written before ricochet frames were implemented. - * Such code will go away when the ports catch up. - */ - static boolean workaroundWithoutRicochetFrames() { - assert(!HAVE_RICOCHET_FRAMES) : "this code should not be executed if `-XX:+UseRicochetFrames is enabled"; - return true; - } -} diff --git a/openjdk/java/lang/invoke/MethodHandles.java b/openjdk/java/lang/invoke/MethodHandles.java deleted file mode 100644 index 6f0db408..00000000 --- a/openjdk/java/lang/invoke/MethodHandles.java +++ /dev/null @@ -1,2273 +0,0 @@ -/* - * Copyright (c) 2008, 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 java.lang.invoke; - -import java.lang.reflect.*; -import sun.invoke.WrapperInstance; -import sun.invoke.util.ValueConversions; -import sun.invoke.util.VerifyAccess; -import sun.invoke.util.Wrapper; -import java.util.List; -import java.util.ArrayList; -import java.util.Arrays; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; -import static java.lang.invoke.MethodHandleStatics.*; -import static java.lang.invoke.MethodHandleNatives.Constants.*; - -/** - * This class consists exclusively of static methods that operate on or return - * method handles. They fall into several categories: - * <ul> - * <li>Lookup methods which help create method handles for methods and fields. - * <li>Combinator methods, which combine or transform pre-existing method handles into new ones. - * <li>Other factory methods to create method handles that emulate other common JVM operations or control flow patterns. - * <li>Wrapper methods which can convert between method handles and interface types. - * </ul> - * <p> - * @author John Rose, JSR 292 EG - */ -public class MethodHandles { - - private MethodHandles() { } // do not instantiate - - private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(); - static { MethodHandleImpl.initStatics(); } - // See IMPL_LOOKUP below. - - //// Method handle creation from ordinary methods. - - /** - * Returns a {@link Lookup lookup object} on the caller, - * which has the capability to access any method handle that the caller has access to, - * including direct method handles to private fields and methods. - * This lookup object is a <em>capability</em> which may be delegated to trusted agents. - * Do not store it in place where untrusted code can access it. - */ - @CallerSensitive - public static Lookup lookup() { - return new Lookup(Reflection.getCallerClass()); - } - - /** - * Returns a {@link Lookup lookup object} which is trusted minimally. - * It can only be used to create method handles to - * publicly accessible fields and methods. - * <p> - * As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class} - * of this lookup object will be {@link java.lang.Object}. - * <p> - * The lookup class can be changed to any other class {@code C} using an expression of the form - * {@linkplain Lookup#in <code>publicLookup().in(C.class)</code>}. - * Since all classes have equal access to public names, - * such a change would confer no new access rights. - */ - public static Lookup publicLookup() { - return Lookup.PUBLIC_LOOKUP; - } - - /** - * A <em>lookup object</em> is a factory for creating method handles, - * when the creation requires access checking. - * Method handles do not perform - * access checks when they are called, but rather when they are created. - * Therefore, method handle access - * restrictions must be enforced when a method handle is created. - * The caller class against which those restrictions are enforced - * is known as the {@linkplain #lookupClass lookup class}. - * <p> - * A lookup class which needs to create method handles will call - * {@link MethodHandles#lookup MethodHandles.lookup} to create a factory for itself. - * When the {@code Lookup} factory object is created, the identity of the lookup class is - * determined, and securely stored in the {@code Lookup} object. - * The lookup class (or its delegates) may then use factory methods - * on the {@code Lookup} object to create method handles for access-checked members. - * This includes all methods, constructors, and fields which are allowed to the lookup class, - * even private ones. - * <p> - * The factory methods on a {@code Lookup} object correspond to all major - * use cases for methods, constructors, and fields. - * Here is a summary of the correspondence between these factory methods and - * the behavior the resulting method handles: - * <code> - * <table border=1 cellpadding=5 summary="lookup method behaviors"> - * <tr><th>lookup expression</th><th>member</th><th>behavior</th></tr> - * <tr> - * <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findGetter lookup.findGetter(C.class,"f",FT.class)}</td> - * <td>FT f;</td><td>(T) this.f;</td> - * </tr> - * <tr> - * <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findStaticGetter lookup.findStaticGetter(C.class,"f",FT.class)}</td> - * <td>static<br>FT f;</td><td>(T) C.f;</td> - * </tr> - * <tr> - * <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findSetter lookup.findSetter(C.class,"f",FT.class)}</td> - * <td>FT f;</td><td>this.f = x;</td> - * </tr> - * <tr> - * <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findStaticSetter lookup.findStaticSetter(C.class,"f",FT.class)}</td> - * <td>static<br>FT f;</td><td>C.f = arg;</td> - * </tr> - * <tr> - * <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findVirtual lookup.findVirtual(C.class,"m",MT)}</td> - * <td>T m(A*);</td><td>(T) this.m(arg*);</td> - * </tr> - * <tr> - * <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findStatic lookup.findStatic(C.class,"m",MT)}</td> - * <td>static<br>T m(A*);</td><td>(T) C.m(arg*);</td> - * </tr> - * <tr> - * <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findSpecial lookup.findSpecial(C.class,"m",MT,this.class)}</td> - * <td>T m(A*);</td><td>(T) super.m(arg*);</td> - * </tr> - * <tr> - * <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findConstructor lookup.findConstructor(C.class,MT)}</td> - * <td>C(A*);</td><td>(T) new C(arg*);</td> - * </tr> - * <tr> - * <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#unreflectGetter lookup.unreflectGetter(aField)}</td> - * <td>(static)?<br>FT f;</td><td>(FT) aField.get(thisOrNull);</td> - * </tr> - * <tr> - * <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#unreflectSetter lookup.unreflectSetter(aField)}</td> - * <td>(static)?<br>FT f;</td><td>aField.set(thisOrNull, arg);</td> - * </tr> - * <tr> - * <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)}</td> - * <td>(static)?<br>T m(A*);</td><td>(T) aMethod.invoke(thisOrNull, arg*);</td> - * </tr> - * <tr> - * <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#unreflectConstructor lookup.unreflectConstructor(aConstructor)}</td> - * <td>C(A*);</td><td>(C) aConstructor.newInstance(arg*);</td> - * </tr> - * <tr> - * <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)}</td> - * <td>(static)?<br>T m(A*);</td><td>(T) aMethod.invoke(thisOrNull, arg*);</td> - * </tr> - * </table> - * </code> - * Here, the type {@code C} is the class or interface being searched for a member, - * documented as a parameter named {@code refc} in the lookup methods. - * The method or constructor type {@code MT} is composed from the return type {@code T} - * and the sequence of argument types {@code A*}. - * Both {@code MT} and the field type {@code FT} are documented as a parameter named {@code type}. - * The formal parameter {@code this} stands for the self-reference of type {@code C}; - * if it is present, it is always the leading argument to the method handle invocation. - * The name {@code arg} stands for all the other method handle arguments. - * In the code examples for the Core Reflection API, the name {@code thisOrNull} - * stands for a null reference if the accessed method or field is static, - * and {@code this} otherwise. - * The names {@code aMethod}, {@code aField}, and {@code aConstructor} stand - * for reflective objects corresponding to the given members. - * <p> - * In cases where the given member is of variable arity (i.e., a method or constructor) - * the returned method handle will also be of {@linkplain MethodHandle#asVarargsCollector variable arity}. - * In all other cases, the returned method handle will be of fixed arity. - * <p> - * The equivalence between looked-up method handles and underlying - * class members can break down in a few ways: - * <ul> - * <li>If {@code C} is not symbolically accessible from the lookup class's loader, - * the lookup can still succeed, even when there is no equivalent - * Java expression or bytecoded constant. - * <li>Likewise, if {@code T} or {@code MT} - * is not symbolically accessible from the lookup class's loader, - * the lookup can still succeed. - * For example, lookups for {@code MethodHandle.invokeExact} and - * {@code MethodHandle.invoke} will always succeed, regardless of requested type. - * <li>If there is a security manager installed, it can forbid the lookup - * on various grounds (<a href="#secmgr">see below</a>). - * By contrast, the {@code ldc} instruction is not subject to - * security manager checks. - * </ul> - * - * <h3><a name="access"></a>Access checking</h3> - * Access checks are applied in the factory methods of {@code Lookup}, - * when a method handle is created. - * This is a key difference from the Core Reflection API, since - * {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke} - * performs access checking against every caller, on every call. - * <p> - * All access checks start from a {@code Lookup} object, which - * compares its recorded lookup class against all requests to - * create method handles. - * A single {@code Lookup} object can be used to create any number - * of access-checked method handles, all checked against a single - * lookup class. - * <p> - * A {@code Lookup} object can be shared with other trusted code, - * such as a metaobject protocol. - * A shared {@code Lookup} object delegates the capability - * to create method handles on private members of the lookup class. - * Even if privileged code uses the {@code Lookup} object, - * the access checking is confined to the privileges of the - * original lookup class. - * <p> - * A lookup can fail, because - * the containing class is not accessible to the lookup class, or - * because the desired class member is missing, or because the - * desired class member is not accessible to the lookup class. - * In any of these cases, a {@code ReflectiveOperationException} will be - * thrown from the attempted lookup. The exact class will be one of - * the following: - * <ul> - * <li>NoSuchMethodException — if a method is requested but does not exist - * <li>NoSuchFieldException — if a field is requested but does not exist - * <li>IllegalAccessException — if the member exists but an access check fails - * </ul> - * <p> - * In general, the conditions under which a method handle may be - * looked up for a method {@code M} are exactly equivalent to the conditions - * under which the lookup class could have compiled and resolved a call to {@code M}. - * And the effect of invoking the method handle resulting from the lookup - * is exactly equivalent to executing the compiled and resolved call to {@code M}. - * The same point is true of fields and constructors. - * <p> - * In some cases, access between nested classes is obtained by the Java compiler by creating - * an wrapper method to access a private method of another class - * in the same top-level declaration. - * For example, a nested class {@code C.D} - * can access private members within other related classes such as - * {@code C}, {@code C.D.E}, or {@code C.B}, - * but the Java compiler may need to generate wrapper methods in - * those related classes. In such cases, a {@code Lookup} object on - * {@code C.E} would be unable to those private members. - * A workaround for this limitation is the {@link Lookup#in Lookup.in} method, - * which can transform a lookup on {@code C.E} into one on any of those other - * classes, without special elevation of privilege. - * <p> - * Although bytecode instructions can only refer to classes in - * a related class loader, this API can search for methods in any - * class, as long as a reference to its {@code Class} object is - * available. Such cross-loader references are also possible with the - * Core Reflection API, and are impossible to bytecode instructions - * such as {@code invokestatic} or {@code getfield}. - * There is a {@linkplain java.lang.SecurityManager security manager API} - * to allow applications to check such cross-loader references. - * These checks apply to both the {@code MethodHandles.Lookup} API - * and the Core Reflection API - * (as found on {@link java.lang.Class Class}). - * <p> - * Access checks only apply to named and reflected methods, - * constructors, and fields. - * Other method handle creation methods, such as - * {@link MethodHandle#asType MethodHandle.asType}, - * do not require any access checks, and are done - * with static methods of {@link MethodHandles}, - * independently of any {@code Lookup} object. - * - * <h3>Security manager interactions</h3> - * <a name="secmgr"></a> - * If a security manager is present, member lookups are subject to - * additional checks. - * From one to four calls are made to the security manager. - * Any of these calls can refuse access by throwing a - * {@link java.lang.SecurityException SecurityException}. - * Define {@code smgr} as the security manager, - * {@code refc} as the containing class in which the member - * is being sought, and {@code defc} as the class in which the - * member is actually defined. - * The calls are made according to the following rules: - * <ul> - * <li>In all cases, {@link SecurityManager#checkMemberAccess - * smgr.checkMemberAccess(refc, Member.PUBLIC)} is called. - * <li>If the class loader of the lookup class is not - * the same as or an ancestor of the class loader of {@code refc}, - * then {@link SecurityManager#checkPackageAccess - * smgr.checkPackageAccess(refcPkg)} is called, - * where {@code refcPkg} is the package of {@code refc}. - * <li>If the retrieved member is not public, - * {@link SecurityManager#checkMemberAccess - * smgr.checkMemberAccess(defc, Member.DECLARED)} is called. - * (Note that {@code defc} might be the same as {@code refc}.) - * The default implementation of this security manager method - * inspects the stack to determine the original caller of - * the reflective request (such as {@code findStatic}), - * and performs additional permission checks if the - * class loader of {@code defc} differs from the class - * loader of the class from which the reflective request came. - * <li>If the retrieved member is not public, - * and if {@code defc} and {@code refc} are in different class loaders, - * and if the class loader of the lookup class is not - * the same as or an ancestor of the class loader of {@code defc}, - * then {@link SecurityManager#checkPackageAccess - * smgr.checkPackageAccess(defcPkg)} is called, - * where {@code defcPkg} is the package of {@code defc}. - * </ul> - */ - public static final - class Lookup { - /** The class on behalf of whom the lookup is being performed. */ - private final Class<?> lookupClass; - - /** The allowed sorts of members which may be looked up (PUBLIC, etc.). */ - private final int allowedModes; - - // [IKVM] when dynamically linking method handle constants, we don't want a security manager check - private final boolean noSecurityCheck; - - /** A single-bit mask representing {@code public} access, - * which may contribute to the result of {@link #lookupModes lookupModes}. - * The value, {@code 0x01}, happens to be the same as the value of the - * {@code public} {@linkplain java.lang.reflect.Modifier#PUBLIC modifier bit}. - */ - public static final int PUBLIC = Modifier.PUBLIC; - - /** A single-bit mask representing {@code private} access, - * which may contribute to the result of {@link #lookupModes lookupModes}. - * The value, {@code 0x02}, happens to be the same as the value of the - * {@code private} {@linkplain java.lang.reflect.Modifier#PRIVATE modifier bit}. - */ - public static final int PRIVATE = Modifier.PRIVATE; - - /** A single-bit mask representing {@code protected} access, - * which may contribute to the result of {@link #lookupModes lookupModes}. - * The value, {@code 0x04}, happens to be the same as the value of the - * {@code protected} {@linkplain java.lang.reflect.Modifier#PROTECTED modifier bit}. - */ - public static final int PROTECTED = Modifier.PROTECTED; - - /** A single-bit mask representing {@code package} access (default access), - * which may contribute to the result of {@link #lookupModes lookupModes}. - * The value is {@code 0x08}, which does not correspond meaningfully to - * any particular {@linkplain java.lang.reflect.Modifier modifier bit}. - */ - public static final int PACKAGE = Modifier.STATIC; - - private static final int ALL_MODES = (PUBLIC | PRIVATE | PROTECTED | PACKAGE); - private static final int TRUSTED = -1; - - private static int fixmods(int mods) { - mods &= (ALL_MODES - PACKAGE); - return (mods != 0) ? mods : PACKAGE; - } - - /** Tells which class is performing the lookup. It is this class against - * which checks are performed for visibility and access permissions. - * <p> - * The class implies a maximum level of access permission, - * but the permissions may be additionally limited by the bitmask - * {@link #lookupModes lookupModes}, which controls whether non-public members - * can be accessed. - */ - public Class<?> lookupClass() { - return lookupClass; - } - - // This is just for calling out to MethodHandleImpl. - private Class<?> lookupClassOrNull() { - return (allowedModes == TRUSTED) ? null : lookupClass; - } - - /** Tells which access-protection classes of members this lookup object can produce. - * The result is a bit-mask of the bits - * {@linkplain #PUBLIC PUBLIC (0x01)}, - * {@linkplain #PRIVATE PRIVATE (0x02)}, - * {@linkplain #PROTECTED PROTECTED (0x04)}, - * and {@linkplain #PACKAGE PACKAGE (0x08)}. - * <p> - * A freshly-created lookup object - * on the {@linkplain java.lang.invoke.MethodHandles#lookup() caller's class} - * has all possible bits set, since the caller class can access all its own members. - * A lookup object on a new lookup class - * {@linkplain java.lang.invoke.MethodHandles.Lookup#in created from a previous lookup object} - * may have some mode bits set to zero. - * The purpose of this is to restrict access via the new lookup object, - * so that it can access only names which can be reached by the original - * lookup object, and also by the new lookup class. - */ - public int lookupModes() { - return allowedModes & ALL_MODES; - } - - /** Embody the current class (the lookupClass) as a lookup class - * for method handle creation. - * Must be called by from a method in this package, - * which in turn is called by a method not in this package. - * <p> - * Also, don't make it private, lest javac interpose - * an access$N method. - */ - Lookup(Class<?> lookupClass) { - this(lookupClass, ALL_MODES); - checkUnprivilegedlookupClass(lookupClass); - } - - private Lookup(Class<?> lookupClass, int allowedModes) { - this(lookupClass, allowedModes, false); - } - - Lookup(Class<?> lookupClass, int allowedModes, boolean noSecurityCheck) { - this.lookupClass = lookupClass; - this.allowedModes = allowedModes; - this.noSecurityCheck = noSecurityCheck; - } - - /** - * Creates a lookup on the specified new lookup class. - * The resulting object will report the specified - * class as its own {@link #lookupClass lookupClass}. - * <p> - * However, the resulting {@code Lookup} object is guaranteed - * to have no more access capabilities than the original. - * In particular, access capabilities can be lost as follows:<ul> - * <li>If the new lookup class differs from the old one, - * protected members will not be accessible by virtue of inheritance. - * (Protected members may continue to be accessible because of package sharing.) - * <li>If the new lookup class is in a different package - * than the old one, protected and default (package) members will not be accessible. - * <li>If the new lookup class is not within the same package member - * as the old one, private members will not be accessible. - * <li>If the new lookup class is not accessible to the old lookup class, - * then no members, not even public members, will be accessible. - * (In all other cases, public members will continue to be accessible.) - * </ul> - * - * @param requestedLookupClass the desired lookup class for the new lookup object - * @return a lookup object which reports the desired lookup class - * @throws NullPointerException if the argument is null - */ - public Lookup in(Class<?> requestedLookupClass) { - requestedLookupClass.getClass(); // null check - if (allowedModes == TRUSTED) // IMPL_LOOKUP can make any lookup at all - return new Lookup(requestedLookupClass, ALL_MODES); - if (requestedLookupClass == this.lookupClass) - return this; // keep same capabilities - int newModes = (allowedModes & (ALL_MODES & ~PROTECTED)); - if ((newModes & PACKAGE) != 0 - && !VerifyAccess.isSamePackage(this.lookupClass, requestedLookupClass)) { - newModes &= ~(PACKAGE|PRIVATE); - } - // Allow nestmate lookups to be created without special privilege: - if ((newModes & PRIVATE) != 0 - && !VerifyAccess.isSamePackageMember(this.lookupClass, requestedLookupClass)) { - newModes &= ~PRIVATE; - } - if ((newModes & PUBLIC) != 0 - && !VerifyAccess.isClassAccessible(requestedLookupClass, this.lookupClass, allowedModes)) { - // The requested class it not accessible from the lookup class. - // No permissions. - newModes = 0; - } - checkUnprivilegedlookupClass(requestedLookupClass); - return new Lookup(requestedLookupClass, newModes); - } - - // Make sure outer class is initialized first. - static { IMPL_NAMES.getClass(); } - - /** Version of lookup which is trusted minimally. - * It can only be used to create method handles to - * publicly accessible members. - */ - static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, PUBLIC); - - /** Package-private version of lookup which is trusted. */ - static final Lookup IMPL_LOOKUP = new Lookup(Object.class, TRUSTED); - - private static void checkUnprivilegedlookupClass(Class<?> lookupClass) { - String name = lookupClass.getName(); - if (name.startsWith("java.lang.invoke.")) - throw newIllegalArgumentException("illegal lookupClass: "+lookupClass); - } - - /** - * Displays the name of the class from which lookups are to be made. - * (The name is the one reported by {@link java.lang.Class#getName() Class.getName}.) - * If there are restrictions on the access permitted to this lookup, - * this is indicated by adding a suffix to the class name, consisting - * of a slash and a keyword. The keyword represents the strongest - * allowed access, and is chosen as follows: - * <ul> - * <li>If no access is allowed, the suffix is "/noaccess". - * <li>If only public access is allowed, the suffix is "/public". - * <li>If only public and package access are allowed, the suffix is "/package". - * <li>If only public, package, and private access are allowed, the suffix is "/private". - * </ul> - * If none of the above cases apply, it is the case that full - * access (public, package, private, and protected) is allowed. - * In this case, no suffix is added. - * This is true only of an object obtained originally from - * {@link java.lang.invoke.MethodHandles#lookup MethodHandles.lookup}. - * Objects created by {@link java.lang.invoke.MethodHandles.Lookup#in Lookup.in} - * always have restricted access, and will display a suffix. - * <p> - * (It may seem strange that protected access should be - * stronger than private access. Viewed independently from - * package access, protected access is the first to be lost, - * because it requires a direct subclass relationship between - * caller and callee.) - * @see #in - */ - @Override - public String toString() { - String cname = lookupClass.getName(); - switch (allowedModes) { - case 0: // no privileges - return cname + "/noaccess"; - case PUBLIC: - return cname + "/public"; - case PUBLIC|PACKAGE: - return cname + "/package"; - case ALL_MODES & ~PROTECTED: - return cname + "/private"; - case ALL_MODES: - return cname; - case TRUSTED: - return "/trusted"; // internal only; not exported - default: // Should not happen, but it's a bitfield... - cname = cname + "/" + Integer.toHexString(allowedModes); - assert(false) : cname; - return cname; - } - } - - /* Obtain the external caller class, when called from Lookup.<init> or a first-level subroutine. */ - private static Class<?> getCallerClassAtEntryPoint(boolean inSubroutine) { - final int CALLER_DEPTH = 4; - // Stack for the constructor entry point (inSubroutine=false): - // 0: Reflection.getCC, 1: getCallerClassAtEntryPoint, - // 2: Lookup.<init>, 3: MethodHandles.*, 4: caller - // The stack is slightly different for a subroutine of a Lookup.find* method: - // 2: Lookup.*, 3: Lookup.find*.*, 4: caller - // Note: This should be the only use of getCallerClass in this file. - assert(Reflection.getCallerClass(CALLER_DEPTH-2) == Lookup.class); - assert(Reflection.getCallerClass(CALLER_DEPTH-1) == (inSubroutine ? Lookup.class : MethodHandles.class)); - return Reflection.getCallerClass(CALLER_DEPTH); - } - - /** - * Produces a method handle for a static method. - * The type of the method handle will be that of the method. - * (Since static methods do not take receivers, there is no - * additional receiver argument inserted into the method handle type, - * as there would be with {@link #findVirtual findVirtual} or {@link #findSpecial findSpecial}.) - * The method and all its argument types must be accessible to the lookup class. - * If the method's class has not yet been initialized, that is done - * immediately, before the method handle is returned. - * <p> - * The returned method handle will have - * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if - * the method's variable arity modifier bit ({@code 0x0080}) is set. - * @param refc the class from which the method is accessed - * @param name the name of the method - * @param type the type of the method - * @return the desired method handle - * @throws NoSuchMethodException if the method does not exist - * @throws IllegalAccessException if access checking fails, - * or if the method is not {@code static}, - * or if the method's variable arity modifier bit - * is set and {@code asVarargsCollector} fails - * @exception SecurityException if a security manager is present and it - * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> - * @throws NullPointerException if any argument is null - */ - public - MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { - MemberName method = resolveOrFail(refc, name, type, true); - checkSecurityManager(refc, method); // stack walk magic: do not refactor - return accessStatic(refc, method); - } - private - MethodHandle accessStatic(Class<?> refc, MemberName method) throws IllegalAccessException { - checkMethod(refc, method, true); - return MethodHandleImpl.findMethod(method, false, lookupClassOrNull()); - } - private - MethodHandle resolveStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { - MemberName method = resolveOrFail(refc, name, type, true); - return accessStatic(refc, method); - } - - /** - * Produces a method handle for a virtual method. - * The type of the method handle will be that of the method, - * with the receiver type (usually {@code refc}) prepended. - * The method and all its argument types must be accessible to the lookup class. - * <p> - * When called, the handle will treat the first argument as a receiver - * and dispatch on the receiver's type to determine which method - * implementation to enter. - * (The dispatching action is identical with that performed by an - * {@code invokevirtual} or {@code invokeinterface} instruction.) - * <p> - * The returned method handle will have - * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if - * the method's variable arity modifier bit ({@code 0x0080}) is set. - * <p> - * Because of the general equivalence between {@code invokevirtual} - * instructions and method handles produced by {@code findVirtual}, - * if the class is {@code MethodHandle} and the name string is - * {@code invokeExact} or {@code invoke}, the resulting - * method handle is equivalent to one produced by - * {@link java.lang.invoke.MethodHandles#exactInvoker MethodHandles.exactInvoker} or - * {@link java.lang.invoke.MethodHandles#invoker MethodHandles.invoker} - * with the same {@code type} argument. - * - * @param refc the class or interface from which the method is accessed - * @param name the name of the method - * @param type the type of the method, with the receiver argument omitted - * @return the desired method handle - * @throws NoSuchMethodException if the method does not exist - * @throws IllegalAccessException if access checking fails, - * or if the method is {@code static} - * or if the method's variable arity modifier bit - * is set and {@code asVarargsCollector} fails - * @exception SecurityException if a security manager is present and it - * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> - * @throws NullPointerException if any argument is null - */ - public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { - MemberName method = resolveOrFail(refc, name, type, false); - checkSecurityManager(refc, method); // stack walk magic: do not refactor - return accessVirtual(refc, method); - } - private MethodHandle resolveVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { - MemberName method = resolveOrFail(refc, name, type, false); - return accessVirtual(refc, method); - } - private MethodHandle accessVirtual(Class<?> refc, MemberName method) throws IllegalAccessException { - checkMethod(refc, method, false); - MethodHandle mh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull()); - return restrictProtectedReceiver(method, mh); - } - - /** - * Produces a method handle which creates an object and initializes it, using - * the constructor of the specified type. - * The parameter types of the method handle will be those of the constructor, - * while the return type will be a reference to the constructor's class. - * The constructor and all its argument types must be accessible to the lookup class. - * If the constructor's class has not yet been initialized, that is done - * immediately, before the method handle is returned. - * <p> - * Note: The requested type must have a return type of {@code void}. - * This is consistent with the JVM's treatment of constructor type descriptors. - * <p> - * The returned method handle will have - * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if - * the constructor's variable arity modifier bit ({@code 0x0080}) is set. - * @param refc the class or interface from which the method is accessed - * @param type the type of the method, with the receiver argument omitted, and a void return type - * @return the desired method handle - * @throws NoSuchMethodException if the constructor does not exist - * @throws IllegalAccessException if access checking fails - * or if the method's variable arity modifier bit - * is set and {@code asVarargsCollector} fails - * @exception SecurityException if a security manager is present and it - * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> - * @throws NullPointerException if any argument is null - */ - public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException { - String name = "<init>"; - MemberName ctor = resolveOrFail(refc, name, type, false, false, lookupClassOrNull()); - checkSecurityManager(refc, ctor); // stack walk magic: do not refactor - return accessConstructor(refc, ctor); - } - private MethodHandle accessConstructor(Class<?> refc, MemberName ctor) throws IllegalAccessException { - assert(ctor.isConstructor()); - checkAccess(refc, ctor); - MethodHandle rawMH = MethodHandleImpl.findMethod(ctor, false, lookupClassOrNull()); - MethodHandle allocMH = MethodHandleImpl.makeAllocator(rawMH); - return fixVarargs(allocMH, rawMH); - } - private MethodHandle resolveConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException { - String name = "<init>"; - MemberName ctor = resolveOrFail(refc, name, type, false, false, lookupClassOrNull()); - return accessConstructor(refc, ctor); - } - - /** Return a version of MH which matches matchMH w.r.t. isVarargsCollector. */ - private static MethodHandle fixVarargs(MethodHandle mh, MethodHandle matchMH) { - boolean va1 = mh.isVarargsCollector(); - boolean va2 = matchMH.isVarargsCollector(); - if (va1 == va2) { - return mh; - } else if (va2) { - MethodType type = mh.type(); - int arity = type.parameterCount(); - return mh.asVarargsCollector(type.parameterType(arity-1)); - } else { - return mh.asFixedArity(); - } - } - - /** - * Produces an early-bound method handle for a virtual method, - * as if called from an {@code invokespecial} - * instruction from {@code caller}. - * The type of the method handle will be that of the method, - * with a suitably restricted receiver type (such as {@code caller}) prepended. - * The method and all its argument types must be accessible - * to the caller. - * <p> - * When called, the handle will treat the first argument as a receiver, - * but will not dispatch on the receiver's type. - * (This direct invocation action is identical with that performed by an - * {@code invokespecial} instruction.) - * <p> - * If the explicitly specified caller class is not identical with the - * lookup class, or if this lookup object does not have private access - * privileges, the access fails. - * <p> - * The returned method handle will have - * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if - * the method's variable arity modifier bit ({@code 0x0080}) is set. - * @param refc the class or interface from which the method is accessed - * @param name the name of the method (which must not be "<init>") - * @param type the type of the method, with the receiver argument omitted - * @param specialCaller the proposed calling class to perform the {@code invokespecial} - * @return the desired method handle - * @throws NoSuchMethodException if the method does not exist - * @throws IllegalAccessException if access checking fails - * or if the method's variable arity modifier bit - * is set and {@code asVarargsCollector} fails - * @exception SecurityException if a security manager is present and it - * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> - * @throws NullPointerException if any argument is null - */ - public MethodHandle findSpecial(Class<?> refc, String name, MethodType type, - Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException { - checkSpecialCaller(specialCaller); - MemberName method = resolveOrFail(refc, name, type, false, false, specialCaller); - checkSecurityManager(refc, method); // stack walk magic: do not refactor - return accessSpecial(refc, method, specialCaller); - } - private MethodHandle accessSpecial(Class<?> refc, MemberName method, - Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException { - checkMethod(refc, method, false); - MethodHandle mh = MethodHandleImpl.findMethod(method, false, specialCaller); - return restrictReceiver(method, mh, specialCaller); - } - private MethodHandle resolveSpecial(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { - Class<?> specialCaller = lookupClass(); - checkSpecialCaller(specialCaller); - MemberName method = resolveOrFail(refc, name, type, false, false, specialCaller); - return accessSpecial(refc, method, specialCaller); - } - - /** - * Produces a method handle giving read access to a non-static field. - * The type of the method handle will have a return type of the field's - * value type. - * The method handle's single argument will be the instance containing - * the field. - * Access checking is performed immediately on behalf of the lookup class. - * @param refc the class or interface from which the method is accessed - * @param name the field's name - * @param type the field's type - * @return a method handle which can load values from the field - * @throws NoSuchFieldException if the field does not exist - * @throws IllegalAccessException if access checking fails, or if the field is {@code static} - * @exception SecurityException if a security manager is present and it - * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> - * @throws NullPointerException if any argument is null - */ - public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { - MemberName field = resolveOrFail(refc, name, type, false); - checkSecurityManager(refc, field); // stack walk magic: do not refactor - return makeAccessor(refc, field, false, false, 0); - } - private MethodHandle resolveGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { - MemberName field = resolveOrFail(refc, name, type, false); - return makeAccessor(refc, field, false, false, 0); - } - - /** - * Produces a method handle giving write access to a non-static field. - * The type of the method handle will have a void return type. - * The method handle will take two arguments, the instance containing - * the field, and the value to be stored. - * The second argument will be of the field's value type. - * Access checking is performed immediately on behalf of the lookup class. - * @param refc the class or interface from which the method is accessed - * @param name the field's name - * @param type the field's type - * @return a method handle which can store values into the field - * @throws NoSuchFieldException if the field does not exist - * @throws IllegalAccessException if access checking fails, or if the field is {@code static} - * @exception SecurityException if a security manager is present and it - * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> - * @throws NullPointerException if any argument is null - */ - public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { - MemberName field = resolveOrFail(refc, name, type, false); - checkSecurityManager(refc, field); // stack walk magic: do not refactor - return makeAccessor(refc, field, false, true, 0); - } - private MethodHandle resolveSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { - MemberName field = resolveOrFail(refc, name, type, false); - return makeAccessor(refc, field, false, true, 0); - } - - /** - * Produces a method handle giving read access to a static field. - * The type of the method handle will have a return type of the field's - * value type. - * The method handle will take no arguments. - * Access checking is performed immediately on behalf of the lookup class. - * @param refc the class or interface from which the method is accessed - * @param name the field's name - * @param type the field's type - * @return a method handle which can load values from the field - * @throws NoSuchFieldException if the field does not exist - * @throws IllegalAccessException if access checking fails, or if the field is not {@code static} - * @exception SecurityException if a security manager is present and it - * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> - * @throws NullPointerException if any argument is null - */ - public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { - MemberName field = resolveOrFail(refc, name, type, true); - checkSecurityManager(refc, field); // stack walk magic: do not refactor - return makeAccessor(refc, field, false, false, 1); - } - private MethodHandle resolveStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { - MemberName field = resolveOrFail(refc, name, type, true); - return makeAccessor(refc, field, false, false, 1); - } - - /** - * Produces a method handle giving write access to a static field. - * The type of the method handle will have a void return type. - * The method handle will take a single - * argument, of the field's value type, the value to be stored. - * Access checking is performed immediately on behalf of the lookup class. - * @param refc the class or interface from which the method is accessed - * @param name the field's name - * @param type the field's type - * @return a method handle which can store values into the field - * @throws NoSuchFieldException if the field does not exist - * @throws IllegalAccessException if access checking fails, or if the field is not {@code static} - * @exception SecurityException if a security manager is present and it - * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> - * @throws NullPointerException if any argument is null - */ - public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { - MemberName field = resolveOrFail(refc, name, type, true); - checkSecurityManager(refc, field); // stack walk magic: do not refactor - return makeAccessor(refc, field, false, true, 1); - } - private MethodHandle resolveStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { - MemberName field = resolveOrFail(refc, name, type, true); - return makeAccessor(refc, field, false, true, 1); - } - - /** - * Produces an early-bound method handle for a non-static method. - * The receiver must have a supertype {@code defc} in which a method - * of the given name and type is accessible to the lookup class. - * The method and all its argument types must be accessible to the lookup class. - * The type of the method handle will be that of the method, - * without any insertion of an additional receiver parameter. - * The given receiver will be bound into the method handle, - * so that every call to the method handle will invoke the - * requested method on the given receiver. - * <p> - * The returned method handle will have - * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if - * the method's variable arity modifier bit ({@code 0x0080}) is set - * <em>and</em> the trailing array argument is not the only argument. - * (If the trailing array argument is the only argument, - * the given receiver value will be bound to it.) - * <p> - * This is equivalent to the following code: - * <blockquote><pre> -import static java.lang.invoke.MethodHandles.*; -import static java.lang.invoke.MethodType.*; -... -MethodHandle mh0 = lookup().{@link #findVirtual findVirtual}(defc, name, type); -MethodHandle mh1 = mh0.{@link MethodHandle#bindTo bindTo}(receiver); -MethodType mt1 = mh1.type(); -if (mh0.isVarargsCollector()) - mh1 = mh1.asVarargsCollector(mt1.parameterType(mt1.parameterCount()-1)); -return mh1; - * </pre></blockquote> - * where {@code defc} is either {@code receiver.getClass()} or a super - * type of that class, in which the requested method is accessible - * to the lookup class. - * (Note that {@code bindTo} does not preserve variable arity.) - * @param receiver the object from which the method is accessed - * @param name the name of the method - * @param type the type of the method, with the receiver argument omitted - * @return the desired method handle - * @throws NoSuchMethodException if the method does not exist - * @throws IllegalAccessException if access checking fails - * or if the method's variable arity modifier bit - * is set and {@code asVarargsCollector} fails - * @exception SecurityException if a security manager is present and it - * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> - * @throws NullPointerException if any argument is null - */ - public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { - Class<? extends Object> refc = receiver.getClass(); // may get NPE - MemberName method = resolveOrFail(refc, name, type, false); - checkSecurityManager(refc, method); // stack walk magic: do not refactor - checkMethod(refc, method, false); - MethodHandle dmh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull()); - MethodHandle bmh = MethodHandleImpl.bindReceiver(dmh, receiver); - if (bmh == null) - throw method.makeAccessException("no access", this); - return fixVarargs(bmh, dmh); - } - - /** - * Makes a direct method handle to <i>m</i>, if the lookup class has permission. - * If <i>m</i> is non-static, the receiver argument is treated as an initial argument. - * If <i>m</i> is virtual, overriding is respected on every call. - * Unlike the Core Reflection API, exceptions are <em>not</em> wrapped. - * The type of the method handle will be that of the method, - * with the receiver type prepended (but only if it is non-static). - * If the method's {@code accessible} flag is not set, - * access checking is performed immediately on behalf of the lookup class. - * If <i>m</i> is not public, do not share the resulting handle with untrusted parties. - * <p> - * The returned method handle will have - * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if - * the method's variable arity modifier bit ({@code 0x0080}) is set. - * @param m the reflected method - * @return a method handle which can invoke the reflected method - * @throws IllegalAccessException if access checking fails - * or if the method's variable arity modifier bit - * is set and {@code asVarargsCollector} fails - * @throws NullPointerException if the argument is null - */ - public MethodHandle unreflect(Method m) throws IllegalAccessException { - MemberName method = new MemberName(m); - assert(method.isMethod()); - if (m.isAccessible()) - return MethodHandleImpl.findMethod(method, true, /*no lookupClass*/ null); - checkMethod(method.getDeclaringClass(), method, method.isStatic()); - MethodHandle mh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull()); - return restrictProtectedReceiver(method, mh); - } - - /** - * Produces a method handle for a reflected method. - * It will bypass checks for overriding methods on the receiver, - * as if by a {@code invokespecial} instruction from within the {@code specialCaller}. - * The type of the method handle will be that of the method, - * with the special caller type prepended (and <em>not</em> the receiver of the method). - * If the method's {@code accessible} flag is not set, - * access checking is performed immediately on behalf of the lookup class, - * as if {@code invokespecial} instruction were being linked. - * <p> - * The returned method handle will have - * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if - * the method's variable arity modifier bit ({@code 0x0080}) is set. - * @param m the reflected method - * @param specialCaller the class nominally calling the method - * @return a method handle which can invoke the reflected method - * @throws IllegalAccessException if access checking fails - * or if the method's variable arity modifier bit - * is set and {@code asVarargsCollector} fails - * @throws NullPointerException if any argument is null - */ - public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException { - checkSpecialCaller(specialCaller); - MemberName method = new MemberName(m); - assert(method.isMethod()); - // ignore m.isAccessible: this is a new kind of access - checkMethod(m.getDeclaringClass(), method, false); - MethodHandle mh = MethodHandleImpl.findMethod(method, false, lookupClassOrNull()); - return restrictReceiver(method, mh, specialCaller); - } - - /** - * Produces a method handle for a reflected constructor. - * The type of the method handle will be that of the constructor, - * with the return type changed to the declaring class. - * The method handle will perform a {@code newInstance} operation, - * creating a new instance of the constructor's class on the - * arguments passed to the method handle. - * <p> - * If the constructor's {@code accessible} flag is not set, - * access checking is performed immediately on behalf of the lookup class. - * <p> - * The returned method handle will have - * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if - * the constructor's variable arity modifier bit ({@code 0x0080}) is set. - * @param c the reflected constructor - * @return a method handle which can invoke the reflected constructor - * @throws IllegalAccessException if access checking fails - * or if the method's variable arity modifier bit - * is set and {@code asVarargsCollector} fails - * @throws NullPointerException if the argument is null - */ - public MethodHandle unreflectConstructor(Constructor c) throws IllegalAccessException { - MemberName ctor = new MemberName(c); - assert(ctor.isConstructor()); - MethodHandle rawCtor; - if (c.isAccessible()) { - rawCtor = MethodHandleImpl.findMethod(ctor, false, /*no lookupClass*/ null); - } else { - checkAccess(c.getDeclaringClass(), ctor); - rawCtor = MethodHandleImpl.findMethod(ctor, false, lookupClassOrNull()); - } - MethodHandle allocator = MethodHandleImpl.makeAllocator(rawCtor); - return fixVarargs(allocator, rawCtor); - } - - /** - * Produces a method handle giving read access to a reflected field. - * The type of the method handle will have a return type of the field's - * value type. - * If the field is static, the method handle will take no arguments. - * Otherwise, its single argument will be the instance containing - * the field. - * If the field's {@code accessible} flag is not set, - * access checking is performed immediately on behalf of the lookup class. - * @param f the reflected field - * @return a method handle which can load values from the reflected field - * @throws IllegalAccessException if access checking fails - * @throws NullPointerException if the argument is null - */ - public MethodHandle unreflectGetter(Field f) throws IllegalAccessException { - return makeAccessor(f.getDeclaringClass(), new MemberName(f), f.isAccessible(), false, -1); - } - - /** - * Produces a method handle giving write access to a reflected field. - * The type of the method handle will have a void return type. - * If the field is static, the method handle will take a single - * argument, of the field's value type, the value to be stored. - * Otherwise, the two arguments will be the instance containing - * the field, and the value to be stored. - * If the field's {@code accessible} flag is not set, - * access checking is performed immediately on behalf of the lookup class. - * @param f the reflected field - * @return a method handle which can store values into the reflected field - * @throws IllegalAccessException if access checking fails - * @throws NullPointerException if the argument is null - */ - public MethodHandle unreflectSetter(Field f) throws IllegalAccessException { - return makeAccessor(f.getDeclaringClass(), new MemberName(f), f.isAccessible(), true, -1); - } - - /// Helper methods, all package-private. - - MemberName resolveOrFail(Class<?> refc, String name, Class<?> type, boolean isStatic) throws NoSuchFieldException, IllegalAccessException { - checkSymbolicClass(refc); // do this before attempting to resolve - name.getClass(); type.getClass(); // NPE - int mods = (isStatic ? Modifier.STATIC : 0); - return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), true, lookupClassOrNull(), - NoSuchFieldException.class); - } - - MemberName resolveOrFail(Class<?> refc, String name, MethodType type, boolean isStatic) throws NoSuchMethodException, IllegalAccessException { - checkSymbolicClass(refc); // do this before attempting to resolve - name.getClass(); type.getClass(); // NPE - int mods = (isStatic ? Modifier.STATIC : 0); - return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), true, lookupClassOrNull(), - NoSuchMethodException.class); - } - - MemberName resolveOrFail(Class<?> refc, String name, MethodType type, boolean isStatic, - boolean searchSupers, Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException { - checkSymbolicClass(refc); // do this before attempting to resolve - name.getClass(); type.getClass(); // NPE - int mods = (isStatic ? Modifier.STATIC : 0); - return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), searchSupers, specialCaller, - NoSuchMethodException.class); - } - - void checkSymbolicClass(Class<?> refc) throws IllegalAccessException { - Class<?> caller = lookupClassOrNull(); - if (caller != null && !VerifyAccess.isClassAccessible(refc, caller, allowedModes)) - throw new MemberName(refc).makeAccessException("symbolic reference class is not public", this); - } - - /** - * Perform necessary <a href="MethodHandles.Lookup.html#secmgr">access checks</a>. - * This function performs stack walk magic: do not refactor it. - */ - void checkSecurityManager(Class<?> refc, MemberName m) { - if (noSecurityCheck) return; - SecurityManager smgr = System.getSecurityManager(); - if (smgr == null) return; - if (allowedModes == TRUSTED) return; - // Step 1: - smgr.checkMemberAccess(refc, Member.PUBLIC); - // Step 2: - Class<?> callerClass = ((allowedModes & PRIVATE) != 0 - ? lookupClass // for strong access modes, no extra check - // next line does stack walk magic; do not refactor: - : getCallerClassAtEntryPoint(true)); - if (!VerifyAccess.classLoaderIsAncestor(lookupClass, refc) || - (callerClass != lookupClass && - !VerifyAccess.classLoaderIsAncestor(callerClass, refc))) - smgr.checkPackageAccess(VerifyAccess.getPackageName(refc)); - // Step 3: - if (m.isPublic()) return; - Class<?> defc = m.getDeclaringClass(); - smgr.checkMemberAccess(defc, Member.DECLARED); // STACK WALK HERE - // Step 4: - if (defc != refc) - smgr.checkPackageAccess(VerifyAccess.getPackageName(defc)); - - // Comment from SM.checkMemberAccess, where which=DECLARED: - /* - * stack depth of 4 should be the caller of one of the - * methods in java.lang.Class that invoke checkMember - * access. The stack should look like: - * - * someCaller [3] - * java.lang.Class.someReflectionAPI [2] - * java.lang.Class.checkMemberAccess [1] - * SecurityManager.checkMemberAccess [0] - * - */ - // For us it is this stack: - // someCaller [3] - // Lookup.findSomeMember [2] - // Lookup.checkSecurityManager [1] - // SecurityManager.checkMemberAccess [0] - } - - void checkMethod(Class<?> refc, MemberName m, boolean wantStatic) throws IllegalAccessException { - String message; - if (m.isConstructor()) - message = "expected a method, not a constructor"; - else if (!m.isMethod()) - message = "expected a method"; - else if (wantStatic != m.isStatic()) - message = wantStatic ? "expected a static method" : "expected a non-static method"; - else - { checkAccess(refc, m); return; } - throw m.makeAccessException(message, this); - } - - void checkAccess(Class<?> refc, MemberName m) throws IllegalAccessException { - int allowedModes = this.allowedModes; - if (allowedModes == TRUSTED) return; - int mods = m.getModifiers(); - if (Modifier.isPublic(mods) && Modifier.isPublic(refc.getModifiers()) && allowedModes != 0) - return; // common case - int requestedModes = fixmods(mods); // adjust 0 => PACKAGE - if ((requestedModes & allowedModes) != 0 - && VerifyAccess.isMemberAccessible(refc, m.getDeclaringClass(), - mods, lookupClass(), allowedModes)) - return; - if (((requestedModes & ~allowedModes) & PROTECTED) != 0 - && (allowedModes & PACKAGE) != 0 - && VerifyAccess.isSamePackage(m.getDeclaringClass(), lookupClass())) - // Protected members can also be checked as if they were package-private. - return; - throw m.makeAccessException(accessFailedMessage(refc, m), this); - } - - String accessFailedMessage(Class<?> refc, MemberName m) { - Class<?> defc = m.getDeclaringClass(); - int mods = m.getModifiers(); - // check the class first: - boolean classOK = (Modifier.isPublic(defc.getModifiers()) && - (defc == refc || - Modifier.isPublic(refc.getModifiers()))); - if (!classOK && (allowedModes & PACKAGE) != 0) { - classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), ALL_MODES) && - (defc == refc || - VerifyAccess.isClassAccessible(refc, lookupClass(), ALL_MODES))); - } - if (!classOK) - return "class is not public"; - if (Modifier.isPublic(mods)) - return "access to public member failed"; // (how?) - if (Modifier.isPrivate(mods)) - return "member is private"; - if (Modifier.isProtected(mods)) - return "member is protected"; - return "member is private to package"; - } - - private static final boolean ALLOW_NESTMATE_ACCESS = false; - - void checkSpecialCaller(Class<?> specialCaller) throws IllegalAccessException { - if (allowedModes == TRUSTED) return; - if ((allowedModes & PRIVATE) == 0 - || (specialCaller != lookupClass() - && !(ALLOW_NESTMATE_ACCESS && - VerifyAccess.isSamePackageMember(specialCaller, lookupClass())))) - throw new MemberName(specialCaller). - makeAccessException("no private access for invokespecial", this); - } - - MethodHandle restrictProtectedReceiver(MemberName method, MethodHandle mh) throws IllegalAccessException { - // The accessing class only has the right to use a protected member - // on itself or a subclass. Enforce that restriction, from JVMS 5.4.4, etc. - if (!method.isProtected() || method.isStatic() - || allowedModes == TRUSTED - || method.getDeclaringClass() == lookupClass() - || VerifyAccess.isSamePackage(method.getDeclaringClass(), lookupClass()) - || (ALLOW_NESTMATE_ACCESS && - VerifyAccess.isSamePackageMember(method.getDeclaringClass(), lookupClass()))) - return mh; - else - return restrictReceiver(method, mh, lookupClass()); - } - MethodHandle restrictReceiver(MemberName method, MethodHandle mh, Class<?> caller) throws IllegalAccessException { - assert(!method.isStatic()); - Class<?> defc = method.getDeclaringClass(); // receiver type of mh is too wide - if (defc.isInterface() || !defc.isAssignableFrom(caller)) { - throw method.makeAccessException("caller class must be a subclass below the method", caller); - } - MethodType rawType = mh.type(); - if (rawType.parameterType(0) == caller) return mh; - MethodType narrowType = rawType.changeParameterType(0, caller); - MethodHandle narrowMH = MethodHandleImpl.convertArguments(mh, narrowType, rawType, 0); - return fixVarargs(narrowMH, mh); - } - - MethodHandle makeAccessor(Class<?> refc, MemberName field, - boolean trusted, boolean isSetter, - int checkStatic) throws IllegalAccessException { - assert(field.isField()); - if (checkStatic >= 0 && (checkStatic != 0) != field.isStatic()) - throw field.makeAccessException((checkStatic != 0) - ? "expected a static field" - : "expected a non-static field", this); - if (trusted) - return MethodHandleImpl.accessField(field, isSetter, /*no lookupClass*/ null); - checkAccess(refc, field); - MethodHandle mh = MethodHandleImpl.accessField(field, isSetter, lookupClassOrNull()); - return restrictProtectedReceiver(field, mh); - } - - /** Hook called from the JVM (via MethodHandleNatives) to link MH constants: - */ - /*non-public*/ - MethodHandle linkMethodHandleConstant(int refKind, Class<?> defc, String name, Object type) throws ReflectiveOperationException { - switch (refKind) { - case REF_getField: return resolveGetter( defc, name, (Class<?>) type ); - case REF_getStatic: return resolveStaticGetter( defc, name, (Class<?>) type ); - case REF_putField: return resolveSetter( defc, name, (Class<?>) type ); - case REF_putStatic: return resolveStaticSetter( defc, name, (Class<?>) type ); - case REF_invokeVirtual: return resolveVirtual( defc, name, (MethodType) type ); - case REF_invokeStatic: return resolveStatic( defc, name, (MethodType) type ); - case REF_invokeSpecial: return resolveSpecial( defc, name, (MethodType) type ); - case REF_newInvokeSpecial: return resolveConstructor( defc, (MethodType) type ); - case REF_invokeInterface: return resolveVirtual( defc, name, (MethodType) type ); - } - // oops - throw new ReflectiveOperationException("bad MethodHandle constant #"+refKind+" "+name+" : "+type); - } - } - - /** - * Produces a method handle giving read access to elements of an array. - * The type of the method handle will have a return type of the array's - * element type. Its first argument will be the array type, - * and the second will be {@code int}. - * @param arrayClass an array type - * @return a method handle which can load values from the given array type - * @throws NullPointerException if the argument is null - * @throws IllegalArgumentException if arrayClass is not an array type - */ - public static - MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentException { - return MethodHandleImpl.accessArrayElement(arrayClass, false); - } - - /** - * Produces a method handle giving write access to elements of an array. - * The type of the method handle will have a void return type. - * Its last argument will be the array's element type. - * The first and second arguments will be the array type and int. - * @return a method handle which can store values into the array type - * @throws NullPointerException if the argument is null - * @throws IllegalArgumentException if arrayClass is not an array type - */ - public static - MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException { - return MethodHandleImpl.accessArrayElement(arrayClass, true); - } - - /// method handle invocation (reflective style) - - /** - * Produces a method handle which will invoke any method handle of the - * given {@code type}, with a given number of trailing arguments replaced by - * a single trailing {@code Object[]} array. - * The resulting invoker will be a method handle with the following - * arguments: - * <ul> - * <li>a single {@code MethodHandle} target - * <li>zero or more leading values (counted by {@code leadingArgCount}) - * <li>an {@code Object[]} array containing trailing arguments - * </ul> - * <p> - * The invoker will invoke its target like a call to {@link MethodHandle#invoke invoke} with - * the indicated {@code type}. - * That is, if the target is exactly of the given {@code type}, it will behave - * like {@code invokeExact}; otherwise it behave as if {@link MethodHandle#asType asType} - * is used to convert the target to the required {@code type}. - * <p> - * The type of the returned invoker will not be the given {@code type}, but rather - * will have all parameters except the first {@code leadingArgCount} - * replaced by a single array of type {@code Object[]}, which will be - * the final parameter. - * <p> - * Before invoking its target, the invoker will spread the final array, apply - * reference casts as necessary, and unbox and widen primitive arguments. - * <p> - * This method is equivalent to the following code (though it may be more efficient): - * <p><blockquote><pre> -MethodHandle invoker = MethodHandles.invoker(type); -int spreadArgCount = type.parameterCount() - leadingArgCount; -invoker = invoker.asSpreader(Object[].class, spreadArgCount); -return invoker; - * </pre></blockquote> - * <p> - * This method throws no reflective or security exceptions. - * @param type the desired target type - * @param leadingArgCount number of fixed arguments, to be passed unchanged to the target - * @return a method handle suitable for invoking any method handle of the given type - * @throws NullPointerException if {@code type} is null - * @throws IllegalArgumentException if {@code leadingArgCount} is not in - * the range from 0 to {@code type.parameterCount()} inclusive - */ - static public - MethodHandle spreadInvoker(MethodType type, int leadingArgCount) { - if (leadingArgCount < 0 || leadingArgCount > type.parameterCount()) - throw new IllegalArgumentException("bad argument count "+leadingArgCount); - return type.invokers().spreadInvoker(leadingArgCount); - } - - /** - * Produces a special <em>invoker method handle</em> which can be used to - * invoke any method handle of the given type, as if by {@link MethodHandle#invokeExact invokeExact}. - * The resulting invoker will have a type which is - * exactly equal to the desired type, except that it will accept - * an additional leading argument of type {@code MethodHandle}. - * <p> - * This method is equivalent to the following code (though it may be more efficient): - * <p><blockquote><pre> -publicLookup().findVirtual(MethodHandle.class, "invokeExact", type) - * </pre></blockquote> - * - * <p style="font-size:smaller;"> - * <em>Discussion:</em> - * Invoker method handles can be useful when working with variable method handles - * of unknown types. - * For example, to emulate an {@code invokeExact} call to a variable method - * handle {@code M}, extract its type {@code T}, - * look up the invoker method {@code X} for {@code T}, - * and call the invoker method, as {@code X.invoke(T, A...)}. - * (It would not work to call {@code X.invokeExact}, since the type {@code T} - * is unknown.) - * If spreading, collecting, or other argument transformations are required, - * they can be applied once to the invoker {@code X} and reused on many {@code M} - * method handle values, as long as they are compatible with the type of {@code X}. - * <p> - * <em>(Note: The invoker method is not available via the Core Reflection API. - * An attempt to call {@linkplain java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke} - * on the declared {@code invokeExact} or {@code invoke} method will raise an - * {@link java.lang.UnsupportedOperationException UnsupportedOperationException}.)</em> - * <p> - * This method throws no reflective or security exceptions. - * @param type the desired target type - * @return a method handle suitable for invoking any method handle of the given type - */ - static public - MethodHandle exactInvoker(MethodType type) { - return type.invokers().exactInvoker(); - } - - /** - * Produces a special <em>invoker method handle</em> which can be used to - * invoke any method handle compatible with the given type, as if by {@link MethodHandle#invoke invoke}. - * The resulting invoker will have a type which is - * exactly equal to the desired type, except that it will accept - * an additional leading argument of type {@code MethodHandle}. - * <p> - * Before invoking its target, if the target differs from the expected type, - * the invoker will apply reference casts as - * necessary and box, unbox, or widen primitive values, as if by {@link MethodHandle#asType asType}. - * Similarly, the return value will be converted as necessary. - * If the target is a {@linkplain MethodHandle#asVarargsCollector variable arity method handle}, - * the required arity conversion will be made, again as if by {@link MethodHandle#asType asType}. - * <p> - * A {@linkplain MethodType#genericMethodType general method type}, - * mentions only {@code Object} arguments and return values. - * An invoker for such a type is capable of calling any method handle - * of the same arity as the general type. - * <p> - * This method is equivalent to the following code (though it may be more efficient): - * <p><blockquote><pre> -publicLookup().findVirtual(MethodHandle.class, "invoke", type) - * </pre></blockquote> - * <p> - * This method throws no reflective or security exceptions. - * @param type the desired target type - * @return a method handle suitable for invoking any method handle convertible to the given type - */ - static public - MethodHandle invoker(MethodType type) { - return type.invokers().generalInvoker(); - } - - /** - * Perform value checking, exactly as if for an adapted method handle. - * It is assumed that the given value is either null, of type T0, - * or (if T0 is primitive) of the wrapper class corresponding to T0. - * The following checks and conversions are made: - * <ul> - * <li>If T0 and T1 are references, then a cast to T1 is applied. - * (The types do not need to be related in any particular way.) - * <li>If T0 and T1 are primitives, then a widening or narrowing - * conversion is applied, if one exists. - * <li>If T0 is a primitive and T1 a reference, and - * T0 has a wrapper class TW, a boxing conversion to TW is applied, - * possibly followed by a reference conversion. - * T1 must be TW or a supertype. - * <li>If T0 is a reference and T1 a primitive, and - * T1 has a wrapper class TW, an unboxing conversion is applied, - * possibly preceded by a reference conversion. - * T0 must be TW or a supertype. - * <li>If T1 is void, the return value is discarded - * <li>If T0 is void and T1 a reference, a null value is introduced. - * <li>If T0 is void and T1 a primitive, a zero value is introduced. - * </ul> - * If the value is discarded, null will be returned. - * @param valueType - * @param value - * @return the value, converted if necessary - * @throws java.lang.ClassCastException if a cast fails - */ - // FIXME: This is used in just one place. Refactor away. - static - <T0, T1> T1 checkValue(Class<T0> t0, Class<T1> t1, Object value) - throws ClassCastException - { - if (t0 == t1) { - // no conversion needed; just reassert the same type - if (t0.isPrimitive()) - return Wrapper.asPrimitiveType(t1).cast(value); - else - return Wrapper.OBJECT.convert(value, t1); - } - boolean prim0 = t0.isPrimitive(), prim1 = t1.isPrimitive(); - if (!prim0) { - // check contract with caller - Wrapper.OBJECT.convert(value, t0); - if (!prim1) { - return Wrapper.OBJECT.convert(value, t1); - } - // convert reference to primitive by unboxing - Wrapper w1 = Wrapper.forPrimitiveType(t1); - return w1.convert(value, t1); - } - // check contract with caller: - Wrapper.asWrapperType(t0).cast(value); - Wrapper w1 = Wrapper.forPrimitiveType(t1); - return w1.convert(value, t1); - } - - // FIXME: Delete this. It is used only for insertArguments & bindTo. - // Replace by a more standard check. - static - Object checkValue(Class<?> T1, Object value) - throws ClassCastException - { - Class<?> T0; - if (value == null) - T0 = Object.class; - else - T0 = value.getClass(); - return checkValue(T0, T1, value); - } - - /// method handle modification (creation from other method handles) - - /** - * Produces a method handle which adapts the type of the - * given method handle to a new type by pairwise argument and return type conversion. - * The original type and new type must have the same number of arguments. - * The resulting method handle is guaranteed to report a type - * which is equal to the desired new type. - * <p> - * If the original type and new type are equal, returns target. - * <p> - * The same conversions are allowed as for {@link MethodHandle#asType MethodHandle.asType}, - * and some additional conversions are also applied if those conversions fail. - * Given types <em>T0</em>, <em>T1</em>, one of the following conversions is applied - * if possible, before or instead of any conversions done by {@code asType}: - * <ul> - * <li>If <em>T0</em> and <em>T1</em> are references, and <em>T1</em> is an interface type, - * then the value of type <em>T0</em> is passed as a <em>T1</em> without a cast. - * (This treatment of interfaces follows the usage of the bytecode verifier.) - * <li>If <em>T0</em> is boolean and <em>T1</em> is another primitive, - * the boolean is converted to a byte value, 1 for true, 0 for false. - * (This treatment follows the usage of the bytecode verifier.) - * <li>If <em>T1</em> is boolean and <em>T0</em> is another primitive, - * <em>T0</em> is converted to byte via Java casting conversion (JLS 5.5), - * and the low order bit of the result is tested, as if by {@code (x & 1) != 0}. - * <li>If <em>T0</em> and <em>T1</em> are primitives other than boolean, - * then a Java casting conversion (JLS 5.5) is applied. - * (Specifically, <em>T0</em> will convert to <em>T1</em> by - * widening and/or narrowing.) - * <li>If <em>T0</em> is a reference and <em>T1</em> a primitive, an unboxing - * conversion will be applied at runtime, possibly followed - * by a Java casting conversion (JLS 5.5) on the primitive value, - * possibly followed by a conversion from byte to boolean by testing - * the low-order bit. - * <li>If <em>T0</em> is a reference and <em>T1</em> a primitive, - * and if the reference is null at runtime, a zero value is introduced. - * </ul> - * @param target the method handle to invoke after arguments are retyped - * @param newType the expected type of the new method handle - * @return a method handle which delegates to the target after performing - * any necessary argument conversions, and arranges for any - * necessary return value conversions - * @throws NullPointerException if either argument is null - * @throws WrongMethodTypeException if the conversion cannot be made - * @see MethodHandle#asType - */ - public static - MethodHandle explicitCastArguments(MethodHandle target, MethodType newType) { - return MethodHandleImpl.convertArguments(target, newType, 2); - } - - /** - * Produces a method handle which adapts the calling sequence of the - * given method handle to a new type, by reordering the arguments. - * The resulting method handle is guaranteed to report a type - * which is equal to the desired new type. - * <p> - * The given array controls the reordering. - * Call {@code #I} the number of incoming parameters (the value - * {@code newType.parameterCount()}, and call {@code #O} the number - * of outgoing parameters (the value {@code target.type().parameterCount()}). - * Then the length of the reordering array must be {@code #O}, - * and each element must be a non-negative number less than {@code #I}. - * For every {@code N} less than {@code #O}, the {@code N}-th - * outgoing argument will be taken from the {@code I}-th incoming - * argument, where {@code I} is {@code reorder[N]}. - * <p> - * No argument or return value conversions are applied. - * The type of each incoming argument, as determined by {@code newType}, - * must be identical to the type of the corresponding outgoing parameter - * or parameters in the target method handle. - * The return type of {@code newType} must be identical to the return - * type of the original target. - * <p> - * The reordering array need not specify an actual permutation. - * An incoming argument will be duplicated if its index appears - * more than once in the array, and an incoming argument will be dropped - * if its index does not appear in the array. - * As in the case of {@link #dropArguments(MethodHandle,int,List) dropArguments}, - * incoming arguments which are not mentioned in the reordering array - * are may be any type, as determined only by {@code newType}. - * <blockquote><pre> -import static java.lang.invoke.MethodHandles.*; -import static java.lang.invoke.MethodType.*; -... -MethodType intfn1 = methodType(int.class, int.class); -MethodType intfn2 = methodType(int.class, int.class, int.class); -MethodHandle sub = ... {int x, int y => x-y} ...; -assert(sub.type().equals(intfn2)); -MethodHandle sub1 = permuteArguments(sub, intfn2, 0, 1); -MethodHandle rsub = permuteArguments(sub, intfn2, 1, 0); -assert((int)rsub.invokeExact(1, 100) == 99); -MethodHandle add = ... {int x, int y => x+y} ...; -assert(add.type().equals(intfn2)); -MethodHandle twice = permuteArguments(add, intfn1, 0, 0); -assert(twice.type().equals(intfn1)); -assert((int)twice.invokeExact(21) == 42); - * </pre></blockquote> - * @param target the method handle to invoke after arguments are reordered - * @param newType the expected type of the new method handle - * @param reorder an index array which controls the reordering - * @return a method handle which delegates to the target after it - * drops unused arguments and moves and/or duplicates the other arguments - * @throws NullPointerException if any argument is null - * @throws IllegalArgumentException if the index array length is not equal to - * the arity of the target, or if any index array element - * not a valid index for a parameter of {@code newType}, - * or if two corresponding parameter types in - * {@code target.type()} and {@code newType} are not identical, - */ - public static - MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder) { - MethodType oldType = target.type(); - checkReorder(reorder, newType, oldType); - return MethodHandleImpl.permuteArguments(target, - newType, oldType, - reorder); - } - - private static void checkReorder(int[] reorder, MethodType newType, MethodType oldType) { - if (newType.returnType() != oldType.returnType()) - throw newIllegalArgumentException("return types do not match", - oldType, newType); - if (reorder.length == oldType.parameterCount()) { - int limit = newType.parameterCount(); - boolean bad = false; - for (int j = 0; j < reorder.length; j++) { - int i = reorder[j]; - if (i < 0 || i >= limit) { - bad = true; break; - } - Class<?> src = newType.parameterType(i); - Class<?> dst = oldType.parameterType(j); - if (src != dst) - throw newIllegalArgumentException("parameter types do not match after reorder", - oldType, newType); - } - if (!bad) return; - } - throw newIllegalArgumentException("bad reorder array: "+Arrays.toString(reorder)); - } - - /** - * Produces a method handle of the requested return type which returns the given - * constant value every time it is invoked. - * <p> - * Before the method handle is returned, the passed-in value is converted to the requested type. - * If the requested type is primitive, widening primitive conversions are attempted, - * else reference conversions are attempted. - * <p>The returned method handle is equivalent to {@code identity(type).bindTo(value)}. - * @param type the return type of the desired method handle - * @param value the value to return - * @return a method handle of the given return type and no arguments, which always returns the given value - * @throws NullPointerException if the {@code type} argument is null - * @throws ClassCastException if the value cannot be converted to the required return type - * @throws IllegalArgumentException if the given type is {@code void.class} - */ - public static - MethodHandle constant(Class<?> type, Object value) { - if (type.isPrimitive()) { - if (type == void.class) - throw newIllegalArgumentException("void type"); - Wrapper w = Wrapper.forPrimitiveType(type); - return insertArguments(identity(type), 0, w.convert(value, type)); - } else { - return identity(type).bindTo(type.cast(value)); - } - } - - /** - * Produces a method handle which returns its sole argument when invoked. - * @param type the type of the sole parameter and return value of the desired method handle - * @return a unary method handle which accepts and returns the given type - * @throws NullPointerException if the argument is null - * @throws IllegalArgumentException if the given type is {@code void.class} - */ - public static - MethodHandle identity(Class<?> type) { - if (type == void.class) - throw newIllegalArgumentException("void type"); - else if (type == Object.class) - return ValueConversions.identity(); - else if (type.isPrimitive()) - return ValueConversions.identity(Wrapper.forPrimitiveType(type)); - else - return AdapterMethodHandle.makeRetypeRaw( - MethodType.methodType(type, type), ValueConversions.identity()); - } - - /** - * Provides a target method handle with one or more <em>bound arguments</em> - * in advance of the method handle's invocation. - * The formal parameters to the target corresponding to the bound - * arguments are called <em>bound parameters</em>. - * Returns a new method handle which saves away the bound arguments. - * When it is invoked, it receives arguments for any non-bound parameters, - * binds the saved arguments to their corresponding parameters, - * and calls the original target. - * <p> - * The type of the new method handle will drop the types for the bound - * parameters from the original target type, since the new method handle - * will no longer require those arguments to be supplied by its callers. - * <p> - * Each given argument object must match the corresponding bound parameter type. - * If a bound parameter type is a primitive, the argument object - * must be a wrapper, and will be unboxed to produce the primitive value. - * <p> - * The {@code pos} argument selects which parameters are to be bound. - * It may range between zero and <i>N-L</i> (inclusively), - * where <i>N</i> is the arity of the target method handle - * and <i>L</i> is the length of the values array. - * @param target the method handle to invoke after the argument is inserted - * @param pos where to insert the argument (zero for the first) - * @param values the series of arguments to insert - * @return a method handle which inserts an additional argument, - * before calling the original method handle - * @throws NullPointerException if the target or the {@code values} array is null - * @see MethodHandle#bindTo - */ - public static - MethodHandle insertArguments(MethodHandle target, int pos, Object... values) { - int insCount = values.length; - MethodType oldType = target.type(); - int outargs = oldType.parameterCount(); - int inargs = outargs - insCount; - if (inargs < 0) - throw newIllegalArgumentException("too many values to insert"); - if (pos < 0 || pos > inargs) - throw newIllegalArgumentException("no argument type to append"); - MethodHandle result = target; - for (int i = 0; i < insCount; i++) { - Object value = values[i]; - Class<?> valueType = oldType.parameterType(pos+i); - value = checkValue(valueType, value); - if (pos == 0 && !valueType.isPrimitive()) { - // At least for now, make bound method handles a special case. - MethodHandle bmh = MethodHandleImpl.bindReceiver(result, value); - if (bmh != null) { - result = bmh; - continue; - } - // else fall through to general adapter machinery - } - result = MethodHandleImpl.bindArgument(result, pos, value); - } - return result; - } - - /** - * Produces a method handle which will discard some dummy arguments - * before calling some other specified <i>target</i> method handle. - * The type of the new method handle will be the same as the target's type, - * except it will also include the dummy argument types, - * at some given position. - * <p> - * The {@code pos} argument may range between zero and <i>N</i>, - * where <i>N</i> is the arity of the target. - * If {@code pos} is zero, the dummy arguments will precede - * the target's real arguments; if {@code pos} is <i>N</i> - * they will come after. - * <p> - * <b>Example:</b> - * <p><blockquote><pre> -import static java.lang.invoke.MethodHandles.*; -import static java.lang.invoke.MethodType.*; -... -MethodHandle cat = lookup().findVirtual(String.class, - "concat", methodType(String.class, String.class)); -assertEquals("xy", (String) cat.invokeExact("x", "y")); -MethodType bigType = cat.type().insertParameterTypes(0, int.class, String.class); -MethodHandle d0 = dropArguments(cat, 0, bigType.parameterList().subList(0,2)); -assertEquals(bigType, d0.type()); -assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z")); - * </pre></blockquote> - * <p> - * This method is also equivalent to the following code: - * <p><blockquote><pre> - * {@link #dropArguments(MethodHandle,int,Class...) dropArguments}(target, pos, valueTypes.toArray(new Class[0])) - * </pre></blockquote> - * @param target the method handle to invoke after the arguments are dropped - * @param valueTypes the type(s) of the argument(s) to drop - * @param pos position of first argument to drop (zero for the leftmost) - * @return a method handle which drops arguments of the given types, - * before calling the original method handle - * @throws NullPointerException if the target is null, - * or if the {@code valueTypes} list or any of its elements is null - * @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class}, - * or if {@code pos} is negative or greater than the arity of the target, - * or if the new method handle's type would have too many parameters - */ - public static - MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes) { - MethodType oldType = target.type(); // get NPE - if (valueTypes.size() == 0) return target; - int outargs = oldType.parameterCount(); - int inargs = outargs + valueTypes.size(); - if (pos < 0 || pos >= inargs) - throw newIllegalArgumentException("no argument type to remove"); - ArrayList<Class<?>> ptypes = - new ArrayList<Class<?>>(oldType.parameterList()); - ptypes.addAll(pos, valueTypes); - MethodType newType = MethodType.methodType(oldType.returnType(), ptypes); - return MethodHandleImpl.dropArguments(target, newType, pos); - } - - /** - * Produces a method handle which will discard some dummy arguments - * before calling some other specified <i>target</i> method handle. - * The type of the new method handle will be the same as the target's type, - * except it will also include the dummy argument types, - * at some given position. - * <p> - * The {@code pos} argument may range between zero and <i>N</i>, - * where <i>N</i> is the arity of the target. - * If {@code pos} is zero, the dummy arguments will precede - * the target's real arguments; if {@code pos} is <i>N</i> - * they will come after. - * <p> - * <b>Example:</b> - * <p><blockquote><pre> -import static java.lang.invoke.MethodHandles.*; -import static java.lang.invoke.MethodType.*; -... -MethodHandle cat = lookup().findVirtual(String.class, - "concat", methodType(String.class, String.class)); -assertEquals("xy", (String) cat.invokeExact("x", "y")); -MethodHandle d0 = dropArguments(cat, 0, String.class); -assertEquals("yz", (String) d0.invokeExact("x", "y", "z")); -MethodHandle d1 = dropArguments(cat, 1, String.class); -assertEquals("xz", (String) d1.invokeExact("x", "y", "z")); -MethodHandle d2 = dropArguments(cat, 2, String.class); -assertEquals("xy", (String) d2.invokeExact("x", "y", "z")); -MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class); -assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z")); - * </pre></blockquote> - * <p> - * This method is also equivalent to the following code: - * <p><blockquote><pre> - * {@link #dropArguments(MethodHandle,int,List) dropArguments}(target, pos, Arrays.asList(valueTypes)) - * </pre></blockquote> - * @param target the method handle to invoke after the arguments are dropped - * @param valueTypes the type(s) of the argument(s) to drop - * @param pos position of first argument to drop (zero for the leftmost) - * @return a method handle which drops arguments of the given types, - * before calling the original method handle - * @throws NullPointerException if the target is null, - * or if the {@code valueTypes} array or any of its elements is null - * @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class}, - * or if {@code pos} is negative or greater than the arity of the target, - * or if the new method handle's type would have too many parameters - */ - public static - MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes) { - return dropArguments(target, pos, Arrays.asList(valueTypes)); - } - - /** - * Adapts a target method handle by pre-processing - * one or more of its arguments, each with its own unary filter function, - * and then calling the target with each pre-processed argument - * replaced by the result of its corresponding filter function. - * <p> - * The pre-processing is performed by one or more method handles, - * specified in the elements of the {@code filters} array. - * The first element of the filter array corresponds to the {@code pos} - * argument of the target, and so on in sequence. - * <p> - * Null arguments in the array are treated as identity functions, - * and the corresponding arguments left unchanged. - * (If there are no non-null elements in the array, the original target is returned.) - * Each filter is applied to the corresponding argument of the adapter. - * <p> - * If a filter {@code F} applies to the {@code N}th argument of - * the target, then {@code F} must be a method handle which - * takes exactly one argument. The type of {@code F}'s sole argument - * replaces the corresponding argument type of the target - * in the resulting adapted method handle. - * The return type of {@code F} must be identical to the corresponding - * parameter type of the target. - * <p> - * It is an error if there are elements of {@code filters} - * (null or not) - * which do not correspond to argument positions in the target. - * <b>Example:</b> - * <p><blockquote><pre> -import static java.lang.invoke.MethodHandles.*; -import static java.lang.invoke.MethodType.*; -... -MethodHandle cat = lookup().findVirtual(String.class, - "concat", methodType(String.class, String.class)); -MethodHandle upcase = lookup().findVirtual(String.class, - "toUpperCase", methodType(String.class)); -assertEquals("xy", (String) cat.invokeExact("x", "y")); -MethodHandle f0 = filterArguments(cat, 0, upcase); -assertEquals("Xy", (String) f0.invokeExact("x", "y")); // Xy -MethodHandle f1 = filterArguments(cat, 1, upcase); -assertEquals("xY", (String) f1.invokeExact("x", "y")); // xY -MethodHandle f2 = filterArguments(cat, 0, upcase, upcase); -assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY - * </pre></blockquote> - * <p> Here is pseudocode for the resulting adapter: - * <blockquote><pre> - * V target(P... p, A[i]... a[i], B... b); - * A[i] filter[i](V[i]); - * T adapter(P... p, V[i]... v[i], B... b) { - * return target(p..., f[i](v[i])..., b...); - * } - * </pre></blockquote> - * - * @param target the method handle to invoke after arguments are filtered - * @param pos the position of the first argument to filter - * @param filters method handles to call initially on filtered arguments - * @return method handle which incorporates the specified argument filtering logic - * @throws NullPointerException if the target is null - * or if the {@code filters} array is null - * @throws IllegalArgumentException if a non-null element of {@code filters} - * does not match a corresponding argument type of target as described above, - * or if the {@code pos+filters.length} is greater than {@code target.type().parameterCount()} - */ - public static - MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) { - MethodType targetType = target.type(); - MethodHandle adapter = target; - MethodType adapterType = null; - assert((adapterType = targetType) != null); - int maxPos = targetType.parameterCount(); - if (pos + filters.length > maxPos) - throw newIllegalArgumentException("too many filters"); - int curPos = pos-1; // pre-incremented - for (MethodHandle filter : filters) { - curPos += 1; - if (filter == null) continue; // ignore null elements of filters - adapter = filterArgument(adapter, curPos, filter); - assert((adapterType = adapterType.changeParameterType(curPos, filter.type().parameterType(0))) != null); - } - assert(adapterType.equals(adapter.type())); - return adapter; - } - - /*non-public*/ static - MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) { - MethodType targetType = target.type(); - MethodType filterType = filter.type(); - if (filterType.parameterCount() != 1 - || filterType.returnType() != targetType.parameterType(pos)) - throw newIllegalArgumentException("target and filter types do not match", targetType, filterType); - return MethodHandleImpl.filterArgument(target, pos, filter); - } - - /** - * Adapts a target method handle by post-processing - * its return value (if any) with a filter (another method handle). - * The result of the filter is returned from the adapter. - * <p> - * If the target returns a value, the filter must accept that value as - * its only argument. - * If the target returns void, the filter must accept no arguments. - * <p> - * The return type of the filter - * replaces the return type of the target - * in the resulting adapted method handle. - * The argument type of the filter (if any) must be identical to the - * return type of the target. - * <b>Example:</b> - * <p><blockquote><pre> -import static java.lang.invoke.MethodHandles.*; -import static java.lang.invoke.MethodType.*; -... -MethodHandle cat = lookup().findVirtual(String.class, - "concat", methodType(String.class, String.class)); -MethodHandle length = lookup().findVirtual(String.class, - "length", methodType(int.class)); -System.out.println((String) cat.invokeExact("x", "y")); // xy -MethodHandle f0 = filterReturnValue(cat, length); -System.out.println((int) f0.invokeExact("x", "y")); // 2 - * </pre></blockquote> - * <p> Here is pseudocode for the resulting adapter: - * <blockquote><pre> - * V target(A...); - * T filter(V); - * T adapter(A... a) { - * V v = target(a...); - * return filter(v); - * } - * // and if the target has a void return: - * void target2(A...); - * T filter2(); - * T adapter2(A... a) { - * target2(a...); - * return filter2(); - * } - * // and if the filter has a void return: - * V target3(A...); - * void filter3(V); - * void adapter3(A... a) { - * V v = target3(a...); - * filter3(v); - * } - * </pre></blockquote> - * @param target the method handle to invoke before filtering the return value - * @param filter method handle to call on the return value - * @return method handle which incorporates the specified return value filtering logic - * @throws NullPointerException if either argument is null - * @throws IllegalArgumentException if the argument list of {@code filter} - * does not match the return type of target as described above - */ - public static - MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) { - MethodType targetType = target.type(); - MethodType filterType = filter.type(); - Class<?> rtype = targetType.returnType(); - int filterValues = filterType.parameterCount(); - if (filterValues == 0 - ? (rtype != void.class) - : (rtype != filterType.parameterType(0))) - throw newIllegalArgumentException("target and filter types do not match", target, filter); - // result = fold( lambda(retval, arg...) { filter(retval) }, - // lambda( arg...) { target(arg...) } ) - MethodType newType = targetType.changeReturnType(filterType.returnType()); - MethodHandle result = null; - if (AdapterMethodHandle.canCollectArguments(filterType, targetType, 0, false)) { - result = AdapterMethodHandle.makeCollectArguments(filter, target, 0, false); - if (result != null) return result; - } - // FIXME: Too many nodes here. - assert(MethodHandleNatives.workaroundWithoutRicochetFrames()); // this class is deprecated - MethodHandle returner = dropArguments(filter, filterValues, targetType.parameterList()); - result = foldArguments(returner, target); - assert(result.type().equals(newType)); - return result; - } - - /** - * Adapts a target method handle by pre-processing - * some of its arguments, and then calling the target with - * the result of the pre-processing, inserted into the original - * sequence of arguments. - * <p> - * The pre-processing is performed by {@code combiner}, a second method handle. - * Of the arguments passed to the adapter, the first {@code N} arguments - * are copied to the combiner, which is then called. - * (Here, {@code N} is defined as the parameter count of the combiner.) - * After this, control passes to the target, with any result - * from the combiner inserted before the original {@code N} incoming - * arguments. - * <p> - * If the combiner returns a value, the first parameter type of the target - * must be identical with the return type of the combiner, and the next - * {@code N} parameter types of the target must exactly match the parameters - * of the combiner. - * <p> - * If the combiner has a void return, no result will be inserted, - * and the first {@code N} parameter types of the target - * must exactly match the parameters of the combiner. - * <p> - * The resulting adapter is the same type as the target, except that the - * first parameter type is dropped, - * if it corresponds to the result of the combiner. - * <p> - * (Note that {@link #dropArguments(MethodHandle,int,List) dropArguments} can be used to remove any arguments - * that either the combiner or the target does not wish to receive. - * If some of the incoming arguments are destined only for the combiner, - * consider using {@link MethodHandle#asCollector asCollector} instead, since those - * arguments will not need to be live on the stack on entry to the - * target.) - * <b>Example:</b> - * <p><blockquote><pre> -import static java.lang.invoke.MethodHandles.*; -import static java.lang.invoke.MethodType.*; -... -MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class, - "println", methodType(void.class, String.class)) - .bindTo(System.out); -MethodHandle cat = lookup().findVirtual(String.class, - "concat", methodType(String.class, String.class)); -assertEquals("boojum", (String) cat.invokeExact("boo", "jum")); -MethodHandle catTrace = foldArguments(cat, trace); -// also prints "boo": -assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); - * </pre></blockquote> - * <p> Here is pseudocode for the resulting adapter: - * <blockquote><pre> - * // there are N arguments in A... - * T target(V, A[N]..., B...); - * V combiner(A...); - * T adapter(A... a, B... b) { - * V v = combiner(a...); - * return target(v, a..., b...); - * } - * // and if the combiner has a void return: - * T target2(A[N]..., B...); - * void combiner2(A...); - * T adapter2(A... a, B... b) { - * combiner2(a...); - * return target2(a..., b...); - * } - * </pre></blockquote> - * @param target the method handle to invoke after arguments are combined - * @param combiner method handle to call initially on the incoming arguments - * @return method handle which incorporates the specified argument folding logic - * @throws NullPointerException if either argument is null - * @throws IllegalArgumentException if {@code combiner}'s return type - * is non-void and not the same as the first argument type of - * the target, or if the initial {@code N} argument types - * of the target - * (skipping one matching the {@code combiner}'s return type) - * are not identical with the argument types of {@code combiner} - */ - public static - MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) { - int pos = 0; - MethodType targetType = target.type(); - MethodType combinerType = combiner.type(); - int foldPos = pos; - int foldArgs = combinerType.parameterCount(); - int foldVals = combinerType.returnType() == void.class ? 0 : 1; - int afterInsertPos = foldPos + foldVals; - boolean ok = (targetType.parameterCount() >= afterInsertPos + foldArgs); - if (ok && !(combinerType.parameterList() - .equals(targetType.parameterList().subList(afterInsertPos, - afterInsertPos + foldArgs)))) - ok = false; - if (ok && foldVals != 0 && !combinerType.returnType().equals(targetType.parameterType(0))) - ok = false; - if (!ok) - throw misMatchedTypes("target and combiner types", targetType, combinerType); - MethodType newType = targetType.dropParameterTypes(foldPos, afterInsertPos); - MethodHandle res = MethodHandleImpl.foldArguments(target, newType, foldPos, combiner); - if (res == null) throw newIllegalArgumentException("cannot fold from "+newType+" to " +targetType); - return res; - } - - /** - * Makes a method handle which adapts a target method handle, - * by guarding it with a test, a boolean-valued method handle. - * If the guard fails, a fallback handle is called instead. - * All three method handles must have the same corresponding - * argument and return types, except that the return type - * of the test must be boolean, and the test is allowed - * to have fewer arguments than the other two method handles. - * <p> Here is pseudocode for the resulting adapter: - * <blockquote><pre> - * boolean test(A...); - * T target(A...,B...); - * T fallback(A...,B...); - * T adapter(A... a,B... b) { - * if (test(a...)) - * return target(a..., b...); - * else - * return fallback(a..., b...); - * } - * </pre></blockquote> - * Note that the test arguments ({@code a...} in the pseudocode) cannot - * be modified by execution of the test, and so are passed unchanged - * from the caller to the target or fallback as appropriate. - * @param test method handle used for test, must return boolean - * @param target method handle to call if test passes - * @param fallback method handle to call if test fails - * @return method handle which incorporates the specified if/then/else logic - * @throws NullPointerException if any argument is null - * @throws IllegalArgumentException if {@code test} does not return boolean, - * or if all three method types do not match (with the return - * type of {@code test} changed to match that of the target). - */ - public static - MethodHandle guardWithTest(MethodHandle test, - MethodHandle target, - MethodHandle fallback) { - MethodType gtype = test.type(); - MethodType ttype = target.type(); - MethodType ftype = fallback.type(); - if (!ttype.equals(ftype)) - throw misMatchedTypes("target and fallback types", ttype, ftype); - if (gtype.returnType() != boolean.class) - throw newIllegalArgumentException("guard type is not a predicate "+gtype); - List<Class<?>> targs = ttype.parameterList(); - List<Class<?>> gargs = gtype.parameterList(); - if (!targs.equals(gargs)) { - int gpc = gargs.size(), tpc = targs.size(); - if (gpc >= tpc || !targs.subList(0, gpc).equals(gargs)) - throw misMatchedTypes("target and test types", ttype, gtype); - test = dropArguments(test, gpc, targs.subList(gpc, tpc)); - gtype = test.type(); - } - return MethodHandleImpl.makeGuardWithTest(test, target, fallback); - } - - static RuntimeException misMatchedTypes(String what, MethodType t1, MethodType t2) { - return newIllegalArgumentException(what + " must match: " + t1 + " != " + t2); - } - - /** - * Makes a method handle which adapts a target method handle, - * by running it inside an exception handler. - * If the target returns normally, the adapter returns that value. - * If an exception matching the specified type is thrown, the fallback - * handle is called instead on the exception, plus the original arguments. - * <p> - * The target and handler must have the same corresponding - * argument and return types, except that handler may omit trailing arguments - * (similarly to the predicate in {@link #guardWithTest guardWithTest}). - * Also, the handler must have an extra leading parameter of {@code exType} or a supertype. - * <p> Here is pseudocode for the resulting adapter: - * <blockquote><pre> - * T target(A..., B...); - * T handler(ExType, A...); - * T adapter(A... a, B... b) { - * try { - * return target(a..., b...); - * } catch (ExType ex) { - * return handler(ex, a...); - * } - * } - * </pre></blockquote> - * Note that the saved arguments ({@code a...} in the pseudocode) cannot - * be modified by execution of the target, and so are passed unchanged - * from the caller to the handler, if the handler is invoked. - * <p> - * The target and handler must return the same type, even if the handler - * always throws. (This might happen, for instance, because the handler - * is simulating a {@code finally} clause). - * To create such a throwing handler, compose the handler creation logic - * with {@link #throwException throwException}, - * in order to create a method handle of the correct return type. - * @param target method handle to call - * @param exType the type of exception which the handler will catch - * @param handler method handle to call if a matching exception is thrown - * @return method handle which incorporates the specified try/catch logic - * @throws NullPointerException if any argument is null - * @throws IllegalArgumentException if {@code handler} does not accept - * the given exception type, or if the method handle types do - * not match in their return types and their - * corresponding parameters - */ - public static - MethodHandle catchException(MethodHandle target, - Class<? extends Throwable> exType, - MethodHandle handler) { - MethodType ttype = target.type(); - MethodType htype = handler.type(); - if (htype.parameterCount() < 1 || - !htype.parameterType(0).isAssignableFrom(exType)) - throw newIllegalArgumentException("handler does not accept exception type "+exType); - if (htype.returnType() != ttype.returnType()) - throw misMatchedTypes("target and handler return types", ttype, htype); - List<Class<?>> targs = ttype.parameterList(); - List<Class<?>> hargs = htype.parameterList(); - hargs = hargs.subList(1, hargs.size()); // omit leading parameter from handler - if (!targs.equals(hargs)) { - int hpc = hargs.size(), tpc = targs.size(); - if (hpc >= tpc || !targs.subList(0, hpc).equals(hargs)) - throw misMatchedTypes("target and handler types", ttype, htype); - handler = dropArguments(handler, 1+hpc, targs.subList(hpc, tpc)); - htype = handler.type(); - } - return MethodHandleImpl.makeGuardWithCatch(target, exType, handler); - } - - /** - * Produces a method handle which will throw exceptions of the given {@code exType}. - * The method handle will accept a single argument of {@code exType}, - * and immediately throw it as an exception. - * The method type will nominally specify a return of {@code returnType}. - * The return type may be anything convenient: It doesn't matter to the - * method handle's behavior, since it will never return normally. - * @return method handle which can throw the given exceptions - * @throws NullPointerException if either argument is null - */ - public static - MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType) { - return MethodHandleImpl.throwException(MethodType.methodType(returnType, exType)); - } -} diff --git a/openjdk/java/lang/invoke/MutableCallSite.java b/openjdk/java/lang/invoke/MutableCallSite.java deleted file mode 100644 index d48f99af..00000000 --- a/openjdk/java/lang/invoke/MutableCallSite.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (c) 2008, 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 java.lang.invoke; - -import java.util.concurrent.atomic.AtomicInteger; - -/** - * A {@code MutableCallSite} is a {@link CallSite} whose target variable - * behaves like an ordinary field. - * An {@code invokedynamic} instruction linked to a {@code MutableCallSite} delegates - * all calls to the site's current target. - * The {@linkplain CallSite#dynamicInvoker dynamic invoker} of a mutable call site - * also delegates each call to the site's current target. - * <p> - * Here is an example of a mutable call site which introduces a - * state variable into a method handle chain. - * <!-- JavaDocExamplesTest.testMutableCallSite --> - * <blockquote><pre> -MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class)); -MethodHandle MH_name = name.dynamicInvoker(); -MethodType MT_str1 = MethodType.methodType(String.class); -MethodHandle MH_upcase = MethodHandles.lookup() - .findVirtual(String.class, "toUpperCase", MT_str1); -MethodHandle worker1 = MethodHandles.filterReturnValue(MH_name, MH_upcase); -name.setTarget(MethodHandles.constant(String.class, "Rocky")); -assertEquals("ROCKY", (String) worker1.invokeExact()); -name.setTarget(MethodHandles.constant(String.class, "Fred")); -assertEquals("FRED", (String) worker1.invokeExact()); -// (mutation can be continued indefinitely) - * </pre></blockquote> - * <p> - * The same call site may be used in several places at once. - * <blockquote><pre> -MethodType MT_str2 = MethodType.methodType(String.class, String.class); -MethodHandle MH_cat = lookup().findVirtual(String.class, - "concat", methodType(String.class, String.class)); -MethodHandle MH_dear = MethodHandles.insertArguments(MH_cat, 1, ", dear?"); -MethodHandle worker2 = MethodHandles.filterReturnValue(MH_name, MH_dear); -assertEquals("Fred, dear?", (String) worker2.invokeExact()); -name.setTarget(MethodHandles.constant(String.class, "Wilma")); -assertEquals("WILMA", (String) worker1.invokeExact()); -assertEquals("Wilma, dear?", (String) worker2.invokeExact()); - * </pre></blockquote> - * <p> - * <em>Non-synchronization of target values:</em> - * A write to a mutable call site's target does not force other threads - * to become aware of the updated value. Threads which do not perform - * suitable synchronization actions relative to the updated call site - * may cache the old target value and delay their use of the new target - * value indefinitely. - * (This is a normal consequence of the Java Memory Model as applied - * to object fields.) - * <p> - * The {@link #syncAll syncAll} operation provides a way to force threads - * to accept a new target value, even if there is no other synchronization. - * <p> - * For target values which will be frequently updated, consider using - * a {@linkplain VolatileCallSite volatile call site} instead. - * @author John Rose, JSR 292 EG - */ -public class MutableCallSite extends CallSite { - /** - * Creates a blank call site object with the given method type. - * The initial target is set to a method handle of the given type - * which will throw an {@link IllegalStateException} if called. - * <p> - * The type of the call site is permanently set to the given type. - * <p> - * Before this {@code CallSite} object is returned from a bootstrap method, - * or invoked in some other manner, - * it is usually provided with a more useful target method, - * via a call to {@link CallSite#setTarget(MethodHandle) setTarget}. - * @param type the method type that this call site will have - * @throws NullPointerException if the proposed type is null - */ - public MutableCallSite(MethodType type) { - super(type); - } - - /** - * Creates a call site object with an initial target method handle. - * The type of the call site is permanently set to the initial target's type. - * @param target the method handle that will be the initial target of the call site - * @throws NullPointerException if the proposed target is null - */ - public MutableCallSite(MethodHandle target) { - super(target); - } - - /** - * Returns the target method of the call site, which behaves - * like a normal field of the {@code MutableCallSite}. - * <p> - * The interactions of {@code getTarget} with memory are the same - * as of a read from an ordinary variable, such as an array element or a - * non-volatile, non-final field. - * <p> - * In particular, the current thread may choose to reuse the result - * of a previous read of the target from memory, and may fail to see - * a recent update to the target by another thread. - * - * @return the linkage state of this call site, a method handle which can change over time - * @see #setTarget - */ - @Override public final MethodHandle getTarget() { - return target; - } - - /** - * Updates the target method of this call site, as a normal variable. - * The type of the new target must agree with the type of the old target. - * <p> - * The interactions with memory are the same - * as of a write to an ordinary variable, such as an array element or a - * non-volatile, non-final field. - * <p> - * In particular, unrelated threads may fail to see the updated target - * until they perform a read from memory. - * Stronger guarantees can be created by putting appropriate operations - * into the bootstrap method and/or the target methods used - * at any given call site. - * - * @param newTarget the new target - * @throws NullPointerException if the proposed new target is null - * @throws WrongMethodTypeException if the proposed new target - * has a method type that differs from the previous target - * @see #getTarget - */ - @Override public void setTarget(MethodHandle newTarget) { - checkTargetChange(this.target, newTarget); - setTargetNormal(newTarget); - } - - /** - * {@inheritDoc} - */ - @Override - public final MethodHandle dynamicInvoker() { - return makeDynamicInvoker(); - } - - /** - * Performs a synchronization operation on each call site in the given array, - * forcing all other threads to throw away any cached values previously - * loaded from the target of any of the call sites. - * <p> - * This operation does not reverse any calls that have already started - * on an old target value. - * (Java supports {@linkplain java.lang.Object#wait() forward time travel} only.) - * <p> - * The overall effect is to force all future readers of each call site's target - * to accept the most recently stored value. - * ("Most recently" is reckoned relative to the {@code syncAll} itself.) - * Conversely, the {@code syncAll} call may block until all readers have - * (somehow) decached all previous versions of each call site's target. - * <p> - * To avoid race conditions, calls to {@code setTarget} and {@code syncAll} - * should generally be performed under some sort of mutual exclusion. - * Note that reader threads may observe an updated target as early - * as the {@code setTarget} call that install the value - * (and before the {@code syncAll} that confirms the value). - * On the other hand, reader threads may observe previous versions of - * the target until the {@code syncAll} call returns - * (and after the {@code setTarget} that attempts to convey the updated version). - * <p> - * This operation is likely to be expensive and should be used sparingly. - * If possible, it should be buffered for batch processing on sets of call sites. - * <p> - * If {@code sites} contains a null element, - * a {@code NullPointerException} will be raised. - * In this case, some non-null elements in the array may be - * processed before the method returns abnormally. - * Which elements these are (if any) is implementation-dependent. - * - * <h3>Java Memory Model details</h3> - * In terms of the Java Memory Model, this operation performs a synchronization - * action which is comparable in effect to the writing of a volatile variable - * by the current thread, and an eventual volatile read by every other thread - * that may access one of the affected call sites. - * <p> - * The following effects are apparent, for each individual call site {@code S}: - * <ul> - * <li>A new volatile variable {@code V} is created, and written by the current thread. - * As defined by the JMM, this write is a global synchronization event. - * <li>As is normal with thread-local ordering of write events, - * every action already performed by the current thread is - * taken to happen before the volatile write to {@code V}. - * (In some implementations, this means that the current thread - * performs a global release operation.) - * <li>Specifically, the write to the current target of {@code S} is - * taken to happen before the volatile write to {@code V}. - * <li>The volatile write to {@code V} is placed - * (in an implementation specific manner) - * in the global synchronization order. - * <li>Consider an arbitrary thread {@code T} (other than the current thread). - * If {@code T} executes a synchronization action {@code A} - * after the volatile write to {@code V} (in the global synchronization order), - * it is therefore required to see either the current target - * of {@code S}, or a later write to that target, - * if it executes a read on the target of {@code S}. - * (This constraint is called "synchronization-order consistency".) - * <li>The JMM specifically allows optimizing compilers to elide - * reads or writes of variables that are known to be useless. - * Such elided reads and writes have no effect on the happens-before - * relation. Regardless of this fact, the volatile {@code V} - * will not be elided, even though its written value is - * indeterminate and its read value is not used. - * </ul> - * Because of the last point, the implementation behaves as if a - * volatile read of {@code V} were performed by {@code T} - * immediately after its action {@code A}. In the local ordering - * of actions in {@code T}, this read happens before any future - * read of the target of {@code S}. It is as if the - * implementation arbitrarily picked a read of {@code S}'s target - * by {@code T}, and forced a read of {@code V} to precede it, - * thereby ensuring communication of the new target value. - * <p> - * As long as the constraints of the Java Memory Model are obeyed, - * implementations may delay the completion of a {@code syncAll} - * operation while other threads ({@code T} above) continue to - * use previous values of {@code S}'s target. - * However, implementations are (as always) encouraged to avoid - * livelock, and to eventually require all threads to take account - * of the updated target. - * - * <p style="font-size:smaller;"> - * <em>Discussion:</em> - * For performance reasons, {@code syncAll} is not a virtual method - * on a single call site, but rather applies to a set of call sites. - * Some implementations may incur a large fixed overhead cost - * for processing one or more synchronization operations, - * but a small incremental cost for each additional call site. - * In any case, this operation is likely to be costly, since - * other threads may have to be somehow interrupted - * in order to make them notice the updated target value. - * However, it may be observed that a single call to synchronize - * several sites has the same formal effect as many calls, - * each on just one of the sites. - * - * <p style="font-size:smaller;"> - * <em>Implementation Note:</em> - * Simple implementations of {@code MutableCallSite} may use - * a volatile variable for the target of a mutable call site. - * In such an implementation, the {@code syncAll} method can be a no-op, - * and yet it will conform to the JMM behavior documented above. - * - * @param sites an array of call sites to be synchronized - * @throws NullPointerException if the {@code sites} array reference is null - * or the array contains a null - */ - public static void syncAll(MutableCallSite[] sites) { - if (sites.length == 0) return; - STORE_BARRIER.lazySet(0); - for (int i = 0; i < sites.length; i++) { - sites[i].getClass(); // trigger NPE on first null - } - // FIXME: NYI - } - private static final AtomicInteger STORE_BARRIER = new AtomicInteger(); -} diff --git a/openjdk/java/lang/invoke/VolatileCallSite.java b/openjdk/java/lang/invoke/VolatileCallSite.java deleted file mode 100644 index de88f36b..00000000 --- a/openjdk/java/lang/invoke/VolatileCallSite.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2010, 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 java.lang.invoke; - -/** - * A {@code VolatileCallSite} is a {@link CallSite} whose target acts like a volatile variable. - * An {@code invokedynamic} instruction linked to a {@code VolatileCallSite} sees updates - * to its call site target immediately, even if the update occurs in another thread. - * There may be a performance penalty for such tight coupling between threads. - * <p> - * Unlike {@code MutableCallSite}, there is no - * {@linkplain MutableCallSite#syncAll syncAll operation} on volatile - * call sites, since every write to a volatile variable is implicitly - * synchronized with reader threads. - * <p> - * In other respects, a {@code VolatileCallSite} is interchangeable - * with {@code MutableCallSite}. - * @see MutableCallSite - * @author John Rose, JSR 292 EG - */ -public class VolatileCallSite extends CallSite { - /** - * Creates a call site with a volatile binding to its target. - * The initial target is set to a method handle - * of the given type which will throw an {@code IllegalStateException} if called. - * @param type the method type that this call site will have - * @throws NullPointerException if the proposed type is null - */ - public VolatileCallSite(MethodType type) { - super(type); - } - - /** - * Creates a call site with a volatile binding to its target. - * The target is set to the given value. - * @param target the method handle that will be the initial target of the call site - * @throws NullPointerException if the proposed target is null - */ - public VolatileCallSite(MethodHandle target) { - super(target); - } - - /** - * Returns the target method of the call site, which behaves - * like a {@code volatile} field of the {@code VolatileCallSite}. - * <p> - * The interactions of {@code getTarget} with memory are the same - * as of a read from a {@code volatile} field. - * <p> - * In particular, the current thread is required to issue a fresh - * read of the target from memory, and must not fail to see - * a recent update to the target by another thread. - * - * @return the linkage state of this call site, a method handle which can change over time - * @see #setTarget - */ - @Override public final MethodHandle getTarget() { - return getTargetVolatile(); - } - - /** - * Updates the target method of this call site, as a volatile variable. - * The type of the new target must agree with the type of the old target. - * <p> - * The interactions with memory are the same as of a write to a volatile field. - * In particular, any threads is guaranteed to see the updated target - * the next time it calls {@code getTarget}. - * @param newTarget the new target - * @throws NullPointerException if the proposed new target is null - * @throws WrongMethodTypeException if the proposed new target - * has a method type that differs from the previous target - * @see #getTarget - */ - @Override public void setTarget(MethodHandle newTarget) { - checkTargetChange(getTargetVolatile(), newTarget); - setTargetVolatile(newTarget); - } - - /** - * {@inheritDoc} - */ - @Override - public final MethodHandle dynamicInvoker() { - return makeDynamicInvoker(); - } -} diff --git a/openjdk/java/lang/management/PlatformComponent.java b/openjdk/java/lang/management/PlatformComponent.java deleted file mode 100644 index 3d29a16b..00000000 --- a/openjdk/java/lang/management/PlatformComponent.java +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Copyright (c) 2008, 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.lang.management; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.HashSet; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import javax.management.MBeanServerConnection; -import javax.management.ObjectName; - -import sun.management.ManagementFactoryHelper; -import sun.management.Util; - -/** - * This enum class defines the list of platform components - * that provides monitoring and management support. - * Each enum represents one MXBean interface. A MXBean - * instance could implement one or more MXBean interfaces. - * - * For example, com.sun.management.GarbageCollectorMXBean - * extends java.lang.management.GarbageCollectorMXBean - * and there is one set of garbage collection MXBean instances, - * each of which implements both c.s.m. and j.l.m. interfaces. - * There are two separate enums GARBAGE_COLLECTOR - * and SUN_GARBAGE_COLLECTOR so that ManagementFactory.getPlatformMXBeans(Class) - * will return the list of MXBeans of the specified type. - * - * To add a new MXBean interface for the Java platform, - * add a new enum constant and implement the MXBeanFetcher. - */ -enum PlatformComponent { - - /** - * Class loading system of the Java virtual machine. - */ - CLASS_LOADING( - "java.lang.management.ClassLoadingMXBean", - "java.lang", "ClassLoading", defaultKeyProperties(), - true, // singleton - new MXBeanFetcher<ClassLoadingMXBean>() { - public List<ClassLoadingMXBean> getMXBeans() { - return Collections.singletonList(ManagementFactoryHelper.getClassLoadingMXBean()); - } - }), - - /** - * Compilation system of the Java virtual machine. - */ - COMPILATION( - "java.lang.management.CompilationMXBean", - "java.lang", "Compilation", defaultKeyProperties(), - true, // singleton - new MXBeanFetcher<CompilationMXBean>() { - public List<CompilationMXBean> getMXBeans() { - CompilationMXBean m = ManagementFactoryHelper.getCompilationMXBean(); - if (m == null) { - return Collections.emptyList(); - } else { - return Collections.singletonList(m); - } - } - }), - - /** - * Memory system of the Java virtual machine. - */ - MEMORY( - "java.lang.management.MemoryMXBean", - "java.lang", "Memory", defaultKeyProperties(), - true, // singleton - new MXBeanFetcher<MemoryMXBean>() { - public List<MemoryMXBean> getMXBeans() { - return Collections.singletonList(ManagementFactoryHelper.getMemoryMXBean()); - } - }), - - /** - * Garbage Collector in the Java virtual machine. - */ - GARBAGE_COLLECTOR( - "java.lang.management.GarbageCollectorMXBean", - "java.lang", "GarbageCollector", keyProperties("name"), - false, // zero or more instances - new MXBeanFetcher<GarbageCollectorMXBean>() { - public List<GarbageCollectorMXBean> getMXBeans() { - return ManagementFactoryHelper. - getGarbageCollectorMXBeans(); - } - }), - - /** - * Memory manager in the Java virtual machine. - */ - MEMORY_MANAGER( - "java.lang.management.MemoryManagerMXBean", - "java.lang", "MemoryManager", keyProperties("name"), - false, // zero or more instances - new MXBeanFetcher<MemoryManagerMXBean>() { - public List<MemoryManagerMXBean> getMXBeans() { - return ManagementFactoryHelper.getMemoryManagerMXBeans(); - } - }, - GARBAGE_COLLECTOR), - - /** - * Memory pool in the Java virtual machine. - */ - MEMORY_POOL( - "java.lang.management.MemoryPoolMXBean", - "java.lang", "MemoryPool", keyProperties("name"), - false, // zero or more instances - new MXBeanFetcher<MemoryPoolMXBean>() { - public List<MemoryPoolMXBean> getMXBeans() { - return ManagementFactoryHelper.getMemoryPoolMXBeans(); - } - }), - - /** - * Operating system on which the Java virtual machine is running - */ - OPERATING_SYSTEM( - "java.lang.management.OperatingSystemMXBean", - "java.lang", "OperatingSystem", defaultKeyProperties(), - true, // singleton - new MXBeanFetcher<OperatingSystemMXBean>() { - public List<OperatingSystemMXBean> getMXBeans() { - return Collections.singletonList(ManagementFactoryHelper.getOperatingSystemMXBean()); - } - }), - - /** - * Runtime system of the Java virtual machine. - */ - RUNTIME( - "java.lang.management.RuntimeMXBean", - "java.lang", "Runtime", defaultKeyProperties(), - true, // singleton - new MXBeanFetcher<RuntimeMXBean>() { - public List<RuntimeMXBean> getMXBeans() { - return Collections.singletonList(ManagementFactoryHelper.getRuntimeMXBean()); - } - }), - - /** - * Threading system of the Java virtual machine. - */ - THREADING( - "java.lang.management.ThreadMXBean", - "java.lang", "Threading", defaultKeyProperties(), - true, // singleton - new MXBeanFetcher<ThreadMXBean>() { - public List<ThreadMXBean> getMXBeans() { - return Collections.singletonList(ManagementFactoryHelper.getThreadMXBean()); - } - }), - - - /** - * Logging facility. - */ - LOGGING( - "java.lang.management.PlatformLoggingMXBean", - "java.util.logging", "Logging", defaultKeyProperties(), - true, // singleton - new MXBeanFetcher<PlatformLoggingMXBean>() { - public List<PlatformLoggingMXBean> getMXBeans() { - PlatformLoggingMXBean m = ManagementFactoryHelper.getPlatformLoggingMXBean(); - if (m == null) { - return Collections.emptyList(); - } else { - return Collections.singletonList(m); - } - } - }), - - /** - * Buffer pools. - */ - BUFFER_POOL( - "java.lang.management.BufferPoolMXBean", - "java.nio", "BufferPool", keyProperties("name"), - false, // zero or more instances - new MXBeanFetcher<BufferPoolMXBean>() { - public List<BufferPoolMXBean> getMXBeans() { - return ManagementFactoryHelper.getBufferPoolMXBeans(); - } - }); - - /** - * A task that returns the MXBeans for a component. - */ - interface MXBeanFetcher<T extends PlatformManagedObject> { - public List<T> getMXBeans(); - } - - /* - * Returns a list of the GC MXBeans of the given type. - */ - private static <T extends GarbageCollectorMXBean> - List<T> getGcMXBeanList(Class<T> gcMXBeanIntf) { - List<GarbageCollectorMXBean> list = - ManagementFactoryHelper.getGarbageCollectorMXBeans(); - List<T> result = new ArrayList<>(list.size()); - for (GarbageCollectorMXBean m : list) { - if (gcMXBeanIntf.isInstance(m)) { - result.add(gcMXBeanIntf.cast(m)); - } - } - return result; - } - - /* - * Returns the OS mxbean instance of the given type. - */ - private static <T extends OperatingSystemMXBean> - List<T> getOSMXBeanList(Class<T> osMXBeanIntf) { - OperatingSystemMXBean m = - ManagementFactoryHelper.getOperatingSystemMXBean(); - if (osMXBeanIntf.isInstance(m)) { - return Collections.singletonList(osMXBeanIntf.cast(m)); - } else { - return Collections.emptyList(); - } - } - - private final String mxbeanInterfaceName; - private final String domain; - private final String type; - private final Set<String> keyProperties; - private final MXBeanFetcher fetcher; - private final PlatformComponent[] subComponents; - private final boolean singleton; - - private PlatformComponent(String intfName, - String domain, String type, - Set<String> keyProperties, - boolean singleton, - MXBeanFetcher fetcher, - PlatformComponent... subComponents) { - this.mxbeanInterfaceName = intfName; - this.domain = domain; - this.type = type; - this.keyProperties = keyProperties; - this.singleton = singleton; - this.fetcher = fetcher; - this.subComponents = subComponents; - } - - private static Set<String> defaultKeyProps; - private static Set<String> defaultKeyProperties() { - if (defaultKeyProps == null) { - defaultKeyProps = Collections.singleton("type"); - } - return defaultKeyProps; - } - - private static Set<String> keyProperties(String... keyNames) { - Set<String> set = new HashSet<>(); - set.add("type"); - for (String s : keyNames) { - set.add(s); - } - return set; - } - - boolean isSingleton() { - return singleton; - } - - String getMXBeanInterfaceName() { - return mxbeanInterfaceName; - } - - @SuppressWarnings("unchecked") - Class<? extends PlatformManagedObject> getMXBeanInterface() { - try { - // Lazy loading the MXBean interface only when it is needed - return (Class<? extends PlatformManagedObject>) - Class.forName(mxbeanInterfaceName, false, null); - } catch (ClassNotFoundException x) { - throw new AssertionError(x); - } - } - - @SuppressWarnings("unchecked") - <T extends PlatformManagedObject> - List<T> getMXBeans(Class<T> mxbeanInterface) - { - return fetcher.getMXBeans(); - } - - <T extends PlatformManagedObject> T getSingletonMXBean(Class<T> mxbeanInterface) - { - if (!singleton) - throw new IllegalArgumentException(mxbeanInterfaceName + - " can have zero or more than one instances"); - - List<T> list = fetcher.getMXBeans(); - assert list.size() == 1; - return list.isEmpty() ? null : list.get(0); - } - - <T extends PlatformManagedObject> - T getSingletonMXBean(MBeanServerConnection mbs, Class<T> mxbeanInterface) - throws java.io.IOException - { - if (!singleton) - throw new IllegalArgumentException(mxbeanInterfaceName + - " can have zero or more than one instances"); - - // ObjectName of a singleton MXBean contains only domain and type - assert keyProperties.size() == 1; - String on = domain + ":type=" + type; - return ManagementFactory.newPlatformMXBeanProxy(mbs, - on, - mxbeanInterface); - } - - <T extends PlatformManagedObject> - List<T> getMXBeans(MBeanServerConnection mbs, Class<T> mxbeanInterface) - throws java.io.IOException - { - List<T> result = new ArrayList<>(); - for (ObjectName on : getObjectNames(mbs)) { - result.add(ManagementFactory. - newPlatformMXBeanProxy(mbs, - on.getCanonicalName(), - mxbeanInterface) - ); - } - return result; - } - - private Set<ObjectName> getObjectNames(MBeanServerConnection mbs) - throws java.io.IOException - { - String domainAndType = domain + ":type=" + type; - if (keyProperties.size() > 1) { - // if there are more than 1 key properties (i.e. other than "type") - domainAndType += ",*"; - } - ObjectName on = Util.newObjectName(domainAndType); - Set<ObjectName> set = mbs.queryNames(on, null); - for (PlatformComponent pc : subComponents) { - set.addAll(pc.getObjectNames(mbs)); - } - return set; - } - - // a map from MXBean interface name to PlatformComponent - private static Map<String, PlatformComponent> enumMap; - private static synchronized void ensureInitialized() { - if (enumMap == null) { - enumMap = new HashMap<>(); - for (PlatformComponent pc: PlatformComponent.values()) { - // Use String as the key rather than Class<?> to avoid - // causing unnecessary class loading of management interface - enumMap.put(pc.getMXBeanInterfaceName(), pc); - } - } - } - - static boolean isPlatformMXBean(String cn) { - ensureInitialized(); - return enumMap.containsKey(cn); - } - - static <T extends PlatformManagedObject> - PlatformComponent getPlatformComponent(Class<T> mxbeanInterface) - { - ensureInitialized(); - String cn = mxbeanInterface.getName(); - PlatformComponent pc = enumMap.get(cn); - if (pc != null && pc.getMXBeanInterface() == mxbeanInterface) - return pc; - return null; - } - - private static final long serialVersionUID = 6992337162326171013L; -} diff --git a/openjdk/java/lang/ref/Reference.java b/openjdk/java/lang/ref/Reference.java deleted file mode 100644 index cc2bfa5c..00000000 --- a/openjdk/java/lang/ref/Reference.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - Copyright (C) 2003-2012 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.ref; - -import cli.System.Collections.Hashtable; -import sun.misc.Cleaner; - -public abstract class Reference<T> -{ - // accessed by inner class - volatile cli.System.WeakReference weakRef; - volatile T strongRef; - volatile ReferenceQueue<? super T> queue; - volatile Reference next; - - private static native boolean noclassgc(); - - Reference(T referent) - { - this(referent, null); - } - - Reference(T referent, ReferenceQueue<? super T> queue) - { - this.queue = queue == null ? ReferenceQueue.NULL : queue; - if (referent != null) - { - if (referent instanceof Class && noclassgc()) - { - // We don't do Class gc, so no point in using a weak reference for classes. - strongRef = referent; - } - else - { - weakRef = new cli.System.WeakReference(referent, this instanceof PhantomReference); - if (queue != null || referent instanceof Cleaner || this instanceof SoftReference) - { - new QueueWatcher(this); - } - } - } - } - - private static final boolean debug = false; - - private static final class QueueWatcher - { - private static final Hashtable keepAlive = Hashtable.Synchronized(new Hashtable()); - private cli.System.WeakReference handle; - - QueueWatcher(Reference r) - { - handle = new cli.System.WeakReference(r, true); - // FXBUG when a WeakReference is finalizer reachable, it gets cleared by the GC (even if we call GC.SuppressFinalize), - // so we have to maintain a strong reference to it to prevent it from being cleared. - keepAlive.Add(handle, null); - } - - boolean check(Reference r) - { - r.strongRef = null; - boolean alive = false; - try - { - if (false) throw new cli.System.InvalidOperationException(); - cli.System.WeakReference referent = r.weakRef; - if (referent == null) - { - // ref was explicitly cleared, so we don't enqueue - return false; - } - alive = referent.get_IsAlive(); - } - catch (cli.System.InvalidOperationException x) - { - // this happens if the reference is already finalized (if we were - // the only one still hanging on to it) - } - if (alive) - { - // we don't want to keep creating finalizable objects during shutdown - if (!cli.System.Environment.get_HasShutdownStarted()) - { - return true; - } - } - else - { - if (r instanceof Cleaner) - { - ((Cleaner)r).clean(); - } - else if (r.queue != null) - { - r.queue.enqueue(r); - } - } - return false; - } - - protected void finalize() - { - Reference r = (Reference)handle.get_Target(); - if (debug) - cli.System.Console.WriteLine("~QueueWatcher: " + hashCode() + " on " + r); - if (r != null && r.next == null && check(r)) - { - cli.System.GC.ReRegisterForFinalize(QueueWatcher.this); - } - else - { - handle.set_Target(null); - keepAlive.Remove(handle); - } - } - } - - public T get() - { - try - { - if (false) throw new cli.System.InvalidOperationException(); - cli.System.WeakReference referent = this.weakRef; - if (referent == null) - { - return strongRef; - } - T value = (T)referent.get_Target(); - if (value == null) - { - queue.enqueue(this); - } - return value; - } - catch (cli.System.InvalidOperationException x) - { - // we were already finalized, so we just return null. - return null; - } - } - - public void clear() - { - weakRef = null; - strongRef = null; - } - - public synchronized boolean isEnqueued() - { - return queue != ReferenceQueue.NULL && next != null; - } - - public boolean enqueue() - { - return queue.enqueue(this); - } -} diff --git a/openjdk/java/lang/ref/SoftReference.java b/openjdk/java/lang/ref/SoftReference.java deleted file mode 100644 index 04d24933..00000000 --- a/openjdk/java/lang/ref/SoftReference.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 1997, 2003, 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.ref; - - -/** - * Soft reference objects, which are cleared at the discretion of the garbage - * collector in response to memory demand. Soft references are most often used - * to implement memory-sensitive caches. - * - * <p> Suppose that the garbage collector determines at a certain point in time - * that an object is <a href="package-summary.html#reachability">softly - * reachable</a>. At that time it may choose to clear atomically all soft - * references to that object and all soft references to any other - * softly-reachable objects from which that object is reachable through a chain - * of strong references. At the same time or at some later time it will - * enqueue those newly-cleared soft references that are registered with - * reference queues. - * - * <p> All soft references to softly-reachable objects are guaranteed to have - * been cleared before the virtual machine throws an - * <code>OutOfMemoryError</code>. Otherwise no constraints are placed upon the - * time at which a soft reference will be cleared or the order in which a set - * of such references to different objects will be cleared. Virtual machine - * implementations are, however, encouraged to bias against clearing - * recently-created or recently-used soft references. - * - * <p> Direct instances of this class may be used to implement simple caches; - * this class or derived subclasses may also be used in larger data structures - * to implement more sophisticated caches. As long as the referent of a soft - * reference is strongly reachable, that is, is actually in use, the soft - * reference will not be cleared. Thus a sophisticated cache can, for example, - * prevent its most recently used entries from being discarded by keeping - * strong referents to those entries, leaving the remaining entries to be - * discarded at the discretion of the garbage collector. - * - * @author Mark Reinhold - * @since 1.2 - */ - -public class SoftReference<T> extends Reference<T> { - - /** - * Timestamp clock, updated by the garbage collector - */ - static private long clock; - - /** - * Timestamp updated by each invocation of the get method. The VM may use - * this field when selecting soft references to be cleared, but it is not - * required to do so. - */ - private long timestamp; - - /** - * Creates a new soft reference that refers to the given object. The new - * reference is not registered with any queue. - * - * @param referent object the new soft reference will refer to - */ - public SoftReference(T referent) { - super(referent); - strongRef = referent; - } - - /** - * Creates a new soft reference that refers to the given object and is - * registered with the given queue. - * - * @param referent object the new soft reference will refer to - * @param q the queue with which the reference is to be registered, - * or <tt>null</tt> if registration is not required - * - */ - public SoftReference(T referent, ReferenceQueue<? super T> q) { - super(referent, q); - strongRef = referent; - } - - /** - * Returns this reference object's referent. If this reference object has - * been cleared, either by the program or by the garbage collector, then - * this method returns <code>null</code>. - * - * @return The object to which this reference refers, or - * <code>null</code> if this reference object has been cleared - */ - public T get() { - T o = super.get(); - strongRef = o; - return o; - } - -} diff --git a/openjdk/java/lang/reflect/Constructor.java b/openjdk/java/lang/reflect/Constructor.java deleted file mode 100644 index b13d30a5..00000000 --- a/openjdk/java/lang/reflect/Constructor.java +++ /dev/null @@ -1,674 +0,0 @@ -/* - * Copyright (c) 1996, 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.lang.reflect; - -import sun.reflect.CallerSensitive; -import sun.reflect.ConstructorAccessor; -import sun.reflect.Reflection; -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 - * constructor for a class. - * - * <p>{@code Constructor} permits widening conversions to occur when matching the - * actual parameters to newInstance() with the underlying - * constructor's formal parameters, but throws an - * {@code IllegalArgumentException} if a narrowing conversion would occur. - * - * @param <T> the class in which the constructor is declared - * - * @see Member - * @see java.lang.Class - * @see java.lang.Class#getConstructors() - * @see java.lang.Class#getConstructor(Class[]) - * @see java.lang.Class#getDeclaredConstructors() - * - * @author Kenneth Russell - * @author Nakul Saraiya - */ -public final - class Constructor<T> extends AccessibleObject implements - GenericDeclaration, - Member { - - private Class<T> clazz; - private int slot; - private Class<?>[] parameterTypes; - private Class<?>[] exceptionTypes; - private int modifiers; - // Generics and annotations support - private transient String signature; - // generic info repository; lazily initialized - private transient ConstructorRepository genericInfo; - - // Generics infrastructure - // Accessor for factory - private GenericsFactory getFactory() { - // create scope and factory - return CoreReflectionFactory.make(this, ConstructorScope.make(this)); - } - - // Accessor for generic info repository - private ConstructorRepository getGenericInfo() { - // lazily initialize repository if necessary - if (genericInfo == null) { - // create and cache generic info repository - genericInfo = - ConstructorRepository.make(getSignature(), - getFactory()); - } - return genericInfo; //return cached repository - } - - private volatile ConstructorAccessor constructorAccessor; - // 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.) - private Constructor<T> root; - - /** - * Package-private constructor used by ReflectAccess to enable - * instantiation of these objects in Java code from the java.lang - * package via sun.reflect.LangReflectAccess. - */ - Constructor(Class<T> declaringClass, - Class<?>[] parameterTypes, - Class<?>[] checkedExceptions, - int modifiers, - int slot, - String signature, - byte[] unused1, - byte[] unused2) - { - this.clazz = declaringClass; - this.parameterTypes = parameterTypes; - this.exceptionTypes = checkedExceptions; - this.modifiers = modifiers; - this.slot = slot; - this.signature = signature; - } - - /** - * Package-private routine (exposed to java.lang.Class via - * ReflectAccess) which returns a copy of this Constructor. The copy's - * "root" field points to this Constructor. - */ - Constructor<T> copy() { - // This routine enables sharing of ConstructorAccessor objects - // among Constructor objects which refer to the same underlying - // method in the VM. (All of this contortion is only necessary - // because of the "accessibility" bit in AccessibleObject, - // which implicitly requires that new java.lang.reflect - // objects be fabricated for each reflective call on Class - // objects.) - Constructor<T> res = new Constructor<>(clazz, - parameterTypes, - exceptionTypes, modifiers, slot, - signature, - null, - null); - res.root = this; - // Might as well eagerly propagate this if already present - res.constructorAccessor = constructorAccessor; - return res; - } - - /** - * Returns the {@code Class} object representing the class that declares - * the constructor represented by this {@code Constructor} object. - */ - public Class<T> getDeclaringClass() { - return clazz; - } - - /** - * Returns the name of this constructor, as a string. This is - * the binary name of the constructor's declaring class. - */ - 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 - */ - 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 - * <cite>The Java™ Virtual Machine Specification</cite> - * @since 1.5 - */ - public TypeVariable<Constructor<T>>[] getTypeParameters() { - if (getSignature() != null) { - return (TypeVariable<Constructor<T>>[])getGenericInfo().getTypeParameters(); - } else - return (TypeVariable<Constructor<T>>[])new TypeVariable[0]; - } - - - /** - * 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 - */ - public Class<?>[] getParameterTypes() { - return (Class<?>[]) 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 Constructor} object. Returns an array of length 0 if the - * underlying method takes no parameters. - * - * <p>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. - * - * <p>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 - * <cite>The Java™ Virtual Machine Specification</cite> - * @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 - * @since 1.5 - */ - public Type[] getGenericParameterTypes() { - if (getSignature() != null) - return getGenericInfo().getParameterTypes(); - else - return getParameterTypes(); - } - - - /** - * 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 - */ - public Class<?>[] getExceptionTypes() { - return (Class<?>[])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. - * - * <p>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 - * <cite>The Java™ Virtual Machine Specification</cite> - * @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 - * @since 1.5 - */ - public Type[] getGenericExceptionTypes() { - Type[] result; - if (getSignature() != null && - ( (result = getGenericInfo().getExceptionTypes()).length > 0 )) - return result; - else - return getExceptionTypes(); - } - - /** - * Compares this {@code Constructor} against the specified object. - * Returns true if the objects are the same. Two {@code Constructor} objects are - * the same if they were declared by the same class and have the - * same formal parameter types. - */ - public boolean equals(Object obj) { - 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 false; - } - - /** - * Returns a hashcode for this {@code Constructor}. The hashcode is - * the same as the hashcode for the underlying constructor's - * declaring class name. - */ - public int hashCode() { - return getDeclaringClass().getName().hashCode(); - } - - /** - * Returns a string describing this {@code Constructor}. The string is - * formatted as the constructor access modifiers, if any, - * followed by the fully-qualified name of the declaring class, - * followed by a parenthesized, comma-separated list of the - * constructor's formal parameter types. For example: - * <pre> - * public java.util.Hashtable(int,float) - * </pre> - * - * <p>The only possible modifiers for constructors are the access - * modifiers {@code public}, {@code protected} or - * {@code private}. Only one of these may appear, or none if the - * constructor has default (package) access. - */ - 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 + ">"; - } - } - - /** - * Returns a string describing this {@code Constructor}, - * including type parameters. The string is formatted as the - * constructor access modifiers, if any, followed by an - * angle-bracketed comma separated list of the constructor's type - * parameters, if any, followed by the fully-qualified name of the - * declaring class, followed by a parenthesized, comma-separated - * list of the constructor's generic formal parameter types. - * - * If this constructor was declared to take a variable number of - * arguments, instead of denoting the last parameter as - * "<tt><i>Type</i>[]</tt>", it is denoted as - * "<tt><i>Type</i>...</tt>". - * - * A space is used to separate access modifiers from one another - * and from the type parameters or return type. If there are no - * type parameters, the type parameter list is elided; if the type - * parameter list is present, a space separates the list from the - * class name. If the constructor is declared to throw - * exceptions, the parameter list is followed by a space, followed - * by the word "{@code throws}" followed by a - * comma-separated list of the thrown exception types. - * - * <p>The only possible modifiers for constructors are the access - * 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}, - * include type parameters - * - * @since 1.5 - */ - 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 + ">"; - } - } - - /** - * Uses the constructor represented by this {@code Constructor} object to - * create and initialize a new instance of the constructor's - * declaring class, with the specified initialization parameters. - * Individual parameters are automatically unwrapped to match - * primitive formal parameters, and both primitive and reference - * parameters are subject to method invocation conversions as necessary. - * - * <p>If the number of formal parameters required by the underlying constructor - * is 0, the supplied {@code initargs} array may be of length 0 or null. - * - * <p>If the constructor's declaring class is an inner class in a - * non-static context, the first argument to the constructor needs - * to be the enclosing instance; see section 15.9.3 of - * <cite>The Java™ Language Specification</cite>. - * - * <p>If the required access and argument checks succeed and the - * instantiation will proceed, the constructor's declaring class - * is initialized if it has not already been initialized. - * - * <p>If the constructor completes normally, returns the newly - * created and initialized instance. - * - * @param initargs array of objects to be passed as arguments to - * the constructor call; values of primitive types are wrapped in - * a wrapper object of the appropriate type (e.g. a {@code float} - * in a {@link java.lang.Float Float}) - * - * @return a new object created by calling the constructor - * this object represents - * - * @exception IllegalAccessException if this {@code Constructor} object - * is enforcing Java language access control and the underlying - * constructor is inaccessible. - * @exception IllegalArgumentException if the number of actual - * and formal parameters differ; if an unwrapping - * conversion for primitive arguments fails; or if, - * after possible unwrapping, a parameter value - * cannot be converted to the corresponding formal - * parameter type by a method invocation conversion; if - * this constructor pertains to an enum type. - * @exception InstantiationException if the class that declares the - * underlying constructor represents an abstract class. - * @exception InvocationTargetException if the underlying constructor - * throws an exception. - * @exception ExceptionInInitializerError if the initialization provoked - * by this method fails. - */ - @CallerSensitive - public T newInstance(Object ... initargs) - throws InstantiationException, IllegalAccessException, - IllegalArgumentException, InvocationTargetException - { - if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class<?> caller = Reflection.getCallerClass(); - checkAccess(caller, clazz, null, modifiers); - } - } - if ((clazz.getModifiers() & Modifier.ENUM) != 0) - throw new IllegalArgumentException("Cannot reflectively create enum objects"); - ConstructorAccessor ca = constructorAccessor; // read volatile - if (ca == null) { - ca = acquireConstructorAccessor(); - } - return (T) ca.newInstance(initargs); - } - - /** - * 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. - * @since 1.5 - */ - public boolean isVarArgs() { - return (getModifiers() & Modifier.VARARGS) != 0; - } - - /** - * 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 - * <cite>The Java™ Language Specification</cite>. - * @since 1.5 - */ - public boolean isSynthetic() { - return Modifier.isSynthetic(getModifiers()); - } - - // NOTE that there is no synchronization used here. It is correct - // (though not efficient) to generate more than one - // ConstructorAccessor for a given Constructor. However, avoiding - // synchronization will probably make the implementation more - // scalable. - private ConstructorAccessor acquireConstructorAccessor() { - // First check to see if one has been created yet, and take it - // if so. - ConstructorAccessor tmp = null; - if (root != null) tmp = root.getConstructorAccessor(); - if (tmp != null) { - constructorAccessor = tmp; - } else { - // Otherwise fabricate one and propagate it up to the root - tmp = reflectionFactory.newConstructorAccessor(this); - setConstructorAccessor(tmp); - } - - return tmp; - } - - // Returns ConstructorAccessor for this Constructor object, not - // looking up the chain to the root - ConstructorAccessor getConstructorAccessor() { - return constructorAccessor; - } - - // Sets the ConstructorAccessor for this Constructor object and - // (recursively) its root - void setConstructorAccessor(ConstructorAccessor accessor) { - constructorAccessor = accessor; - // Propagate up - if (root != null) { - root.setConstructorAccessor(accessor); - } - } - - int getSlot() { - return slot; - } - - String getSignature() { - return signature; - } - - byte[] getRawAnnotations() { - return null; - } - - byte[] getRawParameterAnnotations() { - return null; - } - - /** - * @throws NullPointerException {@inheritDoc} - * @since 1.5 - */ - public <T extends Annotation> T getAnnotation(Class<T> 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<Class<? extends Annotation>, Annotation> declaredAnnotations; - - private synchronized Map<Class<? extends Annotation>, Annotation> declaredAnnotations() { - if (declaredAnnotations == null) { - declaredAnnotations = Method.getDeclaredAnnotationsImpl(this); - } - return declaredAnnotations; - } - - /** - * 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 - * @since 1.5 - */ - 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 result; - } -} diff --git a/openjdk/java/lang/reflect/Field.java b/openjdk/java/lang/reflect/Field.java deleted file mode 100644 index b2cb46b3..00000000 --- a/openjdk/java/lang/reflect/Field.java +++ /dev/null @@ -1,1134 +0,0 @@ -/* - * Copyright (c) 1996, 2006, 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 sun.reflect.CallerSensitive; -import sun.reflect.FieldAccessor; -import sun.reflect.Reflection; -import sun.reflect.generics.repository.FieldRepository; -import sun.reflect.generics.factory.CoreReflectionFactory; -import sun.reflect.generics.factory.GenericsFactory; -import sun.reflect.generics.scope.ClassScope; -import java.lang.annotation.Annotation; -import java.util.Map; -import sun.reflect.annotation.AnnotationParser; - - -/** - * A {@code Field} provides information about, and dynamic access to, a - * single field of a class or an interface. The reflected field may - * be a class (static) field or an instance field. - * - * <p>A {@code Field} permits widening conversions to occur during a get or - * set access operation, but throws an {@code IllegalArgumentException} if a - * narrowing conversion would occur. - * - * @see Member - * @see java.lang.Class - * @see java.lang.Class#getFields() - * @see java.lang.Class#getField(String) - * @see java.lang.Class#getDeclaredFields() - * @see java.lang.Class#getDeclaredField(String) - * - * @author Kenneth Russell - * @author Nakul Saraiya - */ -public final -class Field extends AccessibleObject implements Member { - - private Class<?> clazz; - private int slot; - // This is guaranteed to be interned by the VM in the 1.4 - // reflection implementation - private String name; - private Class<?> type; - private int modifiers; - // Generics and annotations support - private transient String signature; - // generic info repository; lazily initialized - private transient FieldRepository genericInfo; - // Cached field accessor created without override - private FieldAccessor fieldAccessor; - // Cached field accessor created with override - private FieldAccessor overrideFieldAccessor; - // 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.) - private Field root; - - // Generics infrastructure - - private String getGenericSignature() {return signature;} - - // Accessor for factory - private GenericsFactory getFactory() { - Class<?> c = getDeclaringClass(); - // create scope and factory - return CoreReflectionFactory.make(c, ClassScope.make(c)); - } - - // Accessor for generic info repository - private FieldRepository getGenericInfo() { - // lazily initialize repository if necessary - if (genericInfo == null) { - // create and cache generic info repository - genericInfo = FieldRepository.make(getGenericSignature(), - getFactory()); - } - return genericInfo; //return cached repository - } - - - /** - * Package-private constructor used by ReflectAccess to enable - * instantiation of these objects in Java code from the java.lang - * package via sun.reflect.LangReflectAccess. - */ - Field(Class<?> declaringClass, - String name, - Class<?> type, - int modifiers, - int slot, - String signature, - byte[] unused) - { - this.clazz = declaringClass; - this.name = name; - this.type = type; - this.modifiers = modifiers; - this.slot = slot; - this.signature = signature; - } - - /** - * Package-private routine (exposed to java.lang.Class via - * ReflectAccess) which returns a copy of this Field. The copy's - * "root" field points to this Field. - */ - Field copy() { - // This routine enables sharing of FieldAccessor objects - // among Field objects which refer to the same underlying - // method in the VM. (All of this contortion is only necessary - // because of the "accessibility" bit in AccessibleObject, - // which implicitly requires that new java.lang.reflect - // objects be fabricated for each reflective call on Class - // objects.) - 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; - } - - /** - * Returns the {@code Class} object representing the class or interface - * that declares the field represented by this {@code Field} object. - */ - public Class<?> getDeclaringClass() { - return clazz; - } - - /** - * Returns the name of the field represented by this {@code Field} object. - */ - public String getName() { - return name; - } - - /** - * Returns the Java language modifiers for the field represented - * by this {@code Field} object, as an integer. The {@code Modifier} class should - * be used to decode the modifiers. - * - * @see Modifier - */ - public int getModifiers() { - return modifiers; - } - - /** - * Returns {@code true} if this field represents an element of - * an enumerated type; returns {@code false} otherwise. - * - * @return {@code true} if and only if this field represents an element of - * an enumerated type. - * @since 1.5 - */ - public boolean isEnumConstant() { - return (getModifiers() & Modifier.ENUM) != 0; - } - - /** - * Returns {@code true} if this field is a synthetic - * field; returns {@code false} otherwise. - * - * @return true if and only if this field is a synthetic - * field as defined by the Java Language Specification. - * @since 1.5 - */ - public boolean isSynthetic() { - return Modifier.isSynthetic(getModifiers()); - } - - /** - * Returns a {@code Class} object that identifies the - * declared type for the field represented by this - * {@code Field} object. - * - * @return a {@code Class} object identifying the declared - * type of the field represented by this object - */ - public Class<?> getType() { - return type; - } - - /** - * Returns a {@code Type} object that represents the declared type for - * the field represented by this {@code Field} object. - * - * <p>If the {@code Type} is a parameterized type, the - * {@code Type} object returned must accurately reflect the - * actual type parameters used in the source code. - * - * <p>If the type of the underlying field is a type variable or a - * parameterized type, it is created. Otherwise, it is resolved. - * - * @return a {@code Type} object that represents the declared type for - * the field represented by this {@code Field} object - * @throws GenericSignatureFormatError if the generic field - * signature does not conform to the format specified in - * <cite>The Java™ Virtual Machine Specification</cite> - * @throws TypeNotPresentException if the generic type - * signature of the underlying field refers to a non-existent - * type declaration - * @throws MalformedParameterizedTypeException if the generic - * signature of the underlying field refers to a parameterized type - * that cannot be instantiated for any reason - * @since 1.5 - */ - public Type getGenericType() { - if (getGenericSignature() != null) - return getGenericInfo().getGenericType(); - else - return getType(); - } - - - /** - * Compares this {@code Field} against the specified object. Returns - * true if the objects are the same. Two {@code Field} objects are the same if - * they were declared by the same class and have the same name - * and type. - */ - public boolean equals(Object obj) { - if (obj != null && obj instanceof Field) { - Field other = (Field)obj; - return (getDeclaringClass() == other.getDeclaringClass()) - && (getName() == other.getName()) - && (getType() == other.getType()); - } - return false; - } - - /** - * Returns a hashcode for this {@code Field}. This is computed as the - * exclusive-or of the hashcodes for the underlying field's - * declaring class name and its name. - */ - public int hashCode() { - return getDeclaringClass().getName().hashCode() ^ getName().hashCode(); - } - - /** - * Returns a string describing this {@code Field}. The format is - * the access modifiers for the field, if any, followed - * by the field type, followed by a space, followed by - * the fully-qualified name of the class declaring the field, - * followed by a period, followed by the name of the field. - * For example: - * <pre> - * public static final int java.lang.Thread.MIN_PRIORITY - * private int java.io.FileDescriptor.fd - * </pre> - * - * <p>The 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 static}, {@code final}, - * {@code transient}, {@code volatile}. - */ - public String toString() { - int mod = getModifiers(); - return (((mod == 0) ? "" : (Modifier.toString(mod) + " ")) - + getTypeName(getType()) + " " - + getTypeName(getDeclaringClass()) + "." - + getName()); - } - - /** - * Returns a string describing this {@code Field}, including - * its generic type. The format is the access modifiers for the - * field, if any, followed by the generic field type, followed by - * a space, followed by the fully-qualified name of the class - * declaring the field, followed by a period, followed by the name - * of the field. - * - * <p>The 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 static}, {@code final}, - * {@code transient}, {@code volatile}. - * - * @return a string describing this {@code Field}, including - * its generic type - * - * @since 1.5 - */ - 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()) + "." - + getName()); - } - - /** - * Returns the value of the field represented by this {@code Field}, on - * the specified object. The value is automatically wrapped in an - * object if it has a primitive type. - * - * <p>The underlying field's value is obtained as follows: - * - * <p>If the underlying field is a static field, the {@code obj} argument - * is ignored; it may be null. - * - * <p>Otherwise, the underlying field is an instance field. If the - * specified {@code obj} argument is null, the method throws a - * {@code NullPointerException}. If the specified object is not an - * instance of the class or interface declaring the underlying - * field, the method throws an {@code IllegalArgumentException}. - * - * <p>If this {@code Field} object is enforcing Java language access control, and - * the underlying field is inaccessible, the method throws an - * {@code IllegalAccessException}. - * If the underlying field is static, the class that declared the - * field is initialized if it has not already been initialized. - * - * <p>Otherwise, the value is retrieved from the underlying instance - * or static field. If the field has a primitive type, the value - * is wrapped in an object before being returned, otherwise it is - * returned as is. - * - * <p>If the field is hidden in the type of {@code obj}, - * the field's value is obtained according to the preceding rules. - * - * @param obj object from which the represented field's value is - * to be extracted - * @return the value of the represented field in object - * {@code obj}; primitive values are wrapped in an appropriate - * object before being returned - * - * @exception IllegalAccessException if this {@code Field} object - * is enforcing Java language access control and the underlying - * field is inaccessible. - * @exception IllegalArgumentException if the specified object is not an - * instance of the class or interface declaring the underlying - * field (or a subclass or implementor thereof). - * @exception NullPointerException if the specified object is null - * and the field is an instance field. - * @exception ExceptionInInitializerError if the initialization provoked - * by this method fails. - */ - @CallerSensitive - public Object get(Object obj) - throws IllegalArgumentException, IllegalAccessException - { - if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); - } - } - return getFieldAccessor(obj).get(obj); - } - - /** - * Gets the value of a static or instance {@code boolean} field. - * - * @param obj the object to extract the {@code boolean} value - * from - * @return the value of the {@code boolean} field - * - * @exception IllegalAccessException if this {@code Field} object - * is enforcing Java language access control and the underlying - * field is inaccessible. - * @exception IllegalArgumentException if the specified object is not - * an instance of the class or interface declaring the - * underlying field (or a subclass or implementor - * thereof), or if the field value cannot be - * converted to the type {@code boolean} by a - * widening conversion. - * @exception NullPointerException if the specified object is null - * and the field is an instance field. - * @exception ExceptionInInitializerError if the initialization provoked - * by this method fails. - * @see Field#get - */ - @CallerSensitive - public boolean getBoolean(Object obj) - throws IllegalArgumentException, IllegalAccessException - { - if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); - } - } - return getFieldAccessor(obj).getBoolean(obj); - } - - /** - * Gets the value of a static or instance {@code byte} field. - * - * @param obj the object to extract the {@code byte} value - * from - * @return the value of the {@code byte} field - * - * @exception IllegalAccessException if this {@code Field} object - * is enforcing Java language access control and the underlying - * field is inaccessible. - * @exception IllegalArgumentException if the specified object is not - * an instance of the class or interface declaring the - * underlying field (or a subclass or implementor - * thereof), or if the field value cannot be - * converted to the type {@code byte} by a - * widening conversion. - * @exception NullPointerException if the specified object is null - * and the field is an instance field. - * @exception ExceptionInInitializerError if the initialization provoked - * by this method fails. - * @see Field#get - */ - @CallerSensitive - public byte getByte(Object obj) - throws IllegalArgumentException, IllegalAccessException - { - if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); - } - } - return getFieldAccessor(obj).getByte(obj); - } - - /** - * Gets the value of a static or instance field of type - * {@code char} or of another primitive type convertible to - * type {@code char} via a widening conversion. - * - * @param obj the object to extract the {@code char} value - * from - * @return the value of the field converted to type {@code char} - * - * @exception IllegalAccessException if this {@code Field} object - * is enforcing Java language access control and the underlying - * field is inaccessible. - * @exception IllegalArgumentException if the specified object is not - * an instance of the class or interface declaring the - * underlying field (or a subclass or implementor - * thereof), or if the field value cannot be - * converted to the type {@code char} by a - * widening conversion. - * @exception NullPointerException if the specified object is null - * and the field is an instance field. - * @exception ExceptionInInitializerError if the initialization provoked - * by this method fails. - * @see Field#get - */ - @CallerSensitive - public char getChar(Object obj) - throws IllegalArgumentException, IllegalAccessException - { - if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); - } - } - return getFieldAccessor(obj).getChar(obj); - } - - /** - * Gets the value of a static or instance field of type - * {@code short} or of another primitive type convertible to - * type {@code short} via a widening conversion. - * - * @param obj the object to extract the {@code short} value - * from - * @return the value of the field converted to type {@code short} - * - * @exception IllegalAccessException if this {@code Field} object - * is enforcing Java language access control and the underlying - * field is inaccessible. - * @exception IllegalArgumentException if the specified object is not - * an instance of the class or interface declaring the - * underlying field (or a subclass or implementor - * thereof), or if the field value cannot be - * converted to the type {@code short} by a - * widening conversion. - * @exception NullPointerException if the specified object is null - * and the field is an instance field. - * @exception ExceptionInInitializerError if the initialization provoked - * by this method fails. - * @see Field#get - */ - @CallerSensitive - public short getShort(Object obj) - throws IllegalArgumentException, IllegalAccessException - { - if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); - } - } - return getFieldAccessor(obj).getShort(obj); - } - - /** - * Gets the value of a static or instance field of type - * {@code int} or of another primitive type convertible to - * type {@code int} via a widening conversion. - * - * @param obj the object to extract the {@code int} value - * from - * @return the value of the field converted to type {@code int} - * - * @exception IllegalAccessException if this {@code Field} object - * is enforcing Java language access control and the underlying - * field is inaccessible. - * @exception IllegalArgumentException if the specified object is not - * an instance of the class or interface declaring the - * underlying field (or a subclass or implementor - * thereof), or if the field value cannot be - * converted to the type {@code int} by a - * widening conversion. - * @exception NullPointerException if the specified object is null - * and the field is an instance field. - * @exception ExceptionInInitializerError if the initialization provoked - * by this method fails. - * @see Field#get - */ - @CallerSensitive - public int getInt(Object obj) - throws IllegalArgumentException, IllegalAccessException - { - if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); - } - } - return getFieldAccessor(obj).getInt(obj); - } - - /** - * Gets the value of a static or instance field of type - * {@code long} or of another primitive type convertible to - * type {@code long} via a widening conversion. - * - * @param obj the object to extract the {@code long} value - * from - * @return the value of the field converted to type {@code long} - * - * @exception IllegalAccessException if this {@code Field} object - * is enforcing Java language access control and the underlying - * field is inaccessible. - * @exception IllegalArgumentException if the specified object is not - * an instance of the class or interface declaring the - * underlying field (or a subclass or implementor - * thereof), or if the field value cannot be - * converted to the type {@code long} by a - * widening conversion. - * @exception NullPointerException if the specified object is null - * and the field is an instance field. - * @exception ExceptionInInitializerError if the initialization provoked - * by this method fails. - * @see Field#get - */ - @CallerSensitive - public long getLong(Object obj) - throws IllegalArgumentException, IllegalAccessException - { - if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); - } - } - return getFieldAccessor(obj).getLong(obj); - } - - /** - * Gets the value of a static or instance field of type - * {@code float} or of another primitive type convertible to - * type {@code float} via a widening conversion. - * - * @param obj the object to extract the {@code float} value - * from - * @return the value of the field converted to type {@code float} - * - * @exception IllegalAccessException if this {@code Field} object - * is enforcing Java language access control and the underlying - * field is inaccessible. - * @exception IllegalArgumentException if the specified object is not - * an instance of the class or interface declaring the - * underlying field (or a subclass or implementor - * thereof), or if the field value cannot be - * converted to the type {@code float} by a - * widening conversion. - * @exception NullPointerException if the specified object is null - * and the field is an instance field. - * @exception ExceptionInInitializerError if the initialization provoked - * by this method fails. - * @see Field#get - */ - @CallerSensitive - public float getFloat(Object obj) - throws IllegalArgumentException, IllegalAccessException - { - if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); - } - } - return getFieldAccessor(obj).getFloat(obj); - } - - /** - * Gets the value of a static or instance field of type - * {@code double} or of another primitive type convertible to - * type {@code double} via a widening conversion. - * - * @param obj the object to extract the {@code double} value - * from - * @return the value of the field converted to type {@code double} - * - * @exception IllegalAccessException if this {@code Field} object - * is enforcing Java language access control and the underlying - * field is inaccessible. - * @exception IllegalArgumentException if the specified object is not - * an instance of the class or interface declaring the - * underlying field (or a subclass or implementor - * thereof), or if the field value cannot be - * converted to the type {@code double} by a - * widening conversion. - * @exception NullPointerException if the specified object is null - * and the field is an instance field. - * @exception ExceptionInInitializerError if the initialization provoked - * by this method fails. - * @see Field#get - */ - @CallerSensitive - public double getDouble(Object obj) - throws IllegalArgumentException, IllegalAccessException - { - if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); - } - } - return getFieldAccessor(obj).getDouble(obj); - } - - /** - * Sets the field represented by this {@code Field} object on the - * specified object argument to the specified new value. The new - * value is automatically unwrapped if the underlying field has a - * primitive type. - * - * <p>The operation proceeds as follows: - * - * <p>If the underlying field is static, the {@code obj} argument is - * ignored; it may be null. - * - * <p>Otherwise the underlying field is an instance field. If the - * specified object argument is null, the method throws a - * {@code NullPointerException}. If the specified object argument is not - * an instance of the class or interface declaring the underlying - * field, the method throws an {@code IllegalArgumentException}. - * - * <p>If this {@code Field} object is enforcing Java language access control, and - * the underlying field is inaccessible, the method throws an - * {@code IllegalAccessException}. - * - * <p>If the underlying field is final, the method throws an - * {@code IllegalAccessException} unless {@code setAccessible(true)} - * has succeeded for this {@code Field} object - * and the field is non-static. Setting a final field in this way - * is meaningful only during deserialization or reconstruction of - * instances of classes with blank final fields, before they are - * made available for access by other parts of a program. Use in - * any other context may have unpredictable effects, including cases - * in which other parts of a program continue to use the original - * value of this field. - * - * <p>If the underlying field is of a primitive type, an unwrapping - * conversion is attempted to convert the new value to a value of - * a primitive type. If this attempt fails, the method throws an - * {@code IllegalArgumentException}. - * - * <p>If, after possible unwrapping, the new value cannot be - * converted to the type of the underlying field by an identity or - * widening conversion, the method throws an - * {@code IllegalArgumentException}. - * - * <p>If the underlying field is static, the class that declared the - * field is initialized if it has not already been initialized. - * - * <p>The field is set to the possibly unwrapped and widened new value. - * - * <p>If the field is hidden in the type of {@code obj}, - * the field's value is set according to the preceding rules. - * - * @param obj the object whose field should be modified - * @param value the new value for the field of {@code obj} - * being modified - * - * @exception IllegalAccessException if this {@code Field} object - * is enforcing Java language access control and the underlying - * field is either inaccessible or final. - * @exception IllegalArgumentException if the specified object is not an - * instance of the class or interface declaring the underlying - * field (or a subclass or implementor thereof), - * or if an unwrapping conversion fails. - * @exception NullPointerException if the specified object is null - * and the field is an instance field. - * @exception ExceptionInInitializerError if the initialization provoked - * by this method fails. - */ - @CallerSensitive - public void set(Object obj, Object value) - throws IllegalArgumentException, IllegalAccessException - { - if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); - } - } - getFieldAccessor(obj).set(obj, value); - } - - /** - * Sets the value of a field as a {@code boolean} on the specified object. - * This method is equivalent to - * {@code set(obj, zObj)}, - * where {@code zObj} is a {@code Boolean} object and - * {@code zObj.booleanValue() == z}. - * - * @param obj the object whose field should be modified - * @param z the new value for the field of {@code obj} - * being modified - * - * @exception IllegalAccessException if this {@code Field} object - * is enforcing Java language access control and the underlying - * field is either inaccessible or final. - * @exception IllegalArgumentException if the specified object is not an - * instance of the class or interface declaring the underlying - * field (or a subclass or implementor thereof), - * or if an unwrapping conversion fails. - * @exception NullPointerException if the specified object is null - * and the field is an instance field. - * @exception ExceptionInInitializerError if the initialization provoked - * by this method fails. - * @see Field#set - */ - @CallerSensitive - public void setBoolean(Object obj, boolean z) - throws IllegalArgumentException, IllegalAccessException - { - if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); - } - } - getFieldAccessor(obj).setBoolean(obj, z); - } - - /** - * Sets the value of a field as a {@code byte} on the specified object. - * This method is equivalent to - * {@code set(obj, bObj)}, - * where {@code bObj} is a {@code Byte} object and - * {@code bObj.byteValue() == b}. - * - * @param obj the object whose field should be modified - * @param b the new value for the field of {@code obj} - * being modified - * - * @exception IllegalAccessException if this {@code Field} object - * is enforcing Java language access control and the underlying - * field is either inaccessible or final. - * @exception IllegalArgumentException if the specified object is not an - * instance of the class or interface declaring the underlying - * field (or a subclass or implementor thereof), - * or if an unwrapping conversion fails. - * @exception NullPointerException if the specified object is null - * and the field is an instance field. - * @exception ExceptionInInitializerError if the initialization provoked - * by this method fails. - * @see Field#set - */ - @CallerSensitive - public void setByte(Object obj, byte b) - throws IllegalArgumentException, IllegalAccessException - { - if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); - } - } - getFieldAccessor(obj).setByte(obj, b); - } - - /** - * Sets the value of a field as a {@code char} on the specified object. - * This method is equivalent to - * {@code set(obj, cObj)}, - * where {@code cObj} is a {@code Character} object and - * {@code cObj.charValue() == c}. - * - * @param obj the object whose field should be modified - * @param c the new value for the field of {@code obj} - * being modified - * - * @exception IllegalAccessException if this {@code Field} object - * is enforcing Java language access control and the underlying - * field is either inaccessible or final. - * @exception IllegalArgumentException if the specified object is not an - * instance of the class or interface declaring the underlying - * field (or a subclass or implementor thereof), - * or if an unwrapping conversion fails. - * @exception NullPointerException if the specified object is null - * and the field is an instance field. - * @exception ExceptionInInitializerError if the initialization provoked - * by this method fails. - * @see Field#set - */ - @CallerSensitive - public void setChar(Object obj, char c) - throws IllegalArgumentException, IllegalAccessException - { - if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); - } - } - getFieldAccessor(obj).setChar(obj, c); - } - - /** - * Sets the value of a field as a {@code short} on the specified object. - * This method is equivalent to - * {@code set(obj, sObj)}, - * where {@code sObj} is a {@code Short} object and - * {@code sObj.shortValue() == s}. - * - * @param obj the object whose field should be modified - * @param s the new value for the field of {@code obj} - * being modified - * - * @exception IllegalAccessException if this {@code Field} object - * is enforcing Java language access control and the underlying - * field is either inaccessible or final. - * @exception IllegalArgumentException if the specified object is not an - * instance of the class or interface declaring the underlying - * field (or a subclass or implementor thereof), - * or if an unwrapping conversion fails. - * @exception NullPointerException if the specified object is null - * and the field is an instance field. - * @exception ExceptionInInitializerError if the initialization provoked - * by this method fails. - * @see Field#set - */ - @CallerSensitive - public void setShort(Object obj, short s) - throws IllegalArgumentException, IllegalAccessException - { - if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); - } - } - getFieldAccessor(obj).setShort(obj, s); - } - - /** - * Sets the value of a field as an {@code int} on the specified object. - * This method is equivalent to - * {@code set(obj, iObj)}, - * where {@code iObj} is a {@code Integer} object and - * {@code iObj.intValue() == i}. - * - * @param obj the object whose field should be modified - * @param i the new value for the field of {@code obj} - * being modified - * - * @exception IllegalAccessException if this {@code Field} object - * is enforcing Java language access control and the underlying - * field is either inaccessible or final. - * @exception IllegalArgumentException if the specified object is not an - * instance of the class or interface declaring the underlying - * field (or a subclass or implementor thereof), - * or if an unwrapping conversion fails. - * @exception NullPointerException if the specified object is null - * and the field is an instance field. - * @exception ExceptionInInitializerError if the initialization provoked - * by this method fails. - * @see Field#set - */ - @CallerSensitive - public void setInt(Object obj, int i) - throws IllegalArgumentException, IllegalAccessException - { - if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); - } - } - getFieldAccessor(obj).setInt(obj, i); - } - - /** - * Sets the value of a field as a {@code long} on the specified object. - * This method is equivalent to - * {@code set(obj, lObj)}, - * where {@code lObj} is a {@code Long} object and - * {@code lObj.longValue() == l}. - * - * @param obj the object whose field should be modified - * @param l the new value for the field of {@code obj} - * being modified - * - * @exception IllegalAccessException if this {@code Field} object - * is enforcing Java language access control and the underlying - * field is either inaccessible or final. - * @exception IllegalArgumentException if the specified object is not an - * instance of the class or interface declaring the underlying - * field (or a subclass or implementor thereof), - * or if an unwrapping conversion fails. - * @exception NullPointerException if the specified object is null - * and the field is an instance field. - * @exception ExceptionInInitializerError if the initialization provoked - * by this method fails. - * @see Field#set - */ - @CallerSensitive - public void setLong(Object obj, long l) - throws IllegalArgumentException, IllegalAccessException - { - if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); - } - } - getFieldAccessor(obj).setLong(obj, l); - } - - /** - * Sets the value of a field as a {@code float} on the specified object. - * This method is equivalent to - * {@code set(obj, fObj)}, - * where {@code fObj} is a {@code Float} object and - * {@code fObj.floatValue() == f}. - * - * @param obj the object whose field should be modified - * @param f the new value for the field of {@code obj} - * being modified - * - * @exception IllegalAccessException if this {@code Field} object - * is enforcing Java language access control and the underlying - * field is either inaccessible or final. - * @exception IllegalArgumentException if the specified object is not an - * instance of the class or interface declaring the underlying - * field (or a subclass or implementor thereof), - * or if an unwrapping conversion fails. - * @exception NullPointerException if the specified object is null - * and the field is an instance field. - * @exception ExceptionInInitializerError if the initialization provoked - * by this method fails. - * @see Field#set - */ - @CallerSensitive - public void setFloat(Object obj, float f) - throws IllegalArgumentException, IllegalAccessException - { - if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); - } - } - getFieldAccessor(obj).setFloat(obj, f); - } - - /** - * Sets the value of a field as a {@code double} on the specified object. - * This method is equivalent to - * {@code set(obj, dObj)}, - * where {@code dObj} is a {@code Double} object and - * {@code dObj.doubleValue() == d}. - * - * @param obj the object whose field should be modified - * @param d the new value for the field of {@code obj} - * being modified - * - * @exception IllegalAccessException if this {@code Field} object - * is enforcing Java language access control and the underlying - * field is either inaccessible or final. - * @exception IllegalArgumentException if the specified object is not an - * instance of the class or interface declaring the underlying - * field (or a subclass or implementor thereof), - * or if an unwrapping conversion fails. - * @exception NullPointerException if the specified object is null - * and the field is an instance field. - * @exception ExceptionInInitializerError if the initialization provoked - * by this method fails. - * @see Field#set - */ - @CallerSensitive - public void setDouble(Object obj, double d) - throws IllegalArgumentException, IllegalAccessException - { - if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers); - } - } - getFieldAccessor(obj).setDouble(obj, d); - } - - // security check is done before calling this method - private FieldAccessor getFieldAccessor(Object obj) - throws IllegalAccessException - { - boolean ov = override; - FieldAccessor a = (ov) ? overrideFieldAccessor : fieldAccessor; - return (a != null) ? a : acquireFieldAccessor(ov); - } - - // NOTE that there is no synchronization used here. It is correct - // (though not efficient) to generate more than one FieldAccessor - // for a given Field. However, avoiding synchronization will - // probably make the implementation more scalable. - private FieldAccessor acquireFieldAccessor(boolean overrideFinalCheck) { - // First check to see if one has been created yet, and take it - // if so - FieldAccessor tmp = null; - if (root != null) tmp = root.getFieldAccessor(overrideFinalCheck); - if (tmp != null) { - if (overrideFinalCheck) - overrideFieldAccessor = tmp; - else - fieldAccessor = tmp; - } else { - // Otherwise fabricate one and propagate it up to the root - tmp = reflectionFactory.newFieldAccessor(this, overrideFinalCheck); - setFieldAccessor(tmp, overrideFinalCheck); - } - - return tmp; - } - - // Returns FieldAccessor for this Field object, not looking up - // the chain to the root - private FieldAccessor getFieldAccessor(boolean overrideFinalCheck) { - return (overrideFinalCheck)? overrideFieldAccessor : fieldAccessor; - } - - // Sets the FieldAccessor for this Field object and - // (recursively) its root - private void setFieldAccessor(FieldAccessor accessor, boolean overrideFinalCheck) { - if (overrideFinalCheck) - overrideFieldAccessor = accessor; - else - fieldAccessor = accessor; - // Propagate up - if (root != null) { - root.setFieldAccessor(accessor, overrideFinalCheck); - } - } - - /* - * 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 extends Annotation> T getAnnotation(Class<T> 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<Class<? extends Annotation>, Annotation> declaredAnnotations; - - private synchronized Map<Class<? extends Annotation>, Annotation> declaredAnnotations() { - if (declaredAnnotations == null) { - declaredAnnotations = getDeclaredAnnotationsImpl(); - } - return declaredAnnotations; - } - - private native Map<Class<? extends Annotation>, Annotation> getDeclaredAnnotationsImpl(); -} diff --git a/openjdk/java/lang/reflect/Method.java b/openjdk/java/lang/reflect/Method.java deleted file mode 100644 index dce789a4..00000000 --- a/openjdk/java/lang/reflect/Method.java +++ /dev/null @@ -1,749 +0,0 @@ -/* - * Copyright (c) 1996, 2006, 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 ikvm.internal.CallerID; -import sun.reflect.CallerSensitive; -import sun.reflect.MethodAccessor; -import sun.reflect.Reflection; -import sun.reflect.generics.repository.MethodRepository; -import sun.reflect.generics.factory.CoreReflectionFactory; -import sun.reflect.generics.factory.GenericsFactory; -import sun.reflect.generics.scope.MethodScope; -import sun.reflect.annotation.AnnotationType; -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 - * on a class or interface. The reflected method may be a class method - * or an instance method (including an abstract method). - * - * <p>A {@code Method} permits widening conversions to occur when matching the - * actual parameters to invoke with the underlying method's formal - * parameters, but it throws an {@code IllegalArgumentException} if a - * narrowing conversion would occur. - * - * @see Member - * @see java.lang.Class - * @see java.lang.Class#getMethods() - * @see java.lang.Class#getMethod(String, Class[]) - * @see java.lang.Class#getDeclaredMethods() - * @see java.lang.Class#getDeclaredMethod(String, Class[]) - * - * @author Kenneth Russell - * @author Nakul Saraiya - */ -public final - class Method extends AccessibleObject implements GenericDeclaration, - Member { - private Class<?> clazz; - private int slot; - // This is guaranteed to be interned by the VM in the 1.4 - // reflection implementation - private String name; - private Class<?> returnType; - private Class<?>[] parameterTypes; - private Class<?>[] exceptionTypes; - private int modifiers; - // Generics and annotations support - private transient String signature; - // generic info repository; lazily initialized - private transient MethodRepository genericInfo; - private volatile MethodAccessor methodAccessor; - // 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.) - private Method root; - - // Generics infrastructure - - private String getGenericSignature() {return signature;} - - // Accessor for factory - private GenericsFactory getFactory() { - // create scope and factory - return CoreReflectionFactory.make(this, MethodScope.make(this)); - } - - // Accessor for generic info repository - private MethodRepository getGenericInfo() { - // lazily initialize repository if necessary - if (genericInfo == null) { - // create and cache generic info repository - genericInfo = MethodRepository.make(getGenericSignature(), - getFactory()); - } - return genericInfo; //return cached repository - } - - /** - * Package-private constructor used by ReflectAccess to enable - * instantiation of these objects in Java code from the java.lang - * package via sun.reflect.LangReflectAccess. - */ - Method(Class<?> declaringClass, - String name, - Class<?>[] parameterTypes, - Class<?> returnType, - Class<?>[] checkedExceptions, - int modifiers, - int slot, - String signature, - byte[] unused1, - byte[] unused2, - byte[] unused3) - { - this.clazz = declaringClass; - this.name = name; - this.parameterTypes = parameterTypes; - this.returnType = returnType; - this.exceptionTypes = checkedExceptions; - this.modifiers = modifiers; - this.slot = slot; - this.signature = signature; - } - - /** - * Package-private routine (exposed to java.lang.Class via - * ReflectAccess) which returns a copy of this Method. The copy's - * "root" field points to this Method. - */ - Method copy() { - // This routine enables sharing of MethodAccessor objects - // among Method objects which refer to the same underlying - // method in the VM. (All of this contortion is only necessary - // because of the "accessibility" bit in AccessibleObject, - // which implicitly requires that new java.lang.reflect - // objects be fabricated for each reflective call on Class - // objects.) - Method res = new Method(clazz, name, parameterTypes, returnType, - exceptionTypes, modifiers, slot, signature, - null, null, null); - res.root = this; - // Might as well eagerly propagate this if already present - res.methodAccessor = methodAccessor; - return res; - } - - /** - * Returns the {@code Class} object representing the class or interface - * that declares the method represented by this {@code Method} object. - */ - public Class<?> getDeclaringClass() { - return clazz; - } - - /** - * Returns the name of the method represented by this {@code Method} - * object, as a {@code String}. - */ - 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 - */ - 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 - * <cite>The Java™ Virtual Machine Specification</cite> - * @since 1.5 - */ - public TypeVariable<Method>[] getTypeParameters() { - if (getGenericSignature() != null) - return (TypeVariable<Method>[])getGenericInfo().getTypeParameters(); - else - return (TypeVariable<Method>[])new TypeVariable[0]; - } - - /** - * Returns a {@code Class} object that represents the formal return type - * of the method represented by this {@code Method} object. - * - * @return the return type for the method this object represents - */ - public Class<?> getReturnType() { - return returnType; - } - - /** - * Returns a {@code Type} object that represents the formal return - * type of the method represented by this {@code Method} object. - * - * <p>If the return type is a parameterized type, - * the {@code Type} object returned must accurately reflect - * the actual type parameters used in the source code. - * - * <p>If the return type is a type variable or a parameterized type, it - * is created. Otherwise, it is resolved. - * - * @return a {@code Type} object that represents the formal return - * type of the underlying method - * @throws GenericSignatureFormatError - * if the generic method signature does not conform to the format - * specified in - * <cite>The Java™ Virtual Machine Specification</cite> - * @throws TypeNotPresentException if the underlying method's - * return type refers to a non-existent type declaration - * @throws MalformedParameterizedTypeException if the - * underlying method's return typed refers to a parameterized - * type that cannot be instantiated for any reason - * @since 1.5 - */ - public Type getGenericReturnType() { - if (getGenericSignature() != null) { - return getGenericInfo().getReturnType(); - } 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 - */ - public Class<?>[] getParameterTypes() { - return (Class<?>[]) 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. - * - * <p>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. - * - * <p>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 - * <cite>The Java™ Virtual Machine Specification</cite> - * @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 - * @since 1.5 - */ - public Type[] getGenericParameterTypes() { - if (getGenericSignature() != null) - return getGenericInfo().getParameterTypes(); - else - return getParameterTypes(); - } - - - /** - * 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 - */ - public Class<?>[] getExceptionTypes() { - return (Class<?>[]) 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. - * - * <p>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 - * <cite>The Java™ Virtual Machine Specification</cite> - * @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 - * @since 1.5 - */ - public Type[] getGenericExceptionTypes() { - Type[] result; - if (getGenericSignature() != null && - ((result = getGenericInfo().getExceptionTypes()).length > 0)) - return result; - else - return getExceptionTypes(); - } - - /** - * Compares this {@code Method} against the specified object. Returns - * true if the objects are the same. Two {@code Methods} are the same if - * they were declared by the same class and have the same name - * and formal parameter types and return type. - */ - public boolean equals(Object obj) { - if (obj != null && obj instanceof Method) { - Method other = (Method)obj; - if ((getDeclaringClass() == other.getDeclaringClass()) - && (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 false; - } - - /** - * Returns a hashcode for this {@code Method}. The hashcode is computed - * as the exclusive-or of the hashcodes for the underlying - * method's declaring class name and the method's name. - */ - public int hashCode() { - return getDeclaringClass().getName().hashCode() ^ getName().hashCode(); - } - - /** - * Returns a string describing this {@code Method}. The string is - * formatted as the method access modifiers, if any, followed by - * the method return type, followed by a space, followed by the - * class declaring the method, followed by a period, followed by - * the method name, followed by a parenthesized, comma-separated - * list of the method's formal parameter types. If the method - * throws checked exceptions, the parameter list is followed by a - * space, followed by the word throws followed by a - * comma-separated list of the thrown exception types. - * For example: - * <pre> - * public boolean java.lang.Object.equals(java.lang.Object) - * </pre> - * - * <p>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 synchronized}, {@code native}, {@code strictfp}. - */ - 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 + ">"; - } - } - - /** - * Returns a string describing this {@code Method}, including - * type parameters. The string is formatted as the method access - * modifiers, if any, followed by an angle-bracketed - * comma-separated list of the method's type parameters, if any, - * followed by the method's generic return type, followed by a - * space, followed by the class declaring the method, followed by - * a period, followed by the method name, followed by a - * parenthesized, comma-separated list of the method's generic - * formal parameter types. - * - * If this method was declared to take a variable number of - * arguments, instead of denoting the last parameter as - * "<tt><i>Type</i>[]</tt>", it is denoted as - * "<tt><i>Type</i>...</tt>". - * - * A space is used to separate access modifiers from one another - * and from the type parameters or return type. If there are no - * type parameters, the type parameter list is elided; if the type - * parameter list is present, a space separates the list from the - * 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. - * - * <p>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 synchronized}, {@code native}, {@code strictfp}. - * - * @return a string describing this {@code Method}, - * include type parameters - * - * @since 1.5 - */ - 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("> "); - } - - 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 + ">"; - } - } - - /** - * Invokes the underlying method represented by this {@code Method} - * object, on the specified object with the specified parameters. - * Individual parameters are automatically unwrapped to match - * primitive formal parameters, and both primitive and reference - * parameters are subject to method invocation conversions as - * necessary. - * - * <p>If the underlying method is static, then the specified {@code obj} - * argument is ignored. It may be null. - * - * <p>If the number of formal parameters required by the underlying method is - * 0, the supplied {@code args} array may be of length 0 or null. - * - * <p>If the underlying method is an instance method, it is invoked - * using dynamic method lookup as documented in The Java Language - * Specification, Second Edition, section 15.12.4.4; in particular, - * overriding based on the runtime type of the target object will occur. - * - * <p>If the underlying method is static, the class that declared - * the method is initialized if it has not already been initialized. - * - * <p>If the method completes normally, the value it returns is - * returned to the caller of invoke; if the value has a primitive - * type, it is first appropriately wrapped in an object. However, - * if the value has the type of an array of a primitive type, the - * elements of the array are <i>not</i> wrapped in objects; in - * other words, an array of primitive type is returned. If the - * underlying method return type is void, the invocation returns - * null. - * - * @param obj the object the underlying method is invoked from - * @param args the arguments used for the method call - * @return the result of dispatching the method represented by - * this object on {@code obj} with parameters - * {@code args} - * - * @exception IllegalAccessException if this {@code Method} object - * is enforcing Java language access control and the underlying - * method is inaccessible. - * @exception IllegalArgumentException if the method is an - * instance method and the specified object argument - * is not an instance of the class or interface - * declaring the underlying method (or of a subclass - * or implementor thereof); if the number of actual - * and formal parameters differ; if an unwrapping - * conversion for primitive arguments fails; or if, - * after possible unwrapping, a parameter value - * cannot be converted to the corresponding formal - * parameter type by a method invocation conversion. - * @exception InvocationTargetException if the underlying method - * throws an exception. - * @exception NullPointerException if the specified object is null - * and the method is an instance method. - * @exception ExceptionInInitializerError if the initialization - * provoked by this method fails. - */ - @CallerSensitive - public Object invoke(Object obj, Object... args) - throws IllegalAccessException, IllegalArgumentException, - InvocationTargetException - { - if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class<?> caller = Reflection.getCallerClass(); - checkAccess(caller, clazz, obj, modifiers); - } - } - MethodAccessor ma = methodAccessor; // read volatile - if (ma == null) { - ma = acquireMethodAccessor(); - } - return ma.invoke(obj, args, CallerID.getCallerID()); - } - - /** - * Returns {@code true} if this method is a bridge - * method; returns {@code false} otherwise. - * - * @return true if and only if this method is a bridge - * method as defined by the Java Language Specification. - * @since 1.5 - */ - public boolean isBridge() { - return (getModifiers() & Modifier.BRIDGE) != 0; - } - - /** - * 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. - * @since 1.5 - */ - public boolean isVarArgs() { - return (getModifiers() & Modifier.VARARGS) != 0; - } - - /** - * 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. - * @since 1.5 - */ - public boolean isSynthetic() { - return Modifier.isSynthetic(getModifiers()); - } - - // NOTE that there is no synchronization used here. It is correct - // (though not efficient) to generate more than one MethodAccessor - // for a given Method. However, avoiding synchronization will - // probably make the implementation more scalable. - private MethodAccessor acquireMethodAccessor() { - // First check to see if one has been created yet, and take it - // if so - MethodAccessor tmp = null; - if (root != null) tmp = root.getMethodAccessor(); - if (tmp != null) { - methodAccessor = tmp; - } else { - // Otherwise fabricate one and propagate it up to the root - tmp = reflectionFactory.newMethodAccessor(this); - setMethodAccessor(tmp); - } - - return tmp; - } - - // Returns MethodAccessor for this Method object, not looking up - // the chain to the root - MethodAccessor getMethodAccessor() { - return methodAccessor; - } - - // Sets the MethodAccessor for this Method object and - // (recursively) its root - void setMethodAccessor(MethodAccessor accessor) { - methodAccessor = accessor; - // Propagate up - if (root != null) { - root.setMethodAccessor(accessor); - } - } - - /** - * @throws NullPointerException {@inheritDoc} - * @since 1.5 - */ - public <T extends Annotation> T getAnnotation(Class<T> 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<Class<? extends Annotation>, Annotation> declaredAnnotations; - - private synchronized Map<Class<? extends Annotation>, Annotation> declaredAnnotations() { - if (declaredAnnotations == null) { - declaredAnnotations = getDeclaredAnnotationsImpl(this); - } - return declaredAnnotations; - } - - static native Map<Class<? extends Annotation>, 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, - * an instance of the corresponding wrapper type is returned. Returns - * null if no default is associated with the member, or if the method - * instance does not represent a declared member of an annotation type. - * - * @return the default value for the annotation member represented - * by this {@code Method} instance. - * @throws TypeNotPresentException if the annotation is of type - * {@link Class} and no definition can be found for the - * default class value. - * @since 1.5 - */ - 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 - * @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; - } - - static native Annotation[][] getParameterAnnotationsImpl(Object methodOrConstructor); -} diff --git a/openjdk/java/lang/reflect/Proxy.java b/openjdk/java/lang/reflect/Proxy.java deleted file mode 100644 index 3d9850e0..00000000 --- a/openjdk/java/lang/reflect/Proxy.java +++ /dev/null @@ -1,815 +0,0 @@ -/* - * Copyright (c) 1999, 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.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.Map; -import java.util.Set; -import java.util.List; -import java.util.WeakHashMap; -import sun.misc.ProxyGenerator; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; -import sun.reflect.misc.ReflectUtil; -import sun.security.util.SecurityConstants; - -/** - * {@code Proxy} provides static methods for creating dynamic proxy - * classes and instances, and it is also the superclass of all - * dynamic proxy classes created by those methods. - * - * <p>To create a proxy for some interface {@code Foo}: - * <pre> - * 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 }); - * </pre> - * or more simply: - * <pre> - * Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), - * new Class[] { Foo.class }, - * handler); - * </pre> - * - * <p>A <i>dynamic proxy class</i> (simply referred to as a <i>proxy - * class</i> below) is a class that implements a list of interfaces - * specified at runtime when the class is created, with behavior as - * described below. - * - * A <i>proxy interface</i> is such an interface that is implemented - * by a proxy class. - * - * A <i>proxy instance</i> is an instance of a proxy class. - * - * Each proxy instance has an associated <i>invocation handler</i> - * object, which implements the interface {@link InvocationHandler}. - * A method invocation on a proxy instance through one of its proxy - * interfaces will be dispatched to the {@link InvocationHandler#invoke - * invoke} method of the instance's invocation handler, passing the proxy - * instance, a {@code java.lang.reflect.Method} object identifying - * the method that was invoked, and an array of type {@code Object} - * containing the arguments. The invocation handler processes the - * encoded method invocation as appropriate and the result that it - * returns will be returned as the result of the method invocation on - * the proxy instance. - * - * <p>A proxy class has the following properties: - * - * <ul> - * <li>Proxy classes are public, final, and not abstract. - * - * <li>The unqualified name of a proxy class is unspecified. The space - * of class names that begin with the string {@code "$Proxy"} - * should be, however, reserved for proxy classes. - * - * <li>A proxy class extends {@code java.lang.reflect.Proxy}. - * - * <li>A proxy class implements exactly the interfaces specified at its - * creation, in the same order. - * - * <li>If a proxy class implements a non-public interface, then it will - * be defined in the same package as that interface. Otherwise, the - * package of a proxy class is also unspecified. Note that package - * sealing will not prevent a proxy class from being successfully defined - * in a particular package at runtime, and neither will classes already - * defined by the same class loader and the same package with particular - * signers. - * - * <li>Since a proxy class implements all of the interfaces specified at - * its creation, invoking {@code getInterfaces} on its - * {@code Class} object will return an array containing the same - * list of interfaces (in the order specified at its creation), invoking - * {@code getMethods} on its {@code Class} object will return - * an array of {@code Method} objects that include all of the - * methods in those interfaces, and invoking {@code getMethod} will - * find methods in the proxy interfaces as would be expected. - * - * <li>The {@link Proxy#isProxyClass Proxy.isProxyClass} method will - * return true if it is passed a proxy class-- a class returned by - * {@code Proxy.getProxyClass} or the class of an object returned by - * {@code Proxy.newProxyInstance}-- and false otherwise. - * - * <li>The {@code java.security.ProtectionDomain} of a proxy class - * is the same as that of system classes loaded by the bootstrap class - * loader, such as {@code java.lang.Object}, because the code for a - * proxy class is generated by trusted system code. This protection - * domain will typically be granted - * {@code java.security.AllPermission}. - * - * <li>Each proxy class has one public constructor that takes one argument, - * an implementation of the interface {@link InvocationHandler}, to set - * the invocation handler for a proxy instance. Rather than having to use - * the reflection API to access the public constructor, a proxy instance - * can be also be created by calling the {@link Proxy#newProxyInstance - * Proxy.newProxyInstance} method, which combines the actions of calling - * {@link Proxy#getProxyClass Proxy.getProxyClass} with invoking the - * constructor with an invocation handler. - * </ul> - * - * <p>A proxy instance has the following properties: - * - * <ul> - * <li>Given a proxy instance {@code proxy} and one of the - * interfaces implemented by its proxy class {@code Foo}, the - * following expression will return true: - * <pre> - * {@code proxy instanceof Foo} - * </pre> - * and the following cast operation will succeed (rather than throwing - * a {@code ClassCastException}): - * <pre> - * {@code (Foo) proxy} - * </pre> - * - * <li>Each proxy instance has an associated invocation handler, the one - * that was passed to its constructor. The static - * {@link Proxy#getInvocationHandler Proxy.getInvocationHandler} method - * will return the invocation handler associated with the proxy instance - * passed as its argument. - * - * <li>An interface method invocation on a proxy instance will be - * encoded and dispatched to the invocation handler's {@link - * InvocationHandler#invoke invoke} method as described in the - * documentation for that method. - * - * <li>An invocation of the {@code hashCode}, - * {@code equals}, or {@code toString} methods declared in - * {@code java.lang.Object} on a proxy instance will be encoded and - * dispatched to the invocation handler's {@code invoke} method in - * the same manner as interface method invocations are encoded and - * dispatched, as described above. The declaring class of the - * {@code Method} object passed to {@code invoke} will be - * {@code java.lang.Object}. Other public methods of a proxy - * instance inherited from {@code java.lang.Object} are not - * overridden by a proxy class, so invocations of those methods behave - * like they do for instances of {@code java.lang.Object}. - * </ul> - * - * <h3>Methods Duplicated in Multiple Proxy Interfaces</h3> - * - * <p>When two or more interfaces of a proxy class contain a method with - * the same name and parameter signature, the order of the proxy class's - * interfaces becomes significant. When such a <i>duplicate method</i> - * is invoked on a proxy instance, the {@code Method} object passed - * to the invocation handler will not necessarily be the one whose - * declaring class is assignable from the reference type of the interface - * that the proxy's method was invoked through. This limitation exists - * because the corresponding method implementation in the generated proxy - * class cannot determine which interface it was invoked through. - * Therefore, when a duplicate method is invoked on a proxy instance, - * the {@code Method} object for the method in the foremost interface - * that contains the method (either directly or inherited through a - * superinterface) in the proxy class's list of interfaces is passed to - * the invocation handler's {@code invoke} method, regardless of the - * reference type through which the method invocation occurred. - * - * <p>If a proxy interface contains a method with the same name and - * parameter signature as the {@code hashCode}, {@code equals}, - * or {@code toString} methods of {@code java.lang.Object}, - * when such a method is invoked on a proxy instance, the - * {@code Method} object passed to the invocation handler will have - * {@code java.lang.Object} as its declaring class. In other words, - * the public, non-final methods of {@code java.lang.Object} - * logically precede all of the proxy interfaces for the determination of - * which {@code Method} object to pass to the invocation handler. - * - * <p>Note also that when a duplicate method is dispatched to an - * invocation handler, the {@code invoke} method may only throw - * checked exception types that are assignable to one of the exception - * types in the {@code throws} clause of the method in <i>all</i> of - * the proxy interfaces that it can be invoked through. If the - * {@code invoke} method throws a checked exception that is not - * assignable to any of the exception types declared by the method in one - * of the proxy interfaces that it can be invoked through, then an - * unchecked {@code UndeclaredThrowableException} will be thrown by - * the invocation on the proxy instance. This restriction means that not - * all of the exception types returned by invoking - * {@code getExceptionTypes} on the {@code Method} object - * passed to the {@code invoke} method can necessarily be thrown - * successfully by the {@code invoke} method. - * - * @author Peter Jones - * @see InvocationHandler - * @since 1.3 - */ -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 = - { InvocationHandler.class }; - - /** maps a class loader to the proxy class cache for that loader */ - private static Map<ClassLoader, Map<List<String>, 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<Class<?>, Void> proxyClasses = - Collections.synchronizedMap(new WeakHashMap<Class<?>, Void>()); - - /** - * the invocation handler for this proxy instance. - * @serial - */ - protected InvocationHandler h; - - /** - * Prohibits instantiation. - */ - private Proxy() { - } - - /** - * Constructs a new {@code Proxy} instance from a subclass - * (typically, a dynamic proxy class) with the specified value - * for its invocation handler. - * - * @param h the invocation handler for this proxy instance - */ - protected Proxy(InvocationHandler h) { - doNewInstanceCheck(); - 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<String>() { - 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, - * a proxy class for those interfaces will be generated dynamically - * and defined by the class loader. - * - * <p>There are several restrictions on the parameters that may be - * passed to {@code Proxy.getProxyClass}: - * - * <ul> - * <li>All of the {@code Class} objects in the - * {@code interfaces} array must represent interfaces, not - * classes or primitive types. - * - * <li>No two elements in the {@code interfaces} array may - * refer to identical {@code Class} objects. - * - * <li>All of the interface types must be visible by name through the - * specified class loader. In other words, for class loader - * {@code cl} and every interface {@code i}, the following - * expression must be true: - * <pre> - * Class.forName(i.getName(), false, cl) == i - * </pre> - * - * <li>All non-public interfaces must be in the same package; - * otherwise, it would not be possible for the proxy class to - * implement all of the interfaces, regardless of what package it is - * defined in. - * - * <li>For any set of member methods of the specified interfaces - * that have the same signature: - * <ul> - * <li>If the return type of any of the methods is a primitive - * type or void, then all of the methods must have that same - * return type. - * <li>Otherwise, one of the methods must have a return type that - * is assignable to all of the return types of the rest of the - * methods. - * </ul> - * - * <li>The resulting proxy class must not exceed any limits imposed - * on classes by the virtual machine. For example, the VM may limit - * the number of interfaces that a class may implement to 65535; in - * that case, the size of the {@code interfaces} array must not - * exceed 65535. - * </ul> - * - * <p>If any of these restrictions are violated, - * {@code Proxy.getProxyClass} will throw an - * {@code IllegalArgumentException}. If the {@code interfaces} - * array argument or any of its elements are {@code null}, a - * {@code NullPointerException} will be thrown. - * - * <p>Note that the order of the specified proxy interfaces is - * significant: two requests for a proxy class with the same combination - * of interfaces but in a different order will result in two distinct - * proxy classes. - * - * @param loader the class loader to define the proxy class - * @param interfaces the list of interfaces for the proxy class - * to implement - * @return a proxy class that is defined in the specified class loader - * and that implements the specified interfaces - * @throws IllegalArgumentException if any of the restrictions on the - * parameters that may be passed to {@code getProxyClass} - * are violated - * @throws NullPointerException if the {@code interfaces} array - * argument or any of its elements are {@code null} - */ - @CallerSensitive - public static Class<?> getProxyClass(ClassLoader loader, - Class<?>... interfaces) - throws IllegalArgumentException - { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - checkProxyAccess(Reflection.getCallerClass(), loader, interfaces); - } - - return getProxyClass0(loader, interfaces); - } - - /* - * Check permissions required to create a Proxy class. - * - * To define a proxy class, it performs the access checks as in - * Class.forName (VM will invoke ClassLoader.checkPackageAccess): - * 1. "getClassLoader" permission check if loader == null - * 2. checkPackageAccess on the interfaces it implements - * - * To get a constructor and new instance of a proxy class, it performs - * the package access check on the interfaces it implements - * as in Class.getConstructor. - * - * If an interface is non-public, the proxy class must be defined by - * the defining loader of the interface. If the caller's class loader - * is not the same as the defining loader of the interface, the VM - * will throw IllegalAccessError when the generated proxy class is - * being defined via the defineClass0 method. - */ - private static void checkProxyAccess(Class<?> caller, - ClassLoader loader, - Class<?>... interfaces) - { - 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); - } - } - ReflectUtil.checkProxyPackageAccess(ccl, interfaces); - } - } - - /** - * Generate a proxy class. Must call the checkProxyAccess method - * to perform permission checks before calling this. - */ - private static Class<?> getProxyClass0(ClassLoader loader, - Class<?>... interfaces) { - if (interfaces.length > 65535) { - throw new IllegalArgumentException("interface limit exceeded"); - } - - Class<?> proxyClass = null; - - /* collect interface names to use as key for proxy class cache */ - String[] interfaceNames = new String[interfaces.length]; - - // for detecting duplicates - Set<Class<?>> interfaceSet = new HashSet<>(); - - 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"); - } - - /* - * 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; - } - - /* - * 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<String> key = Arrays.asList(interfaceNames); - - /* - * Find or create the proxy class cache for the class loader. - */ - Map<List<String>, 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. - */ - } - - /* - * 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(); - } - 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); - } - - try { - String proxyPkg = null; // package to define proxy class in - - /* - * 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(); - if (!Modifier.isPublic(flags)) { - String name = interfaces[i].getName(); - int n = name.lastIndexOf('.'); - String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); - if (proxyPkg == null) { - proxyPkg = pkg; - } else if (!pkg.equals(proxyPkg)) { - throw new IllegalArgumentException( - "non-public interfaces from different packages"); - } - } - } - - if (proxyPkg == null) { - // if no non-public proxy interfaces, use com.sun.proxy package - 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. - */ - synchronized (cache) { - if (proxyClass != null) { - cache.put(key, new WeakReference<Class<?>>(proxyClass)); - } else { - cache.remove(key); - } - cache.notifyAll(); - } - } - 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: - * <pre> - * Proxy.getProxyClass(loader, interfaces). - * getConstructor(new Class[] { InvocationHandler.class }). - * newInstance(new Object[] { handler }); - * </pre> - * - * <p>{@code Proxy.newProxyInstance} throws - * {@code IllegalArgumentException} for the same reasons that - * {@code Proxy.getProxyClass} does. - * - * @param loader the class loader to define the proxy class - * @param interfaces the list of interfaces for the proxy class - * to implement - * @param h the invocation handler to dispatch method invocations to - * @return a proxy instance with the specified invocation handler of a - * proxy class that is defined by the specified class loader - * and that implements the specified interfaces - * @throws IllegalArgumentException if any of the restrictions on the - * parameters that may be passed to {@code getProxyClass} - * are violated - * @throws NullPointerException if the {@code interfaces} array - * argument or any of its elements are {@code null}, or - * if the invocation handler, {@code h}, is - * {@code null} - */ - @CallerSensitive - public static Object newProxyInstance(ClassLoader loader, - Class<?>[] interfaces, - InvocationHandler h) - throws IllegalArgumentException - { - if (h == null) { - throw new NullPointerException(); - } - - final SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - checkProxyAccess(Reflection.getCallerClass(), loader, interfaces); - } - - /* - * Look up or generate the designated proxy class. - */ - Class<?> cl = getProxyClass0(loader, interfaces); - - /* - * Invoke its constructor with the designated invocation handler. - */ - try { - 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<Object>() { - public Object run() { - return newInstance(cons, ih); - } - }); - } 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()); - } catch (InvocationTargetException e) { - Throwable t = e.getCause(); - if (t instanceof RuntimeException) { - throw (RuntimeException) t; - } else { - throw new InternalError(t.toString()); - } - } - } - - /** - * Returns true if and only if the specified class was dynamically - * generated to be a proxy class using the {@code getProxyClass} - * method or the {@code newProxyInstance} method. - * - * <p>The reliability of this method is important for the ability - * to use it to make security decisions, so its implementation should - * not just test if the class in question extends {@code Proxy}. - * - * @param cl the class to test - * @return {@code true} if the class is a proxy class and - * {@code false} otherwise - * @throws NullPointerException if {@code cl} is {@code null} - */ - public static boolean isProxyClass(Class<?> cl) { - if (cl == null) { - throw new NullPointerException(); - } - - return proxyClasses.containsKey(cl); - } - - /** - * Returns the invocation handler for the specified proxy instance. - * - * @param proxy the proxy instance to return the invocation handler for - * @return the invocation handler for the proxy instance - * @throws IllegalArgumentException if the argument is not a - * proxy instance - */ - public static InvocationHandler getInvocationHandler(Object proxy) - throws IllegalArgumentException - { - /* - * Verify that the object is actually a proxy instance. - */ - if (!isProxyClass(proxy.getClass())) { - throw new IllegalArgumentException("not a proxy instance"); - } - - Proxy p = (Proxy) proxy; - return p.h; - } - - 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/openjdk/java/lang/reflect/ReflectHelper.java b/openjdk/java/lang/reflect/ReflectHelper.java deleted file mode 100644 index e0eb38cb..00000000 --- a/openjdk/java/lang/reflect/ReflectHelper.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - Copyright (C) 2007-2012 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.reflect; - -@ikvm.lang.Internal -public final class ReflectHelper -{ - private ReflectHelper() {} - - public static Field copyFieldAndMakeAccessible(Field field) - { - field = field.copy(); - field.override = true; - return field; - } - - public static Field createFieldAndMakeAccessible(Class c, String name) - { - // we pass in ReflectHelper.class as the field type (which isn't used) - // to make Field.toString() return something "meaningful" instead of crash - Field field = new Field(c, name, ReflectHelper.class, 0, -1, null, null); - field.override = true; - return field; - } -} diff --git a/openjdk/java/net/DefaultDatagramSocketImplFactory.java b/openjdk/java/net/DefaultDatagramSocketImplFactory.java deleted file mode 100644 index 7d4f8edb..00000000 --- a/openjdk/java/net/DefaultDatagramSocketImplFactory.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 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.security.AccessController; -import java.security.PrivilegedAction; - -/** - * This class defines a factory for creating DatagramSocketImpls. It defaults - * to creating plain DatagramSocketImpls, but may create other DatagramSocketImpls - * by setting the impl.prefix system property. - * - * For Windows versions lower than Windows Vista a TwoStacksPlainDatagramSocketImpl - * is always created. This impl supports IPv6 on these platform where available. - * - * On Windows platforms greater than Vista that support a dual layer TCP/IP stack - * a DualStackPlainDatagramSocketImpl is created for DatagramSockets. For MulticastSockets - * a TwoStacksPlainDatagramSocketImpl is always created. This is to overcome the lack - * of behavior defined for multicasting over a dual layer socket by the RFC. - * - * @author Chris Hegarty - */ - -class DefaultDatagramSocketImplFactory -{ - static Class prefixImplClass = null; - - /* the windows version. */ - private static float version; - - /* java.net.preferIPv4Stack */ - private static boolean preferIPv4Stack = false; - - /* If the version supports a dual stack TCP implementation */ - private static boolean useDualStackImpl = false; - - /* sun.net.useExclusiveBind */ - private static String exclBindProp; - - /* True if exclusive binding is on for Windows */ - private static boolean exclusiveBind = true; - - - static { - // Determine Windows Version. - java.security.AccessController.doPrivileged( - new PrivilegedAction<Object>() { - public Object run() { - version = 0; - try { - version = Float.parseFloat(System.getProperties() - .getProperty("os.version")); - preferIPv4Stack = Boolean.parseBoolean( - System.getProperties() - .getProperty( - "java.net.preferIPv4Stack")); - exclBindProp = System.getProperty( - "sun.net.useExclusiveBind"); - } catch (NumberFormatException e ) { - assert false : e; - } - return null; // nothing to return - } - }); - - String ipv6 = ikvm.internal.Util.SafeGetEnvironmentVariable("IKVM_IPV6"); - if (ipv6 != null) { - try { - if ((Integer.parseInt(ipv6) & 4) == 0) { - preferIPv4Stack = true; - } else { - useDualStackImpl = true; - } - } catch (NumberFormatException _) { - } - } else if (!InetAddressImplFactory.isIPv6Supported()) { - preferIPv4Stack = true; - } - - // (version >= 6.0) implies Vista or greater. - if (version >= 6.0 && !preferIPv4Stack) { - useDualStackImpl = true; - } - if (exclBindProp != null) { - // sun.net.useExclusiveBind is true - exclusiveBind = exclBindProp.length() == 0 ? true - : Boolean.parseBoolean(exclBindProp); - } else if (version < 6.0) { - exclusiveBind = false; - } - - // impl.prefix - String prefix = null; - try { - prefix = AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("impl.prefix", null)); - if (prefix != null) - prefixImplClass = Class.forName("java.net."+prefix+"DatagramSocketImpl"); - } catch (Exception e) { - System.err.println("Can't find class: java.net." + - prefix + - "DatagramSocketImpl: check impl.prefix property"); - } - } - - /** - * Creates a new <code>DatagramSocketImpl</code> instance. - * - * @param isMulticast true if this impl is to be used for a MutlicastSocket - * @return a new instance of <code>PlainDatagramSocketImpl</code>. - */ - static DatagramSocketImpl createDatagramSocketImpl(boolean isMulticast) - throws SocketException { - if (prefixImplClass != null) { - try { - return (DatagramSocketImpl) prefixImplClass.newInstance(); - } catch (Exception e) { - throw new SocketException("can't instantiate DatagramSocketImpl"); - } - } else { - if (isMulticast) - exclusiveBind = false; - if (useDualStackImpl && !isMulticast) - return new DualStackPlainDatagramSocketImpl(exclusiveBind); - else - return new TwoStacksPlainDatagramSocketImpl(exclusiveBind); - } - } -} diff --git a/openjdk/java/net/DualStackPlainDatagramSocketImpl.java b/openjdk/java/net/DualStackPlainDatagramSocketImpl.java deleted file mode 100644 index 1d74e28c..00000000 --- a/openjdk/java/net/DualStackPlainDatagramSocketImpl.java +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright (c) 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.IOException; - -/** - * This class defines the plain DatagramSocketImpl that is used on - * Windows platforms greater than or equal to Windows Vista. These - * platforms have a dual layer TCP/IP stack and can handle both IPv4 - * and IPV6 through a single file descriptor. - * <p> - * Note: Multicasting on a dual layer TCP/IP stack is always done with - * TwoStacksPlainDatagramSocketImpl. This is to overcome the lack - * of behavior defined for multicasting over a dual layer socket by the RFC. - * - * @author Chris Hegarty - */ - -class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl -{ - - // true if this socket is exclusively bound - private final boolean exclusiveBind; - - /* - * Set to true if SO_REUSEADDR is set after the socket is bound to - * indicate SO_REUSEADDR is being emulated - */ - private boolean reuseAddressEmulated; - - // emulates SO_REUSEADDR when exclusiveBind is true and socket is bound - private boolean isReuseAddress; - - DualStackPlainDatagramSocketImpl(boolean exclBind) { - exclusiveBind = exclBind; - } - - protected void datagramSocketCreate() throws SocketException { - if (fd == null) - throw new SocketException("Socket closed"); - - cli.System.Net.Sockets.Socket newfd = socketCreate(false /* v6Only */); - - fd.setSocket(newfd); - } - - protected synchronized void bind0(int lport, InetAddress laddr) - throws SocketException { - cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); - - if (laddr == null) - throw new NullPointerException("argument address"); - - socketBind(nativefd, laddr, lport, exclusiveBind); - if (lport == 0) { - localPort = socketLocalPort(nativefd); - } else { - localPort = lport; - } - } - - protected synchronized int peek(InetAddress address) throws IOException { - cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); - - if (address == null) - throw new NullPointerException("Null address in peek()"); - - // Use peekData() - DatagramPacket peekPacket = new DatagramPacket(new byte[1], 1); - int peekPort = peekData(peekPacket); - address = peekPacket.getAddress(); - return peekPort; - } - - protected synchronized int peekData(DatagramPacket p) throws IOException { - cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); - - if (p == null) - throw new NullPointerException("packet"); - if (p.getData() == null) - throw new NullPointerException("packet buffer"); - - return socketReceiveOrPeekData(nativefd, p, timeout, connected, true /*peek*/); - } - - protected synchronized void receive0(DatagramPacket p) throws IOException { - cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); - - if (p == null) - throw new NullPointerException("packet"); - if (p.getData() == null) - throw new NullPointerException("packet buffer"); - - socketReceiveOrPeekData(nativefd, p, timeout, connected, false /*receive*/); - } - - protected void send(DatagramPacket p) throws IOException { - cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); - - if (p == null) - throw new NullPointerException("null packet"); - - if (p.getAddress() == null ||p.getData() ==null) - throw new NullPointerException("null address || null buffer"); - - socketSend(nativefd, p.getData(), p.getOffset(), p.getLength(), - p.getAddress(), p.getPort(), connected); - } - - protected void connect0(InetAddress address, int port) throws SocketException { - cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); - - if (address == null) - throw new NullPointerException("address"); - - socketConnect(nativefd, address, port); - } - - protected void disconnect0(int family /*unused*/) { - if (fd == null || !fd.valid()) - return; // disconnect doesn't throw any exceptions - - socketDisconnect(fd.getSocket()); - } - - protected void datagramSocketClose() { - if (fd == null || !fd.valid()) - return; // close doesn't throw any exceptions - - socketClose(fd.getSocket()); - fd.setSocket(null); - } - - @SuppressWarnings("fallthrough") - protected void socketSetOption(int opt, Object val) throws SocketException { - cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); - - int optionValue = 0; - - switch(opt) { - case IP_TOS : - case SO_RCVBUF : - case SO_SNDBUF : - optionValue = ((Integer)val).intValue(); - break; - case SO_REUSEADDR : - if (exclusiveBind && localPort != 0) { - // socket already bound, emulate SO_REUSEADDR - reuseAddressEmulated = true; - isReuseAddress = (Boolean)val; - return; - } - //Intentional fallthrough - case SO_BROADCAST : - optionValue = ((Boolean)val).booleanValue() ? 1 : 0; - break; - default: /* shouldn't get here */ - throw new SocketException("Option not supported"); - } - - socketSetIntOption(nativefd, opt, optionValue); - } - - protected Object socketGetOption(int opt) throws SocketException { - cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); - - // SO_BINDADDR is not a socket option. - if (opt == SO_BINDADDR) { - return socketLocalAddress(nativefd); - } - if (opt == SO_REUSEADDR && reuseAddressEmulated) - return isReuseAddress; - - int value = socketGetIntOption(nativefd, opt); - Object returnValue = null; - - switch (opt) { - case SO_REUSEADDR : - case SO_BROADCAST : - returnValue = (value == 0) ? Boolean.FALSE : Boolean.TRUE; - break; - case IP_TOS : - case SO_RCVBUF : - case SO_SNDBUF : - returnValue = new Integer(value); - break; - default: /* shouldn't get here */ - throw new SocketException("Option not supported"); - } - - return returnValue; - } - - /* Multicast specific methods. - * Multicasting on a dual layer TCP/IP stack is always done with - * TwoStacksPlainDatagramSocketImpl. This is to overcome the lack - * of behavior defined for multicasting over a dual layer socket by the RFC. - */ - protected void join(InetAddress inetaddr, NetworkInterface netIf) - throws IOException { - throw new IOException("Method not implemented!"); - } - - protected void leave(InetAddress inetaddr, NetworkInterface netIf) - throws IOException { - throw new IOException("Method not implemented!"); - } - - protected void setTimeToLive(int ttl) throws IOException { - throw new IOException("Method not implemented!"); - } - - protected int getTimeToLive() throws IOException { - throw new IOException("Method not implemented!"); - } - - - protected void setTTL(byte ttl) throws IOException { - throw new IOException("Method not implemented!"); - } - - protected byte getTTL() throws IOException { - throw new IOException("Method not implemented!"); - } - /* END Multicast specific methods */ - - private cli.System.Net.Sockets.Socket checkAndReturnNativeFD() throws SocketException { - if (fd == null || !fd.valid()) - throw new SocketException("Socket closed"); - - return fd.getSocket(); - } - - /* Native methods */ - - private static cli.System.Net.Sockets.Socket socketCreate(boolean v6Only) { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - cli.System.Net.Sockets.Socket ret = DualStackPlainDatagramSocketImpl_c.socketCreate(env, v6Only); - env.ThrowPendingException(); - return ret; - } - - private static void socketBind(cli.System.Net.Sockets.Socket fd, InetAddress localAddress, - int localport, boolean exclBind) throws SocketException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - DualStackPlainDatagramSocketImpl_c.socketBind(env, fd, localAddress, localport, exclBind); - env.ThrowPendingException(); - } - - private static void socketConnect(cli.System.Net.Sockets.Socket fd, InetAddress address, int port) - throws SocketException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - DualStackPlainDatagramSocketImpl_c.socketConnect(env, fd, address, port); - env.ThrowPendingException(); - } - - private static void socketDisconnect(cli.System.Net.Sockets.Socket fd) { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - DualStackPlainDatagramSocketImpl_c.socketDisconnect(env, fd); - env.ThrowPendingException(); - } - - private static void socketClose(cli.System.Net.Sockets.Socket fd) { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - DualStackPlainDatagramSocketImpl_c.socketClose(env, fd); - env.ThrowPendingException(); - } - - private static int socketLocalPort(cli.System.Net.Sockets.Socket fd) throws SocketException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - int ret = DualStackPlainDatagramSocketImpl_c.socketLocalPort(env, fd); - env.ThrowPendingException(); - return ret; - } - - private static Object socketLocalAddress(cli.System.Net.Sockets.Socket fd) throws SocketException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - Object ret = DualStackPlainDatagramSocketImpl_c.socketLocalAddress(env, fd); - env.ThrowPendingException(); - return ret; - } - - private static int socketReceiveOrPeekData(cli.System.Net.Sockets.Socket fd, DatagramPacket packet, - int timeout, boolean connected, boolean peek) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - int ret = DualStackPlainDatagramSocketImpl_c.socketReceiveOrPeekData(env, fd, packet, timeout, connected, peek); - env.ThrowPendingException(); - return ret; - } - - private static void socketSend(cli.System.Net.Sockets.Socket fd, byte[] data, int offset, int length, - InetAddress address, int port, boolean connected) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - DualStackPlainDatagramSocketImpl_c.socketSend(env, fd, data, offset, length, address, port, connected); - env.ThrowPendingException(); - } - - private static void socketSetIntOption(cli.System.Net.Sockets.Socket fd, int cmd, - int optionValue) throws SocketException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - DualStackPlainDatagramSocketImpl_c.socketSetIntOption(env, fd, cmd, optionValue); - env.ThrowPendingException(); - } - - private static int socketGetIntOption(cli.System.Net.Sockets.Socket fd, int cmd) throws SocketException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - int ret = DualStackPlainDatagramSocketImpl_c.socketGetIntOption(env, fd, cmd); - env.ThrowPendingException(); - return ret; - } -} diff --git a/openjdk/java/net/DualStackPlainDatagramSocketImpl_c.java b/openjdk/java/net/DualStackPlainDatagramSocketImpl_c.java deleted file mode 100644 index 1f4ed69b..00000000 --- a/openjdk/java/net/DualStackPlainDatagramSocketImpl_c.java +++ /dev/null @@ -1,488 +0,0 @@ -/* - * Copyright (c) 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 static ikvm.internal.JNI.*; -import static ikvm.internal.Winsock.*; -import static java.net.net_util_md.*; - -final class DualStackPlainDatagramSocketImpl_c -{ -static final int TRUE = 1; -static final int FALSE = 0; - -static final int JVM_IO_ERR = -1; -static final int JVM_IO_INTR = -2; - -/* -#include <windows.h> -#include <winsock2.h> -#include "jni.h" -#include "net_util.h" -#include "java_net_DualStackPlainDatagramSocketImpl.h" - -/* - * This function "purges" all outstanding ICMP port unreachable packets - * outstanding on a socket and returns JNI_TRUE if any ICMP messages - * have been purged. The rational for purging is to emulate normal BSD - * behaviour whereby receiving a "connection reset" status resets the - * socket. - */ -static boolean purgeOutstandingICMP(JNIEnv env, cli.System.Net.Sockets.Socket fd) -{ - boolean got_icmp = false; - byte[] buf = new byte[1]; - fd_set tbl = new fd_set(); - timeval t = new timeval(); - SOCKETADDRESS rmtaddr = null; - - /* - * Peek at the queue to see if there is an ICMP port unreachable. If there - * is then receive it. - */ - FD_ZERO(tbl); - FD_SET(fd, tbl); - while(true) { - if (select(tbl, null, null, t) <= 0) { - break; - } - if (recvfrom(fd, buf, 1, MSG_PEEK, - rmtaddr) != JVM_IO_ERR) { - break; - } - if (WSAGetLastError() != WSAECONNRESET) { - /* some other error - we don't care here */ - break; - } - - recvfrom(fd, buf, 1, 0, rmtaddr); - got_icmp = JNI_TRUE; - } - - return got_icmp; -} - -/* - * Class: java_net_DualStackPlainDatagramSocketImpl - * Method: socketCreate - * Signature: (Z)I - */ -static cli.System.Net.Sockets.Socket socketCreate - (JNIEnv env, boolean v6Only /*unused*/) { - cli.System.Net.Sockets.Socket fd; - int rv, opt=0, t=TRUE; - - fd = socket(AF_INET6, SOCK_DGRAM, 0); - if (fd == INVALID_SOCKET) { - NET_ThrowNew(env, WSAGetLastError(), "Socket creation failed"); - return null; - } - - rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, opt); - if (rv == SOCKET_ERROR) { - NET_ThrowNew(env, WSAGetLastError(), "Socket creation failed"); - return null; - } - - //SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE); - NET_SetSockOpt(fd, SOL_SOCKET, SO_BROADCAST, t); - - /* SIO_UDP_CONNRESET fixes a "bug" introduced in Windows 2000, which - * returns connection reset errors on unconnected UDP sockets (as well - * as connected sockets). The solution is to only enable this feature - * when the socket is connected. - */ - t = FALSE; - WSAIoctl(fd ,SIO_UDP_CONNRESET ,false); - - return fd; -} - -/* - * Class: java_net_DualStackPlainDatagramSocketImpl - * Method: socketBind - * Signature: (ILjava/net/InetAddress;I)V - */ -static void socketBind - (JNIEnv env, cli.System.Net.Sockets.Socket fd, InetAddress iaObj, int port, boolean exclBind) { - SOCKETADDRESS sa; - sa = new SOCKETADDRESS(); - int rv; - - if (NET_InetAddressToSockaddr(env, iaObj, port, sa, - JNI_TRUE) != 0) { - return; - } - rv = NET_WinBind(fd, sa, exclBind); - - if (rv == SOCKET_ERROR) { - if (WSAGetLastError() == WSAEACCES) { - WSASetLastError(WSAEADDRINUSE); - } - NET_ThrowNew(env, WSAGetLastError(), "Cannot bind"); - } -} - -/* - * Class: java_net_DualStackPlainDatagramSocketImpl - * Method: socketConnect - * Signature: (ILjava/net/InetAddress;I)V - */ -static void socketConnect - (JNIEnv env, cli.System.Net.Sockets.Socket fd, InetAddress iaObj, int port) { - SOCKETADDRESS sa; - sa = new SOCKETADDRESS(); - int rv; - int t = TRUE; - - if (NET_InetAddressToSockaddr(env, iaObj, port, sa, - JNI_TRUE) != 0) { - return; - } - - rv = connect(fd, sa); - if (rv == SOCKET_ERROR) { - NET_ThrowNew(env, WSAGetLastError(), "connect"); - return; - } - - /* see comment in socketCreate */ - WSAIoctl(fd, SIO_UDP_CONNRESET, true); -} - -/* - * Class: java_net_DualStackPlainDatagramSocketImpl - * Method: socketDisconnect - * Signature: (I)V - */ -static void socketDisconnect - (JNIEnv env, cli.System.Net.Sockets.Socket fd ) { - SOCKETADDRESS sa; - sa = new SOCKETADDRESS(); - - connect(fd, sa); - - /* see comment in socketCreate */ - WSAIoctl(fd, SIO_UDP_CONNRESET, false); -} - -/* - * Class: java_net_DualStackPlainDatagramSocketImpl - * Method: socketClose - * Signature: (I)V - */ -static void socketClose - (JNIEnv env, cli.System.Net.Sockets.Socket fd) { - NET_SocketClose(fd); -} - - -/* - * Class: java_net_DualStackPlainDatagramSocketImpl - * Method: socketLocalPort - * Signature: (I)I - */ -static int socketLocalPort - (JNIEnv env, cli.System.Net.Sockets.Socket fd) { - SOCKETADDRESS sa; - sa = new SOCKETADDRESS(); - - if (getsockname(fd, sa) == SOCKET_ERROR) { - NET_ThrowNew(env, WSAGetLastError(), "JVM_GetSockName"); - return -1; - } - return ntohs(GET_PORT(sa)); -} - -/* - * Class: java_net_DualStackPlainDatagramSocketImpl - * Method: socketLocalAddress - * Signature: (I)Ljava/lang/Object; - */ -static InetAddress socketLocalAddress - (JNIEnv env , cli.System.Net.Sockets.Socket fd) { - SOCKETADDRESS sa; - sa = new SOCKETADDRESS(); - InetAddress iaObj; - int[] port = { 0 }; - - if (getsockname(fd, sa) == SOCKET_ERROR) { - NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name"); - return null; - } - - iaObj = NET_SockaddrToInetAddress(env, sa, port); - return iaObj; -} - -/* - * Class: java_net_DualStackPlainDatagramSocketImpl - * Method: socketReceiveOrPeekData - * Signature: (ILjava/net/DatagramPacket;IZZ)I - */ -static int socketReceiveOrPeekData - (JNIEnv env, cli.System.Net.Sockets.Socket fd, DatagramPacket dpObj, - int timeout, boolean connected, boolean peek) { - SOCKETADDRESS sa; - sa = new SOCKETADDRESS(); - int port, rv, flags=0; - boolean retry; - long prevTime = 0; - - int packetBufferOffset, packetBufferLen; - byte[] packetBuffer; - - /* if we are only peeking. Called from peekData */ - if (peek) { - flags = MSG_PEEK; - } - - packetBuffer = dpObj.buf; - packetBufferOffset = dpObj.offset; - packetBufferLen = dpObj.bufLength; - - /* - 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"); - return -1; - } - } else { - fullPacket = &(BUF[0]); - } - */ - - do { - retry = false; - - if (timeout != 0) { - if (prevTime == 0) { - prevTime = JVM_CurrentTimeMillis(env, 0); - } - rv = NET_Timeout(fd, timeout); - if (rv <= 0) { - if (rv == 0) { - JNU_ThrowByName(env,JNU_JAVANETPKG+"SocketTimeoutException", - "Receive timed out"); - } else if (rv == JVM_IO_ERR) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Socket closed"); - } else if (rv == JVM_IO_INTR) { - JNU_ThrowByName(env, JNU_JAVAIOPKG+"InterruptedIOException", - "operation interrupted"); - } - return -1; - } - } - - /* receive the packet */ - rv = recvfrom(fd, packetBuffer, packetBufferOffset, packetBufferLen, flags, - sa); - - if (rv == SOCKET_ERROR && (WSAGetLastError() == WSAECONNRESET)) { - /* An icmp port unreachable - we must receive this as Windows - * does not reset the state of the socket until this has been - * received. - */ - purgeOutstandingICMP(env, fd); - - if (connected) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"PortUnreachableException", - "ICMP Port Unreachable"); - return -1; - } else if (timeout != 0) { - /* Adjust timeout */ - long newTime = JVM_CurrentTimeMillis(env, 0); - timeout -= (int)(newTime - prevTime); - if (timeout <= 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketTimeoutException", - "Receive timed out"); - return -1; - } - prevTime = newTime; - } - retry = true; - } - } while (retry); - - port = ntohs (GET_PORT(sa)); - - /* truncate the data if the packet's length is too small */ - if (rv > packetBufferLen) { - rv = packetBufferLen; - } - if (rv < 0) { - if (WSAGetLastError() == WSAEMSGSIZE) { - /* it is because the buffer is too small. It's UDP, it's - * unreliable, it's all good. discard the rest of the - * data.. - */ - rv = packetBufferLen; - } else { - /* failure */ - dpObj.length = 0; - } - } - - if (rv == -1) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "socket closed"); - } else if (rv == -2) { - JNU_ThrowByName(env, JNU_JAVAIOPKG+"InterruptedIOException", - "operation interrupted"); - } else if (rv < 0) { - NET_ThrowCurrent(env, "Datagram receive failed"); - } else { - InetAddress packetAddress; - /* - * Check if there is an InetAddress already associated with this - * packet. If so, we check if it is the same source address. We - * can't update any existing InetAddress because it is immutable - */ - packetAddress = dpObj.address; - if (packetAddress != NULL) { - if (!NET_SockaddrEqualsInetAddress(sa, - packetAddress)) { - /* force a new InetAddress to be created */ - packetAddress = null; - } - } - if (packetAddress == NULL) { - int[] tmp = { port }; - packetAddress = NET_SockaddrToInetAddress(sa, tmp); - port = tmp[0]; - /* stuff the new Inetaddress into the packet */ - dpObj.address = packetAddress; - } - - /* populate the packet */ - dpObj.port = port; - dpObj.length = rv; - } - - return port; -} - -/* - * Class: java_net_DualStackPlainDatagramSocketImpl - * Method: socketSend - * Signature: (I[BIILjava/net/InetAddress;IZ)V - */ -static void socketSend - (JNIEnv env, cli.System.Net.Sockets.Socket fd, byte[] data, int offset, int length, - InetAddress iaObj, int port, boolean connected) { - SOCKETADDRESS sa; - int rv; - - if (connected) { - sa = null; /* arg to JVM_Sendto () null in this case */ - } else { - sa = new SOCKETADDRESS(); - if (NET_InetAddressToSockaddr(env, iaObj, port, sa, - JNI_TRUE) != 0) { - return; - } - } - - /* - if (length > 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 (length > MAX_PACKET_LEN) { - length = MAX_PACKET_LEN; - } - fullPacket = (char *)malloc(length); - if (!fullPacket) { - JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); - return; - } - } else { - fullPacket = &(BUF[0]); - } - */ - - rv = sendto(fd, data, offset, length, 0, sa); - if (rv == SOCKET_ERROR) { - if (rv == JVM_IO_ERR) { - NET_ThrowNew(env, WSAGetLastError(), "Datagram send failed"); - } else if (rv == JVM_IO_INTR) { - JNU_ThrowByName(env, JNU_JAVAIOPKG+"InterruptedIOException", - "operation interrupted"); - } - } - -} - -/* - * Class: java_net_DualStackPlainDatagramSocketImpl - * Method: socketSetIntOption - * Signature: (III)V - */ -static void socketSetIntOption - (JNIEnv env, cli.System.Net.Sockets.Socket fd , int cmd, int value) { - int[] level = { 0 }, opt = { 0 }; - - if (NET_MapSocketOption(cmd, level, opt) < 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Invalid option"); - return; - } - - if (NET_SetSockOpt(fd, level[0], opt[0], value) < 0) { - NET_ThrowNew(env, WSAGetLastError(), "setsockopt"); - } -} - -/* - * Class: java_net_DualStackPlainDatagramSocketImpl - * Method: socketGetIntOption - * Signature: (II)I - */ -static int socketGetIntOption - (JNIEnv env, cli.System.Net.Sockets.Socket fd, int cmd) { - int[] level = { 0 }, opt = { 0 }, result = { 0 }; - - if (NET_MapSocketOption(cmd, level, opt) < 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Invalid option"); - return -1; - } - - if (NET_GetSockOpt(fd, level[0], opt[0], result) < 0) { - NET_ThrowNew(env, WSAGetLastError(), "getsockopt"); - return -1; - } - - return result[0]; -} -} diff --git a/openjdk/java/net/DualStackPlainSocketImpl.java b/openjdk/java/net/DualStackPlainSocketImpl.java deleted file mode 100644 index a3584d86..00000000 --- a/openjdk/java/net/DualStackPlainSocketImpl.java +++ /dev/null @@ -1,360 +0,0 @@ -/* - * Copyright (c) 2007, 2008, 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.IOException; -import java.io.FileDescriptor; - -/** - * This class defines the plain SocketImpl that is used on Windows platforms - * greater or equal to Windows Vista. These platforms have a dual - * layer TCP/IP stack and can handle both IPv4 and IPV6 through a - * single file descriptor. - * - * @author Chris Hegarty - */ - -class DualStackPlainSocketImpl extends AbstractPlainSocketImpl -{ - - - // true if this socket is exclusively bound - private final boolean exclusiveBind; - - // emulates SO_REUSEADDR when exclusiveBind is true - private boolean isReuseAddress; - - public DualStackPlainSocketImpl(boolean exclBind) { - exclusiveBind = exclBind; - } - - public DualStackPlainSocketImpl(FileDescriptor fd, boolean exclBind) { - this.fd = fd; - exclusiveBind = exclBind; - } - - void socketCreate(boolean stream) throws IOException { - if (fd == null) - throw new SocketException("Socket closed"); - - cli.System.Net.Sockets.Socket newfd = socket0(stream, false /*v6 Only*/); - - fd.setSocket(newfd); - } - - void socketConnect(InetAddress address, int port, int timeout) - throws IOException { - cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); - - if (address == null) - throw new NullPointerException("inet address argument is null."); - - int connectResult; - if (timeout <= 0) { - connectResult = connect0(nativefd, address, port); - } else { - configureBlocking(nativefd, false); - try { - connectResult = connect0(nativefd, address, port); - if (connectResult == WOULDBLOCK) { - waitForConnect(nativefd, timeout); - } - } finally { - configureBlocking(nativefd, true); - } - } - /* - * We need to set the local port field. If bind was called - * previous to the connect (by the client) then localport field - * will already be set. - */ - if (localport == 0) - localport = localPort0(nativefd); - } - - void socketBind(InetAddress address, int port) throws IOException { - cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); - - if (address == null) - throw new NullPointerException("inet address argument is null."); - - bind0(nativefd, address, port, exclusiveBind); - if (port == 0) { - localport = localPort0(nativefd); - } else { - localport = port; - } - - this.address = address; - } - - void socketListen(int backlog) throws IOException { - cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); - - listen0(nativefd, backlog); - } - - void socketAccept(SocketImpl s) throws IOException { - cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); - - if (s == null) - throw new NullPointerException("socket is null"); - - cli.System.Net.Sockets.Socket newfd = null; - InetSocketAddress[] isaa = new InetSocketAddress[1]; - if (timeout <= 0) { - newfd = accept0(nativefd, isaa); - } else { - configureBlocking(nativefd, false); - try { - waitForNewConnection(nativefd, timeout); - newfd = accept0(nativefd, isaa); - if (newfd != null) { - configureBlocking(newfd, true); - } - } finally { - configureBlocking(nativefd, true); - } - } - /* Update (SocketImpl)s' fd */ - s.fd.setSocket(newfd); - /* Update socketImpls remote port, address and localport */ - InetSocketAddress isa = isaa[0]; - s.port = isa.getPort(); - s.address = isa.getAddress(); - s.localport = localport; - } - - int socketAvailable() throws IOException { - cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); - return available0(nativefd); - } - - void socketClose0(boolean useDeferredClose/*unused*/) throws IOException { - if (fd == null) - throw new SocketException("Socket closed"); - - if (!fd.valid()) - return; - - close0(fd.getSocket()); - fd.setSocket(null); - } - - void socketShutdown(int howto) throws IOException { - cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); - shutdown0(nativefd, howto); - } - - // Intentional fallthrough after SO_REUSEADDR - @SuppressWarnings("fallthrough") - void socketSetOption(int opt, boolean on, Object value) - throws SocketException { - cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); - - if (opt == SO_TIMEOUT) { // timeout implemented through select. - return; - } - - int optionValue = 0; - - switch(opt) { - case SO_REUSEADDR : - if (exclusiveBind) { - // SO_REUSEADDR emulated when using exclusive bind - isReuseAddress = on; - return; - } - // intentional fallthrough - case TCP_NODELAY : - case SO_OOBINLINE : - case SO_KEEPALIVE : - optionValue = on ? 1 : 0; - break; - case SO_SNDBUF : - case SO_RCVBUF : - case IP_TOS : - optionValue = ((Integer)value).intValue(); - break; - case SO_LINGER : - if (on) { - optionValue = ((Integer)value).intValue(); - } else { - optionValue = -1; - } - break; - default :/* shouldn't get here */ - throw new SocketException("Option not supported"); - } - - setIntOption(nativefd, opt, optionValue); - } - - int socketGetOption(int opt, Object iaContainerObj) throws SocketException { - cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); - - // SO_BINDADDR is not a socket option. - if (opt == SO_BINDADDR) { - localAddress(nativefd, (InetAddressContainer)iaContainerObj); - return 0; // return value doesn't matter. - } - - // SO_REUSEADDR emulated when using exclusive bind - if (opt == SO_REUSEADDR && exclusiveBind) - return isReuseAddress? 1 : -1; - - int value = getIntOption(nativefd, opt); - - switch (opt) { - case TCP_NODELAY : - case SO_OOBINLINE : - case SO_KEEPALIVE : - case SO_REUSEADDR : - return (value == 0) ? -1 : 1; - } - return value; - } - - void socketSendUrgentData(int data) throws IOException { - cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); - sendOOB(nativefd, data); - } - - private cli.System.Net.Sockets.Socket checkAndReturnNativeFD() throws SocketException { - if (fd == null || !fd.valid()) - throw new SocketException("Socket closed"); - - return fd.getSocket(); - } - - static final int WOULDBLOCK = -2; // Nothing available (non-blocking) - - /* Native methods */ - - static cli.System.Net.Sockets.Socket socket0(boolean stream, boolean v6Only) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - cli.System.Net.Sockets.Socket ret = DualStackPlainSocketImpl_c.socket0(env, stream, v6Only); - env.ThrowPendingException(); - return ret; - } - - static void bind0(cli.System.Net.Sockets.Socket fd, InetAddress localAddress, int localport, - boolean exclBind) - throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - DualStackPlainSocketImpl_c.bind0(env, fd, localAddress, localport, exclBind); - env.ThrowPendingException(); - } - - static int connect0(cli.System.Net.Sockets.Socket fd, InetAddress remote, int remotePort) - throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - int ret = DualStackPlainSocketImpl_c.connect0(env, fd, remote, remotePort); - env.ThrowPendingException(); - return ret; - } - - static void waitForConnect(cli.System.Net.Sockets.Socket fd, int timeout) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - DualStackPlainSocketImpl_c.waitForConnect(env, fd, timeout); - env.ThrowPendingException(); - } - - static int localPort0(cli.System.Net.Sockets.Socket fd) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - int ret = DualStackPlainSocketImpl_c.localPort0(env, fd); - env.ThrowPendingException(); - return ret; - } - - static void localAddress(cli.System.Net.Sockets.Socket fd, InetAddressContainer in) throws SocketException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - DualStackPlainSocketImpl_c.localAddress(env, fd, in); - env.ThrowPendingException(); - } - - static void listen0(cli.System.Net.Sockets.Socket fd, int backlog) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - DualStackPlainSocketImpl_c.listen0(env, fd, backlog); - env.ThrowPendingException(); - } - - static cli.System.Net.Sockets.Socket accept0(cli.System.Net.Sockets.Socket fd, InetSocketAddress[] isaa) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - cli.System.Net.Sockets.Socket ret = DualStackPlainSocketImpl_c.accept0(env, fd, isaa); - env.ThrowPendingException(); - return ret; - } - - static void waitForNewConnection(cli.System.Net.Sockets.Socket fd, int timeout) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - DualStackPlainSocketImpl_c.waitForNewConnection(env, fd, timeout); - env.ThrowPendingException(); - } - - static int available0(cli.System.Net.Sockets.Socket fd) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - int ret = DualStackPlainSocketImpl_c.available0(env, fd); - env.ThrowPendingException(); - return ret; - } - - static void close0(cli.System.Net.Sockets.Socket fd) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - DualStackPlainSocketImpl_c.close0(env, fd); - env.ThrowPendingException(); - } - - static void shutdown0(cli.System.Net.Sockets.Socket fd, int howto) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - DualStackPlainSocketImpl_c.shutdown0(env, fd, howto); - env.ThrowPendingException(); - } - - static void setIntOption(cli.System.Net.Sockets.Socket fd, int cmd, int optionValue) throws SocketException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - DualStackPlainSocketImpl_c.setIntOption(env, fd, cmd, optionValue); - env.ThrowPendingException(); - } - - static int getIntOption(cli.System.Net.Sockets.Socket fd, int cmd) throws SocketException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - int ret = DualStackPlainSocketImpl_c.getIntOption(env, fd, cmd); - env.ThrowPendingException(); - return ret; - } - - static void sendOOB(cli.System.Net.Sockets.Socket fd, int data) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - DualStackPlainSocketImpl_c.sendOOB(env, fd, data); - env.ThrowPendingException(); - } - - static void configureBlocking(cli.System.Net.Sockets.Socket fd, boolean blocking) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - DualStackPlainSocketImpl_c.configureBlocking(env, fd, blocking); - env.ThrowPendingException(); - } -} diff --git a/openjdk/java/net/DualStackPlainSocketImpl_c.java b/openjdk/java/net/DualStackPlainSocketImpl_c.java deleted file mode 100644 index 15c2a184..00000000 --- a/openjdk/java/net/DualStackPlainSocketImpl_c.java +++ /dev/null @@ -1,490 +0,0 @@ -/* - * Copyright (c) 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 static ikvm.internal.JNI.*; -import static ikvm.internal.Winsock.*; -import static java.net.net_util_md.*; - -final class DualStackPlainSocketImpl_c -{ -private static final int JVM_IO_ERR = -1; -private static final int JVM_IO_INTR = -2; - -private static final int SET_BLOCKING = 0; -private static final int SET_NONBLOCKING = 1; -/* -#include <windows.h> -#include <winsock2.h> -#include "jni.h" -#include "net_util.h" -#include "java_net_DualStackPlainSocketImpl.h" - -#define SET_BLOCKING 0 -#define SET_NONBLOCKING 1 - -static jclass isa_class; /* java.net.InetSocketAddress *-/ -static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) *-/ - -/* - * Class: java_net_DualStackPlainSocketImpl - * Method: initIDs - * Signature: ()V - *-/ -JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_initIDs - (JNIEnv *env, jclass clazz) { - - jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress"); - isa_class = (*env)->NewGlobalRef(env, cls); - isa_ctorID = (*env)->GetMethodID(env, cls, "<init>", - "(Ljava/net/InetAddress;I)V"); - - // implement read timeout with select. - isRcvTimeoutSupported = 0; -} - -/* - * Class: java_net_DualStackPlainSocketImpl - * Method: socket0 - * Signature: (ZZ)I - */ -static cli.System.Net.Sockets.Socket socket0 - (JNIEnv env, boolean stream, boolean v6Only /*unused*/) { - cli.System.Net.Sockets.Socket fd; - int rv, opt=0; - - fd = NET_Socket(AF_INET6, (stream ? SOCK_STREAM : SOCK_DGRAM), 0); - if (fd == INVALID_SOCKET) { - NET_ThrowNew(env, WSAGetLastError(), "create"); - return null; - } - - rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, opt); - if (rv == SOCKET_ERROR) { - NET_ThrowNew(env, WSAGetLastError(), "create"); - } - - - return fd; -} - -/* - * Class: java_net_DualStackPlainSocketImpl - * Method: bind0 - * Signature: (ILjava/net/InetAddress;I)V - */ -static void bind0 - (JNIEnv env, cli.System.Net.Sockets.Socket fd, InetAddress iaObj, int port, - boolean exclBind) -{ - SOCKETADDRESS sa; - sa = new SOCKETADDRESS(); - int rv; - - if (NET_InetAddressToSockaddr(env, iaObj, port, sa, - JNI_TRUE) != 0) { - return; - } - - rv = NET_WinBind(fd, sa, exclBind); - - if (rv == SOCKET_ERROR) - NET_ThrowNew(env, WSAGetLastError(), "JVM_Bind"); -} - -/* - * Class: java_net_DualStackPlainSocketImpl - * Method: connect0 - * Signature: (ILjava/net/InetAddress;I)I - */ -static int connect0 - (JNIEnv env, cli.System.Net.Sockets.Socket fd, InetAddress iaObj, int port) { - SOCKETADDRESS sa; - sa = new SOCKETADDRESS(); - int rv; - - if (NET_InetAddressToSockaddr(env, iaObj, port, sa, - JNI_TRUE) != 0) { - return -1; - } - - rv = connect(fd, sa); - if (rv == SOCKET_ERROR) { - int err = WSAGetLastError(); - if (err == WSAEWOULDBLOCK) { - return java.net.DualStackPlainSocketImpl.WOULDBLOCK; - } else if (err == WSAEADDRNOTAVAIL) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"ConnectException", - "connect: Address is invalid on local machine, or port is not valid on remote machine"); - } else { - NET_ThrowNew(env, err, "connect"); - } - return -1; // return value not important. - } - return rv; -} - -/* - * Class: java_net_DualStackPlainSocketImpl - * Method: waitForConnect - * Signature: (II)V - */ -static void waitForConnect - (JNIEnv env, cli.System.Net.Sockets.Socket fd, int timeout) { - int rv, retry; - fd_set wr, ex; - wr = new fd_set(); ex = new fd_set(); - timeval t = new timeval(); - - FD_ZERO(wr); - FD_ZERO(ex); - FD_SET(fd, wr); - FD_SET(fd, ex); - t.tv_sec = timeout / 1000; - t.tv_usec = (timeout % 1000) * 1000; - - /* - * Wait for timeout, connection established or - * connection failed. - */ - rv = select(null, wr, ex, t); - - /* - * Timeout before connection is established/failed so - * we throw exception and shutdown input/output to prevent - * socket from being used. - * The socket should be closed immediately by the caller. - */ - if (rv == 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketTimeoutException", - "connect timed out"); - shutdown( fd, SD_BOTH ); - return; - } - - /* - * Socket is writable or error occured. On some Windows editions - * the socket will appear writable when the connect fails so we - * check for error rather than writable. - */ - if (!FD_ISSET(fd, ex)) { - return; /* connection established */ - } - - /* - * Connection failed. The logic here is designed to work around - * bug on Windows NT whereby using getsockopt to obtain the - * last error (SO_ERROR) indicates there is no error. The workaround - * on NT is to allow winsock to be scheduled and this is done by - * yielding and retrying. As yielding is problematic in heavy - * load conditions we attempt up to 3 times to get the error reason. - */ - for (retry=0; retry<3; retry++) { - int[] tmp = { 0 }; - NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, - tmp); - rv = tmp[0]; - if (rv != 0) { - break; - } - Sleep(0); - } - - if (rv == 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Unable to establish connection"); - } else { - NET_ThrowNew(env, rv, "connect"); - } -} - -/* - * Class: java_net_DualStackPlainSocketImpl - * Method: localPort0 - * Signature: (I)I - */ -static int localPort0 - (JNIEnv env, cli.System.Net.Sockets.Socket fd) { - SOCKETADDRESS sa; - sa = new SOCKETADDRESS(); - - if (getsockname(fd, sa) == SOCKET_ERROR) { - if (WSAGetLastError() == WSAENOTSOCK) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Socket closed"); - } else { - NET_ThrowNew(env, WSAGetLastError(), "getsockname failed"); - } - return -1; - } - return ntohs(GET_PORT(sa)); -} - -/* - * Class: java_net_DualStackPlainSocketImpl - * Method: localAddress - * Signature: (ILjava/net/InetAddressContainer;)V - */ -static void localAddress - (JNIEnv env, cli.System.Net.Sockets.Socket fd, InetAddressContainer iaContainerObj) { - int[] port = { 0 }; - SOCKETADDRESS sa; - sa = new SOCKETADDRESS(); - InetAddress iaObj; - - if (getsockname(fd, sa) == SOCKET_ERROR) { - NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name"); - return; - } - iaObj = NET_SockaddrToInetAddress(env, sa, port); - - iaContainerObj.addr = iaObj; -} - - -/* - * Class: java_net_DualStackPlainSocketImpl - * Method: listen0 - * Signature: (II)V - */ -static void listen0 - (JNIEnv env, cli.System.Net.Sockets.Socket fd, int backlog) { - if (listen(fd, backlog) == SOCKET_ERROR) { - NET_ThrowNew(env, WSAGetLastError(), "listen failed"); - } -} - -/* - * Class: java_net_DualStackPlainSocketImpl - * Method: accept0 - * Signature: (I[Ljava/net/InetSocketAddress;)I - */ -static cli.System.Net.Sockets.Socket accept0 - (JNIEnv env, cli.System.Net.Sockets.Socket fd, InetSocketAddress[] isaa) { - cli.System.Net.Sockets.Socket newfd; - int[] port = { 0 }; - InetSocketAddress isa; - InetAddress ia; - SOCKETADDRESS sa; - sa = new SOCKETADDRESS(); - - newfd = accept(fd, sa); - - if (newfd == INVALID_SOCKET) { - if (WSAGetLastError() == -2) { - JNU_ThrowByName(env, JNU_JAVAIOPKG+"InterruptedIOException", - "operation interrupted"); - } else { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "socket closed"); - } - return null; - } - - ia = NET_SockaddrToInetAddress(env, sa, port); - isa = new InetSocketAddress(ia, port[0]); - isaa[0] = isa; - - return newfd; -} - -/* - * Class: java_net_DualStackPlainSocketImpl - * Method: waitForNewConnection - * Signature: (II)V - */ -static void waitForNewConnection - (JNIEnv env, cli.System.Net.Sockets.Socket fd, int timeout) { - int rv; - - rv = NET_Timeout(fd, timeout); - if (rv == 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketTimeoutException", - "Accept timed out"); - } else if (rv == -1) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "socket closed"); - } else if (rv == -2) { - JNU_ThrowByName(env, JNU_JAVAIOPKG+"InterruptedIOException", - "operation interrupted"); - } -} - -/* - * Class: java_net_DualStackPlainSocketImpl - * Method: available0 - * Signature: (I)I - */ -static int available0 - (JNIEnv env, cli.System.Net.Sockets.Socket fd) { - int[] available = { -1 }; - - if ((ioctlsocket(fd, FIONREAD, available)) == SOCKET_ERROR) { - NET_ThrowNew(env, WSAGetLastError(), "socket available"); - } - - return available[0]; -} - -/* - * Class: java_net_DualStackPlainSocketImpl - * Method: close0 - * Signature: (I)V - */ -static void close0 - (JNIEnv env, cli.System.Net.Sockets.Socket fd) { - NET_SocketClose(fd); -} - -/* - * Class: java_net_DualStackPlainSocketImpl - * Method: shutdown0 - * Signature: (II)V - */ -static void shutdown0 - (JNIEnv env, cli.System.Net.Sockets.Socket fd, int howto) { - shutdown(fd, howto); -} - - -/* - * Class: java_net_DualStackPlainSocketImpl - * Method: setIntOption - * Signature: (III)V - */ -static void setIntOption - (JNIEnv env, cli.System.Net.Sockets.Socket fd, int cmd, int value) { - - int[] level = { 0 }; - int[] opt = { 0 }; - linger linger; - Object optval; - - if (NET_MapSocketOption(cmd, level, opt) < 0) { - JNU_ThrowByName(env, - JNU_JAVANETPKG+"SocketException", - "Invalid option"); - return; - } - - if (opt[0] == java.net.SocketOptions.SO_LINGER) { - linger = new linger(); - if (value >= 0) { - linger.l_onoff = 1; - linger.l_linger = value & 0xFFFF; - } else { - linger.l_onoff = 0; - linger.l_linger = 0; - } - optval = linger; - } else { - optval = value; - } - - if (NET_SetSockOpt(fd, level[0], opt[0], optval) < 0) { - NET_ThrowNew(env, WSAGetLastError(), "setsockopt"); - } -} - -/* - * Class: java_net_DualStackPlainSocketImpl - * Method: getIntOption - * Signature: (II)I - */ -static int getIntOption - (JNIEnv env, cli.System.Net.Sockets.Socket fd, int cmd) { - - int[] level = { 0 }; - int[] opt = { 0 }; - int[] result = { 0 }; - linger linger; - Object optval; - - if (NET_MapSocketOption(cmd, level, opt) < 0) { - JNU_ThrowByName(env, - JNU_JAVANETPKG+"SocketException", - "Unsupported socket option"); - return -1; - } - - if (opt[0] == java.net.SocketOptions.SO_LINGER) { - linger = new linger(); - optval = linger; - } else { - linger = null; - optval = result; - } - - if (NET_GetSockOpt(fd, level[0], opt[0], optval) < 0) { - NET_ThrowNew(env, WSAGetLastError(), "getsockopt"); - return -1; - } - - if (opt[0] == java.net.SocketOptions.SO_LINGER) - return linger.l_onoff != 0 ? linger.l_linger : -1; - else - return result[0]; -} - - -/* - * Class: java_net_DualStackPlainSocketImpl - * Method: sendOOB - * Signature: (II)V - */ -static void sendOOB - (JNIEnv env, cli.System.Net.Sockets.Socket fd, int data) { - int n; - - n = send(fd, new byte[] { (byte)data }, 1, MSG_OOB); - if (n == JVM_IO_ERR) { - NET_ThrowNew(env, WSAGetLastError(), "send"); - } else if (n == JVM_IO_INTR) { - JNU_ThrowByName(env, "java.io.InterruptedIOException", null); - } -} - -/* - * Class: java_net_DualStackPlainSocketImpl - * Method: configureBlocking - * Signature: (IZ)V - */ -static void configureBlocking - (JNIEnv env, cli.System.Net.Sockets.Socket fd, boolean blocking) { - int arg; - int result; - - if (blocking == JNI_TRUE) { - arg = SET_BLOCKING; // 0 - } else { - arg = SET_NONBLOCKING; // 1 - } - - result = ioctlsocket(fd, FIONBIO, arg); - if (result == SOCKET_ERROR) { - NET_ThrowNew(env, WSAGetLastError(), "configureBlocking"); - } -} -} diff --git a/openjdk/java/net/PlainSocketImpl.java b/openjdk/java/net/PlainSocketImpl.java deleted file mode 100644 index 5b7f850d..00000000 --- a/openjdk/java/net/PlainSocketImpl.java +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Copyright (c) 2007, 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 java.net; - -import java.io.*; -import java.security.PrivilegedAction; - -/* - * This class PlainSocketImpl simply delegates to the appropriate real - * SocketImpl. We do this because PlainSocketImpl is already extended - * by SocksSocketImpl. - * <p> - * There are two possibilities for the real SocketImpl, - * TwoStacksPlainSocketImpl or DualStackPlainSocketImpl. We use - * DualStackPlainSocketImpl on systems that have a dual stack - * TCP implementation. Otherwise we create an instance of - * TwoStacksPlainSocketImpl and delegate to it. - * - * @author Chris Hegarty - */ - -class PlainSocketImpl extends AbstractPlainSocketImpl -{ - private AbstractPlainSocketImpl impl; - - /* the windows version. */ - private static float version; - - /* java.net.preferIPv4Stack */ - private static boolean preferIPv4Stack = false; - - /* If the version supports a dual stack TCP implementation */ - private static boolean useDualStackImpl = false; - - /* sun.net.useExclusiveBind */ - private static String exclBindProp; - - /* True if exclusive binding is on for Windows */ - private static boolean exclusiveBind = true; - - static { - java.security.AccessController.doPrivileged( new PrivilegedAction<Object>() { - public Object run() { - version = 0; - try { - version = Float.parseFloat(System.getProperties().getProperty("os.version")); - preferIPv4Stack = Boolean.parseBoolean( - System.getProperties().getProperty("java.net.preferIPv4Stack")); - exclBindProp = System.getProperty("sun.net.useExclusiveBind"); - } catch (NumberFormatException e ) { - assert false : e; - } - return null; // nothing to return - } }); - - String ipv6 = ikvm.internal.Util.SafeGetEnvironmentVariable("IKVM_IPV6"); - if (ipv6 != null) { - try { - if ((Integer.parseInt(ipv6) & 4) == 0) { - preferIPv4Stack = true; - } else { - useDualStackImpl = true; - } - } catch (NumberFormatException _) { - } - } else if (!InetAddressImplFactory.isIPv6Supported()) { - preferIPv4Stack = true; - } - - // (version >= 6.0) implies Vista or greater. - if (version >= 6.0 && !preferIPv4Stack) { - useDualStackImpl = true; - } - - if (exclBindProp != null) { - // sun.net.useExclusiveBind is true - exclusiveBind = exclBindProp.length() == 0 ? true - : Boolean.parseBoolean(exclBindProp); - } else if (version < 6.0) { - exclusiveBind = false; - } - } - - /** - * Constructs an empty instance. - */ - PlainSocketImpl() { - if (useDualStackImpl) { - impl = new DualStackPlainSocketImpl(exclusiveBind); - } else { - impl = new TwoStacksPlainSocketImpl(exclusiveBind); - } - } - - /** - * Constructs an instance with the given file descriptor. - */ - PlainSocketImpl(FileDescriptor fd) { - if (useDualStackImpl) { - impl = new DualStackPlainSocketImpl(fd, exclusiveBind); - } else { - impl = new TwoStacksPlainSocketImpl(fd, exclusiveBind); - } - } - - // Override methods in SocketImpl that access impl's fields. - - protected FileDescriptor getFileDescriptor() { - return impl.getFileDescriptor(); - } - - protected InetAddress getInetAddress() { - return impl.getInetAddress(); - } - - protected int getPort() { - return impl.getPort(); - } - - protected int getLocalPort() { - return impl.getLocalPort(); - } - - void setSocket(Socket soc) { - impl.setSocket(soc); - } - - Socket getSocket() { - return impl.getSocket(); - } - - void setServerSocket(ServerSocket soc) { - impl.setServerSocket(soc); - } - - ServerSocket getServerSocket() { - return impl.getServerSocket(); - } - - public String toString() { - return impl.toString(); - } - - // Override methods in AbstractPlainSocketImpl that access impl's fields. - - protected synchronized void create(boolean stream) throws IOException { - impl.create(stream); - - // set fd to delegate's fd to be compatible with older releases - this.fd = impl.fd; - } - - protected void connect(String host, int port) - throws UnknownHostException, IOException - { - impl.connect(host, port); - } - - protected void connect(InetAddress address, int port) throws IOException { - impl.connect(address, port); - } - - protected void connect(SocketAddress address, int timeout) throws IOException { - impl.connect(address, timeout); - } - - public void setOption(int opt, Object val) throws SocketException { - impl.setOption(opt, val); - } - - public Object getOption(int opt) throws SocketException { - return impl.getOption(opt); - } - - synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException { - impl.doConnect(address, port, timeout); - } - - protected synchronized void bind(InetAddress address, int lport) - throws IOException - { - impl.bind(address, lport); - } - - protected synchronized void accept(SocketImpl s) throws IOException { - // pass in the real impl not the wrapper. - SocketImpl delegate = ((PlainSocketImpl)s).impl; - delegate.address = new InetAddress(); - delegate.fd = new FileDescriptor(); - impl.accept(delegate); - - // set fd to delegate's fd to be compatible with older releases - s.fd = delegate.fd; - } - - void setFileDescriptor(FileDescriptor fd) { - impl.setFileDescriptor(fd); - } - - void setAddress(InetAddress address) { - impl.setAddress(address); - } - - void setPort(int port) { - impl.setPort(port); - } - - void setLocalPort(int localPort) { - impl.setLocalPort(localPort); - } - - protected synchronized InputStream getInputStream() throws IOException { - return impl.getInputStream(); - } - - void setInputStream(SocketInputStream in) { - impl.setInputStream(in); - } - - protected synchronized OutputStream getOutputStream() throws IOException { - return impl.getOutputStream(); - } - - protected void close() throws IOException { - try { - impl.close(); - } finally { - // set fd to delegate's fd to be compatible with older releases - this.fd = null; - } - } - - void reset() throws IOException { - try { - impl.reset(); - } finally { - // set fd to delegate's fd to be compatible with older releases - this.fd = null; - } - } - - protected void shutdownInput() throws IOException { - impl.shutdownInput(); - } - - protected void shutdownOutput() throws IOException { - impl.shutdownOutput(); - } - - protected void sendUrgentData(int data) throws IOException { - impl.sendUrgentData(data); - } - - FileDescriptor acquireFD() { - return impl.acquireFD(); - } - - void releaseFD() { - impl.releaseFD(); - } - - public boolean isConnectionReset() { - return impl.isConnectionReset(); - } - - public boolean isConnectionResetPending() { - return impl.isConnectionResetPending(); - } - - public void setConnectionReset() { - impl.setConnectionReset(); - } - - public void setConnectionResetPending() { - impl.setConnectionResetPending(); - } - - public boolean isClosedOrPending() { - return impl.isClosedOrPending(); - } - - public int getTimeout() { - return impl.getTimeout(); - } - - // Override methods in AbstractPlainSocketImpl that need to be implemented. - - void socketCreate(boolean isServer) throws IOException { - impl.socketCreate(isServer); - } - - void socketConnect(InetAddress address, int port, int timeout) - throws IOException { - impl.socketConnect(address, port, timeout); - } - - void socketBind(InetAddress address, int port) - throws IOException { - impl.socketBind(address, port); - } - - void socketListen(int count) throws IOException { - impl.socketListen(count); - } - - void socketAccept(SocketImpl s) throws IOException { - impl.socketAccept(s); - } - - int socketAvailable() throws IOException { - return impl.socketAvailable(); - } - - void socketClose0(boolean useDeferredClose) throws IOException { - impl.socketClose0(useDeferredClose); - } - - void socketShutdown(int howto) throws IOException { - impl.socketShutdown(howto); - } - - void socketSetOption(int cmd, boolean on, Object value) - throws SocketException { - socketSetOption(cmd, on, value); - } - - int socketGetOption(int opt, Object iaContainerObj) throws SocketException { - return impl.socketGetOption(opt, iaContainerObj); - } - - void socketSendUrgentData(int data) throws IOException { - impl.socketSendUrgentData(data); - } -} diff --git a/openjdk/java/net/SocketInputStream.java b/openjdk/java/net/SocketInputStream.java deleted file mode 100644 index 161947cc..00000000 --- a/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 <b>NOT</b> 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.</p> - * - * The <code>getChannel</code> method of <code>SocketInputStream</code> - * returns <code>null</code> since it is a socket based stream.</p> - * - * @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 <i>b</i> at offset <i>off</i>, - * <i>length</i> 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/openjdk/java/net/SocketOutputStream.java b/openjdk/java/net/SocketOutputStream.java deleted file mode 100644 index fd6e2c4f..00000000 --- a/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 <b>NOT</b> 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. </p> - * - * The <code>getChannel</code> method of <code>SocketOutputStream</code> - * returns <code>null</code> since it is a socket based stream.</p> - * - * @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 <i>b</i> 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 <i>length</i> bytes from buffer <i>b</i> starting at - * offset <i>len</i>. - * @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/openjdk/java/net/SocketUtil.java b/openjdk/java/net/SocketUtil.java deleted file mode 100644 index d9a30869..00000000 --- a/openjdk/java/net/SocketUtil.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - Copyright (C) 2002-2010 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.net; - -import cli.System.Net.IPAddress; -import cli.System.Net.IPEndPoint; -import cli.System.Net.Sockets.SocketOptionName; -import cli.System.Net.Sockets.SocketOptionLevel; -import ikvm.lang.CIL; -import java.io.IOException; - -@ikvm.lang.Internal -public final class SocketUtil -{ - private SocketUtil() { } - - // Winsock Error Codes - public static final int WSAEINVAL = 10022; - public static final int WSAEWOULDBLOCK = 10035; - public static final int WSAEMSGSIZE = 10040; - public static final int WSAENOPROTOOPT = 10042; - public static final int WSAEADDRINUSE = 10048; - public static final int WSAENETUNREACH = 10051; - public static final int WSAECONNRESET = 10054; - public static final int WSAESHUTDOWN = 10058; - public static final int WSAETIMEDOUT = 10060; - public static final int WSAECONNREFUSED = 10061; - public static final int WSAEHOSTUNREACH = 10065; - public static final int WSAHOST_NOT_FOUND = 11001; - - public static IOException convertSocketExceptionToIOException(cli.System.Net.Sockets.SocketException x) throws IOException - { - switch (x.get_ErrorCode()) - { - case WSAEADDRINUSE: - return new BindException(x.getMessage()); - case WSAENETUNREACH: - case WSAEHOSTUNREACH: - return new NoRouteToHostException(x.getMessage()); - case WSAETIMEDOUT: - return new SocketTimeoutException(x.getMessage()); - case WSAECONNREFUSED: - return new PortUnreachableException(x.getMessage()); - case WSAHOST_NOT_FOUND: - return new UnknownHostException(x.getMessage()); - default: - return new SocketException(x.getMessage() + "\nError Code: " + x.get_ErrorCode()); - } - } - - public static IPAddress getAddressFromInetAddress(InetAddress addr) - { - return getAddressFromInetAddress(addr, false); - } - - public static IPAddress getAddressFromInetAddress(InetAddress addr, boolean v4mapped) - { - byte[] b = addr.getAddress(); - if (b.length == 16) - { - // FXBUG in .NET 1.1 you can only construct IPv6 addresses (not IPv4) with this constructor - // (according to the documentation this was fixed in .NET 2.0) - return new IPAddress(b); - } - else if (v4mapped) - { - if (b[0] == 0 && b[1] == 0 && b[2] == 0 && b[3] == 0) - { - return IPAddress.IPv6Any; - } - byte[] b16 = new byte[16]; - b16[10] = -1; - b16[11] = -1; - b16[12] = b[0]; - b16[13] = b[1]; - b16[14] = b[2]; - b16[15] = b[3]; - return new IPAddress(b16); - } - else - { - return new IPAddress((((b[3] & 0xff) << 24) + ((b[2] & 0xff) << 16) + ((b[1] & 0xff) << 8) + (b[0] & 0xff)) & 0xffffffffL); - } - } - - public static InetAddress getInetAddressFromIPEndPoint(IPEndPoint endpoint) - { - try - { - return InetAddress.getByAddress(endpoint.get_Address().GetAddressBytes()); - } - catch (UnknownHostException x) - { - // this exception only happens if the address byte array is of invalid length, which cannot happen unless - // the .NET socket returns a bogus address - throw (InternalError)new InternalError().initCause(x); - } - } - - static void setCommonSocketOption(cli.System.Net.Sockets.Socket netSocket, int cmd, boolean on, Object value) throws SocketException - { - try - { - if (false) throw new cli.System.Net.Sockets.SocketException(); - if (false) throw new cli.System.ObjectDisposedException(""); - switch (cmd) - { - case SocketOptions.SO_REUSEADDR: - netSocket.SetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.ReuseAddress), on ? 1 : 0); - break; - case SocketOptions.SO_SNDBUF: - netSocket.SetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.SendBuffer), ((Integer)value).intValue()); - break; - case SocketOptions.SO_RCVBUF: - netSocket.SetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.ReceiveBuffer), ((Integer)value).intValue()); - break; - case SocketOptions.IP_TOS: - netSocket.SetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.IP), SocketOptionName.wrap(SocketOptionName.TypeOfService), ((Integer)value).intValue()); - break; - case SocketOptions.SO_BINDADDR: // read-only - default: - throw new SocketException("Invalid socket option: " + cmd); - } - } - catch (cli.System.Net.Sockets.SocketException x) - { - throw new SocketException(x.getMessage()); - } - catch (cli.System.ObjectDisposedException x1) - { - throw new SocketException("Socket is closed"); - } - } - - static int getCommonSocketOption(cli.System.Net.Sockets.Socket netSocket, int opt, Object iaContainerObj) throws SocketException - { - try - { - if (false) throw new cli.System.Net.Sockets.SocketException(); - if (false) throw new cli.System.ObjectDisposedException(""); - switch (opt) - { - case SocketOptions.SO_REUSEADDR: - return CIL.unbox_int(netSocket.GetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.ReuseAddress))) == 0 ? -1 : 1; - case SocketOptions.SO_SNDBUF: - return CIL.unbox_int(netSocket.GetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.SendBuffer))); - case SocketOptions.SO_RCVBUF: - return CIL.unbox_int(netSocket.GetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.ReceiveBuffer))); - case SocketOptions.IP_TOS: - // TODO handle IPv6 here - return CIL.unbox_int(netSocket.GetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.IP), SocketOptionName.wrap(SocketOptionName.TypeOfService))); - case SocketOptions.SO_BINDADDR: - ((InetAddressContainer)iaContainerObj).addr = getInetAddressFromIPEndPoint((IPEndPoint)netSocket.get_LocalEndPoint()); - return 0; - default: - throw new SocketException("Invalid socket option: " + opt); - } - } - catch (cli.System.Net.Sockets.SocketException x) - { - throw new SocketException(x.getMessage()); - } - catch (cli.System.ObjectDisposedException x1) - { - throw new SocketException("Socket is closed"); - } - } -} diff --git a/openjdk/java/net/TwoStacksPlainDatagramSocketImpl.java b/openjdk/java/net/TwoStacksPlainDatagramSocketImpl.java deleted file mode 100644 index 2b2bde1b..00000000 --- a/openjdk/java/net/TwoStacksPlainDatagramSocketImpl.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright (c) 2007, 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 java.net; - -import java.io.IOException; -import java.io.FileDescriptor; -import sun.net.ResourceManager; - -/** - * This class defines the plain DatagramSocketImpl that is used for all - * Windows versions lower than Vista. It adds support for IPv6 on - * these platforms where available. - * - * For backward compatibility windows platforms that do not have IPv6 - * support also use this implementation, and fd1 gets set to null - * during socket creation. - * - * @author Chris Hegarty - */ - -class TwoStacksPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl -{ - /* Used for IPv6 on Windows only */ - FileDescriptor fd1; - - /* - * Needed for ipv6 on windows because we need to know - * if the socket was bound to ::0 or 0.0.0.0, when a caller - * asks for it. In this case, both sockets are used, but we - * don't know whether the caller requested ::0 or 0.0.0.0 - * and need to remember it here. - */ - private InetAddress anyLocalBoundAddr=null; - - cli.System.Net.Sockets.Socket fduse=null; /* saved between peek() and receive() calls */ - - /* saved between successive calls to receive, if data is detected - * on both sockets at same time. To ensure that one socket is not - * starved, they rotate using this field - */ - cli.System.Net.Sockets.Socket lastfd=null; - - // true if this socket is exclusively bound - private final boolean exclusiveBind; - - /* - * Set to true if SO_REUSEADDR is set after the socket is bound to - * indicate SO_REUSEADDR is being emulated - */ - private boolean reuseAddressEmulated; - - // emulates SO_REUSEADDR when exclusiveBind is true and socket is bound - private boolean isReuseAddress; - - TwoStacksPlainDatagramSocketImpl(boolean exclBind) { - exclusiveBind = exclBind; - } - - protected synchronized void create() throws SocketException { - fd1 = new FileDescriptor(); - try { - super.create(); - } catch (SocketException e) { - fd1 = null; - throw e; - } - } - - protected synchronized void bind(int lport, InetAddress laddr) - throws SocketException { - super.bind(lport, laddr); - if (laddr.isAnyLocalAddress()) { - anyLocalBoundAddr = laddr; - } - } - - @Override - protected synchronized void bind0(int lport, InetAddress laddr) - throws SocketException - { - bind0(lport, laddr, exclusiveBind); - - } - - protected synchronized void receive(DatagramPacket p) - throws IOException { - try { - receive0(p); - } finally { - fduse = null; - } - } - - public Object getOption(int optID) throws SocketException { - if (isClosed()) { - throw new SocketException("Socket Closed"); - } - - if (optID == SO_BINDADDR) { - if (fd != null && fd1 != null) { - return anyLocalBoundAddr; - } - return socketGetOption(optID); - } else if (optID == SO_REUSEADDR && reuseAddressEmulated) { - return isReuseAddress; - } else { - return super.getOption(optID); - } - } - - protected void socketSetOption(int opt, Object val) - throws SocketException - { - if (opt == SO_REUSEADDR && exclusiveBind && localPort != 0) { - // socket already bound, emulate - reuseAddressEmulated = true; - isReuseAddress = (Boolean)val; - } else { - socketNativeSetOption(opt, val); - } - - } - - protected boolean isClosed() { - return (fd == null && fd1 == null) ? true : false; - } - - protected void close() { - if (fd != null || fd1 != null) { - datagramSocketClose(); - ResourceManager.afterUdpClose(); - fd = null; - fd1 = null; - } - } - - /* Native methods */ - - protected synchronized void bind0(int lport, InetAddress laddr, - boolean exclBind) throws SocketException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - TwoStacksPlainDatagramSocketImpl_c.bind0(env, this, lport, laddr, exclBind); - env.ThrowPendingException(); - } - - protected void send(DatagramPacket packet) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - TwoStacksPlainDatagramSocketImpl_c.send(env, this, packet); - env.ThrowPendingException(); - } - - protected synchronized int peek(InetAddress addressObj) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - int ret = TwoStacksPlainDatagramSocketImpl_c.peek(env, this, addressObj); - env.ThrowPendingException(); - return ret; - } - - protected synchronized int peekData(DatagramPacket p) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - int ret = TwoStacksPlainDatagramSocketImpl_c.peekData(env, this, p); - env.ThrowPendingException(); - return ret; - } - - protected synchronized void receive0(DatagramPacket packet) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - TwoStacksPlainDatagramSocketImpl_c.receive0(env, this, packet); - env.ThrowPendingException(); - } - - protected void setTimeToLive(int ttl) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - TwoStacksPlainDatagramSocketImpl_c.setTimeToLive(env, this, ttl); - env.ThrowPendingException(); - } - - protected int getTimeToLive() throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - int ret = TwoStacksPlainDatagramSocketImpl_c.getTimeToLive(env, this); - env.ThrowPendingException(); - return ret; - } - - protected void setTTL(byte ttl) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - TwoStacksPlainDatagramSocketImpl_c.setTTL(env, this, ttl); - env.ThrowPendingException(); - } - - protected byte getTTL() throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - byte ret = TwoStacksPlainDatagramSocketImpl_c.getTTL(env, this); - env.ThrowPendingException(); - return ret; - } - - protected void join(InetAddress inetaddr, NetworkInterface netIf) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - TwoStacksPlainDatagramSocketImpl_c.join(env, this, inetaddr, netIf); - env.ThrowPendingException(); - } - - protected void leave(InetAddress inetaddr, NetworkInterface netIf) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - TwoStacksPlainDatagramSocketImpl_c.leave(env, this, inetaddr, netIf); - env.ThrowPendingException(); - } - - protected void datagramSocketCreate() throws SocketException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - TwoStacksPlainDatagramSocketImpl_c.datagramSocketCreate(env, this); - env.ThrowPendingException(); - } - - protected void datagramSocketClose() { - TwoStacksPlainDatagramSocketImpl_c.datagramSocketClose(this); - } - - protected void socketNativeSetOption(int opt, Object val) throws SocketException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - TwoStacksPlainDatagramSocketImpl_c.socketNativeSetOption(env, this, opt, val); - env.ThrowPendingException(); - } - - protected Object socketGetOption(int opt) throws SocketException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - Object ret = TwoStacksPlainDatagramSocketImpl_c.socketGetOption(env, this, opt); - env.ThrowPendingException(); - return ret; - } - - protected void connect0(InetAddress address, int port) throws SocketException { - if (ikvm.internal.Util.MONO) { - // MONOBUG Mono doesn't allow Socket.Connect(IPAddress.Any, 0) to disconnect a datagram socket, - // so we throw a SocketException, this will cause DatagramSocket to emulate connectedness - throw new SocketException("connected datagram sockets not supported on Mono"); - } - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - TwoStacksPlainDatagramSocketImpl_c.connect0(env, this, address, port); - env.ThrowPendingException(); - } - - protected void disconnect0(int family) { - TwoStacksPlainDatagramSocketImpl_c.disconnect0(this, family); - } -} diff --git a/openjdk/java/net/TwoStacksPlainDatagramSocketImpl_c.java b/openjdk/java/net/TwoStacksPlainDatagramSocketImpl_c.java deleted file mode 100644 index d84a427b..00000000 --- a/openjdk/java/net/TwoStacksPlainDatagramSocketImpl_c.java +++ /dev/null @@ -1,2463 +0,0 @@ -/* - * 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 - * 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 static ikvm.internal.JNI.*; -import static ikvm.internal.Winsock.*; -import static java.net.net_util_md.*; -import static java.net.InetAddress.IPv4; -import static java.net.InetAddress.IPv6; - -final class TwoStacksPlainDatagramSocketImpl_c -{ -static final int ni_class = 0; -static final int JVM_IO_ERR = -1; -static final int JVM_IO_INTR = -2; - -static final int java_net_SocketOptions_SO_BINDADDR = SocketOptions.SO_BINDADDR; -static final int java_net_SocketOptions_SO_SNDBUF = SocketOptions.SO_SNDBUF; -static final int java_net_SocketOptions_SO_RCVBUF = SocketOptions.SO_RCVBUF; -static final int java_net_SocketOptions_IP_TOS = SocketOptions.IP_TOS; -static final int java_net_SocketOptions_SO_REUSEADDR = SocketOptions.SO_REUSEADDR; -static final int java_net_SocketOptions_SO_BROADCAST = SocketOptions.SO_BROADCAST; -static final int java_net_SocketOptions_IP_MULTICAST_LOOP = SocketOptions.IP_MULTICAST_LOOP; -static final int java_net_SocketOptions_IP_MULTICAST_IF = SocketOptions.IP_MULTICAST_IF; -static final int java_net_SocketOptions_IP_MULTICAST_IF2 = SocketOptions.IP_MULTICAST_IF2; - -/* - -#include <windows.h> -#include <winsock2.h> -#include <ws2tcpip.h> -#include <ctype.h> -#include <stdio.h> -#include <stdlib.h> -#include <malloc.h> -#include <sys/types.h> - -#ifndef IPTOS_TOS_MASK -#define IPTOS_TOS_MASK 0x1e -#endif -#ifndef IPTOS_PREC_MASK -#define IPTOS_PREC_MASK 0xe0 -#endif - -#include "java_net_TwoStacksPlainDatagramSocketImpl.h" -#include "java_net_SocketOptions.h" -#include "java_net_NetworkInterface.h" - -#include "NetworkInterface.h" -#include "jvm.h" -#include "jni_util.h" -#include "net_util.h" - -#define IN_CLASSD(i) (((long)(i) & 0xf0000000) == 0xe0000000) -#define IN_MULTICAST(i) IN_CLASSD(i) - -*/ - -static boolean IN_MULTICAST(int ipv4address) { - return ((ipv4address >> 24) & 0xf0) == 0xe0; -} - -/************************************************************************ - * TwoStacksPlainDatagramSocketImpl - */ - -/* -static jfieldID IO_fd_fdID; -static jfieldID pdsi_trafficClassID; -jfieldID pdsi_fdID; -jfieldID pdsi_fd1ID; -jfieldID pdsi_fduseID; -jfieldID pdsi_lastfdID; -jfieldID pdsi_timeoutID; - -jfieldID pdsi_localPortID; -jfieldID pdsi_connected; - -static jclass ia4_clazz; -static jmethodID ia4_ctor; - -static CRITICAL_SECTION sizeCheckLock; -*/ - -/* Windows OS version is XP or better */ -static final boolean xp_or_later = true; -/* Windows OS version is Windows 2000 or better */ -//static int w2k_or_later = 0; - -/* - * Notes about UDP/IPV6 on Windows (XP and 2003 server): - * - * fd always points to the IPv4 fd, and fd1 points to the IPv6 fd. - * Both fds are used when we bind to a wild-card address. When a specific - * address is used, only one of them is used. - */ - -/* - * Returns a java.lang.Integer based on 'i' - */ -/* -jobject createInteger(JNIEnv *env, int i) { - static jclass i_class; - static jmethodID i_ctrID; - static jfieldID i_valueID; - - if (i_class == NULL) { - jclass c = (*env)->FindClass(env, "java/lang/Integer"); - CHECK_NULL_RETURN(c, NULL); - i_ctrID = (*env)->GetMethodID(env, c, "<init>", "(I)V"); - CHECK_NULL_RETURN(i_ctrID, NULL); - i_class = (*env)->NewGlobalRef(env, c); - CHECK_NULL_RETURN(i_class, NULL); - } - - return ( (*env)->NewObject(env, i_class, i_ctrID, i) ); -} -*/ - -/* - * Returns a java.lang.Boolean based on 'b' - */ -/* -jobject createBoolean(JNIEnv *env, int b) { - static jclass b_class; - static jmethodID b_ctrID; - static jfieldID b_valueID; - - if (b_class == NULL) { - jclass c = (*env)->FindClass(env, "java/lang/Boolean"); - CHECK_NULL_RETURN(c, NULL); - b_ctrID = (*env)->GetMethodID(env, c, "<init>", "(Z)V"); - CHECK_NULL_RETURN(b_ctrID, NULL); - b_class = (*env)->NewGlobalRef(env, c); - CHECK_NULL_RETURN(b_class, NULL); - } - - return( (*env)->NewObject(env, b_class, b_ctrID, (jboolean)(b!=0)) ); -} -*/ - - -static cli.System.Net.Sockets.Socket getFD(JNIEnv env, TwoStacksPlainDatagramSocketImpl _this) { - FileDescriptor fdObj = _this.fd; - - if (fdObj == NULL) { - return null; - } - return fdObj.getSocket(); -} - -static cli.System.Net.Sockets.Socket getFD1(JNIEnv env, TwoStacksPlainDatagramSocketImpl _this) { - FileDescriptor fdObj = _this.fd1; - - if (fdObj == NULL) { - return null; - } - return fdObj.getSocket(); -} - -/* - * This function returns JNI_TRUE if the datagram size exceeds the underlying - * provider's ability to send to the target address. The following OS - * oddities have been observed :- - * - * 1. On Windows 95/98 if we try to send a datagram > 12k to an application - * on the same machine then the send will fail silently. - * - * 2. On Windows ME if we try to send a datagram > supported by underlying - * provider then send will not return an error. - * - * 3. On Windows NT/2000 if we exceeds the maximum size then send will fail - * with WSAEADDRNOTAVAIL. - * - * 4. On Windows 95/98 if we exceed the maximum size when sending to - * another machine then WSAEINVAL is returned. - * - */ -/* -jboolean exceedSizeLimit(JNIEnv *env, jint fd, jint addr, jint size) -{ -#define DEFAULT_MSG_SIZE 65527 - static jboolean initDone; - static jboolean is95or98; - static int maxmsg; - - typedef struct _netaddr { /* Windows 95/98 only *-/ - unsigned long addr; - struct _netaddr *next; - } netaddr; - static netaddr *addrList; - netaddr *curr; - - /* - * First time we are called we must determine which OS this is and also - * get the maximum size supported by the underlying provider. - * - * In addition on 95/98 we must enumerate our IP addresses. - *-/ - if (!initDone) { - EnterCriticalSection(&sizeCheckLock); - - if (initDone) { - /* another thread got there first *-/ - LeaveCriticalSection(&sizeCheckLock); - - } else { - OSVERSIONINFO ver; - int len; - - /* - * Step 1: Determine which OS this is. - *-/ - ver.dwOSVersionInfoSize = sizeof(ver); - GetVersionEx(&ver); - - is95or98 = JNI_FALSE; - if (ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && - ver.dwMajorVersion == 4 && - (ver.dwMinorVersion == 0 || ver.dwMinorVersion == 10)) { - - is95or98 = JNI_TRUE; - } - - /* - * Step 2: Determine the maximum datagram supported by the - * underlying provider. On Windows 95 if winsock hasn't been - * upgraded (ie: unsupported configuration) then we assume - * the default 64k limit. - *-/ - len = sizeof(maxmsg); - if (NET_GetSockOpt(fd, SOL_SOCKET, SO_MAX_MSG_SIZE, (char *)&maxmsg, &len) < 0) { - maxmsg = DEFAULT_MSG_SIZE; - } - - /* - * Step 3: On Windows 95/98 then enumerate the IP addresses on - * this machine. This is neccesary because we need to check if the - * datagram is being sent to an application on the same machine. - *-/ - if (is95or98) { - char hostname[255]; - struct hostent *hp; - - if (gethostname(hostname, sizeof(hostname)) == -1) { - LeaveCriticalSection(&sizeCheckLock); - JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unable to obtain hostname"); - return JNI_TRUE; - } - hp = (struct hostent *)gethostbyname(hostname); - if (hp != NULL) { - struct in_addr **addrp = (struct in_addr **) hp->h_addr_list; - - while (*addrp != (struct in_addr *) 0) { - curr = (netaddr *)malloc(sizeof(netaddr)); - if (curr == NULL) { - while (addrList != NULL) { - curr = addrList->next; - free(addrList); - addrList = curr; - } - LeaveCriticalSection(&sizeCheckLock); - JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); - return JNI_TRUE; - } - curr->addr = htonl((*addrp)->S_un.S_addr); - curr->next = addrList; - addrList = curr; - addrp++; - } - } - } - - /* - * Step 4: initialization is done so set flag and unlock cs - *-/ - initDone = JNI_TRUE; - LeaveCriticalSection(&sizeCheckLock); - } - } - - /* - * Now examine the size of the datagram :- - * - * (a) If exceeds size of service provider return 'false' to indicate that - * we exceed the limit. - * (b) If not 95/98 then return 'true' to indicate that the size is okay. - * (c) On 95/98 if the size is <12k we are okay. - * (d) On 95/98 if size > 12k then check if the destination is the current - * machine. - *-/ - if (size > maxmsg) { /* step (a) *-/ - return JNI_TRUE; - } - if (!is95or98) { /* step (b) *-/ - return JNI_FALSE; - } - if (size <= 12280) { /* step (c) *-/ - return JNI_FALSE; - } - - /* step (d) *-/ - - if ((addr & 0x7f000000) == 0x7f000000) { - return JNI_TRUE; - } - curr = addrList; - while (curr != NULL) { - if (curr->addr == addr) { - return JNI_TRUE; - } - curr = curr->next; - } - return JNI_FALSE; -} -*/ - -/* - * Return JNI_TRUE if this Windows edition supports ICMP Port Unreachable - */ -static boolean supportPortUnreachable() { - // we don't support anything pre-Win2K anyway - return true; -} - -/* - * This function "purges" all outstanding ICMP port unreachable packets - * outstanding on a socket and returns JNI_TRUE if any ICMP messages - * have been purged. The rational for purging is to emulate normal BSD - * behaviour whereby receiving a "connection reset" status resets the - * socket. - */ -static boolean purgeOutstandingICMP(cli.System.Net.Sockets.Socket fd) -{ - boolean got_icmp = false; - byte[] buf = new byte[1]; - fd_set tbl = new fd_set(); - timeval t = new timeval(); - SOCKETADDRESS rmtaddr = null; - - /* - * A no-op if this OS doesn't support it. - */ - if (!supportPortUnreachable()) { - return JNI_FALSE; - } - - /* - * Peek at the queue to see if there is an ICMP port unreachable. If there - * is then receive it. - */ - FD_ZERO(tbl); - FD_SET(fd, tbl); - while(true) { - if (select(tbl, null, null, t) <= 0) { - break; - } - if (recvfrom(fd, buf, 1, MSG_PEEK, - rmtaddr) != JVM_IO_ERR) { - break; - } - if (WSAGetLastError() != WSAECONNRESET) { - /* some other error - we don't care here */ - break; - } - - recvfrom(fd, buf, 1, 0, rmtaddr); - got_icmp = JNI_TRUE; - } - - return got_icmp; -} - - -/* - * Class: java_net_TwoStacksPlainDatagramSocketImpl - * Method: init - * Signature: ()V - */ -/* -JNIEXPORT void JNICALL -Java_java_net_TwoStacksPlainDatagramSocketImpl_init(JNIEnv *env, jclass cls) { - - OSVERSIONINFO ver; - int version; - ver.dwOSVersionInfoSize = sizeof(ver); - GetVersionEx(&ver); - - version = ver.dwMajorVersion * 10 + ver.dwMinorVersion; - xp_or_later = (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) && (version >= 51); - w2k_or_later = (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) && (version >= 50); - - /* get fieldIDs *-/ - pdsi_fdID = (*env)->GetFieldID(env, cls, "fd", "Ljava/io/FileDescriptor;"); - CHECK_NULL(pdsi_fdID); - pdsi_fd1ID = (*env)->GetFieldID(env, cls, "fd1", "Ljava/io/FileDescriptor;"); - CHECK_NULL(pdsi_fd1ID); - pdsi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I"); - CHECK_NULL(pdsi_timeoutID); - pdsi_fduseID = (*env)->GetFieldID(env, cls, "fduse", "I"); - CHECK_NULL(pdsi_fduseID); - pdsi_lastfdID = (*env)->GetFieldID(env, cls, "lastfd", "I"); - CHECK_NULL(pdsi_lastfdID); - pdsi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I"); - CHECK_NULL(pdsi_trafficClassID); - pdsi_localPortID = (*env)->GetFieldID(env, cls, "localPort", "I"); - CHECK_NULL(pdsi_localPortID); - pdsi_connected = (*env)->GetFieldID(env, cls, "connected", "Z"); - CHECK_NULL(pdsi_connected); - - cls = (*env)->FindClass(env, "java/io/FileDescriptor"); - CHECK_NULL(cls); - IO_fd_fdID = NET_GetFileDescriptorID(env); - CHECK_NULL(IO_fd_fdID); - - ia4_clazz = (*env)->FindClass(env, "java/net/Inet4Address"); - CHECK_NULL(ia4_clazz); - ia4_clazz = (*env)->NewGlobalRef(env, ia4_clazz); - CHECK_NULL(ia4_clazz); - ia4_ctor = (*env)->GetMethodID(env, ia4_clazz, "<init>", "()V"); - CHECK_NULL(ia4_ctor); - - - InitializeCriticalSection(&sizeCheckLock); -} -*/ - -static void bind0(JNIEnv env, TwoStacksPlainDatagramSocketImpl _this, - int port, InetAddress addressObj, - boolean exclBind) { - FileDescriptor fdObj = _this.fd; - FileDescriptor fd1Obj = _this.fd1; - - cli.System.Net.Sockets.Socket fd = null; - cli.System.Net.Sockets.Socket fd1 = null; - int family; - boolean ipv6_supported = ipv6_available(); - - SOCKETADDRESS lcladdr; - lcladdr = new SOCKETADDRESS(); - - family = getInetAddress_family(env, addressObj); - if (family == IPv6 && !ipv6_supported) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Protocol family not supported"); - return; - } - - if (IS_NULL(fdObj) || (ipv6_supported && IS_NULL(fd1Obj))) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "socket closed"); - return; - } else { - fd = fdObj.getSocket(); - if (ipv6_supported) { - fd1 = fd1Obj.getSocket(); - } - } - if (IS_NULL(addressObj)) { - JNU_ThrowNullPointerException(env, "argument address"); - return; - } - - if (NET_InetAddressToSockaddr(env, addressObj, port, lcladdr, JNI_FALSE) != 0) { - return; - } - - if (ipv6_supported) { - ipv6bind v6bind = new ipv6bind(); - v6bind.addr = lcladdr; - v6bind.ipv4_fd = fd; - v6bind.ipv6_fd = fd1; - if (NET_BindV6(v6bind, exclBind) != -1) { - /* check if the fds have changed */ - if (v6bind.ipv4_fd != fd) { - fd = v6bind.ipv4_fd; - if (fd == null) { - /* socket is closed. */ - _this.fd = null; - } else { - /* socket was re-created */ - fdObj.setSocket(fd); - } - } - if (v6bind.ipv6_fd != fd1) { - fd1 = v6bind.ipv6_fd; - if (fd1 == null) { - /* socket is closed. */ - _this.fd1 = null; - } else { - /* socket was re-created */ - fd1Obj.setSocket(fd1); - } - } - } else { - NET_ThrowCurrent (env, "Cannot bind"); - return; - } - } else { - if (NET_WinBind(fd, lcladdr, exclBind) == -1) { - if (WSAGetLastError() == WSAEACCES) { - WSASetLastError(WSAEADDRINUSE); - } - NET_ThrowCurrent(env, "Cannot bind"); - return; - } - } - - if (port == 0) { - if (fd == null) { - /* must be an IPV6 only socket. */ - fd = fd1; - } - if (getsockname(fd, lcladdr) == -1) { - NET_ThrowCurrent(env, "JVM_GetSockName"); - return; - } - port = ntohs(GET_PORT (lcladdr)); - } - _this.localPort = port; -} - - -/* - * Class: java_net_TwoStacksPlainDatagramSocketImpl - * Method: connect0 - * Signature: (Ljava/net/InetAddress;I)V - */ - -static void connect0(JNIEnv env, TwoStacksPlainDatagramSocketImpl _this, InetAddress address, int port) { - /* The object's field */ - FileDescriptor fdObj = _this.fd; - FileDescriptor fd1Obj = _this.fd1; - /* The fdObj'fd */ - cli.System.Net.Sockets.Socket fd = null; - cli.System.Net.Sockets.Socket fd1 = null; - cli.System.Net.Sockets.Socket fdc; - /* The packetAddress address, family and port */ - int addr, family; - SOCKETADDRESS rmtaddr; - rmtaddr = new SOCKETADDRESS(); - boolean ipv6_supported = ipv6_available(); - - if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Socket closed"); - return; - } - if (!IS_NULL(fdObj)) { - fd = fdObj.getSocket(); - } - if (!IS_NULL(fd1Obj)) { - fd1 = fd1Obj.getSocket(); - } - - if (IS_NULL(address)) { - JNU_ThrowNullPointerException(env, "address"); - return; - } - - addr = getInetAddress_addr(env, address); - - family = getInetAddress_family(env, address); - if (family == IPv6 && !ipv6_supported) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Protocol family not supported"); - return; - } - - fdc = family == IPv4? fd: fd1; - - if (xp_or_later) { - /* SIO_UDP_CONNRESET fixes a bug introduced in Windows 2000, which - * returns connection reset errors on connected UDP sockets (as well - * as connected sockets). The solution is to only enable this feature - * when the socket is connected - */ - WSAIoctl(fdc, SIO_UDP_CONNRESET, true); - } - - if (NET_InetAddressToSockaddr(env, address, port, rmtaddr, JNI_FALSE) != 0) { - return; - } - - if (connect(fdc, rmtaddr) == -1) { - NET_ThrowCurrent(env, "connect"); - return; - } -} - -/* - * Class: java_net_TwoStacksPlainDatagramSocketImpl - * Method: disconnect0 - * Signature: ()V - */ - -static void disconnect0(TwoStacksPlainDatagramSocketImpl _this, int family) { - /* The object's field */ - FileDescriptor fdObj; - /* The fdObj'fd */ - cli.System.Net.Sockets.Socket fd; - SOCKETADDRESS addr; - addr = new SOCKETADDRESS(); - - if (family == IPv4) { - fdObj = _this.fd; - } else { - fdObj = _this.fd1; - } - - if (IS_NULL(fdObj)) { - /* disconnect doesn't throw any exceptions */ - return; - } - fd = fdObj.getSocket(); - - connect(fd, addr); - - /* - * use SIO_UDP_CONNRESET - * to disable ICMP port unreachable handling here. - */ - if (xp_or_later) { - WSAIoctl(fd,SIO_UDP_CONNRESET,false); - } -} - -/* - * Class: java_net_TwoStacksPlainDatagramSocketImpl - * Method: send - * Signature: (Ljava/net/DatagramPacket;)V - */ -static void send(JNIEnv env, TwoStacksPlainDatagramSocketImpl _this, DatagramPacket packet) { - FileDescriptor fdObj; - cli.System.Net.Sockets.Socket fd; - - InetAddress iaObj; - int address; - int family; - - int packetBufferOffset, packetBufferLen, packetPort; - byte[] packetBuffer; - boolean connected; - - SOCKETADDRESS rmtaddr; - rmtaddr = new SOCKETADDRESS(); - - if (IS_NULL(packet)) { - JNU_ThrowNullPointerException(env, "null packet"); - return; - } - - iaObj = packet.address; - - packetPort = packet.port; - packetBufferOffset = packet.offset; - packetBuffer = packet.buf; - connected = _this.connected; - - if (IS_NULL(iaObj) || IS_NULL(packetBuffer)) { - JNU_ThrowNullPointerException(env, "null address || null buffer"); - return; - } - - family = getInetAddress_family(env, iaObj); - if (family == IPv4) { - fdObj = _this.fd; - } else { - if (!ipv6_available()) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Protocol not allowed"); - return; - } - fdObj = _this.fd1; - } - - if (IS_NULL(fdObj)) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Socket closed"); - return; - } - fd = fdObj.getSocket(); - - packetBufferLen = packet.length; - /* Note: the buffer needn't be greater than 65,536 (0xFFFF)... - * the maximum size of an IP packet. Anything bigger is truncated anyway. - */ - if (packetBufferLen > MAX_PACKET_LEN) { - packetBufferLen = MAX_PACKET_LEN; - } - - if (connected) { - rmtaddr = null; - } else { - if (NET_InetAddressToSockaddr(env, iaObj, packetPort, rmtaddr, JNI_FALSE) != 0) { - return; - } - } - - /* - if (packetBufferLen > MAX_BUFFER_LEN) { - - /* - * On 95/98 if we try to send a datagram >12k to an application - * on the same machine then this will fail silently. Thus we - * catch this situation here so that we can throw an exception - * when this arises. - * On ME if we try to send a datagram with a size greater than - * that supported by the service provider then no error is - * returned. - *-/ - if (!w2k_or_later) { /* avoid this check on Win 2K or better. Does not work with IPv6. - * Check is not necessary on these OSes *-/ - if (connected) { - address = getInetAddress_addr(env, iaObj); - } else { - address = ntohl(rmtaddr.him4.sin_addr.s_addr); - } - - if (exceedSizeLimit(env, fd, address, packetBufferLen)) { - if (!((*env)->ExceptionOccurred(env))) { - NET_ThrowNew(env, WSAEMSGSIZE, "Datagram send failed"); - } - return; - } - } - - /* When JNI-ifying the JDK's IO routines, we turned - * reads and writes of byte arrays of size greater - * than 2048 bytes into several operations of size 2048. - * This saves a malloc()/memcpy()/free() for big - * buffers. This is OK for file IO and TCP, but that - * strategy violates the semantics of a datagram protocol. - * (one big send) != (several smaller sends). So here - * we *must* alloc the buffer. Note it needn't be bigger - * than 65,536 (0xFFFF) the max size of an IP packet. - * anything bigger is truncated anyway. - *-/ - fullPacket = (char *)malloc(packetBufferLen); - if (!fullPacket) { - JNU_ThrowOutOfMemoryError(env, "Send buf native heap allocation failed"); - return; - } - } else { - fullPacket = &(BUF[0]); - } - */ - - switch (sendto(fd, packetBuffer, packetBufferOffset, packetBufferLen, 0, rmtaddr)) { - case JVM_IO_ERR: - NET_ThrowCurrent(env, "Datagram send failed"); - break; - - case JVM_IO_INTR: - JNU_ThrowByName(env, JNU_JAVAIOPKG+"InterruptedIOException", - "operation interrupted"); - } -} - -/* - * check which socket was last serviced when there was data on both sockets. - * Only call this if sure that there is data on both sockets. - */ -private static cli.System.Net.Sockets.Socket checkLastFD (TwoStacksPlainDatagramSocketImpl _this, cli.System.Net.Sockets.Socket fd, cli.System.Net.Sockets.Socket fd1) { - cli.System.Net.Sockets.Socket nextfd, lastfd = _this.lastfd; - if (lastfd == null) { - /* arbitrary. Choose fd */ - _this.lastfd = fd; - return fd; - } else { - if (lastfd == fd) { - nextfd = fd1; - } else { - nextfd = fd; - } - _this.lastfd = nextfd; - return nextfd; - } -} - -/* - * Class: java_net_TwoStacksPlainDatagramSocketImpl - * Method: peek - * Signature: (Ljava/net/InetAddress;)I - */ -static int peek(JNIEnv env, TwoStacksPlainDatagramSocketImpl _this, InetAddress addressObj) { - FileDescriptor fdObj = _this.fd; - int timeout = _this.timeout; - cli.System.Net.Sockets.Socket fd; - - /* The address and family fields of addressObj */ - int address, family; - - int n; - SOCKETADDRESS remote_addr = new SOCKETADDRESS(); - byte[] buf = new byte[1]; - boolean retry; - long prevTime = 0; - - if (IS_NULL(fdObj)) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "Socket closed"); - return -1; - } else { - fd = fdObj.getSocket(); - if (fd == null) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "socket closed"); - return -1; - } - } - if (IS_NULL(addressObj)) { - JNU_ThrowNullPointerException(env, "Null address in peek()"); - return -1; - } else { - address = getInetAddress_addr(env, addressObj); - /* We only handle IPv4 for now. Will support IPv6 once its in the os */ - family = AF_INET; - } - - do { - retry = FALSE; - - /* - * If a timeout has been specified then we select on the socket - * waiting for a read event or a timeout. - */ - if (timeout != 0) { - int ret; - prevTime = JVM_CurrentTimeMillis(env, 0); - ret = NET_Timeout (fd, timeout); - if (ret == 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketTimeoutException", - "Peek timed out"); - return ret; - } else if (ret == JVM_IO_ERR) { - NET_ThrowCurrent(env, "timeout in datagram socket peek"); - return ret; - } else if (ret == JVM_IO_INTR) { - JNU_ThrowByName(env, JNU_JAVAIOPKG+"InterruptedIOException", - "operation interrupted"); - return ret; - } - } - - /* now try the peek */ - n = recvfrom(fd, buf, 1, MSG_PEEK, - remote_addr); - - if (n == JVM_IO_ERR) { - if (WSAGetLastError() == WSAECONNRESET) { - boolean connected; - - /* - * An icmp port unreachable - we must receive this as Windows - * does not reset the state of the socket until this has been - * received. - */ - purgeOutstandingICMP(fd); - - connected = _this.connected; - if (connected) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"PortUnreachableException", - "ICMP Port Unreachable"); - return 0; - } - - /* - * If a timeout was specified then we need to adjust it because - * we may have used up some of the timeout befor the icmp port - * unreachable arrived. - */ - if (timeout != 0) { - long newTime = JVM_CurrentTimeMillis(env, 0); - timeout -= (newTime - prevTime); - if (timeout <= 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketTimeoutException", - "Receive timed out"); - return 0; - } - prevTime = newTime; - } - - /* Need to retry the recv */ - retry = TRUE; - } - } - } while (retry); - - if (n == JVM_IO_ERR && WSAGetLastError() != WSAEMSGSIZE) { - NET_ThrowCurrent(env, "Datagram peek failed"); - return 0; - } - if (n == JVM_IO_INTR) { - JNU_ThrowByName(env, JNU_JAVAIOPKG+"InterruptedIOException", null); - return 0; - } - addressObj.holder().address = ntohl(remote_addr.sin_addr.s_addr); - addressObj.holder().family = IPv4; - - /* return port */ - return ntohs(remote_addr.sin_port); -} - -static int peekData(JNIEnv env, TwoStacksPlainDatagramSocketImpl _this, DatagramPacket packet) { - - FileDescriptor fdObj = _this.fd; - FileDescriptor fd1Obj = _this.fd1; - int timeout = _this.timeout; - - byte[] packetBuffer; - int packetBufferOffset, packetBufferLen; - - cli.System.Net.Sockets.Socket fd = null, fd1 = null, fduse = null; - int nsockets=0, errorCode; - int port; - byte[] data; - - boolean checkBoth = false; - int datalen; - int n; - SOCKETADDRESS remote_addr; - remote_addr = new SOCKETADDRESS(); - boolean retry; - long prevTime = 0; - - if (!IS_NULL(fdObj)) { - fd = fdObj.getSocket(); - if (fd == null) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "socket closed"); - return -1; - } - nsockets = 1; - } - - if (!IS_NULL(fd1Obj)) { - fd1 = fd1Obj.getSocket(); - if (fd1 == null) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "socket closed"); - return -1; - } - nsockets ++; - } - - switch (nsockets) { - case 0: - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "socket closed"); - return -1; - case 1: - if (!IS_NULL(fdObj)) { - fduse = fd; - } else { - fduse = fd1; - } - break; - case 2: - checkBoth = TRUE; - break; - } - - if (IS_NULL(packet)) { - JNU_ThrowNullPointerException(env, "packet"); - return -1; - } - - packetBuffer = packet.buf; - - if (IS_NULL(packetBuffer)) { - JNU_ThrowNullPointerException(env, "packet buffer"); - return -1; - } - - packetBufferOffset = packet.offset; - packetBufferLen = packet.bufLength; - - /* - if (packetBufferLen > MAX_BUFFER_LEN) { - - /* When JNI-ifying the JDK's IO routines, we turned - * read's and write's of byte arrays of size greater - * than 2048 bytes into several operations of size 2048. - * This saves a malloc()/memcpy()/free() for big - * buffers. This is OK for file IO and TCP, but that - * strategy violates the semantics of a datagram protocol. - * (one big send) != (several smaller sends). So here - * we *must* alloc the buffer. Note it needn't be bigger - * than 65,536 (0xFFFF) the max size of an IP packet. - * anything bigger is truncated anyway. - *-/ - fullPacket = (char *)malloc(packetBufferLen); - if (!fullPacket) { - JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); - return -1; - } - } else { - fullPacket = &(BUF[0]); - } - */ - - do { - int ret; - retry = FALSE; - - /* - * If a timeout has been specified then we select on the socket - * waiting for a read event or a timeout. - */ - if (checkBoth) { - int t = timeout == 0 ? -1: timeout; - prevTime = JVM_CurrentTimeMillis(env, 0); - cli.System.Net.Sockets.Socket[] tmp = new cli.System.Net.Sockets.Socket[] { fduse }; - ret = NET_Timeout2 (fd, fd1, t, tmp); - fduse = tmp[0]; - /* all subsequent calls to recv() or select() will use the same fd - * for this call to peek() */ - if (ret <= 0) { - if (ret == 0) { - JNU_ThrowByName(env,JNU_JAVANETPKG+"SocketTimeoutException", - "Peek timed out"); - } else if (ret == JVM_IO_ERR) { - NET_ThrowCurrent(env, "timeout in datagram socket peek"); - } else if (ret == JVM_IO_INTR) { - JNU_ThrowByName(env, JNU_JAVAIOPKG+"InterruptedIOException", - "operation interrupted"); - } - return -1; - } - if (ret == 2) { - fduse = checkLastFD (_this, fd, fd1); - } - checkBoth = FALSE; - } else if (timeout != 0) { - if (prevTime == 0) { - prevTime = JVM_CurrentTimeMillis(env, 0); - } - ret = NET_Timeout (fduse, timeout); - if (ret <= 0) { - if (ret == 0) { - JNU_ThrowByName(env,JNU_JAVANETPKG+"SocketTimeoutException", - "Receive timed out"); - } else if (ret == JVM_IO_ERR) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Socket closed"); - } else if (ret == JVM_IO_INTR) { - JNU_ThrowByName(env, JNU_JAVAIOPKG+"InterruptedIOException", - "operation interrupted"); - } - return -1; - } - } - - /* receive the packet */ - n = recvfrom(fduse, packetBuffer, packetBufferOffset, packetBufferLen, MSG_PEEK, remote_addr); - port = ntohs (GET_PORT(remote_addr)); - if (n == JVM_IO_ERR) { - if (WSAGetLastError() == WSAECONNRESET) { - boolean connected; - - /* - * An icmp port unreachable - we must receive this as Windows - * does not reset the state of the socket until this has been - * received. - */ - purgeOutstandingICMP(fduse); - - connected = _this.connected; - if (connected) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"PortUnreachableException", - "ICMP Port Unreachable"); - - return -1; - } - - /* - * If a timeout was specified then we need to adjust it because - * we may have used up some of the timeout befor the icmp port - * unreachable arrived. - */ - if (timeout != 0) { - long newTime = JVM_CurrentTimeMillis(env, 0); - timeout -= (newTime - prevTime); - if (timeout <= 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketTimeoutException", - "Receive timed out"); - return -1; - } - prevTime = newTime; - } - retry = TRUE; - } - } - } while (retry); - - if (n < 0) { - errorCode = WSAGetLastError(); - /* check to see if it's because the buffer was too small */ - if (errorCode == WSAEMSGSIZE) { - /* it is because the buffer is too small. It's UDP, it's - * unreliable, it's all good. discard the rest of the - * data.. - */ - n = packetBufferLen; - } else { - /* failure */ - packet.length = 0; - } - } - if (n == -1) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "socket closed"); - } else if (n == -2) { - JNU_ThrowByName(env, JNU_JAVAIOPKG+"InterruptedIOException", - "operation interrupted"); - } else if (n < 0) { - NET_ThrowCurrent(env, "Datagram receive failed"); - } else { - InetAddress packetAddress; - - /* - * Check if there is an InetAddress already associated with this - * packet. If so we check if it is the same source address. We - * can't update any existing InetAddress because it is immutable - */ - packetAddress = packet.address; - if (packetAddress != NULL) { - if (!NET_SockaddrEqualsInetAddress(remote_addr, packetAddress)) { - /* force a new InetAddress to be created */ - packetAddress = null; - } - } - if (packetAddress == NULL) { - int[] tmp = { port }; - packetAddress = NET_SockaddrToInetAddress(remote_addr, tmp); - port = tmp[0]; - /* stuff the new Inetaddress in the packet */ - packet.address = packetAddress; - } - - /* populate the packet */ - packet.port = port; - packet.length = n; - } - - /* make sure receive() picks up the right fd */ - _this.fduse = fduse; - - return port; -} - -/* - * Class: java_net_TwoStacksPlainDatagramSocketImpl - * Method: receive - * Signature: (Ljava/net/DatagramPacket;)V - */ -static void receive0(JNIEnv env, TwoStacksPlainDatagramSocketImpl _this, DatagramPacket packet) { - FileDescriptor fdObj = _this.fd; - FileDescriptor fd1Obj = _this.fd1; - int timeout = _this.timeout; - byte[] packetBuffer; - int packetBufferOffset, packetBufferLen; - boolean ipv6_supported = ipv6_available(); - - /* as a result of the changes for ipv6, peek() or peekData() - * must be called prior to receive() so that fduse can be set. - */ - cli.System.Net.Sockets.Socket fd = null; - cli.System.Net.Sockets.Socket fd1 = null; - cli.System.Net.Sockets.Socket fduse = null; - int errorCode; - - int n, nsockets=0; - SOCKETADDRESS remote_addr; - remote_addr = new SOCKETADDRESS(); - boolean retry; - long prevTime = 0, selectTime=0; - boolean connected; - - if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Socket closed"); - return; - } - - if (!IS_NULL(fdObj)) { - fd = fdObj.getSocket(); - nsockets ++; - } - if (!IS_NULL(fd1Obj)) { - fd1 = fd1Obj.getSocket(); - nsockets ++; - } - - if (nsockets == 2) { /* need to choose one of them */ - /* was fduse set in peek? */ - fduse = _this.fduse; - if (fduse == null) { - /* not set in peek(), must select on both sockets */ - int ret, t = (timeout == 0) ? -1: timeout; - cli.System.Net.Sockets.Socket[] tmp = new cli.System.Net.Sockets.Socket[] { fduse }; - ret = NET_Timeout2 (fd, fd1, t, tmp); - fduse = tmp[0]; - if (ret == 2) { - fduse = checkLastFD (_this, fd, fd1); - } else if (ret <= 0) { - if (ret == 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketTimeoutException", - "Receive timed out"); - } else if (ret == JVM_IO_ERR) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Socket closed"); - } else if (ret == JVM_IO_INTR) { - JNU_ThrowByName(env, JNU_JAVAIOPKG+"InterruptedIOException", - "operation interrupted"); - } - return; - } - } - } else if (!ipv6_supported) { - fduse = fd; - } else if (IS_NULL(fdObj)) { - /* ipv6 supported: and this socket bound to an IPV6 only address */ - fduse = fd1; - } else { - /* ipv6 supported: and this socket bound to an IPV4 only address */ - fduse = fd; - } - - if (IS_NULL(packet)) { - JNU_ThrowNullPointerException(env, "packet"); - return; - } - - packetBuffer = packet.buf; - - if (IS_NULL(packetBuffer)) { - JNU_ThrowNullPointerException(env, "packet buffer"); - return; - } - - packetBufferOffset = packet.offset; - packetBufferLen = packet.bufLength; - - /* - if (packetBufferLen > MAX_BUFFER_LEN) { - - /* When JNI-ifying the JDK's IO routines, we turned - * read's and write's of byte arrays of size greater - * than 2048 bytes into several operations of size 2048. - * This saves a malloc()/memcpy()/free() for big - * buffers. This is OK for file IO and TCP, but that - * strategy violates the semantics of a datagram protocol. - * (one big send) != (several smaller sends). So here - * we *must* alloc the buffer. Note it needn't be bigger - * than 65,536 (0xFFFF) the max size of an IP packet. - * anything bigger is truncated anyway. - *-/ - fullPacket = (char *)malloc(packetBufferLen); - if (!fullPacket) { - JNU_ThrowOutOfMemoryError(env, "Receive buf native heap allocation failed"); - return; - } - } else { - fullPacket = &(BUF[0]); - } - */ - - - - /* - * If this Windows edition supports ICMP port unreachable and if we - * are not connected then we need to know if a timeout has been specified - * and if so we need to pick up the current time. These are required in - * order to implement the semantics of timeout, viz :- - * timeout set to t1 but ICMP port unreachable arrives in t2 where - * t2 < t1. In this case we must discard the ICMP packets and then - * wait for the next packet up to a maximum of t1 minus t2. - */ - connected = _this.connected; - if (supportPortUnreachable() && !connected && timeout != 0 &&!ipv6_supported) { - prevTime = JVM_CurrentTimeMillis(env, 0); - } - - if (timeout != 0 && nsockets == 1) { - int ret; - ret = NET_Timeout(fduse, timeout); - if (ret <= 0) { - if (ret == 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketTimeoutException", - "Receive timed out"); - } else if (ret == JVM_IO_ERR) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Socket closed"); - } else if (ret == JVM_IO_INTR) { - JNU_ThrowByName(env, JNU_JAVAIOPKG+"InterruptedIOException", - "operation interrupted"); - } - return; - } - } - - /* - * Loop only if we discarding ICMP port unreachable packets - */ - do { - retry = FALSE; - - /* receive the packet */ - n = recvfrom(fduse, packetBuffer, packetBufferOffset, packetBufferLen, 0, remote_addr); - - if (n == JVM_IO_ERR) { - if (WSAGetLastError() == WSAECONNRESET) { - /* - * An icmp port unreachable has been received - consume any other - * outstanding packets. - */ - purgeOutstandingICMP(fduse); - - /* - * If connected throw a PortUnreachableException - */ - - if (connected) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"PortUnreachableException", - "ICMP Port Unreachable"); - return; - } - - /* - * If a timeout was specified then we need to adjust it because - * we may have used up some of the timeout before the icmp port - * unreachable arrived. - */ - if (timeout != 0) { - int ret; - long newTime = JVM_CurrentTimeMillis(env, 0); - timeout -= (newTime - prevTime); - prevTime = newTime; - - if (timeout <= 0) { - ret = 0; - } else { - ret = NET_Timeout(fduse, timeout); - } - - if (ret <= 0) { - if (ret == 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketTimeoutException", - "Receive timed out"); - } else if (ret == JVM_IO_ERR) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Socket closed"); - } else if (ret == JVM_IO_INTR) { - JNU_ThrowByName(env, JNU_JAVAIOPKG+"InterruptedIOException", - "operation interrupted"); - } - return; - } - } - - /* - * An ICMP port unreachable was received but we are - * not connected so ignore it. - */ - retry = TRUE; - } - } - } while (retry); - - if (n < 0) { - errorCode = WSAGetLastError(); - /* check to see if it's because the buffer was too small */ - if (errorCode == WSAEMSGSIZE) { - /* it is because the buffer is too small. It's UDP, it's - * unreliable, it's all good. discard the rest of the - * data.. - */ - n = packetBufferLen; - } else { - /* failure */ - packet.length = 0; - } - } - if (n == -1) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "socket closed"); - } else if (n == -2) { - JNU_ThrowByName(env, JNU_JAVAIOPKG+"InterruptedIOException", - "operation interrupted"); - } else if (n < 0) { - NET_ThrowCurrent(env, "Datagram receive failed"); - } else { - int port; - InetAddress packetAddress; - - /* - * Check if there is an InetAddress already associated with this - * packet. If so we check if it is the same source address. We - * can't update any existing InetAddress because it is immutable - */ - packetAddress = packet.address; - - if (packetAddress != NULL) { - if (!NET_SockaddrEqualsInetAddress(remote_addr, packetAddress)) { - /* force a new InetAddress to be created */ - packetAddress = null; - } - } - if (packetAddress == NULL) { - int[] tmp = { 0 }; - packetAddress = NET_SockaddrToInetAddress(remote_addr, tmp); - port = tmp[0]; - /* stuff the new Inetaddress in the packet */ - packet.address = packetAddress; - } else { - /* only get the new port number */ - port = NET_GetPortFromSockaddr(remote_addr); - } - /* populate the packet */ - packet.port = port; - packet.length = n; - } -} - -/* - * Class: java_net_TwoStacksPlainDatagramSocketImpl - * Method: datagramSocketCreate - * Signature: ()V - */ -static void datagramSocketCreate(JNIEnv env, TwoStacksPlainDatagramSocketImpl _this) { - FileDescriptor fdObj = _this.fd; - FileDescriptor fd1Obj = _this.fd1; - cli.System.Net.Sockets.Socket fd = null; - cli.System.Net.Sockets.Socket fd1 = null; - boolean ipv6_supported = ipv6_available(); - - if (IS_NULL(fdObj) || (ipv6_supported && IS_NULL(fd1Obj))) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "Socket closed"); - return; - } else { - fd = socket (AF_INET, SOCK_DGRAM, 0); - } - if (fd == INVALID_SOCKET) { - NET_ThrowCurrent(env, "Socket creation failed"); - return; - } - fdObj.setSocket(fd); - NET_SetSockOpt(fd, SOL_SOCKET, SO_BROADCAST, true); - - if (ipv6_supported) { - /* SIO_UDP_CONNRESET fixes a bug introduced in Windows 2000, which - * returns connection reset errors un connected UDP sockets (as well - * as connected sockets. The solution is to only enable this feature - * when the socket is connected - */ - WSAIoctl(fd,SIO_UDP_CONNRESET,false); - fd1 = socket (AF_INET6, SOCK_DGRAM, 0); - if (fd1 == INVALID_SOCKET) { - NET_ThrowCurrent(env, "Socket creation failed"); - return; - } - NET_SetSockOpt(fd1, SOL_SOCKET, SO_BROADCAST, true); - WSAIoctl(fd1,SIO_UDP_CONNRESET,false); - fd1Obj.setSocket(fd1); - } else { - /* drop the second fd */ - _this.fd1 = null; - } -} - -/* - * Class: java_net_TwoStacksPlainDatagramSocketImpl - * Method: datagramSocketClose - * Signature: ()V - */ -static void datagramSocketClose(TwoStacksPlainDatagramSocketImpl _this) { - /* - * REMIND: PUT A LOCK AROUND THIS CODE - */ - FileDescriptor fdObj = _this.fd; - FileDescriptor fd1Obj = _this.fd1; - boolean ipv6_supported = ipv6_available(); - cli.System.Net.Sockets.Socket fd = null, fd1 = null; - - if (IS_NULL(fdObj) && (!ipv6_supported || IS_NULL(fd1Obj))) { - return; - } - - if (!IS_NULL(fdObj)) { - fd = fdObj.getSocket(); - if (fd != null) { - fdObj.setSocket(null); - NET_SocketClose(fd); - } - } - - if (ipv6_supported && fd1Obj != NULL) { - fd1 = fd1Obj.getSocket(); - if (fd1 == null) { - return; - } - fd1Obj.setSocket(null); - NET_SocketClose(fd1); - } -} - -/* - * check the addresses attached to the NetworkInterface object - * and return the first one (of the requested family Ipv4 or Ipv6) - * in *iaddr - */ - -private static int getInetAddrFromIf (JNIEnv env, int family, NetworkInterface nif, InetAddress[] iaddr) -{ - InetAddress[] addrArray; - int len; - InetAddress addr; - int i; - - addrArray = getNetworkInterfaceAddresses(nif); - len = addrArray.length; - - /* - * Check that there is at least one address bound to this - * interface. - */ - if (len < 1) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "bad argument for IP_MULTICAST_IF2: No IP addresses bound to interface"); - return -1; - } - for (i=0; i<len; i++) { - int fam; - addr = addrArray[i]; - fam = getInetAddress_family(env, addr); - if (fam == family) { - iaddr[0] = addr; - return 0; - } - } - return -1; -} - -private static int getInet4AddrFromIf (JNIEnv env, NetworkInterface nif, in_addr iaddr) -{ - InetAddress[] addr = new InetAddress[1]; - - int ret = getInetAddrFromIf (env, IPv4, nif, addr); - if (ret == -1) { - return -1; - } - - iaddr.s_addr = htonl(getInetAddress_addr(env, addr[0])); - return 0; -} - -/* Get the multicasting index from the interface */ - -private static int getIndexFromIf (JNIEnv env, NetworkInterface nif) { - return nif.getIndex(); -} - -private static InetAddress[] getNetworkInterfaceAddresses(final NetworkInterface nif) { - // [IKVM] this is IKVM specific, because I don't want to use reflection (or map.xml hacks) to access the "addrs" member of NetworkInterface - return java.security.AccessController.doPrivileged(new java.security.PrivilegedAction<InetAddress[]>() { - public InetAddress[] run() { - java.util.ArrayList<InetAddress> list = new java.util.ArrayList<InetAddress>(); - for (java.util.Enumeration<InetAddress> e = nif.getInetAddresses(); e.hasMoreElements(); ) { - list.add(e.nextElement()); - } - return list.toArray(new InetAddress[list.size()]); - } - }); -} - -static int isAdapterIpv6Enabled(JNIEnv env, int index) { - return java.security.AccessController.doPrivileged(new java.security.PrivilegedAction<Integer>() { - public Integer run() { - try { - for (java.util.Enumeration<InetAddress> e = NetworkInterface.getByIndex(index).getInetAddresses(); e.hasMoreElements(); ) { - if (e.nextElement() instanceof Inet6Address) { - return 1; - } - } - } catch (SocketException x) { - } - return 0; - } - }).intValue(); -} - -private static NetworkInterface Java_java_net_NetworkInterface_getByIndex(JNIEnv env, int ni_class, int index) -{ - try { - return NetworkInterface.getByIndex(index); - } catch (Exception x) { - env.Throw(x); - return null; - } -} - -private static NetworkInterface Java_java_net_NetworkInterface_getByInetAddress0(JNIEnv env, int ni_class, Object address) -{ - try { - return NetworkInterface.getByInetAddress((InetAddress)address); - } catch (Exception x) { - env.Throw(x); - return null; - } -} - -/* - * Sets the multicast interface. - * - * SocketOptions.IP_MULTICAST_IF (argument is an InetAddress) :- - * IPv4: set outgoing multicast interface using - * IPPROTO_IP/IP_MULTICAST_IF - * - * IPv6: Get the interface to which the - * InetAddress is bound - * and do same as SockOptions.IF_MULTICAST_IF2 - * - * SockOptions.IF_MULTICAST_IF2 (argument is a NetworkInterface ) :- - * For each stack: - * IPv4: Obtain IP address bound to network interface - * (NetworkInterface.addres[0]) - * set outgoing multicast interface using - * IPPROTO_IP/IP_MULTICAST_IF - * - * IPv6: Obtain NetworkInterface.index - * Set outgoing multicast interface using - * IPPROTO_IPV6/IPV6_MULTICAST_IF - * - */ -private static void setMulticastInterface(JNIEnv env, TwoStacksPlainDatagramSocketImpl _this, cli.System.Net.Sockets.Socket fd, cli.System.Net.Sockets.Socket fd1, - int opt, Object value) -{ - boolean ipv6_supported = ipv6_available(); - - if (opt == java_net_SocketOptions_IP_MULTICAST_IF) { - /* - * value is an InetAddress. - * On IPv4 system use IP_MULTICAST_IF socket option - * On IPv6 system get the NetworkInterface that this IP - * address is bound to and use the IPV6_MULTICAST_IF - * option instead of IP_MULTICAST_IF - */ - if (ipv6_supported) { - value = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, value); - if (value == NULL) { - if (env.ExceptionOccurred() == null) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "bad argument for IP_MULTICAST_IF" - +": address not bound to any interface"); - } - return; - } - opt = java_net_SocketOptions_IP_MULTICAST_IF2; - } else { - in_addr in = new in_addr(); - - in.s_addr = htonl(getInetAddress_addr(env, (InetAddress)value)); - - if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, - in) < 0) { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG+"SocketException", - "Error setting socket option"); - } - return; - } - } - - if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) { - /* - * value is a NetworkInterface. - * On IPv6 system get the index of the interface and use the - * IPV6_MULTICAST_IF socket option - * On IPv4 system extract addr[0] and use the IP_MULTICAST_IF - * option. For IPv6 both must be done. - */ - if (ipv6_supported) { - in_addr in = new in_addr(); - int index; - - index = ((NetworkInterface)value).getIndex(); - - if ( isAdapterIpv6Enabled(env, index) != 0 ) { - if (setsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF, - index) < 0) { - if (WSAGetLastError() == WSAEINVAL && index > 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "IPV6_MULTICAST_IF failed (interface has IPv4 " - +"address only?)"); - } else { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG+"SocketException", - "Error setting socket option"); - } - return; - } - } - - /* If there are any IPv4 addresses on this interface then - * repeat the operation on the IPv4 fd */ - - if (getInet4AddrFromIf (env, (NetworkInterface)value, in) < 0) { - return; - } - if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, - in) < 0) { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG+"SocketException", - "Error setting socket option"); - } - return; - } else { - in_addr in = new in_addr(); - - if (getInet4AddrFromIf (env, (NetworkInterface)value, in) < 0) { - if (env.ExceptionOccurred() != null) { - return; - } - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "no InetAddress instances of requested type"); - return; - } - - if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, - in) < 0) { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG+"SocketException", - "Error setting socket option"); - } - return; - } - } -} - -/* - * Class: java_net_TwoStacksPlainDatagramSocketImpl - * Method: socketNativeSetOption - * Signature: (ILjava/lang/Object;)V - */ -static void socketNativeSetOption(JNIEnv env, TwoStacksPlainDatagramSocketImpl _this, int opt, Object value) { - cli.System.Net.Sockets.Socket fd = null; - cli.System.Net.Sockets.Socket fd1 = null; - int[] levelv4 = new int[1]; - int[] levelv6 = new int[1]; - int[] optnamev4 = new int[1]; - int[] optnamev6 = new int[1]; - Object optval; - boolean ipv6_supported = ipv6_available(); - - fd = getFD(env, _this); - - if (ipv6_supported) { - fd1 = getFD1(env, _this); - } - if (fd == null && fd1 == null) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "socket closed"); - return; - } - - if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) || - (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) { - - setMulticastInterface(env, _this, fd, fd1, opt, value); - return; - } - - /* - * Map the Java level socket option to the platform specific - * level(s) and option name(s). - */ - if (fd1 != null) { - if (NET_MapSocketOptionV6(opt, levelv6, optnamev6) != 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "Invalid option"); - return; - } - } - if (fd != null) { - if (NET_MapSocketOption(opt, levelv4, optnamev4) != 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "Invalid option"); - return; - } - } - - switch (opt) { - case java_net_SocketOptions_SO_SNDBUF : - case java_net_SocketOptions_SO_RCVBUF : - case java_net_SocketOptions_IP_TOS : - optval = ((Integer)value).intValue(); - break; - - case java_net_SocketOptions_SO_REUSEADDR: - case java_net_SocketOptions_SO_BROADCAST: - case java_net_SocketOptions_IP_MULTICAST_LOOP: - { - boolean on = ((Boolean)value).booleanValue(); - optval = on; - /* - * setLoopbackMode (true) disables IP_MULTICAST_LOOP rather - * than enabling it. - */ - if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP) { - optval = !on; - } - } - break; - - default : - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Socket option not supported by PlainDatagramSocketImp"); - return; - } - - if (fd1 != null) { - if (NET_SetSockOpt(fd1, levelv6[0], optnamev6[0], optval) < 0) { - NET_ThrowCurrent(env, "setsockopt IPv6"); - return; - } - } - if (fd != null) { - if (NET_SetSockOpt(fd, levelv4[0], optnamev4[0], optval) < 0) { - NET_ThrowCurrent(env, "setsockopt"); - return; - } - } -} - -/* - * - * called by getMulticastInterface to retrieve a NetworkInterface - * configured for IPv4. - * The ipv4Mode parameter, is a closet boolean, which allows for a NULL return, - * or forces the creation of a NetworkInterface object with null data. - * It relates to its calling context in getMulticastInterface. - * ipv4Mode == 1, the context is IPV4 processing only. - * ipv4Mode == 0, the context is IPV6 processing - * - *-/ -static jobject getIPv4NetworkInterface (JNIEnv *env, jobject this, int fd, jint opt, int ipv4Mode) { - static jclass inet4_class; - static jmethodID inet4_ctrID; - - static jclass ni_class; static jmethodID ni_ctrID; - static jfieldID ni_indexID; - static jfieldID ni_addrsID; - - jobjectArray addrArray; - jobject addr; - jobject ni; - - struct in_addr in; - struct in_addr *inP = ∈ - int len = sizeof(struct in_addr); - if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, - (char *)inP, &len) < 0) { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "Error getting socket option"); - return NULL; - } - - /* - * Construct and populate an Inet4Address - *-/ - if (inet4_class == NULL) { - jclass c = (*env)->FindClass(env, "java/net/Inet4Address"); - CHECK_NULL_RETURN(c, NULL); - inet4_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V"); - CHECK_NULL_RETURN(inet4_ctrID, NULL); - inet4_class = (*env)->NewGlobalRef(env, c); - CHECK_NULL_RETURN(inet4_class, NULL); - } - addr = (*env)->NewObject(env, inet4_class, inet4_ctrID, 0); - CHECK_NULL_RETURN(addr, NULL); - - setInetAddress_addr(env, addr, ntohl(in.s_addr)); - - /* - * For IP_MULTICAST_IF return InetAddress - *-/ - if (opt == java_net_SocketOptions_IP_MULTICAST_IF) { - return addr; - } - - /* - * For IP_MULTICAST_IF2 we get the NetworkInterface for - * this address and return it - *-/ - if (ni_class == NULL) { - jclass c = (*env)->FindClass(env, "java/net/NetworkInterface"); - CHECK_NULL_RETURN(c, NULL); - ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V"); - CHECK_NULL_RETURN(ni_ctrID, NULL); - ni_indexID = (*env)->GetFieldID(env, c, "index", "I"); - CHECK_NULL_RETURN(ni_indexID, NULL); - ni_addrsID = (*env)->GetFieldID(env, c, "addrs", - "[Ljava/net/InetAddress;"); - CHECK_NULL_RETURN(ni_addrsID, NULL); - ni_class = (*env)->NewGlobalRef(env, c); - CHECK_NULL_RETURN(ni_class, NULL); - } - ni = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, addr); - if (ni) { - return ni; - } - if (ipv4Mode) { - ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0); - CHECK_NULL_RETURN(ni, NULL); - - (*env)->SetIntField(env, ni, ni_indexID, -1); - addrArray = (*env)->NewObjectArray(env, 1, inet4_class, NULL); - CHECK_NULL_RETURN(addrArray, NULL); - (*env)->SetObjectArrayElement(env, addrArray, 0, addr); - (*env)->SetObjectField(env, ni, ni_addrsID, addrArray); - } else { - ni = NULL; - } - return ni; -} - -/* - * Return the multicast interface: - * - * SocketOptions.IP_MULTICAST_IF - * IPv4: Query IPPROTO_IP/IP_MULTICAST_IF - * Create InetAddress - * IP_MULTICAST_IF returns struct ip_mreqn on 2.2 - * kernel but struct in_addr on 2.4 kernel - * IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF or - * obtain from impl is Linux 2.2 kernel - * If index == 0 return InetAddress representing - * anyLocalAddress. - * If index > 0 query NetworkInterface by index - * and returns addrs[0] - * - * SocketOptions.IP_MULTICAST_IF2 - * IPv4: Query IPPROTO_IP/IP_MULTICAST_IF - * Query NetworkInterface by IP address and - * return the NetworkInterface that the address - * is bound too. - * IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF - * (except Linux .2 kernel) - * Query NetworkInterface by index and - * return NetworkInterface. - */ -private static Object getMulticastInterface(JNIEnv env, TwoStacksPlainDatagramSocketImpl _this, cli.System.Net.Sockets.Socket fd, cli.System.Net.Sockets.Socket fd1, int opt) { - boolean isIPV4 = !ipv6_available() || fd1 == null; - - /* - * IPv4 implementation - */ - if (isIPV4) { - Inet4Address addr; - - in_addr in = new in_addr(); - - if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, - in) < 0) { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG+"SocketException", - "Error getting socket option"); - return NULL; - } - - /* - * Construct and populate an Inet4Address - */ - addr = new Inet4Address(); - addr.holder().address = ntohl(in.s_addr); - - /* - * For IP_MULTICAST_IF return InetAddress - */ - if (opt == java_net_SocketOptions_IP_MULTICAST_IF) { - return addr; - } - - NetworkInterface ni; - ni = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, addr); - if (ni != null) { - return ni; - } - - /* - * The address doesn't appear to be bound at any known - * NetworkInterface. Therefore we construct a NetworkInterface - * with this address. - */ - return new NetworkInterface(null, -1, new InetAddress[] { addr }); - } - - - /* - * IPv6 implementation - */ - if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) || - (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) { - - int index; - - InetAddress[] addrArray; - InetAddress addr; - NetworkInterface ni; - - { - int[] tmp = { 0 }; - if (getsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF, - tmp) < 0) { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG+"SocketException", - "Error getting socket option"); - return NULL; - } - index = tmp[0]; - } - - /* - * If multicast to a specific interface then return the - * interface (for IF2) or the any address on that interface - * (for IF). - */ - if (index > 0) { - ni = Java_java_net_NetworkInterface_getByIndex(env, ni_class, - index); - if (ni == NULL) { - String errmsg = "IPV6_MULTICAST_IF returned index to unrecognized interface: " + index; - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", errmsg); - return NULL; - } - - /* - * For IP_MULTICAST_IF2 return the NetworkInterface - */ - if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) { - return ni; - } - - /* - * For IP_MULTICAST_IF return addrs[0] - */ - addrArray = getNetworkInterfaceAddresses(ni); - if (addrArray.length < 1) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "IPV6_MULTICAST_IF returned interface without IP bindings"); - return NULL; - } - - addr = addrArray[0]; - return addr; - } - - /* - * Multicast to any address - return anyLocalAddress - * or a NetworkInterface with addrs[0] set to anyLocalAddress - */ - - addr = InetAddress.anyLocalAddress(); - if (opt == java_net_SocketOptions_IP_MULTICAST_IF) { - return addr; - } - - return new NetworkInterface(null, -1, new InetAddress[] { addr }); - } - return NULL; -} -/* - * Returns relevant info as a jint. - * - * Class: java_net_TwoStacksPlainDatagramSocketImpl - * Method: socketGetOption - * Signature: (I)Ljava/lang/Object; - */ -static Object socketGetOption(JNIEnv env, TwoStacksPlainDatagramSocketImpl _this, int opt) { - cli.System.Net.Sockets.Socket fd = null; - cli.System.Net.Sockets.Socket fd1 = null; - int[] level = new int[1]; - int[] optname = new int[1]; - int[] optval = new int[1]; - boolean ipv6_supported = ipv6_available(); - - fd = getFD(env, _this); - if (ipv6_supported) { - fd1 = getFD1(env, _this); - } - - if (fd == null && fd1 == null) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Socket closed"); - return NULL; - } - - /* - * Handle IP_MULTICAST_IF separately - */ - if (opt == java_net_SocketOptions_IP_MULTICAST_IF || - opt == java_net_SocketOptions_IP_MULTICAST_IF2) { - return getMulticastInterface(env, _this, fd, fd1, opt); - } - - /* - * Map the Java level socket option to the platform specific - * level and option name. - */ - if (NET_MapSocketOption(opt, level, optname) != 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "Invalid option"); - return NULL; - } - - if (fd == null) { - if (NET_MapSocketOptionV6(opt, level, optname) != 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "Invalid option"); - return NULL; - } - fd = fd1; /* must be IPv6 only */ - } - - if (NET_GetSockOpt(fd, level[0], optname[0], optval) < 0) { - String errmsg = "error getting socket option: " + WSAGetLastError(); - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", errmsg); - return NULL; - } - - switch (opt) { - case java_net_SocketOptions_SO_BROADCAST: - case java_net_SocketOptions_SO_REUSEADDR: - return optval[0] != 0; - - case java_net_SocketOptions_IP_MULTICAST_LOOP: - /* getLoopbackMode() returns true if IP_MULTICAST_LOOP is disabled */ - return optval[0] == 0; - - case java_net_SocketOptions_SO_SNDBUF: - case java_net_SocketOptions_SO_RCVBUF: - case java_net_SocketOptions_IP_TOS: - return optval[0]; - - default : - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Socket option not supported by TwoStacksPlainDatagramSocketImpl"); - return NULL; - - } -} - -/* - * Returns local address of the socket. - * - * Class: java_net_TwoStacksPlainDatagramSocketImpl - * Method: socketLocalAddress - * Signature: (I)Ljava/lang/Object; - */ -static Object socketLocalAddress(JNIEnv env, TwoStacksPlainDatagramSocketImpl _this, - int family) { - cli.System.Net.Sockets.Socket fd = null; - cli.System.Net.Sockets.Socket fd1 = null; - SOCKETADDRESS him; - him = new SOCKETADDRESS(); - Object iaObj; - boolean ipv6_supported = ipv6_available(); - - fd = getFD(env, _this); - if (ipv6_supported) { - fd1 = getFD1(env, _this); - } - - if (fd == null && fd1 == null) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Socket closed"); - return NULL; - } - - /* find out local IP address */ - - /* family==-1 when socket is not connected */ - if ((family == IPv6) || (family == -1 && fd == null)) { - fd = fd1; /* must be IPv6 only */ - } - - if (fd == null) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Socket closed"); - return NULL; - } - - if (getsockname(fd, him) == -1) { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG+"SocketException", - "Error getting socket name"); - return NULL; - } - iaObj = NET_SockaddrToInetAddress(him, new int[1]); - - return iaObj; -} - -/* - * Class: java_net_TwoStacksPlainDatagramSocketImpl - * Method: setTimeToLive - * Signature: (I)V - */ -static void setTimeToLive(JNIEnv env, TwoStacksPlainDatagramSocketImpl _this, int ttl) { - FileDescriptor fdObj = _this.fd; - FileDescriptor fd1Obj = _this.fd1; - cli.System.Net.Sockets.Socket fd = null; - cli.System.Net.Sockets.Socket fd1 = null; - - if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Socket closed"); - return; - } else { - if (!IS_NULL(fdObj)) { - fd = fdObj.getSocket(); - } - if (!IS_NULL(fd1Obj)) { - fd1 = fd1Obj.getSocket(); - } - } - - /* setsockopt to be correct ttl */ - if (fd != null) { - if (NET_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, ttl) < 0) { - NET_ThrowCurrent(env, "set IP_MULTICAST_TTL failed"); - } - } - - if (fd1 != null) { - if (NET_SetSockOpt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, ttl) <0) { - NET_ThrowCurrent(env, "set IPV6_MULTICAST_HOPS failed"); - } - } -} - -/* - * Class: java_net_TwoStacksPlainDatagramSocketImpl - * Method: setTTL - * Signature: (B)V - */ -static void setTTL(JNIEnv env, TwoStacksPlainDatagramSocketImpl _this, byte ttl) { - setTimeToLive(env, _this, ttl & 0xFF); -} - -/* - * Class: java_net_TwoStacksPlainDatagramSocketImpl - * Method: getTimeToLive - * Signature: ()I - */ -static int getTimeToLive(JNIEnv env, TwoStacksPlainDatagramSocketImpl _this) { - FileDescriptor fdObj = _this.fd; - FileDescriptor fd1Obj = _this.fd1; - cli.System.Net.Sockets.Socket fd = null; - cli.System.Net.Sockets.Socket fd1 = null; - int[] ttl = new int[1]; - - if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Socket closed"); - return -1; - } else { - if (!IS_NULL(fdObj)) { - fd = fdObj.getSocket(); - } - if (!IS_NULL(fd1Obj)) { - fd1 = fd1Obj.getSocket(); - } - } - - /* getsockopt of ttl */ - if (fd != null) { - if (NET_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, ttl) < 0) { - NET_ThrowCurrent(env, "get IP_MULTICAST_TTL failed"); - return -1; - } - return ttl[0]; - } - if (fd1 != null) { - if (NET_GetSockOpt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, ttl) < 0) { - NET_ThrowCurrent(env, "get IP_MULTICAST_TTL failed"); - return -1; - } - return ttl[0]; - } - return -1; -} - -/* - * Class: java_net_TwoStacksPlainDatagramSocketImpl - * Method: getTTL - * Signature: ()B - */ -static byte getTTL(JNIEnv env, TwoStacksPlainDatagramSocketImpl _this) { - int result = getTimeToLive(env, _this); - - return (byte)result; -} - -/* join/leave the named group on the named interface, or if no interface specified - * then the interface set with setInterfac(), or the default interface otherwise */ - -private static void mcast_join_leave(JNIEnv env, TwoStacksPlainDatagramSocketImpl _this, InetAddress iaObj, NetworkInterface niObj, boolean join) -{ - FileDescriptor fdObj = _this.fd; - FileDescriptor fd1Obj = _this.fd1; - cli.System.Net.Sockets.Socket fd = null; - cli.System.Net.Sockets.Socket fd1 = null; - - SOCKETADDRESS name; - name = new SOCKETADDRESS(); - ip_mreq mname = new ip_mreq(); - ipv6_mreq mname6 = new ipv6_mreq(); - - in_addr in = new in_addr(); - int ifindex; - - int family; - boolean ipv6_supported = ipv6_available(); - int cmd ; - - if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Socket closed"); - return; - } - if (!IS_NULL(fdObj)) { - fd = fdObj.getSocket(); - } - if (ipv6_supported && !IS_NULL(fd1Obj)) { - fd1 = fd1Obj.getSocket(); - } - - if (IS_NULL(iaObj)) { - JNU_ThrowNullPointerException(env, "address"); - return; - } - - if (NET_InetAddressToSockaddr(env, iaObj, 0, name, JNI_FALSE) != 0) { - return; - } - - /* Set the multicast group address in the ip_mreq field - * eventually this check should be done by the security manager - */ - family = name.him.sa_family; - - if (family == AF_INET) { - int address = name.him4.sin_addr.s_addr; - if (!IN_MULTICAST(ntohl(address))) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "not in multicast"); - return; - } - mname.imr_multiaddr.s_addr = address; - if (fd == null) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "Can't join an IPv4 group on an IPv6 only socket"); - return; - } - if (IS_NULL(niObj)) { - if (NET_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF, in) < 0) { - NET_ThrowCurrent(env, "get IP_MULTICAST_IF failed"); - return; - } - mname.imr_interface.s_addr = in.s_addr; - } else { - if (getInet4AddrFromIf (env, niObj, mname.imr_interface) != 0) { - NET_ThrowCurrent(env, "no Inet4Address associated with interface"); - return; - } - } - - cmd = join ? IP_ADD_MEMBERSHIP: IP_DROP_MEMBERSHIP; - - /* Join the multicast group */ - if (NET_SetSockOpt(fd, IPPROTO_IP, cmd, mname) < 0) { - if (WSAGetLastError() == WSAENOBUFS) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "IP_ADD_MEMBERSHIP failed (out of hardware filters?)"); - } else { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException","error setting options"); - } - } - } else /* AF_INET6 */ { - if (ipv6_supported) { - in6_addr address; - address = in6_addr.FromSockAddr(name); - if (!IN6_IS_ADDR_MULTICAST(address)) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "not in6 multicast"); - return; - } - mname6.ipv6mr_multiaddr = address; - } else { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "IPv6 not supported"); - return; - } - if (fd1 == null) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "Can't join an IPv6 group on a IPv4 socket"); - return; - } - if (IS_NULL(niObj)) { - int[] tmp = { 0 }; - if (NET_GetSockOpt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF, tmp) < 0) { - NET_ThrowCurrent(env, "get IPV6_MULTICAST_IF failed"); - return; - } - ifindex = tmp[0]; - } else { - ifindex = getIndexFromIf (env, niObj); - if (ifindex == -1) { - NET_ThrowCurrent(env, "get ifindex failed"); - return; - } - } - mname6.ipv6mr_interface = ifindex; - cmd = join ? IPV6_ADD_MEMBERSHIP: IPV6_DROP_MEMBERSHIP; - - /* Join the multicast group */ - if (NET_SetSockOpt(fd1, IPPROTO_IPV6, cmd, mname6) < 0) { - if (WSAGetLastError() == WSAENOBUFS) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "IP_ADD_MEMBERSHIP failed (out of hardware filters?)"); - } else { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException","error setting options"); - } - } - } - - return; -} - -/* - * Class: java_net_TwoStacksPlainDatagramSocketImpl - * Method: join - * Signature: (Ljava/net/InetAddress;)V - */ -static void join(JNIEnv env, TwoStacksPlainDatagramSocketImpl _this, InetAddress inetaddr, NetworkInterface netIf) { - mcast_join_leave(env, _this, inetaddr, netIf, true); -} - -/* - * Class: java_net_TwoStacksPlainDatagramSocketImpl - * Method: leave - * Signature: (Ljava/net/InetAddress;)V - */ -static void leave(JNIEnv env, TwoStacksPlainDatagramSocketImpl _this, InetAddress inetaddr, NetworkInterface netIf) { - mcast_join_leave(env, _this, inetaddr, netIf, false); -} - -} diff --git a/openjdk/java/net/TwoStacksPlainSocketImpl.java b/openjdk/java/net/TwoStacksPlainSocketImpl.java deleted file mode 100644 index 12c1794f..00000000 --- a/openjdk/java/net/TwoStacksPlainSocketImpl.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright (c) 2007, 2008, 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.IOException; -import java.io.FileDescriptor; -import sun.net.ResourceManager; - -/* - * This class defines the plain SocketImpl that is used for all - * Windows version lower than Vista. It adds support for IPv6 on - * these platforms where available. - * - * For backward compatibility Windows platforms that do not have IPv6 - * support also use this implementation, and fd1 gets set to null - * during socket creation. - * - * @author Chris Hegarty - */ - -class TwoStacksPlainSocketImpl extends AbstractPlainSocketImpl -{ - /* second fd, used for ipv6 on windows only. - * fd1 is used for listeners and for client sockets at initialization - * until the socket is connected. Up to this point fd always refers - * to the ipv4 socket and fd1 to the ipv6 socket. After the socket - * becomes connected, fd always refers to the connected socket - * (either v4 or v6) and fd1 is closed. - * - * For ServerSockets, fd always refers to the v4 listener and - * fd1 the v6 listener. - */ - FileDescriptor fd1; - - /* - * Needed for ipv6 on windows because we need to know - * if the socket is bound to ::0 or 0.0.0.0, when a caller - * asks for it. Otherwise we don't know which socket to ask. - */ - private InetAddress anyLocalBoundAddr = null; - - /* to prevent starvation when listening on two sockets, this is - * is used to hold the id of the last socket we accepted on. - */ - cli.System.Net.Sockets.Socket lastfd = null; - - // true if this socket is exclusively bound - private final boolean exclusiveBind; - - // emulates SO_REUSEADDR when exclusiveBind is true - private boolean isReuseAddress; - - - public TwoStacksPlainSocketImpl(boolean exclBind) { - exclusiveBind = exclBind; - } - - public TwoStacksPlainSocketImpl(FileDescriptor fd, boolean exclBind) { - this.fd = fd; - exclusiveBind = exclBind; - } - - /** - * Creates a socket with a boolean that specifies whether this - * is a stream socket (true) or an unconnected UDP socket (false). - */ - protected synchronized void create(boolean stream) throws IOException { - fd1 = new FileDescriptor(); - try { - super.create(stream); - } catch (IOException e) { - fd1 = null; - throw e; - } - } - - /** - * Binds the socket to the specified address of the specified local port. - * @param address the address - * @param port the port - */ - protected synchronized void bind(InetAddress address, int lport) - throws IOException - { - super.bind(address, lport); - if (address.isAnyLocalAddress()) { - anyLocalBoundAddr = address; - } - } - - public Object getOption(int opt) throws SocketException { - if (isClosedOrPending()) { - throw new SocketException("Socket Closed"); - } - if (opt == SO_BINDADDR) { - if (fd != null && fd1 != null ) { - /* must be unbound or else bound to anyLocal */ - return anyLocalBoundAddr; - } - InetAddressContainer in = new InetAddressContainer(); - socketGetOption(opt, in); - return in.addr; - } else if (opt == SO_REUSEADDR && exclusiveBind) { - // SO_REUSEADDR emulated when using exclusive bind - return isReuseAddress; - } else - return super.getOption(opt); - } - - @Override - void socketBind(InetAddress address, int port) throws IOException { - socketBind(address, port, exclusiveBind); - } - - @Override - void socketSetOption(int opt, boolean on, Object value) - throws SocketException - { - // SO_REUSEADDR emulated when using exclusive bind - if (opt == SO_REUSEADDR && exclusiveBind) - isReuseAddress = on; - else - socketNativeSetOption(opt, on, value); - } - - /** - * Closes the socket. - */ - @Override - protected void close() throws IOException { - synchronized(fdLock) { - if (fd != null || fd1 != null) { - if (!stream) { - ResourceManager.afterUdpClose(); - } - if (fdUseCount == 0) { - if (closePending) { - return; - } - closePending = true; - socketClose(); - fd = null; - fd1 = null; - return; - } else { - /* - * If a thread has acquired the fd and a close - * isn't pending then use a deferred close. - * Also decrement fdUseCount to signal the last - * thread that releases the fd to close it. - */ - if (!closePending) { - closePending = true; - fdUseCount--; - socketClose(); - } - } - } - } - } - - @Override - void reset() throws IOException { - if (fd != null || fd1 != null) { - socketClose(); - } - fd = null; - fd1 = null; - super.reset(); - } - - /* - * Return true if already closed or close is pending - */ - @Override - public boolean isClosedOrPending() { - /* - * Lock on fdLock to ensure that we wait if a - * close is in progress. - */ - synchronized (fdLock) { - if (closePending || (fd == null && fd1 == null)) { - return true; - } else { - return false; - } - } - } - - /* Native methods */ - - void socketCreate(boolean stream) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - TwoStacksPlainSocketImpl_c.socketCreate(env, this, stream); - env.ThrowPendingException(); - } - - void socketConnect(InetAddress address, int port, int timeout) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - TwoStacksPlainSocketImpl_c.socketConnect(env, this, address, port, timeout); - env.ThrowPendingException(); - } - - void socketBind(InetAddress address, int localport, boolean exclBind) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - TwoStacksPlainSocketImpl_c.socketBind(env, this, address, localport, exclBind); - env.ThrowPendingException(); - } - - void socketListen(int count) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - TwoStacksPlainSocketImpl_c.socketListen(env, this, count); - env.ThrowPendingException(); - } - - void socketAccept(SocketImpl socket) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - TwoStacksPlainSocketImpl_c.socketAccept(env, this, socket); - env.ThrowPendingException(); - } - - int socketAvailable() throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - int ret = TwoStacksPlainSocketImpl_c.socketAvailable(env, this); - env.ThrowPendingException(); - return ret; - } - - void socketClose0(boolean useDeferredClose) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - TwoStacksPlainSocketImpl_c.socketClose0(env, this, useDeferredClose); - env.ThrowPendingException(); - } - - void socketShutdown(int howto) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - TwoStacksPlainSocketImpl_c.socketShutdown(env, this, howto); - env.ThrowPendingException(); - } - - void socketNativeSetOption(int cmd, boolean on, Object value) throws SocketException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - TwoStacksPlainSocketImpl_c.socketNativeSetOption(env, this, cmd, on, value); - env.ThrowPendingException(); - } - - int socketGetOption(int opt, Object iaContainerObj) throws SocketException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - int ret = TwoStacksPlainSocketImpl_c.socketGetOption(env, this, opt, iaContainerObj); - env.ThrowPendingException(); - return ret; - } - - int socketGetOption1(int opt, Object iaContainerObj, FileDescriptor fd) throws SocketException { - throw new UnsatisfiedLinkError(); - } - - void socketSendUrgentData(int data) throws IOException { - ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); - TwoStacksPlainSocketImpl_c.socketSendUrgentData(env, this, data); - env.ThrowPendingException(); - } -} diff --git a/openjdk/java/net/TwoStacksPlainSocketImpl_c.java b/openjdk/java/net/TwoStacksPlainSocketImpl_c.java deleted file mode 100644 index d86e84d0..00000000 --- a/openjdk/java/net/TwoStacksPlainSocketImpl_c.java +++ /dev/null @@ -1,1080 +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 java.net; - -import java.io.FileDescriptor; -import static ikvm.internal.JNI.*; -import static ikvm.internal.Winsock.*; -import static java.net.net_util_md.*; -import static java.net.InetAddress.IPv4; -import static java.net.InetAddress.IPv6; - -final class TwoStacksPlainSocketImpl_c -{ -static final int JVM_IO_ERR = -1; -static final int JVM_IO_INTR = -2; - -static final int java_net_SocketOptions_SO_TIMEOUT = SocketOptions.SO_TIMEOUT; -static final int java_net_SocketOptions_SO_BINDADDR = SocketOptions.SO_BINDADDR; -static final int java_net_SocketOptions_SO_SNDBUF = SocketOptions.SO_SNDBUF; -static final int java_net_SocketOptions_SO_RCVBUF = SocketOptions.SO_RCVBUF; -static final int java_net_SocketOptions_IP_TOS = SocketOptions.IP_TOS; -static final int java_net_SocketOptions_SO_REUSEADDR = SocketOptions.SO_REUSEADDR; -static final int java_net_SocketOptions_TCP_NODELAY = SocketOptions.TCP_NODELAY; -static final int java_net_SocketOptions_SO_OOBINLINE = SocketOptions.SO_OOBINLINE; -static final int java_net_SocketOptions_SO_KEEPALIVE = SocketOptions.SO_KEEPALIVE; -static final int java_net_SocketOptions_SO_LINGER = SocketOptions.SO_LINGER; - -/* -#include <windows.h> -#include <winsock2.h> -#include <ctype.h> -#include <stdio.h> -#include <stdlib.h> -#include <malloc.h> -#include <sys/types.h> - -#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" - -#include "jvm.h" -#include "net_util.h" -#include "jni_util.h" -*/ - -/************************************************************************ - * TwoStacksPlainSocketImpl - */ - -/* -static jfieldID IO_fd_fdID; - -jfieldID psi_fdID; -jfieldID psi_fd1ID; -jfieldID psi_addressID; -jfieldID psi_portID; -jfieldID psi_localportID; -jfieldID psi_timeoutID; -jfieldID psi_trafficClassID; -jfieldID psi_serverSocketID; -jfieldID psi_lastfdID; -*/ - -/* - * the level of the TCP protocol for setsockopt and getsockopt - * we only want to look this up once, from the static initializer - * of TwoStacksPlainSocketImpl - */ -static int tcp_level = -1; - -static cli.System.Net.Sockets.Socket getFD(JNIEnv env, TwoStacksPlainSocketImpl _this) { - FileDescriptor fdObj = _this.fd; - - if (fdObj == NULL) { - return null; - } - return fdObj.getSocket(); -} - -static cli.System.Net.Sockets.Socket getFD1(JNIEnv env, TwoStacksPlainSocketImpl _this) { - FileDescriptor fdObj = _this.fd1; - - if (fdObj == NULL) { - return null; - } - return fdObj.getSocket(); -} - - -/* - * The initProto function is called whenever TwoStacksPlainSocketImpl is - * loaded, to cache fieldIds for efficiency. This is called everytime - * the Java class is loaded. - * - * Class: java_net_TwoStacksPlainSocketImpl - * Method: initProto - - * Signature: ()V - */ -/* -JNIEXPORT void JNICALL -Java_java_net_TwoStacksPlainSocketImpl_initProto(JNIEnv *env, jclass cls) { - - struct protoent *proto = getprotobyname("TCP"); - tcp_level = (proto == 0 ? IPPROTO_TCP: proto->p_proto); - - psi_fdID = (*env)->GetFieldID(env, cls , "fd", "Ljava/io/FileDescriptor;"); - CHECK_NULL(psi_fdID); - psi_fd1ID =(*env)->GetFieldID(env, cls , "fd1", "Ljava/io/FileDescriptor;"); - CHECK_NULL(psi_fd1ID); - psi_addressID = (*env)->GetFieldID(env, cls, "address", - "Ljava/net/InetAddress;"); - CHECK_NULL(psi_addressID); - psi_portID = (*env)->GetFieldID(env, cls, "port", "I"); - CHECK_NULL(psi_portID); - psi_lastfdID = (*env)->GetFieldID(env, cls, "lastfd", "I"); - CHECK_NULL(psi_portID); - psi_localportID = (*env)->GetFieldID(env, cls, "localport", "I"); - CHECK_NULL(psi_localportID); - psi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I"); - CHECK_NULL(psi_timeoutID); - psi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I"); - CHECK_NULL(psi_trafficClassID); - psi_serverSocketID = (*env)->GetFieldID(env, cls, "serverSocket", - "Ljava/net/ServerSocket;"); - CHECK_NULL(psi_serverSocketID); - IO_fd_fdID = NET_GetFileDescriptorID(env); - CHECK_NULL(IO_fd_fdID); -} -*/ - -/* - * Class: java_net_TwoStacksPlainSocketImpl - * Method: socketCreate - * Signature: (Z)V - */ -static void socketCreate(JNIEnv env, TwoStacksPlainSocketImpl _this, boolean stream) { - FileDescriptor fdObj = _this.fd; - FileDescriptor fd1Obj = _this.fd1; - cli.System.Net.Sockets.Socket fd = null; - cli.System.Net.Sockets.Socket fd1 = null; - - if (IS_NULL(fdObj)) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "null fd object"); - return; - } - fd = socket(AF_INET, (stream ? SOCK_STREAM: SOCK_DGRAM), 0); - if (fd == INVALID_SOCKET) { - NET_ThrowCurrent(env, "create"); - return; - } else { - /* Set socket attribute so it is not passed to any child process */ - //SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE); - fdObj.setSocket(fd); - } - if (ipv6_available()) { - - if (IS_NULL(fd1Obj)) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "null fd1 object"); - fdObj.setSocket(null); - NET_SocketClose(fd); - return; - } - fd1 = socket(AF_INET6, (stream ? SOCK_STREAM: SOCK_DGRAM), 0); - if (fd1 == INVALID_SOCKET) { - NET_ThrowCurrent(env, "create"); - fdObj.setSocket(null); - NET_SocketClose(fd); - return; - } else { - fd1Obj.setSocket(fd1); - } - } else { - _this.fd1 = null; - } -} - -/* - * inetAddress is the address object passed to the socket connect - * call. - * - * Class: java_net_TwoStacksPlainSocketImpl - * Method: socketConnect - * Signature: (Ljava/net/InetAddress;I)V - */ -static void socketConnect(JNIEnv env, TwoStacksPlainSocketImpl _this, InetAddress iaObj, int port, int timeout) -{ - int localport = _this.localport; - - /* family and localport are int fields of iaObj */ - int family; - cli.System.Net.Sockets.Socket fd = null; - cli.System.Net.Sockets.Socket fd1 = null; - boolean ipv6_supported = ipv6_available(); - - /* fd initially points to the IPv4 socket and fd1 to the IPv6 socket - * If we want to connect to IPv6 then we swap the two sockets/objects - * This way, fd is always the connected socket, and fd1 always gets closed. - */ - FileDescriptor fdObj = _this.fd; - FileDescriptor fd1Obj = _this.fd1; - - SOCKETADDRESS him; - him = new SOCKETADDRESS(); - - /* The result of the connection */ - int connect_res; - - if (!IS_NULL(fdObj)) { - fd = fdObj.getSocket(); - } - - if (ipv6_supported && !IS_NULL(fd1Obj)) { - fd1 = fd1Obj.getSocket(); - } - - if (IS_NULL(iaObj)) { - JNU_ThrowNullPointerException(env, "inet address argument is null."); - return; - } - - if (NET_InetAddressToSockaddr(env, iaObj, port, him, JNI_FALSE) != 0) { - return; - } - - family = him.him.sa_family; - if (family == AF_INET6) { - if (!ipv6_supported) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Protocol family not supported"); - return; - } else { - if (fd1 == null) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Destination unreachable"); - return; - } - /* close the v4 socket, and set fd to be the v6 socket */ - _this.fd = fd1Obj; - _this.fd1 = null; - NET_SocketClose(fd); - fd = fd1; fdObj = fd1Obj; - } - } else { - if (fd1 != null) { - fd1Obj.setSocket(null); - NET_SocketClose(fd1); - } - if (fd == null) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Destination unreachable"); - return; - } - } - _this.fd1 = null; - - if (timeout <= 0) { - connect_res = connect(fd, him); - if (connect_res == SOCKET_ERROR) { - connect_res = WSAGetLastError(); - } - } else { - int optval; - - /* make socket non-blocking */ - optval = 1; - ioctlsocket( fd, FIONBIO, optval ); - - /* initiate the connect */ - connect_res = connect(fd, him); - if (connect_res == SOCKET_ERROR) { - if (WSAGetLastError() != WSAEWOULDBLOCK) { - connect_res = WSAGetLastError(); - } else { - fd_set wr, ex; - wr = new fd_set(); ex = new fd_set(); - timeval t = new timeval(); - - FD_ZERO(wr); - FD_ZERO(ex); - FD_SET(fd, wr); - FD_SET(fd, ex); - t.tv_sec = timeout / 1000; - t.tv_usec = (timeout % 1000) * 1000; - - /* - * Wait for timout, connection established or - * connection failed. - */ - connect_res = select(null, wr, ex, t); - - /* - * Timeout before connection is established/failed so - * we throw exception and shutdown input/output to prevent - * socket from being used. - * The socket should be closed immediately by the caller. - */ - if (connect_res == 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketTimeoutException", - "connect timed out"); - shutdown( fd, SD_BOTH ); - - /* make socket blocking again - just in case */ - optval = 0; - ioctlsocket( fd, FIONBIO, optval ); - return; - } - - /* - * We must now determine if the connection has been established - * or if it has failed. The logic here is designed to work around - * bug on Windows NT whereby using getsockopt to obtain the - * last error (SO_ERROR) indicates there is no error. The workaround - * on NT is to allow winsock to be scheduled and this is done by - * yielding and retrying. As yielding is problematic in heavy - * load conditions we attempt up to 3 times to get the error reason. - */ - if (!FD_ISSET(fd, ex)) { - connect_res = 0; - } else { - int retry; - for (retry=0; retry<3; retry++) { - int[] tmp = { 0 }; - NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, - tmp); - connect_res = tmp[0]; - if (connect_res != 0) { - break; - } - Sleep(0); - } - - if (connect_res == 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Unable to establish connection"); - return; - } - } - } - } - - /* make socket blocking again */ - optval = 0; - ioctlsocket(fd, FIONBIO, optval); - } - - if (connect_res != 0) { - if (connect_res == WSAEADDRNOTAVAIL) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"ConnectException", - "connect: Address is invalid on local machine, or port is not valid on remote machine"); - } else { - NET_ThrowNew(env, connect_res, "connect"); - } - return; - } - - fdObj.setSocket(fd); - - /* set the remote peer address and port */ - _this.address = iaObj; - _this.port = port; - - /* - * we need to initialize the local port field if bind was called - * previously to the connect (by the client) then localport field - * will already be initialized - */ - if (localport == 0) { - /* Now that we're a connected socket, let's extract the port number - * that the system chose for us and store it in the Socket object. - */ - if (getsockname(fd, him) == -1) { - - if (WSAGetLastError() == WSAENOTSOCK) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Socket closed"); - } else { - NET_ThrowCurrent(env, "getsockname failed"); - } - return; - } - port = ntohs (GET_PORT(him)); - _this.localport = port; - } -} - -/* - * Class: java_net_TwoStacksPlainSocketImpl - * Method: socketBind - * Signature: (Ljava/net/InetAddress;I)V - */ -static void socketBind(JNIEnv env, TwoStacksPlainSocketImpl _this, - InetAddress iaObj, int localport, - boolean exclBind) { - FileDescriptor fdObj = _this.fd; - FileDescriptor fd1Obj = _this.fd1; - cli.System.Net.Sockets.Socket fd = null; - cli.System.Net.Sockets.Socket fd1 = null; - boolean ipv6_supported = ipv6_available(); - - /* family is an int field of iaObj */ - int family; - int rv; - - SOCKETADDRESS him; - him = new SOCKETADDRESS(); - - family = getInetAddress_family(env, iaObj); - - if (family == IPv6 && !ipv6_supported) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Protocol family not supported"); - return; - } - - if (IS_NULL(fdObj) || (ipv6_supported && IS_NULL(fd1Obj))) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Socket closed"); - return; - } else { - fd = fdObj.getSocket(); - if (ipv6_supported) { - fd1 = fd1Obj.getSocket(); - } - } - if (IS_NULL(iaObj)) { - JNU_ThrowNullPointerException(env, "inet address argument"); - return; - } - - if (NET_InetAddressToSockaddr(env, iaObj, localport, - him, JNI_FALSE) != 0) { - return; - } - if (ipv6_supported) { - ipv6bind v6bind = new ipv6bind(); - v6bind.addr = him; - v6bind.ipv4_fd = fd; - v6bind.ipv6_fd = fd1; - rv = NET_BindV6(v6bind, exclBind); - if (rv != -1) { - /* check if the fds have changed */ - if (v6bind.ipv4_fd != fd) { - fd = v6bind.ipv4_fd; - if (fd == null) { - /* socket is closed. */ - _this.fd = null; - } else { - /* socket was re-created */ - fdObj.setSocket(fd); - } - } - if (v6bind.ipv6_fd != fd1) { - fd1 = v6bind.ipv6_fd; - if (fd1 == null) { - /* socket is closed. */ - _this.fd1 = null; - } else { - /* socket was re-created */ - fd1Obj.setSocket(fd1); - } - } - } - } else { - rv = NET_WinBind(fd, him, exclBind); - } - - if (rv == -1) { - NET_ThrowCurrent(env, "JVM_Bind"); - return; - } - - /* set the address */ - _this.address = iaObj; - - /* intialize the local port */ - if (localport == 0) { - /* Now that we're a bound socket, let's extract the port number - * that the system chose for us and store it in the Socket object. - */ - int port; - fd = him.him.sa_family == AF_INET? fd: fd1; - - if (getsockname(fd, him) == -1) { - NET_ThrowCurrent(env, "getsockname in plain socketBind"); - return; - } - port = ntohs (GET_PORT (him)); - - _this.localport = port; - } else { - _this.localport = localport; - } -} - -/* - * Class: java_net_TwoStacksPlainSocketImpl - * Method: socketListen - * Signature: (I)V - */ -static void socketListen (JNIEnv env, TwoStacksPlainSocketImpl _this, int count) -{ - /* this FileDescriptor fd field */ - FileDescriptor fdObj = _this.fd; - FileDescriptor fd1Obj = _this.fd1; - InetAddress address; - /* fdObj's int fd field */ - cli.System.Net.Sockets.Socket fd = null; - cli.System.Net.Sockets.Socket fd1 = null; - SOCKETADDRESS addr = new SOCKETADDRESS(); - - if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "socket closed"); - return; - } - - if (!IS_NULL(fdObj)) { - fd = fdObj.getSocket(); - } - /* Listen on V4 if address type is v4 or if v6 and address is ::0. - * Listen on V6 if address type is v6 or if v4 and address is 0.0.0.0. - * In cases, where we listen on one space only, we close the other socket. - */ - address = _this.address; - if (IS_NULL(address)) { - JNU_ThrowNullPointerException(env, "socket address"); - return; - } - if (NET_InetAddressToSockaddr(env, address, 0, addr, - JNI_FALSE) != 0) { - return; - } - - if (addr.him.sa_family == AF_INET || IN6ADDR_ISANY(addr.him6)) { - /* listen on v4 */ - if (listen(fd, count) == -1) { - NET_ThrowCurrent(env, "listen failed"); - } - } else { - NET_SocketClose (fd); - _this.fd = null; - } - if (ipv6_available() && !IS_NULL(fd1Obj)) { - fd1 = fd1Obj.getSocket(); - if (addr.him.sa_family == AF_INET6 || addr.him4.sin_addr.s_addr == INADDR_ANY) { - /* listen on v6 */ - if (listen(fd1, count) == -1) { - NET_ThrowCurrent(env, "listen failed"); - } - } else { - NET_SocketClose (fd1); - _this.fd1 = null; - } - } -} - -/* - * Class: java_net_TwoStacksPlainSocketImpl - * Method: socketAccept - * Signature: (Ljava/net/SocketImpl;)V - */ -static void socketAccept(JNIEnv env, TwoStacksPlainSocketImpl _this, SocketImpl socket) -{ - /* fields on this */ - int port; - int timeout = _this.timeout; - FileDescriptor fdObj = _this.fd; - FileDescriptor fd1Obj = _this.fd1; - - /* the FileDescriptor field on socket */ - FileDescriptor socketFdObj; - - /* the InetAddress field on socket */ - InetAddress socketAddressObj; - - /* the fd int field on fdObj */ - cli.System.Net.Sockets.Socket fd=null, fd1=null; - - SOCKETADDRESS him; - him = new SOCKETADDRESS(); - - if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Socket closed"); - return; - } - if (!IS_NULL(fdObj)) { - fd = fdObj.getSocket(); - } - if (!IS_NULL(fd1Obj)) { - fd1 = fd1Obj.getSocket(); - } - if (IS_NULL(socket)) { - JNU_ThrowNullPointerException(env, "socket is null"); - return; - } else { - socketFdObj = socket.fd; - socketAddressObj = socket.address; - } - if ((IS_NULL(socketAddressObj)) || (IS_NULL(socketFdObj))) { - JNU_ThrowNullPointerException(env, "socket address or fd obj"); - return; - } - if (fd != null && fd1 != null) { - fd_set rfds = new fd_set(); - timeval t = new timeval(); - cli.System.Net.Sockets.Socket lastfd, fd2; - FD_ZERO(rfds); - FD_SET(fd,rfds); - FD_SET(fd1,rfds); - if (timeout != 0) { - t.tv_sec = timeout/1000; - t.tv_usec = (timeout%1000)*1000; - } else { - t = null; - } - int res = select (rfds, null, null, t); - if (res == 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketTimeoutException", - "Accept timed out"); - return; - } else if (res == 1) { - fd2 = FD_ISSET(fd, rfds)? fd: fd1; - } else if (res == 2) { - /* avoid starvation */ - lastfd = _this.lastfd; - if (lastfd != null) { - fd2 = lastfd==fd? fd1: fd; - } else { - fd2 = fd; - } - _this.lastfd = fd2; - } else { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "select failed"); - return; - } - fd = fd2; - } else { - int ret; - if (fd1 != null) { - fd = fd1; - } - if (timeout != 0) { - ret = NET_Timeout(fd, timeout); - if (ret == 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketTimeoutException", - "Accept timed out"); - return; - } else if (ret == -1) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "socket closed"); - /* REMIND: SOCKET CLOSED PROBLEM */ - /* NET_ThrowCurrent(env, "Accept failed"); */ - return; - } else if (ret == -2) { - JNU_ThrowByName(env, JNU_JAVAIOPKG+"InterruptedIOException", - "operation interrupted"); - return; - } - } - } - fd = accept(fd, him); - if (fd == null) { - /* REMIND: SOCKET CLOSED PROBLEM */ - if (false) { - JNU_ThrowByName(env, JNU_JAVAIOPKG+"InterruptedIOException", - "operation interrupted"); - } else { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "socket closed"); - } - return; - } - socketFdObj.setSocket(fd); - - if (him.him.sa_family == AF_INET) { - - /* - * fill up the remote peer port and address in the new socket structure - */ - socketAddressObj = new Inet4Address(null, ntohl(him.him4.sin_addr.s_addr)); - socket.address = socketAddressObj; - } else { - /* AF_INET6 -> Inet6Address */ - - // [IKVM] We need to convert scope_id 0 to -1 here, because for sin6_scope_id 0 means unspecified, whereas Java uses -1 - int scopeId = him.him6.sin6_scope_id; - socketAddressObj = new Inet6Address(null, him.him6.sin6_addr, scopeId == 0 ? -1 : scopeId); - } - /* fields common to AF_INET and AF_INET6 */ - - port = ntohs (GET_PORT (him)); - socket.port = port; - port = _this.localport; - socket.localport = port; - socket.address = socketAddressObj; -} - -/* - * Class: java_net_TwoStacksPlainSocketImpl - * Method: socketAvailable - * Signature: ()I - */ -static int socketAvailable(JNIEnv env, TwoStacksPlainSocketImpl _this) { - - int[] available = { -1 }; - int res; - FileDescriptor fdObj = _this.fd; - cli.System.Net.Sockets.Socket fd; - - if (IS_NULL(fdObj)) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "Socket closed"); - return -1; - } else { - fd = fdObj.getSocket(); - } - res = ioctlsocket(fd, FIONREAD, available); - /* if result isn't 0, it means an error */ - if (res != 0) { - NET_ThrowNew(env, res, "socket available"); - } - return available[0]; -} - -/* - * Class: java_net_TwoStacksPlainSocketImpl - * Method: socketClose - * Signature: ()V - */ -static void socketClose0(JNIEnv env, TwoStacksPlainSocketImpl _this, boolean useDeferredClose) { - - FileDescriptor fdObj = _this.fd; - FileDescriptor fd1Obj = _this.fd1; - cli.System.Net.Sockets.Socket fd = null; - cli.System.Net.Sockets.Socket fd1 = null; - - if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "socket already closed"); - return; - } - if (!IS_NULL(fdObj)) { - fd = fdObj.getSocket(); - } - if (!IS_NULL(fd1Obj)) { - fd1 = fd1Obj.getSocket(); - } - if (fd != null) { - fdObj.setSocket(null); - NET_SocketClose(fd); - } - if (fd1 != null) { - fd1Obj.setSocket(null); - NET_SocketClose(fd1); - } -} - -/* - * Socket options for plainsocketImpl - * - * - * Class: java_net_TwoStacksPlainSocketImpl - * Method: socketNativeSetOption - * Signature: (IZLjava/lang/Object;)V - */ -static void socketNativeSetOption(JNIEnv env, TwoStacksPlainSocketImpl _this, int cmd, boolean on, Object value) { - cli.System.Net.Sockets.Socket fd, fd1; - int[] level = new int[1]; - int[] optname = new int[1]; - Object optval; - - /* - * Get SOCKET and check that it hasn't been closed - */ - fd = getFD(env, _this); - fd1 = getFD1(env, _this); - if (fd == null && fd1 == null) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "Socket closed"); - return; - } - - /* - * SO_TIMEOUT is the socket option used to specify the timeout - * for ServerSocket.accept and Socket.getInputStream().read. - * It does not typically map to a native level socket option. - * For Windows we special-case this and use the SOL_SOCKET/SO_RCVTIMEO - * socket option to specify a receive timeout on the socket. This - * receive timeout is applicable to Socket only and the socket - * option should not be set on ServerSocket. - */ - if (cmd == java_net_SocketOptions_SO_TIMEOUT) { - - /* - * Don't enable the socket option on ServerSocket as it's - * meaningless (we don't receive on a ServerSocket). - */ - Object ssObj = _this.serverSocket; - if (ssObj != NULL) { - return; - } - - /* - * SO_RCVTIMEO is only supported on Microsoft's implementation - * of Windows Sockets so if WSAENOPROTOOPT returned then - * reset flag and timeout will be implemented using - * select() -- see SocketInputStream.socketRead. - */ - if (isRcvTimeoutSupported) { - int timeout = ((Integer)value).intValue(); - - /* - * Disable SO_RCVTIMEO if timeout is <= 5 second. - */ - if (timeout <= 5000) { - timeout = 0; - } - - if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, timeout) < 0) { - if (WSAGetLastError() == WSAENOPROTOOPT) { - isRcvTimeoutSupported = JNI_FALSE; - } else { - NET_ThrowCurrent(env, "setsockopt SO_RCVTIMEO"); - } - } - if (fd1 != null) { - if (setsockopt(fd1, SOL_SOCKET, SO_RCVTIMEO, timeout) < 0) { - NET_ThrowCurrent(env, "setsockopt SO_RCVTIMEO"); - } - } - } - return; - } - - /* - * Map the Java level socket option to the platform specific - * level - */ - if (NET_MapSocketOption(cmd, level, optname) != 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Invalid option"); - return; - } - - switch (cmd) { - - case java_net_SocketOptions_TCP_NODELAY : - case java_net_SocketOptions_SO_OOBINLINE : - case java_net_SocketOptions_SO_KEEPALIVE : - case java_net_SocketOptions_SO_REUSEADDR : - optval = on; - break; - - case java_net_SocketOptions_SO_SNDBUF : - case java_net_SocketOptions_SO_RCVBUF : - case java_net_SocketOptions_IP_TOS : - optval = ((Integer)value).intValue(); - break; - - case java_net_SocketOptions_SO_LINGER : - { - linger ling = new linger(); - if (on) { - ling.l_onoff = 1; - ling.l_linger = ((Integer)value).intValue(); - } else { - ling.l_onoff = 0; - ling.l_linger = 0; - } - optval = ling; - } - break; - - default: /* shouldn't get here */ - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Option not supported by TwoStacksPlainSocketImpl"); - return; - } - - if (fd != null) { - if (NET_SetSockOpt(fd, level[0], optname[0], optval) < 0) { - NET_ThrowCurrent(env, "setsockopt"); - } - } - - if (fd1 != null) { - if (NET_SetSockOpt(fd1, level[0], optname[0], optval) < 0) { - NET_ThrowCurrent(env, "setsockopt"); - } - } -} - - -/* - * Class: java_net_TwoStacksPlainSocketImpl - * Method: socketGetOption - * Signature: (I)I - */ -static int socketGetOption(JNIEnv env, TwoStacksPlainSocketImpl _this, int opt, Object iaContainerObj) { - - cli.System.Net.Sockets.Socket fd, fd1; - int[] level = new int[1]; - int[] optname = new int[1]; - Object optval; - - /* - * Get SOCKET and check it hasn't been closed - */ - fd = getFD(env, _this); - fd1 = getFD1(env, _this); - - if (fd == null && fd1 == null) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "Socket closed"); - return -1; - } - if (fd == null) { - fd = fd1; - } - - /* For IPv6, we assume both sockets have the same setting always */ - - /* - * SO_BINDADDR isn't a socket option - */ - if (opt == java_net_SocketOptions_SO_BINDADDR) { - SOCKETADDRESS him; - him = new SOCKETADDRESS(); - int[] port = { 0 }; - InetAddress iaObj; - - if (fd == null) { - /* must be an IPV6 only socket. Case where both sockets are != -1 - * is handled in java - */ - fd = getFD1 (env, _this); - } - - if (getsockname(fd, him) < 0) { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG+"SocketException", - "Error getting socket name"); - return -1; - } - iaObj = NET_SockaddrToInetAddress(him, port); - ((InetAddressContainer)iaContainerObj).addr = iaObj; - return 0; /* notice change from before */ - } - - /* - * Map the Java level socket option to the platform specific - * level and option name. - */ - if (NET_MapSocketOption(opt, level, optname) != 0) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "Invalid option"); - return -1; - } - - /* - * Args are int except for SO_LINGER - */ - if (opt == java_net_SocketOptions_SO_LINGER) { - optval = new linger(); - } else { - optval = new int[1]; - } - - if (NET_GetSockOpt(fd, level[0], optname[0], optval) < 0) { - NET_ThrowCurrent(env, "getsockopt"); - return -1; - } - - switch (opt) { - case java_net_SocketOptions_SO_LINGER: - return (((linger)optval).l_onoff != 0 ? ((linger)optval).l_linger: -1); - - case java_net_SocketOptions_SO_SNDBUF: - case java_net_SocketOptions_SO_RCVBUF: - case java_net_SocketOptions_IP_TOS: - return ((int[])optval)[0]; - - case java_net_SocketOptions_TCP_NODELAY : - case java_net_SocketOptions_SO_OOBINLINE : - case java_net_SocketOptions_SO_KEEPALIVE : - case java_net_SocketOptions_SO_REUSEADDR : - return (((int[])optval)[0] == 0) ? -1 : 1; - - default: /* shouldn't get here */ - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "Option not supported by TwoStacksPlainSocketImpl"); - return -1; - } -} - -/* - * Class: java_net_TwoStacksPlainSocketImpl - * Method: socketShutdown - * Signature: (I)V - */ -static void socketShutdown(JNIEnv env, TwoStacksPlainSocketImpl _this, int howto) -{ - - FileDescriptor fdObj = _this.fd; - cli.System.Net.Sockets.Socket fd; - - /* - * WARNING: THIS NEEDS LOCKING. ALSO: SHOULD WE CHECK for fd being - * -1 already? - */ - if (IS_NULL(fdObj)) { - JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", - "socket already closed"); - return; - } else { - fd = fdObj.getSocket(); - } - shutdown(fd, howto); -} - -/* - * Class: java_net_TwoStacksPlainSocketImpl - * Method: socketSendUrgentData - * Signature: (B)V - */ -static void socketSendUrgentData(JNIEnv env, TwoStacksPlainSocketImpl _this, int data) { - /* The fd field */ - FileDescriptor fdObj = _this.fd; - int n; - cli.System.Net.Sockets.Socket fd; - - if (IS_NULL(fdObj)) { - JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); - return; - } else { - fd = fdObj.getSocket(); - /* Bug 4086704 - If the Socket associated with this file descriptor - * was closed (sysCloseFD), the the file descriptor is set to -1. - */ - if (fd == null) { - JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); - return; - } - - } - n = send(fd, new byte[] { (byte)data }, 1, MSG_OOB); - if (n == JVM_IO_ERR) { - NET_ThrowCurrent(env, "send"); - return; - } - if (n == JVM_IO_INTR) { - JNU_ThrowByName(env, "java/io/InterruptedIOException", null); - return; - } -} -} diff --git a/openjdk/java/net/net_util_md.java b/openjdk/java/net/net_util_md.java deleted file mode 100644 index 724ba4cc..00000000 --- a/openjdk/java/net/net_util_md.java +++ /dev/null @@ -1,884 +0,0 @@ -/* - * Copyright (c) 1997, 2008, 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 cli.System.Net.IPAddress; -import cli.System.Net.IPEndPoint; -import static ikvm.internal.JNI.*; -import static ikvm.internal.Winsock.*; - -final class net_util_md -{ - private net_util_md() { } - - static final int INADDR_ANY = 0; - - static final int IPTOS_TOS_MASK = 0x1e; - static final int IPTOS_PREC_MASK = 0xe0; - - static boolean isRcvTimeoutSupported = true; - - /* - * Table of Windows Sockets errors, the specific exception we - * throw for the error, and the error text. - * - * Note that this table excludes OS dependent errors. - * - * Latest list of Windows Sockets errors can be found at :- - * http://msdn.microsoft.com/library/psdk/winsock/errors_3wc2.htm - */ - private static class WinsockError - { - final int errCode; - final int exc; - final String errString; - - WinsockError(int errCode, int exc, String errString) - { - this.errCode = errCode; - this.exc = exc; - this.errString = errString; - } - } - - private static final int Exception_BindException = 1; - private static final int Exception_ConnectException = 2; - private static final int Exception_NoRouteToHostException = 3; - - private static final WinsockError[] winsock_errors = { - new WinsockError(WSAEACCES, 0, "Permission denied"), - new WinsockError(WSAEADDRINUSE, Exception_BindException, "Address already in use"), - new WinsockError(WSAEADDRNOTAVAIL, Exception_BindException, "Cannot assign requested address"), - new WinsockError(WSAEAFNOSUPPORT, 0, "Address family not supported by protocol family"), - new WinsockError(WSAEALREADY, 0, "Operation already in progress"), - new WinsockError(WSAECONNABORTED, 0, "Software caused connection abort"), - new WinsockError(WSAECONNREFUSED, Exception_ConnectException, "Connection refused"), - new WinsockError(WSAECONNRESET, 0, "Connection reset by peer"), - new WinsockError(WSAEDESTADDRREQ, 0, "Destination address required"), - new WinsockError(WSAEFAULT, 0, "Bad address"), - new WinsockError(WSAEHOSTDOWN, 0, "Host is down"), - new WinsockError(WSAEHOSTUNREACH, Exception_NoRouteToHostException, "No route to host"), - new WinsockError(WSAEINPROGRESS, 0, "Operation now in progress"), - new WinsockError(WSAEINTR, 0, "Interrupted function call"), - new WinsockError(WSAEINVAL, 0, "Invalid argument"), - new WinsockError(WSAEISCONN, 0, "Socket is already connected"), - new WinsockError(WSAEMFILE, 0, "Too many open files"), - new WinsockError(WSAEMSGSIZE, 0, "The message is larger than the maximum supported by the underlying transport"), - new WinsockError(WSAENETDOWN, 0, "Network is down"), - new WinsockError(WSAENETRESET, 0, "Network dropped connection on reset"), - new WinsockError(WSAENETUNREACH, 0, "Network is unreachable"), - new WinsockError(WSAENOBUFS, 0, "No buffer space available (maximum connections reached?)"), - new WinsockError(WSAENOPROTOOPT, 0, "Bad protocol option"), - new WinsockError(WSAENOTCONN, 0, "Socket is not connected"), - new WinsockError(WSAENOTSOCK, 0, "Socket operation on nonsocket"), - new WinsockError(WSAEOPNOTSUPP, 0, "Operation not supported"), - new WinsockError(WSAEPFNOSUPPORT, 0, "Protocol family not supported"), - new WinsockError(WSAEPROCLIM, 0, "Too many processes"), - new WinsockError(WSAEPROTONOSUPPORT, 0, "Protocol not supported"), - new WinsockError(WSAEPROTOTYPE, 0, "Protocol wrong type for socket"), - new WinsockError(WSAESHUTDOWN, 0, "Cannot send after socket shutdown"), - new WinsockError(WSAESOCKTNOSUPPORT, 0, "Socket type not supported"), - new WinsockError(WSAETIMEDOUT, Exception_ConnectException, "Connection timed out"), - new WinsockError(WSATYPE_NOT_FOUND, 0, "Class type not found"), - new WinsockError(WSAEWOULDBLOCK, 0, "Resource temporarily unavailable"), - new WinsockError(WSAHOST_NOT_FOUND, 0, "Host not found"), - new WinsockError(WSA_NOT_ENOUGH_MEMORY, 0, "Insufficient memory available"), - new WinsockError(WSANOTINITIALISED, 0, "Successful WSAStartup not yet performed"), - new WinsockError(WSANO_DATA, 0, "Valid name, no data record of requested type"), - new WinsockError(WSANO_RECOVERY, 0, "This is a nonrecoverable error"), - new WinsockError(WSASYSNOTREADY, 0, "Network subsystem is unavailable"), - new WinsockError(WSATRY_AGAIN, 0, "Nonauthoritative host not found"), - new WinsockError(WSAVERNOTSUPPORTED, 0, "Winsock.dll version out of range"), - new WinsockError(WSAEDISCON, 0, "Graceful shutdown in progress"), - new WinsockError(WSA_OPERATION_ABORTED, 0, "Overlapped operation aborted") - }; - - /* - * Since winsock doesn't have the equivalent of strerror(errno) - * use table to lookup error text for the error. - */ - static SocketException NET_ThrowNew(int errorNum, String msg) - { - int i; - int table_size = winsock_errors.length; - int excP = 0; - String fullMsg; - - if (msg == null) { - msg = "no further information"; - } - - /* - * Check table for known winsock errors - */ - i=0; - while (i < table_size) { - if (errorNum == winsock_errors[i].errCode) { - break; - } - i++; - } - - /* - * If found get pick the specific exception and error - * message corresponding to this error. - */ - if (i < table_size) { - excP = winsock_errors[i].exc; - fullMsg = winsock_errors[i].errString + ": " + msg; - } else { - fullMsg = "Unrecognized Windows Sockets error: " + errorNum + ": " + msg; - } - - /* - * Throw SocketException if no specific exception for this - * error. - */ - switch (excP) { - case Exception_BindException: - return new BindException(fullMsg); - case Exception_ConnectException: - return new ConnectException(fullMsg); - case Exception_NoRouteToHostException: - return new NoRouteToHostException(fullMsg); - default: - return new SocketException(fullMsg); - } - } - - static void NET_ThrowNew(JNIEnv env, int errorNum, String msg) - { - env.Throw(NET_ThrowNew(errorNum, msg)); - } - - static SocketException NET_ThrowCurrent(String msg) - { - return NET_ThrowNew(WSAGetLastError(), msg); - } - - static void NET_ThrowCurrent(JNIEnv env, String msg) - { - env.Throw(NET_ThrowCurrent(msg)); - } - - /* - * Return the default TOS value - */ - static int NET_GetDefaultTOS() { - // we always use the "default" default... - return 0; - } - - /* - * Map the Java level socket option to the platform specific - * level and option name. - */ - - private static final class sockopts { - int cmd; - int level; - int optname; - - sockopts(int cmd, int level, int optname) { - this.cmd = cmd; - this.level = level; - this.optname = optname; - } - } - - private static final sockopts opts[] = { - new sockopts(SocketOptions.TCP_NODELAY, IPPROTO_TCP, TCP_NODELAY ), - new sockopts(SocketOptions.SO_OOBINLINE, SOL_SOCKET, SO_OOBINLINE ), - new sockopts(SocketOptions.SO_LINGER, SOL_SOCKET, SO_LINGER ), - new sockopts(SocketOptions.SO_SNDBUF, SOL_SOCKET, SO_SNDBUF ), - new sockopts(SocketOptions.SO_RCVBUF, SOL_SOCKET, SO_RCVBUF ), - new sockopts(SocketOptions.SO_KEEPALIVE, SOL_SOCKET, SO_KEEPALIVE ), - new sockopts(SocketOptions.SO_REUSEADDR, SOL_SOCKET, SO_REUSEADDR ), - new sockopts(SocketOptions.SO_BROADCAST, SOL_SOCKET, SO_BROADCAST ), - new sockopts(SocketOptions.IP_MULTICAST_IF, IPPROTO_IP, IP_MULTICAST_IF ), - new sockopts(SocketOptions.IP_MULTICAST_LOOP, IPPROTO_IP, IP_MULTICAST_LOOP ), - new sockopts(SocketOptions.IP_TOS, IPPROTO_IP, IP_TOS ), - - }; - - /* call NET_MapSocketOptionV6 for the IPv6 fd only - * and NET_MapSocketOption for the IPv4 fd - */ - static int NET_MapSocketOptionV6(int cmd, int[] level, int[] optname) { - - switch (cmd) { - case SocketOptions.IP_MULTICAST_IF: - case SocketOptions.IP_MULTICAST_IF2: - level[0] = IPPROTO_IPV6; - optname[0] = IPV6_MULTICAST_IF; - return 0; - - case SocketOptions.IP_MULTICAST_LOOP: - level[0] = IPPROTO_IPV6; - optname[0] = IPV6_MULTICAST_LOOP; - return 0; - } - return NET_MapSocketOption (cmd, level, optname); - } - - static int NET_MapSocketOption(int cmd, int[] level, int[] optname) { - /* - * Map the Java level option to the native level - */ - for (int i=0; i<opts.length; i++) { - if (cmd == opts[i].cmd) { - level[0] = opts[i].level; - optname[0] = opts[i].optname; - return 0; - } - } - - /* not found */ - return -1; - } - - static int NET_SetSockOpt(cli.System.Net.Sockets.Socket s, int level, int optname, Object optval) - { - int rv; - - if (level == IPPROTO_IP && optname == IP_TOS) { - int tos = (Integer)optval; - tos &= (IPTOS_TOS_MASK | IPTOS_PREC_MASK); - optval = tos; - } - - if (optname == SO_REUSEADDR) { - /* - * Do not set SO_REUSEADDE if SO_EXCLUSIVEADDUSE is already set - */ - int[] parg = new int[1]; - rv = NET_GetSockOpt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, parg); - if (rv == 0 && parg[0] == 1) { - return rv; - } - } - - rv = setsockopt(s, level, optname, optval); - - if (rv == SOCKET_ERROR) { - /* - * IP_TOS & IP_MULTICAST_LOOP can't be set on some versions - * of Windows. - */ - if ((WSAGetLastError() == WSAENOPROTOOPT) && - (level == IPPROTO_IP) && - (optname == IP_TOS || optname == IP_MULTICAST_LOOP)) { - rv = 0; - } - - /* - * IP_TOS can't be set on unbound UDP sockets. - */ - if ((WSAGetLastError() == WSAEINVAL) && - (level == IPPROTO_IP) && - (optname == IP_TOS)) { - rv = 0; - } - } - - return rv; - } - - /* - * Wrapper for setsockopt dealing with Windows specific issues :- - * - * IP_TOS is not supported on some versions of Windows so - * instead return the default value for the OS. - */ - static int NET_GetSockOpt(cli.System.Net.Sockets.Socket s, int level, int optname, Object optval) - { - int rv; - - rv = getsockopt(s, level, optname, optval); - - - /* - * IPPROTO_IP/IP_TOS is not supported on some Windows - * editions so return the default type-of-service - * value. - */ - if (rv == SOCKET_ERROR) { - - if (WSAGetLastError() == WSAENOPROTOOPT && - level == IPPROTO_IP && optname == IP_TOS) { - - ((int[])optval)[0] = NET_GetDefaultTOS(); - - rv = 0; - } - } - - return rv; - } - - /* - * Sets SO_ECLUSIVEADDRUSE if SO_REUSEADDR is not already set. - */ - static void setExclusiveBind(cli.System.Net.Sockets.Socket fd) { - int[] parg = new int[1]; - int rv = 0; - rv = NET_GetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, parg); - if (rv == 0 && parg[0] == 0) { - rv = NET_SetSockOpt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, 1); - } - } - - /* - * Wrapper for bind winsock call - transparent converts an - * error related to binding to a port that has exclusive access - * into an error indicating the port is in use (facilitates - * better error reporting). - */ - static int NET_Bind(cli.System.Net.Sockets.Socket s, SOCKETADDRESS him) - { - int rv; - rv = bind(s, him); - - if (rv == SOCKET_ERROR) { - /* - * If bind fails with WSAEACCES it means that a privileged - * process has done an exclusive bind (NT SP4/2000/XP only). - */ - if (WSAGetLastError() == WSAEACCES) { - WSASetLastError(WSAEADDRINUSE); - } - } - - return rv; - } - - /* - * Wrapper for NET_Bind call. Sets SO_EXCLUSIVEADDRUSE - * if required, and then calls NET_BIND - */ - static int NET_WinBind(cli.System.Net.Sockets.Socket s, SOCKETADDRESS him, boolean exclBind) - { - if (exclBind == JNI_TRUE) - setExclusiveBind(s); - return NET_Bind(s, him); - } - - static int NET_SocketClose(cli.System.Net.Sockets.Socket fd) { - linger l = new linger(); - int ret; - if (getsockopt(fd, SOL_SOCKET, SO_LINGER, l) == 0) { - if (l.l_onoff == 0) { - WSASendDisconnect(fd); - } - } - ret = closesocket (fd); - return ret; - } - - static int NET_Timeout(cli.System.Net.Sockets.Socket fd, long timeout) { - int ret; - fd_set tbl = new fd_set(); - timeval t = new timeval(); - t.tv_sec = timeout / 1000; - t.tv_usec = (timeout % 1000) * 1000; - FD_ZERO(tbl); - FD_SET(fd, tbl); - ret = select (tbl, null, null, t); - return ret; - } - - /* - * differs from NET_Timeout() as follows: - * - * If timeout = -1, it blocks forever. - * - * returns 1 or 2 depending if only one or both sockets - * fire at same time. - * - * *fdret is (one of) the active fds. If both sockets - * fire at same time, *fdret = fd always. - */ - static int NET_Timeout2(cli.System.Net.Sockets.Socket fd, cli.System.Net.Sockets.Socket fd1, long timeout, cli.System.Net.Sockets.Socket[] fdret) { - int ret; - fd_set tbl = new fd_set(); - timeval t = new timeval(); - if (timeout == -1) { - t = null; - } else { - t.tv_sec = timeout / 1000; - t.tv_usec = (timeout % 1000) * 1000; - } - FD_ZERO(tbl); - FD_SET(fd, tbl); - FD_SET(fd1, tbl); - ret = select (tbl, null, null, t); - switch (ret) { - case 0: - return 0; /* timeout */ - case 1: - if (FD_ISSET (fd, tbl)) { - fdret[0]= fd; - } else { - fdret[0]= fd1; - } - return 1; - case 2: - fdret[0]= fd; - return 2; - } - return -1; - } - - /* - * if ipv6 is available, call NET_BindV6 to bind to the required address/port. - * Because the same port number may need to be reserved in both v4 and v6 space, - * this may require socket(s) to be re-opened. Therefore, all of this information - * is passed in and returned through the ipv6bind structure. - * - * If the request is to bind to a specific address, then this (by definition) means - * only bind in either v4 or v6, and this is just the same as normal. ie. a single - * call to bind() will suffice. The other socket is closed in this case. - * - * The more complicated case is when the requested address is ::0 or 0.0.0.0. - * - * Two further cases: - * 2. If the reqeusted port is 0 (ie. any port) then we try to bind in v4 space - * first with a wild-card port argument. We then try to bind in v6 space - * using the returned port number. If this fails, we repeat the process - * until a free port common to both spaces becomes available. - * - * 3. If the requested port is a specific port, then we just try to get that - * port in both spaces, and if it is not free in both, then the bind fails. - * - * On failure, sockets are closed and an error returned with CLOSE_SOCKETS_AND_RETURN - */ - - static class ipv6bind { - SOCKETADDRESS addr; - cli.System.Net.Sockets.Socket ipv4_fd; - cli.System.Net.Sockets.Socket ipv6_fd; - } - - private static int CLOSE_SOCKETS_AND_RETURN( - cli.System.Net.Sockets.Socket fd, - cli.System.Net.Sockets.Socket ofd, - cli.System.Net.Sockets.Socket close_fd, - cli.System.Net.Sockets.Socket close_ofd, - ipv6bind b) { - if (fd != null) { - closesocket (fd); - } - if (ofd != null) { - closesocket (ofd); - } - if (close_fd != null) { - closesocket (close_fd); - } - if (close_ofd != null) { - closesocket (close_ofd); - } - b.ipv4_fd = b.ipv6_fd = null; - return SOCKET_ERROR; - } - - static int NET_BindV6(ipv6bind b, boolean exclBind) { - cli.System.Net.Sockets.Socket fd = null; - cli.System.Net.Sockets.Socket ofd = null; - int rv; - /* need to defer close until new sockets created */ - cli.System.Net.Sockets.Socket close_fd = null; - cli.System.Net.Sockets.Socket close_ofd = null; - - SOCKETADDRESS oaddr = new SOCKETADDRESS(); - int family = b.addr.him.sa_family; - int ofamily; - int port; - int bound_port; - - if (family == AF_INET && (b.addr.him4.sin_addr.s_addr != INADDR_ANY)) { - /* bind to v4 only */ - int ret; - ret = NET_WinBind (b.ipv4_fd, b.addr, exclBind); - if (ret == SOCKET_ERROR) { - return CLOSE_SOCKETS_AND_RETURN(fd, ofd, close_fd, close_ofd, b); - } - closesocket (b.ipv6_fd); - b.ipv6_fd = null; - return 0; - } - if (family == AF_INET6 && (!IN6ADDR_ISANY(b.addr))) { - /* bind to v6 only */ - int ret; - ret = NET_WinBind (b.ipv6_fd, b.addr, exclBind); - if (ret == SOCKET_ERROR) { - return CLOSE_SOCKETS_AND_RETURN(fd, ofd, close_fd, close_ofd, b); - } - closesocket (b.ipv4_fd); - b.ipv4_fd = null; - return 0; - } - - /* We need to bind on both stacks, with the same port number */ - - if (family == AF_INET) { - ofamily = AF_INET6; - fd = b.ipv4_fd; - ofd = b.ipv6_fd; - port = GET_PORT (b.addr); - oaddr.set(new IPEndPoint(IPAddress.IPv6Any, htons(port))); - } else { - ofamily = AF_INET; - ofd = b.ipv4_fd; - fd = b.ipv6_fd; - port = GET_PORT (b.addr); - oaddr.set(new IPEndPoint(IPAddress.Any, htons(port))); - } - - rv = NET_WinBind (fd, b.addr, exclBind); - if (rv == SOCKET_ERROR) { - return CLOSE_SOCKETS_AND_RETURN(fd, ofd, close_fd, close_ofd, b); - } - - /* get the port and set it in the other address */ - if (getsockname(fd, b.addr) == -1) { - return CLOSE_SOCKETS_AND_RETURN(fd, ofd, close_fd, close_ofd, b); - } - bound_port = b.addr.sin_port; - oaddr.sin_port = bound_port; - if ((rv=NET_Bind (ofd, oaddr)) == SOCKET_ERROR) { - - /* no retries unless, the request was for any free port */ - - if (port != 0) { - return CLOSE_SOCKETS_AND_RETURN(fd, ofd, close_fd, close_ofd, b); - } - - int sotype = fd.get_SocketType().Value; - - /* 50 is an arbitrary limit, just to ensure that this - * cannot be an endless loop. Would expect socket creation to - * succeed sooner. - */ - for (int retries = 0; retries < 50 /*SOCK_RETRIES*/; retries ++) { - close_fd = fd; - fd = null; - close_ofd = ofd; - ofd = null; - b.ipv4_fd = null; - b.ipv6_fd = null; - - /* create two new sockets */ - fd = socket (family, sotype, 0); - if (fd == INVALID_SOCKET) { - return CLOSE_SOCKETS_AND_RETURN(fd, ofd, close_fd, close_ofd, b); - } - ofd = socket (ofamily, sotype, 0); - if (ofd == INVALID_SOCKET) { - return CLOSE_SOCKETS_AND_RETURN(fd, ofd, close_fd, close_ofd, b); - } - - /* bind random port on first socket */ - oaddr.sin_port = 0; - rv = NET_WinBind (ofd, oaddr, - exclBind); - if (rv == SOCKET_ERROR) { - return CLOSE_SOCKETS_AND_RETURN(fd, ofd, close_fd, close_ofd, b); - } - /* close the original pair of sockets before continuing */ - closesocket (close_fd); - closesocket (close_ofd); - close_fd = close_ofd = null; - - /* bind new port on second socket */ - if (getsockname(ofd, oaddr) == -1) { - return CLOSE_SOCKETS_AND_RETURN(fd, ofd, close_fd, close_ofd, b); - } - bound_port = oaddr.sin_port; - b.addr.sin_port = bound_port; - rv = NET_WinBind (fd, b.addr, - exclBind); - - if (rv != SOCKET_ERROR) { - if (family == AF_INET) { - b.ipv4_fd = fd; - b.ipv6_fd = ofd; - } else { - b.ipv4_fd = ofd; - b.ipv6_fd = fd; - } - return 0; - } - } - return CLOSE_SOCKETS_AND_RETURN(fd, ofd, close_fd, close_ofd, b); - } - return 0; - } - - /* If address types is IPv6, then IPv6 must be available. Otherwise - * no address can be generated. In the case of an IPv4 Inetaddress this - * method will return an IPv4 mapped address where IPv6 is available and - * v4MappedAddress is TRUE. Otherwise it will return a sockaddr_in - * 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)); - return 0; - } else { - Inet6Address v6addr = (Inet6Address)iaObj; - int scope = v6addr.getScopeId(); - if (scope == 0) { - him.set(new IPEndPoint(new IPAddress(v6addr.ipaddress), port)); - return 0; - } else { - him.set(new IPEndPoint(new IPAddress(v6addr.ipaddress, scope & 0xFFFFFFFFL), port)); - return 0; - } - } - } - - static int NET_GetPortFromSockaddr(SOCKETADDRESS him) { - return ntohs(GET_PORT(him)); - } - - static boolean NET_IsIPv4Mapped(byte[] caddr) { - int i; - for (i = 0; i < 10; i++) { - if (caddr[i] != 0x00) { - return false; - } - } - - if (((caddr[10] & 0xff) == 0xff) && ((caddr[11] & 0xff) == 0xff)) { - return true; - } - return false; - } - - static int NET_IPv4MappedToIPv4(byte[] caddr) { - return ((caddr[12] & 0xff) << 24) | ((caddr[13] & 0xff) << 16) | ((caddr[14] & 0xff) << 8) - | (caddr[15] & 0xff); - } - - static boolean NET_IsEqual(byte[] caddr1, byte[] caddr2) { - int i; - for (i = 0; i < 16; i++) { - if (caddr1[i] != caddr2[i]) { - return false; - } - } - return true; - } - - static int getScopeID (SOCKETADDRESS him) { - return him.him6.sin6_scope_id; - } - - static boolean cmpScopeID (int scope, SOCKETADDRESS him) { - return him.him6.sin6_scope_id == scope; - } - - /* these methods are not from net_util_md.c */ - - static boolean ipv6_available() { - return InetAddressImplFactory.isIPv6Supported(); - } - - static boolean IS_NULL(Object obj) { - return obj == null; - } - - static boolean IN6ADDR_ISANY(SOCKETADDRESS him) { - if (him.sa_family != AF_INET6) { - return false; - } - byte[] addr = him.him6.sin6_addr; - byte b = 0; - for (int i = 0; i < addr.length; i++) { - b |= addr[i]; - } - return b == 0; - } - - static boolean NET_SockaddrEqualsInetAddress(SOCKETADDRESS him, InetAddress iaObj) { - int family = iaObj.family == InetAddress.IPv4 ? AF_INET : AF_INET6; - - if (him.sa_family == AF_INET6) { - byte[] caddrNew = him.him6.sin6_addr; - if (NET_IsIPv4Mapped(caddrNew)) { - int addrNew; - int addrCur; - if (family == AF_INET6) { - return false; - } - addrNew = NET_IPv4MappedToIPv4(caddrNew); - addrCur = iaObj.address; - if (addrNew == addrCur) { - return true; - } else { - return false; - } - } else { - byte[] caddrCur; - int scope; - - if (family == AF_INET) { - return false; - } - scope = ((Inet6Address)iaObj).getScopeId(); - caddrCur = ((Inet6Address)iaObj).ipaddress; - if (NET_IsEqual(caddrNew, caddrCur) && cmpScopeID(scope, him)) { - return true; - } else { - return false; - } - } - } else { - int addrNew, addrCur; - if (family != AF_INET) { - return false; - } - addrNew = ntohl(him.him4.sin_addr.s_addr); - addrCur = iaObj.address; - if (addrNew == addrCur) { - return true; - } else { - return false; - } - } - } - - static InetAddress NET_SockaddrToInetAddress(JNIEnv env, SOCKETADDRESS him, int[] port) { - return NET_SockaddrToInetAddress(him, port); - } - - static InetAddress NET_SockaddrToInetAddress(SOCKETADDRESS him, int[] port) { - InetAddress iaObj; - if (him.sa_family == AF_INET6) { - byte[] caddr = him.him6.sin6_addr; - if (NET_IsIPv4Mapped(caddr)) { - iaObj = new Inet4Address(null, NET_IPv4MappedToIPv4(caddr)); - } else { - int scope = getScopeID(him); - iaObj = new Inet6Address(null, caddr, scope > 0 ? scope : -1); - } - port[0] = ntohs(him.him6.sin_port); - } else { - iaObj = new Inet4Address(null, ntohl(him.him4.sin_addr.s_addr)); - port[0] = ntohs(him.him4.sin_port); - } - return iaObj; - } - - static void NET_ThrowByNameWithLastError(JNIEnv env, String exceptionClass, String message) { - JNU_ThrowByName(env, exceptionClass, "errno: " + WSAGetLastError() + ", error: " + message + "\n"); - } - - static boolean IN_MULTICAST(int ipv4address) { - return ((ipv4address >> 24) & 0xf0) == 0xe0; - } - - static boolean IN6_IS_ADDR_MULTICAST(in6_addr address) { - return (address.s6_bytes()[0] & 0xff) == 0xff; - } - - static final class SOCKETADDRESS implements IIPEndPointWrapper { - final SOCKETADDRESS him = this; - final SOCKETADDRESS him4 = this; - final SOCKETADDRESS him6 = this; - final SOCKETADDRESS sin_addr = this; - int sa_family; - int sin_port; - int s_addr; - byte[] sin6_addr; - int sin6_scope_id; - - public void set(IPEndPoint ep) { - if (ep == null) { - sa_family = 0; - sin_port = 0; - s_addr = 0; - sin6_addr = null; - sin6_scope_id = 0; - } else { - sa_family = ep.get_AddressFamily().Value; - sin_port = htons(ep.get_Port()); - if (sa_family == AF_INET) { - s_addr = (int)ep.get_Address().get_Address(); - sin6_addr = null; - sin6_scope_id = 0; - } else { - s_addr = 0; - IPAddress addr = ep.get_Address(); - sin6_addr = addr.GetAddressBytes(); - sin6_scope_id = (int)addr.get_ScopeId(); - } - } - } - - public IPEndPoint get() { - if (sa_family == AF_INET) { - return new IPEndPoint(new IPAddress(s_addr & 0xFFFFFFFFL), ntohs(sin_port)); - } else if (sa_family == AF_INET6) { - IPAddress addr; - if (sin6_addr == null) { - addr = IPAddress.IPv6Any; - } else { - addr = new IPAddress(sin6_addr, sin6_scope_id & 0xFFFFFFFFL); - } - return new IPEndPoint(addr, ntohs(sin_port)); - } else { - return null; - } - } - } - - static int GET_PORT(SOCKETADDRESS sockaddr) { - return sockaddr.sin_port; - } - - static void Sleep(int ms) { - cli.System.Threading.Thread.Sleep(ms); - } - - static cli.System.Net.Sockets.Socket NET_Socket (int domain, int type, int protocol) { - cli.System.Net.Sockets.Socket sock; - sock = socket (domain, type, protocol); - if (sock != INVALID_SOCKET) { - //SetHandleInformation((HANDLE)(uintptr_t)sock, HANDLE_FLAG_INHERIT, FALSE); - } - return sock; - } - - static int getInetAddress_addr(JNIEnv env, InetAddress iaObj) { - return iaObj.address; - } - - static int getInetAddress_family(JNIEnv env, InetAddress iaObj) { - return iaObj.family; - } -} diff --git a/openjdk/java/nio/Bits.java b/openjdk/java/nio/Bits.java deleted file mode 100644 index cea374fc..00000000 --- a/openjdk/java/nio/Bits.java +++ /dev/null @@ -1,850 +0,0 @@ -/* - * Copyright (c) 2000, 2012, 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.nio; - -import java.security.AccessController; -import sun.misc.Unsafe; -import sun.misc.VM; - -/** - * Access to bits, native and otherwise. - */ - -class Bits { // package-private - - private Bits() { } - - - // -- Swapping -- - - static short swap(short x) { - return Short.reverseBytes(x); - } - - static char swap(char x) { - return Character.reverseBytes(x); - } - - static int swap(int x) { - return Integer.reverseBytes(x); - } - - static long swap(long x) { - return Long.reverseBytes(x); - } - - - // -- get/put char -- - - static private char makeChar(byte b1, byte b0) { - return (char)((b1 << 8) | (b0 & 0xff)); - } - - static char getCharL(ByteBuffer bb, int bi) { - return makeChar(bb._get(bi + 1), - bb._get(bi )); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static char getCharL(long a) { - return makeChar(_get(a + 1), - _get(a )); - } - - static char getCharB(ByteBuffer bb, int bi) { - return makeChar(bb._get(bi ), - bb._get(bi + 1)); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static char getCharB(long a) { - return makeChar(_get(a ), - _get(a + 1)); - } - - static char getChar(ByteBuffer bb, int bi, boolean bigEndian) { - return bigEndian ? getCharB(bb, bi) : getCharL(bb, bi); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static char getChar(long a, boolean bigEndian) { - return bigEndian ? getCharB(a) : getCharL(a); - } - - private static byte char1(char x) { return (byte)(x >> 8); } - private static byte char0(char x) { return (byte)(x ); } - - static void putCharL(ByteBuffer bb, int bi, char x) { - bb._put(bi , char0(x)); - bb._put(bi + 1, char1(x)); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static void putCharL(long a, char x) { - _put(a , char0(x)); - _put(a + 1, char1(x)); - } - - static void putCharB(ByteBuffer bb, int bi, char x) { - bb._put(bi , char1(x)); - bb._put(bi + 1, char0(x)); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static void putCharB(long a, char x) { - _put(a , char1(x)); - _put(a + 1, char0(x)); - } - - static void putChar(ByteBuffer bb, int bi, char x, boolean bigEndian) { - if (bigEndian) - putCharB(bb, bi, x); - else - putCharL(bb, bi, x); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static void putChar(long a, char x, boolean bigEndian) { - if (bigEndian) - putCharB(a, x); - else - putCharL(a, x); - } - - - // -- get/put short -- - - static private short makeShort(byte b1, byte b0) { - return (short)((b1 << 8) | (b0 & 0xff)); - } - - static short getShortL(ByteBuffer bb, int bi) { - return makeShort(bb._get(bi + 1), - bb._get(bi )); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static short getShortL(long a) { - return makeShort(_get(a + 1), - _get(a )); - } - - static short getShortB(ByteBuffer bb, int bi) { - return makeShort(bb._get(bi ), - bb._get(bi + 1)); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static short getShortB(long a) { - return makeShort(_get(a ), - _get(a + 1)); - } - - static short getShort(ByteBuffer bb, int bi, boolean bigEndian) { - return bigEndian ? getShortB(bb, bi) : getShortL(bb, bi); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static short getShort(long a, boolean bigEndian) { - return bigEndian ? getShortB(a) : getShortL(a); - } - - private static byte short1(short x) { return (byte)(x >> 8); } - private static byte short0(short x) { return (byte)(x ); } - - static void putShortL(ByteBuffer bb, int bi, short x) { - bb._put(bi , short0(x)); - bb._put(bi + 1, short1(x)); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static void putShortL(long a, short x) { - _put(a , short0(x)); - _put(a + 1, short1(x)); - } - - static void putShortB(ByteBuffer bb, int bi, short x) { - bb._put(bi , short1(x)); - bb._put(bi + 1, short0(x)); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static void putShortB(long a, short x) { - _put(a , short1(x)); - _put(a + 1, short0(x)); - } - - static void putShort(ByteBuffer bb, int bi, short x, boolean bigEndian) { - if (bigEndian) - putShortB(bb, bi, x); - else - putShortL(bb, bi, x); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static void putShort(long a, short x, boolean bigEndian) { - if (bigEndian) - putShortB(a, x); - else - putShortL(a, x); - } - - - // -- get/put int -- - - static private int makeInt(byte b3, byte b2, byte b1, byte b0) { - return (((b3 ) << 24) | - ((b2 & 0xff) << 16) | - ((b1 & 0xff) << 8) | - ((b0 & 0xff) )); - } - - static int getIntL(ByteBuffer bb, int bi) { - return makeInt(bb._get(bi + 3), - bb._get(bi + 2), - bb._get(bi + 1), - bb._get(bi )); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static int getIntL(long a) { - return makeInt(_get(a + 3), - _get(a + 2), - _get(a + 1), - _get(a )); - } - - static int getIntB(ByteBuffer bb, int bi) { - return makeInt(bb._get(bi ), - bb._get(bi + 1), - bb._get(bi + 2), - bb._get(bi + 3)); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static int getIntB(long a) { - return makeInt(_get(a ), - _get(a + 1), - _get(a + 2), - _get(a + 3)); - } - - static int getInt(ByteBuffer bb, int bi, boolean bigEndian) { - return bigEndian ? getIntB(bb, bi) : getIntL(bb, bi) ; - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static int getInt(long a, boolean bigEndian) { - return bigEndian ? getIntB(a) : getIntL(a) ; - } - - private static byte int3(int x) { return (byte)(x >> 24); } - private static byte int2(int x) { return (byte)(x >> 16); } - private static byte int1(int x) { return (byte)(x >> 8); } - private static byte int0(int x) { return (byte)(x ); } - - static void putIntL(ByteBuffer bb, int bi, int x) { - bb._put(bi + 3, int3(x)); - bb._put(bi + 2, int2(x)); - bb._put(bi + 1, int1(x)); - bb._put(bi , int0(x)); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static void putIntL(long a, int x) { - _put(a + 3, int3(x)); - _put(a + 2, int2(x)); - _put(a + 1, int1(x)); - _put(a , int0(x)); - } - - static void putIntB(ByteBuffer bb, int bi, int x) { - bb._put(bi , int3(x)); - bb._put(bi + 1, int2(x)); - bb._put(bi + 2, int1(x)); - bb._put(bi + 3, int0(x)); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static void putIntB(long a, int x) { - _put(a , int3(x)); - _put(a + 1, int2(x)); - _put(a + 2, int1(x)); - _put(a + 3, int0(x)); - } - - static void putInt(ByteBuffer bb, int bi, int x, boolean bigEndian) { - if (bigEndian) - putIntB(bb, bi, x); - else - putIntL(bb, bi, x); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static void putInt(long a, int x, boolean bigEndian) { - if (bigEndian) - putIntB(a, x); - else - putIntL(a, x); - } - - - // -- get/put long -- - - static private long makeLong(byte b7, byte b6, byte b5, byte b4, - byte b3, byte b2, byte b1, byte b0) - { - return ((((long)b7 ) << 56) | - (((long)b6 & 0xff) << 48) | - (((long)b5 & 0xff) << 40) | - (((long)b4 & 0xff) << 32) | - (((long)b3 & 0xff) << 24) | - (((long)b2 & 0xff) << 16) | - (((long)b1 & 0xff) << 8) | - (((long)b0 & 0xff) )); - } - - static long getLongL(ByteBuffer bb, int bi) { - return makeLong(bb._get(bi + 7), - bb._get(bi + 6), - bb._get(bi + 5), - bb._get(bi + 4), - bb._get(bi + 3), - bb._get(bi + 2), - bb._get(bi + 1), - bb._get(bi )); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static long getLongL(long a) { - return makeLong(_get(a + 7), - _get(a + 6), - _get(a + 5), - _get(a + 4), - _get(a + 3), - _get(a + 2), - _get(a + 1), - _get(a )); - } - - static long getLongB(ByteBuffer bb, int bi) { - return makeLong(bb._get(bi ), - bb._get(bi + 1), - bb._get(bi + 2), - bb._get(bi + 3), - bb._get(bi + 4), - bb._get(bi + 5), - bb._get(bi + 6), - bb._get(bi + 7)); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static long getLongB(long a) { - return makeLong(_get(a ), - _get(a + 1), - _get(a + 2), - _get(a + 3), - _get(a + 4), - _get(a + 5), - _get(a + 6), - _get(a + 7)); - } - - static long getLong(ByteBuffer bb, int bi, boolean bigEndian) { - return bigEndian ? getLongB(bb, bi) : getLongL(bb, bi); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static long getLong(long a, boolean bigEndian) { - return bigEndian ? getLongB(a) : getLongL(a); - } - - private static byte long7(long x) { return (byte)(x >> 56); } - private static byte long6(long x) { return (byte)(x >> 48); } - private static byte long5(long x) { return (byte)(x >> 40); } - private static byte long4(long x) { return (byte)(x >> 32); } - private static byte long3(long x) { return (byte)(x >> 24); } - private static byte long2(long x) { return (byte)(x >> 16); } - private static byte long1(long x) { return (byte)(x >> 8); } - private static byte long0(long x) { return (byte)(x ); } - - static void putLongL(ByteBuffer bb, int bi, long x) { - bb._put(bi + 7, long7(x)); - bb._put(bi + 6, long6(x)); - bb._put(bi + 5, long5(x)); - bb._put(bi + 4, long4(x)); - bb._put(bi + 3, long3(x)); - bb._put(bi + 2, long2(x)); - bb._put(bi + 1, long1(x)); - bb._put(bi , long0(x)); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static void putLongL(long a, long x) { - _put(a + 7, long7(x)); - _put(a + 6, long6(x)); - _put(a + 5, long5(x)); - _put(a + 4, long4(x)); - _put(a + 3, long3(x)); - _put(a + 2, long2(x)); - _put(a + 1, long1(x)); - _put(a , long0(x)); - } - - static void putLongB(ByteBuffer bb, int bi, long x) { - bb._put(bi , long7(x)); - bb._put(bi + 1, long6(x)); - bb._put(bi + 2, long5(x)); - bb._put(bi + 3, long4(x)); - bb._put(bi + 4, long3(x)); - bb._put(bi + 5, long2(x)); - bb._put(bi + 6, long1(x)); - bb._put(bi + 7, long0(x)); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static void putLongB(long a, long x) { - _put(a , long7(x)); - _put(a + 1, long6(x)); - _put(a + 2, long5(x)); - _put(a + 3, long4(x)); - _put(a + 4, long3(x)); - _put(a + 5, long2(x)); - _put(a + 6, long1(x)); - _put(a + 7, long0(x)); - } - - static void putLong(ByteBuffer bb, int bi, long x, boolean bigEndian) { - if (bigEndian) - putLongB(bb, bi, x); - else - putLongL(bb, bi, x); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static void putLong(long a, long x, boolean bigEndian) { - if (bigEndian) - putLongB(a, x); - else - putLongL(a, x); - } - - - // -- get/put float -- - - static float getFloatL(ByteBuffer bb, int bi) { - return Float.intBitsToFloat(getIntL(bb, bi)); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static float getFloatL(long a) { - return Float.intBitsToFloat(getIntL(a)); - } - - static float getFloatB(ByteBuffer bb, int bi) { - return Float.intBitsToFloat(getIntB(bb, bi)); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static float getFloatB(long a) { - return Float.intBitsToFloat(getIntB(a)); - } - - static float getFloat(ByteBuffer bb, int bi, boolean bigEndian) { - return bigEndian ? getFloatB(bb, bi) : getFloatL(bb, bi); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static float getFloat(long a, boolean bigEndian) { - return bigEndian ? getFloatB(a) : getFloatL(a); - } - - static void putFloatL(ByteBuffer bb, int bi, float x) { - putIntL(bb, bi, Float.floatToRawIntBits(x)); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static void putFloatL(long a, float x) { - putIntL(a, Float.floatToRawIntBits(x)); - } - - static void putFloatB(ByteBuffer bb, int bi, float x) { - putIntB(bb, bi, Float.floatToRawIntBits(x)); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static void putFloatB(long a, float x) { - putIntB(a, Float.floatToRawIntBits(x)); - } - - static void putFloat(ByteBuffer bb, int bi, float x, boolean bigEndian) { - if (bigEndian) - putFloatB(bb, bi, x); - else - putFloatL(bb, bi, x); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static void putFloat(long a, float x, boolean bigEndian) { - if (bigEndian) - putFloatB(a, x); - else - putFloatL(a, x); - } - - - // -- get/put double -- - - static double getDoubleL(ByteBuffer bb, int bi) { - return Double.longBitsToDouble(getLongL(bb, bi)); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static double getDoubleL(long a) { - return Double.longBitsToDouble(getLongL(a)); - } - - static double getDoubleB(ByteBuffer bb, int bi) { - return Double.longBitsToDouble(getLongB(bb, bi)); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static double getDoubleB(long a) { - return Double.longBitsToDouble(getLongB(a)); - } - - static double getDouble(ByteBuffer bb, int bi, boolean bigEndian) { - return bigEndian ? getDoubleB(bb, bi) : getDoubleL(bb, bi); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static double getDouble(long a, boolean bigEndian) { - return bigEndian ? getDoubleB(a) : getDoubleL(a); - } - - static void putDoubleL(ByteBuffer bb, int bi, double x) { - putLongL(bb, bi, Double.doubleToRawLongBits(x)); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static void putDoubleL(long a, double x) { - putLongL(a, Double.doubleToRawLongBits(x)); - } - - static void putDoubleB(ByteBuffer bb, int bi, double x) { - putLongB(bb, bi, Double.doubleToRawLongBits(x)); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static void putDoubleB(long a, double x) { - putLongB(a, Double.doubleToRawLongBits(x)); - } - - static void putDouble(ByteBuffer bb, int bi, double x, boolean bigEndian) { - if (bigEndian) - putDoubleB(bb, bi, x); - else - putDoubleL(bb, bi, x); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static void putDouble(long a, double x, boolean bigEndian) { - if (bigEndian) - putDoubleB(a, x); - else - putDoubleL(a, x); - } - - - // -- Unsafe access -- - - private static final Unsafe unsafe = Unsafe.getUnsafe(); - - @cli.System.Security.SecurityCriticalAttribute.Annotation - private static byte _get(long a) { - return unsafe.getByte(a); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - private static void _put(long a, byte b) { - unsafe.putByte(a, b); - } - - static Unsafe unsafe() { - return unsafe; - } - - - // -- Processor and memory-system properties -- - - private static final ByteOrder byteOrder; - - static ByteOrder byteOrder() { - if (byteOrder == null) - throw new Error("Unknown byte order"); - return byteOrder; - } - - static { - if (cli.System.BitConverter.IsLittleEndian) { - byteOrder = ByteOrder.LITTLE_ENDIAN; - } else { - byteOrder = ByteOrder.BIG_ENDIAN; - } - } - - - private static int pageSize = -1; - - static int pageSize() { - if (pageSize == -1) - pageSize = unsafe().pageSize(); - return pageSize; - } - - static int pageCount(long size) { - return (int)(size + (long)pageSize() - 1L) / pageSize(); - } - - private static boolean unaligned; - private static boolean unalignedKnown = false; - - static boolean unaligned() { - if (unalignedKnown) - return unaligned; - String arch = AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("os.arch")); - unaligned = arch.equals("i386") || arch.equals("x86") - || arch.equals("amd64") || arch.equals("x86_64"); - unalignedKnown = true; - return unaligned; - } - - - // -- Direct memory management -- - - // A user-settable upper limit on the maximum amount of allocatable - // direct buffer memory. This value may be changed during VM - // initialization if it is launched with "-XX:MaxDirectMemorySize=<size>". - private static volatile long maxMemory = VM.maxDirectMemory(); - private static volatile long reservedMemory; - private static volatile long totalCapacity; - private static volatile long count; - private static boolean memoryLimitSet = false; - - // These methods should be called whenever direct memory is allocated or - // freed. They allow the user to control the amount of direct memory - // which a process may access. All sizes are specified in bytes. - static void reserveMemory(long size, int cap) { - synchronized (Bits.class) { - if (!memoryLimitSet && VM.isBooted()) { - maxMemory = VM.maxDirectMemory(); - memoryLimitSet = true; - } - // -XX:MaxDirectMemorySize limits the total capacity rather than the - // actual memory usage, which will differ when buffers are page - // aligned. - if (cap <= maxMemory - totalCapacity) { - reservedMemory += size; - totalCapacity += cap; - count++; - return; - } - } - - System.gc(); - try { - Thread.sleep(100); - } catch (InterruptedException x) { - // Restore interrupt status - Thread.currentThread().interrupt(); - } - synchronized (Bits.class) { - if (totalCapacity + cap > maxMemory) - throw new OutOfMemoryError("Direct buffer memory"); - reservedMemory += size; - totalCapacity += cap; - count++; - } - - } - - static synchronized void unreserveMemory(long size, int cap) { - if (reservedMemory > 0) { - reservedMemory -= size; - totalCapacity -= cap; - count--; - assert (reservedMemory > -1); - } - } - - // -- Monitoring of direct buffer usage -- - - static { - // setup access to this package in SharedSecrets - sun.misc.SharedSecrets.setJavaNioAccess( - new sun.misc.JavaNioAccess() { - @Override - public sun.misc.JavaNioAccess.BufferPool getDirectBufferPool() { - return new sun.misc.JavaNioAccess.BufferPool() { - @Override - public String getName() { - return "direct"; - } - @Override - public long getCount() { - return Bits.count; - } - @Override - public long getTotalCapacity() { - return Bits.totalCapacity; - } - @Override - public long getMemoryUsed() { - return Bits.reservedMemory; - } - }; - } - @Override - public ByteBuffer newDirectByteBuffer(long addr, int cap, Object ob) { - return new DirectByteBuffer(addr, cap, ob); - } - @Override - public void truncate(Buffer buf) { - buf.truncate(); - } - }); - } - - // -- Bulk get/put acceleration -- - - // These numbers represent the point at which we have empirically - // determined that the average cost of a JNI call exceeds the expense - // of an element by element copy. These numbers may change over time. - static final int JNI_COPY_TO_ARRAY_THRESHOLD = 6; - static final int JNI_COPY_FROM_ARRAY_THRESHOLD = 6; - - // This number limits the number of bytes to copy per call to Unsafe's - // copyMemory method. A limit is imposed to allow for safepoint polling - // during a large copy - static final long UNSAFE_COPY_THRESHOLD = 1024L * 1024L; - - // These methods do no bounds checking. Verification that the copy will not - // result in memory corruption should be done prior to invocation. - // All positions and lengths are specified in bytes. - - /** - * Copy from given source array to destination address. - * - * @param src - * source array - * @param srcBaseOffset - * offset of first element of storage in source array - * @param srcPos - * offset within source array of the first element to read - * @param dstAddr - * destination address - * @param length - * number of bytes to copy - */ - @cli.System.Security.SecurityCriticalAttribute.Annotation - static void copyFromArray(Object src, long srcBaseOffset, long srcPos, - long dstAddr, long length) - { - long offset = srcBaseOffset + srcPos; - while (length > 0) { - long size = (length > UNSAFE_COPY_THRESHOLD) ? UNSAFE_COPY_THRESHOLD : length; - unsafe.copyMemory(src, offset, null, dstAddr, size); - length -= size; - offset += size; - dstAddr += size; - } - } - - /** - * Copy from source address into given destination array. - * - * @param srcAddr - * source address - * @param dst - * destination array - * @param dstBaseOffset - * offset of first element of storage in destination array - * @param dstPos - * offset within destination array of the first element to write - * @param length - * number of bytes to copy - */ - @cli.System.Security.SecurityCriticalAttribute.Annotation - static void copyToArray(long srcAddr, Object dst, long dstBaseOffset, long dstPos, - long length) - { - long offset = dstBaseOffset + dstPos; - while (length > 0) { - long size = (length > UNSAFE_COPY_THRESHOLD) ? UNSAFE_COPY_THRESHOLD : length; - unsafe.copyMemory(null, srcAddr, dst, offset, size); - length -= size; - srcAddr += size; - offset += size; - } - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static void copyFromCharArray(Object src, long srcPos, long dstAddr, - long length) - { - copyFromShortArray(src, srcPos, dstAddr, length); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static void copyToCharArray(long srcAddr, Object dst, long dstPos, - long length) - { - copyToShortArray(srcAddr, dst, dstPos, length); - } - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static native void copyFromShortArray(Object src, long srcPos, long dstAddr, - long length); - @cli.System.Security.SecurityCriticalAttribute.Annotation - static native void copyToShortArray(long srcAddr, Object dst, long dstPos, - long length); - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static native void copyFromIntArray(Object src, long srcPos, long dstAddr, - long length); - @cli.System.Security.SecurityCriticalAttribute.Annotation - static native void copyToIntArray(long srcAddr, Object dst, long dstPos, - long length); - - @cli.System.Security.SecurityCriticalAttribute.Annotation - static native void copyFromLongArray(Object src, long srcPos, long dstAddr, - long length); - @cli.System.Security.SecurityCriticalAttribute.Annotation - static native void copyToLongArray(long srcAddr, Object dst, long dstPos, - long length); - -} diff --git a/openjdk/java/security/AccessController.java b/openjdk/java/security/AccessController.java deleted file mode 100644 index 19d4af96..00000000 --- a/openjdk/java/security/AccessController.java +++ /dev/null @@ -1,633 +0,0 @@ -/* - * Copyright (c) 1997, 2012, 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.security; - -import ikvm.internal.CallerID; -import sun.misc.Unsafe; -import sun.security.util.Debug; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; - -/** - * <p> The AccessController class is used for access control operations - * and decisions. - * - * <p> More specifically, the AccessController class is used for - * three purposes: - * - * <ul> - * <li> to decide whether an access to a critical system - * resource is to be allowed or denied, based on the security policy - * currently in effect,<p> - * <li>to mark code as being "privileged", thus affecting subsequent - * access determinations, and<p> - * <li>to obtain a "snapshot" of the current calling context so - * access-control decisions from a different context can be made with - * respect to the saved context. </ul> - * - * <p> The {@link #checkPermission(Permission) checkPermission} method - * determines whether the access request indicated by a specified - * permission should be granted or denied. A sample call appears - * below. In this example, <code>checkPermission</code> will determine - * whether or not to grant "read" access to the file named "testFile" in - * the "/temp" directory. - * - * <pre> - * - * FilePermission perm = new FilePermission("/temp/testFile", "read"); - * AccessController.checkPermission(perm); - * - * </pre> - * - * <p> If a requested access is allowed, - * <code>checkPermission</code> returns quietly. If denied, an - * AccessControlException is - * thrown. AccessControlException can also be thrown if the requested - * permission is of an incorrect type or contains an invalid value. - * Such information is given whenever possible. - * - * Suppose the current thread traversed m callers, in the order of caller 1 - * to caller 2 to caller m. Then caller m invoked the - * <code>checkPermission</code> method. - * The <code>checkPermission </code>method determines whether access - * is granted or denied based on the following algorithm: - * - * <pre> {@code - * for (int i = m; i > 0; i--) { - * - * if (caller i's domain does not have the permission) - * throw AccessControlException - * - * else if (caller i is marked as privileged) { - * if (a context was specified in the call to doPrivileged) - * context.checkPermission(permission) - * return; - * } - * }; - * - * // Next, check the context inherited when the thread was created. - * // Whenever a new thread is created, the AccessControlContext at - * // that time is stored and associated with the new thread, as the - * // "inherited" context. - * - * inheritedContext.checkPermission(permission); - * }</pre> - * - * <p> A caller can be marked as being "privileged" - * (see {@link #doPrivileged(PrivilegedAction) doPrivileged} and below). - * When making access control decisions, the <code>checkPermission</code> - * method stops checking if it reaches a caller that - * was marked as "privileged" via a <code>doPrivileged</code> - * call without a context argument (see below for information about a - * context argument). If that caller's domain has the - * specified permission, no further checking is done and - * <code>checkPermission</code> - * returns quietly, indicating that the requested access is allowed. - * If that domain does not have the specified permission, an exception - * is thrown, as usual. - * - * <p> The normal use of the "privileged" feature is as follows. If you - * don't need to return a value from within the "privileged" block, do - * the following: - * - * <pre> {@code - * somemethod() { - * ...normal code here... - * AccessController.doPrivileged(new PrivilegedAction<Void>() { - * public Void run() { - * // privileged code goes here, for example: - * System.loadLibrary("awt"); - * return null; // nothing to return - * } - * }); - * ...normal code here... - * }}</pre> - * - * <p> - * PrivilegedAction is an interface with a single method, named - * <code>run</code>. - * The above example shows creation of an implementation - * of that interface; a concrete implementation of the - * <code>run</code> method is supplied. - * When the call to <code>doPrivileged</code> is made, an - * instance of the PrivilegedAction implementation is passed - * to it. The <code>doPrivileged</code> method calls the - * <code>run</code> method from the PrivilegedAction - * implementation after enabling privileges, and returns the - * <code>run</code> method's return value as the - * <code>doPrivileged</code> return value (which is - * ignored in this example). - * - * <p> If you need to return a value, you can do something like the following: - * - * <pre> {@code - * somemethod() { - * ...normal code here... - * String user = AccessController.doPrivileged( - * new PrivilegedAction<String>() { - * public String run() { - * return System.getProperty("user.name"); - * } - * }); - * ...normal code here... - * }}</pre> - * - * <p>If the action performed in your <code>run</code> method could - * throw a "checked" exception (those listed in the <code>throws</code> clause - * of a method), then you need to use the - * <code>PrivilegedExceptionAction</code> interface instead of the - * <code>PrivilegedAction</code> interface: - * - * <pre> {@code - * somemethod() throws FileNotFoundException { - * ...normal code here... - * try { - * FileInputStream fis = AccessController.doPrivileged( - * new PrivilegedExceptionAction<FileInputStream>() { - * public FileInputStream run() throws FileNotFoundException { - * return new FileInputStream("someFile"); - * } - * }); - * } catch (PrivilegedActionException e) { - * // e.getException() should be an instance of FileNotFoundException, - * // as only "checked" exceptions will be "wrapped" in a - * // PrivilegedActionException. - * throw (FileNotFoundException) e.getException(); - * } - * ...normal code here... - * }}</pre> - * - * <p> Be *very* careful in your use of the "privileged" construct, and - * always remember to make the privileged code section as small as possible. - * - * <p> Note that <code>checkPermission</code> always performs security checks - * within the context of the currently executing thread. - * Sometimes a security check that should be made within a given context - * will actually need to be done from within a - * <i>different</i> context (for example, from within a worker thread). - * The {@link #getContext() getContext} method and - * AccessControlContext class are provided - * for this situation. The <code>getContext</code> method takes a "snapshot" - * of the current calling context, and places - * it in an AccessControlContext object, which it returns. A sample call is - * the following: - * - * <pre> - * - * AccessControlContext acc = AccessController.getContext() - * - * </pre> - * - * <p> - * AccessControlContext itself has a <code>checkPermission</code> method - * that makes access decisions based on the context <i>it</i> encapsulates, - * rather than that of the current execution thread. - * Code within a different context can thus call that method on the - * previously-saved AccessControlContext object. A sample call is the - * following: - * - * <pre> - * - * acc.checkPermission(permission) - * - * </pre> - * - * <p> There are also times where you don't know a priori which permissions - * to check the context against. In these cases you can use the - * doPrivileged method that takes a context: - * - * <pre> {@code - * somemethod() { - * AccessController.doPrivileged(new PrivilegedAction<Object>() { - * public Object run() { - * // Code goes here. Any permission checks within this - * // run method will require that the intersection of the - * // callers protection domain and the snapshot's - * // context have the desired permission. - * } - * }, acc); - * ...normal code here... - * }}</pre> - * - * @see AccessControlContext - * - * @author Li Gong - * @author Roland Schemers - */ - -public final class AccessController { - - @cli.System.ThreadStaticAttribute.Annotation - private static PrivilegedElement privileged_stack_top; - - @ikvm.lang.Internal - public static final class LazyContext { - LazyContext parent; - CallerID callerID; - AccessControlContext context; - final cli.System.Diagnostics.StackTrace stackTrace = new cli.System.Diagnostics.StackTrace(1); - } - - @ikvm.lang.Internal - public static LazyContext getLazyContext(LazyContext parent) { - LazyContext lc = new LazyContext(); - lc.parent = parent; - if (privileged_stack_top != null) { - lc.callerID = privileged_stack_top.callerID; - lc.context = privileged_stack_top.context; - } - return lc; - } - - private static final class PrivilegedElement { - CallerID callerID; - AccessControlContext context; - } - - private static Object doPrivileged(Object action, AccessControlContext context, CallerID callerID) { - PrivilegedElement savedPrivilegedElement = privileged_stack_top; - try { - PrivilegedElement pi = new PrivilegedElement(); - pi.callerID = callerID; - pi.context = context; - privileged_stack_top = pi; - try { - if (action instanceof PrivilegedAction) { - return ((PrivilegedAction)action).run(); - } else { - return ((PrivilegedExceptionAction)action).run(); - } - } catch (Exception x) { - if (!(x instanceof RuntimeException)) { - Unsafe.getUnsafe().throwException(new PrivilegedActionException(x)); - } - throw (RuntimeException)x; - } - } finally { - privileged_stack_top = savedPrivilegedElement; - } - } - - /** - * Don't allow anyone to instantiate an AccessController - */ - private AccessController() { } - - /** - * Performs the specified <code>PrivilegedAction</code> with privileges - * enabled. The action is performed with <i>all</i> of the permissions - * possessed by the caller's protection domain. - * - * <p> If the action's <code>run</code> method throws an (unchecked) - * exception, it will propagate through this method. - * - * <p> Note that any DomainCombiner associated with the current - * AccessControlContext will be ignored while the action is performed. - * - * @param action the action to be performed. - * - * @return the value returned by the action's <code>run</code> method. - * - * @exception NullPointerException if the action is <code>null</code> - * - * @see #doPrivileged(PrivilegedAction,AccessControlContext) - * @see #doPrivileged(PrivilegedExceptionAction) - * @see #doPrivilegedWithCombiner(PrivilegedAction) - * @see java.security.DomainCombiner - */ - - @CallerSensitive - public static <T> T doPrivileged(PrivilegedAction<T> action) { - return (T)doPrivileged(action, null, CallerID.getCallerID()); - } - - /** - * Performs the specified <code>PrivilegedAction</code> with privileges - * enabled. The action is performed with <i>all</i> of the permissions - * possessed by the caller's protection domain. - * - * <p> If the action's <code>run</code> method throws an (unchecked) - * exception, it will propagate through this method. - * - * <p> This method preserves the current AccessControlContext's - * DomainCombiner (which may be null) while the action is performed. - * - * @param action the action to be performed. - * - * @return the value returned by the action's <code>run</code> method. - * - * @exception NullPointerException if the action is <code>null</code> - * - * @see #doPrivileged(PrivilegedAction) - * @see java.security.DomainCombiner - * - * @since 1.6 - */ - @CallerSensitive - public static <T> T doPrivilegedWithCombiner(PrivilegedAction<T> action) { - AccessControlContext acc = getStackAccessControlContext(); - if (acc == null) { - return AccessController.doPrivileged(action); - } - DomainCombiner dc = acc.getAssignedCombiner(); - return AccessController.doPrivileged(action, preserveCombiner(dc, Reflection.getCallerClass())); - } - - - /** - * Performs the specified <code>PrivilegedAction</code> with privileges - * enabled and restricted by the specified - * <code>AccessControlContext</code>. - * The action is performed with the intersection of the permissions - * possessed by the caller's protection domain, and those possessed - * by the domains represented by the specified - * <code>AccessControlContext</code>. - * <p> - * If the action's <code>run</code> method throws an (unchecked) exception, - * it will propagate through this method. - * - * @param action the action to be performed. - * @param context an <i>access control context</i> - * representing the restriction to be applied to the - * caller's domain's privileges before performing - * the specified action. If the context is - * <code>null</code>, - * then no additional restriction is applied. - * - * @return the value returned by the action's <code>run</code> method. - * - * @exception NullPointerException if the action is <code>null</code> - * - * @see #doPrivileged(PrivilegedAction) - * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext) - */ - @CallerSensitive - public static <T> T doPrivileged(PrivilegedAction<T> action, - AccessControlContext context) { - return (T)doPrivileged(action, context, CallerID.getCallerID()); - } - - /** - * Performs the specified <code>PrivilegedExceptionAction</code> with - * privileges enabled. The action is performed with <i>all</i> of the - * permissions possessed by the caller's protection domain. - * - * <p> If the action's <code>run</code> method throws an <i>unchecked</i> - * exception, it will propagate through this method. - * - * <p> Note that any DomainCombiner associated with the current - * AccessControlContext will be ignored while the action is performed. - * - * @param action the action to be performed - * - * @return the value returned by the action's <code>run</code> method - * - * @exception PrivilegedActionException if the specified action's - * <code>run</code> method threw a <i>checked</i> exception - * @exception NullPointerException if the action is <code>null</code> - * - * @see #doPrivileged(PrivilegedAction) - * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext) - * @see #doPrivilegedWithCombiner(PrivilegedExceptionAction) - * @see java.security.DomainCombiner - */ - @CallerSensitive - public static <T> T - doPrivileged(PrivilegedExceptionAction<T> action) - throws PrivilegedActionException { - return (T)doPrivileged(action, null, CallerID.getCallerID()); - } - - - /** - * Performs the specified <code>PrivilegedExceptionAction</code> with - * privileges enabled. The action is performed with <i>all</i> of the - * permissions possessed by the caller's protection domain. - * - * <p> If the action's <code>run</code> method throws an <i>unchecked</i> - * exception, it will propagate through this method. - * - * <p> This method preserves the current AccessControlContext's - * DomainCombiner (which may be null) while the action is performed. - * - * @param action the action to be performed. - * - * @return the value returned by the action's <code>run</code> method - * - * @exception PrivilegedActionException if the specified action's - * <code>run</code> method threw a <i>checked</i> exception - * @exception NullPointerException if the action is <code>null</code> - * - * @see #doPrivileged(PrivilegedAction) - * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext) - * @see java.security.DomainCombiner - * - * @since 1.6 - */ - @CallerSensitive - public static <T> T doPrivilegedWithCombiner - (PrivilegedExceptionAction<T> action) throws PrivilegedActionException { - - AccessControlContext acc = getStackAccessControlContext(); - if (acc == null) { - return AccessController.doPrivileged(action); - } - DomainCombiner dc = acc.getAssignedCombiner(); - return AccessController.doPrivileged(action, preserveCombiner(dc, Reflection.getCallerClass())); - } - - /** - * preserve the combiner across the doPrivileged call - */ - private static AccessControlContext preserveCombiner(DomainCombiner combiner, - final Class<?> caller) { - ProtectionDomain callerPd = doPrivileged - (new PrivilegedAction<ProtectionDomain>() { - public ProtectionDomain run() { - return caller.getProtectionDomain(); - } - }); - - // perform 'combine' on the caller of doPrivileged, - // even if the caller is from the bootclasspath - ProtectionDomain[] pds = new ProtectionDomain[] {callerPd}; - if (combiner == null) { - return new AccessControlContext(pds); - } else { - return new AccessControlContext(combiner.combine(pds, null), - combiner); - } - } - - - /** - * Performs the specified <code>PrivilegedExceptionAction</code> with - * privileges enabled and restricted by the specified - * <code>AccessControlContext</code>. The action is performed with the - * intersection of the permissions possessed by the caller's - * protection domain, and those possessed by the domains represented by the - * specified <code>AccessControlContext</code>. - * <p> - * If the action's <code>run</code> method throws an <i>unchecked</i> - * exception, it will propagate through this method. - * - * @param action the action to be performed - * @param context an <i>access control context</i> - * representing the restriction to be applied to the - * caller's domain's privileges before performing - * the specified action. If the context is - * <code>null</code>, - * then no additional restriction is applied. - * - * @return the value returned by the action's <code>run</code> method - * - * @exception PrivilegedActionException if the specified action's - * <code>run</code> method - * threw a <i>checked</i> exception - * @exception NullPointerException if the action is <code>null</code> - * - * @see #doPrivileged(PrivilegedAction) - * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext) - */ - @CallerSensitive - public static <T> T - doPrivileged(PrivilegedExceptionAction<T> action, - AccessControlContext context) - throws PrivilegedActionException { - return (T)doPrivileged(action, context, CallerID.getCallerID()); - } - - /** - * Returns the AccessControl context. i.e., it gets - * the protection domains of all the callers on the stack, - * starting at the first class with a non-null - * ProtectionDomain. - * - * @return the access control context based on the current stack or - * null if there was only privileged system code. - */ - - private static AccessControlContext getStackAccessControlContext() { - AccessControlContext context = null; - CallerID callerID = null; - PrivilegedElement pi = privileged_stack_top; - if (pi != null) { - context = pi.context; - callerID = pi.callerID; - } - return getStackAccessControlContext(context, callerID); - } - - private static native AccessControlContext getStackAccessControlContext(AccessControlContext context, CallerID callerID); - - /** - * Returns the "inherited" AccessControl context. This is the context - * that existed when the thread was created. Package private so - * AccessControlContext can use it. - */ - - static native AccessControlContext getInheritedAccessControlContext(); - - /** - * This method takes a "snapshot" of the current calling context, which - * includes the current Thread's inherited AccessControlContext, - * and places it in an AccessControlContext object. This context may then - * be checked at a later point, possibly in another thread. - * - * @see AccessControlContext - * - * @return the AccessControlContext based on the current context. - */ - - public static AccessControlContext getContext() - { - AccessControlContext acc = getStackAccessControlContext(); - if (acc == null) { - // all we had was privileged system code. We don't want - // to return null though, so we construct a real ACC. - return new AccessControlContext(null, true); - } else { - return acc.optimize(); - } - } - - /** - * Determines whether the access request indicated by the - * specified permission should be allowed or denied, based on - * the current AccessControlContext and security policy. - * This method quietly returns if the access request - * is permitted, or throws an AccessControlException otherwise. The - * getPermission method of the AccessControlException returns the - * <code>perm</code> Permission object instance. - * - * @param perm the requested permission. - * - * @exception AccessControlException if the specified permission - * is not permitted, based on the current security policy. - * @exception NullPointerException if the specified permission - * is <code>null</code> and is checked based on the - * security policy currently in effect. - */ - - public static void checkPermission(Permission perm) - throws AccessControlException - { - //System.err.println("checkPermission "+perm); - //Thread.currentThread().dumpStack(); - - if (perm == null) { - throw new NullPointerException("permission can't be null"); - } - - AccessControlContext stack = getStackAccessControlContext(); - // if context is null, we had privileged system code on the stack. - if (stack == null) { - Debug debug = AccessControlContext.getDebug(); - boolean dumpDebug = false; - if (debug != null) { - dumpDebug = !Debug.isOn("codebase="); - dumpDebug &= !Debug.isOn("permission=") || - Debug.isOn("permission=" + perm.getClass().getCanonicalName()); - } - - if (dumpDebug && Debug.isOn("stack")) { - Thread.currentThread().dumpStack(); - } - - if (dumpDebug && Debug.isOn("domain")) { - debug.println("domain (context is null)"); - } - - if (dumpDebug) { - debug.println("access allowed "+perm); - } - return; - } - - AccessControlContext acc = stack.optimize(); - acc.checkPermission(perm); - } -} diff --git a/openjdk/java/security/ProtectionDomain.java b/openjdk/java/security/ProtectionDomain.java deleted file mode 100644 index 3ceda027..00000000 --- a/openjdk/java/security/ProtectionDomain.java +++ /dev/null @@ -1,528 +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 java.security; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Enumeration; -import java.util.List; -import java.util.Map; -import java.util.WeakHashMap; -import sun.misc.JavaSecurityProtectionDomainAccess; -import static sun.misc.JavaSecurityProtectionDomainAccess.ProtectionDomainCache; -import sun.misc.SharedSecrets; -import sun.security.util.Debug; -import sun.security.util.SecurityConstants; -import sun.misc.JavaSecurityAccess; -import sun.misc.SharedSecrets; - -/** - * - *<p> - * This ProtectionDomain class encapsulates the characteristics of a domain, - * which encloses a set of classes whose instances are granted a set - * of permissions when being executed on behalf of a given set of Principals. - * <p> - * A static set of permissions can be bound to a ProtectionDomain when it is - * constructed; such permissions are granted to the domain regardless of the - * Policy in force. However, to support dynamic security policies, a - * ProtectionDomain can also be constructed such that it is dynamically - * mapped to a set of permissions by the current Policy whenever a permission - * is checked. - * <p> - * - * @author Li Gong - * @author Roland Schemers - * @author Gary Ellison - */ - -public class ProtectionDomain { - - static { - // Set up JavaSecurityAccess in SharedSecrets - SharedSecrets.setJavaSecurityAccess( - new JavaSecurityAccess() { - public <T> T doIntersectionPrivilege( - PrivilegedAction<T> action, - final AccessControlContext stack, - final AccessControlContext context) - { - if (action == null) { - throw new NullPointerException(); - } - return AccessController.doPrivileged( - action, - new AccessControlContext( - stack.getContext(), context).optimize() - ); - } - - public <T> T doIntersectionPrivilege( - PrivilegedAction<T> action, - AccessControlContext context) - { - return doIntersectionPrivilege(action, - AccessController.getContext(), context); - } - } - ); - } - - /* CodeSource */ - private CodeSource codesource ; - - /* [IKVM] If this is a protection from an Assembly class loader, we lazily construct the codesource, classloader and permissions */ - private cli.System.Reflection.Assembly assembly; - - /* ClassLoader the protection domain was consed from */ - private ClassLoader classloader; - - /* Principals running-as within this protection domain */ - private Principal[] principals; - - /* the rights this protection domain is granted */ - private PermissionCollection permissions; - - /* if the permissions object has AllPermission */ - private boolean hasAllPerm = false; - - /* the PermissionCollection is static (pre 1.4 constructor) - or dynamic (via a policy refresh) */ - private boolean staticPermissions; - - /* - * An object used as a key when the ProtectionDomain is stored in a Map. - */ - final Key key = new Key(); - - /* [IKVM] constructor for use by the runtime (AssemblyClassLoader) */ - ProtectionDomain(cli.System.Reflection.Assembly assembly) { - this.assembly = assembly; - this.hasAllPerm = true; - this.staticPermissions = true; - this.principals = new Principal[0]; - } - - /* [IKVM] */ - private void lazyInitClassLoader() { - if (classloader == null && assembly != null) { - classloader = ikvm.runtime.AssemblyClassLoader.getAssemblyClassLoader(assembly); - } - } - - /* [IKVM] */ - private void lazyInitPermissions() { - if (permissions == null && hasAllPerm) { - Permissions p = new Permissions(); - p.add(new AllPermission()); - p.setReadOnly(); - // we lock on principals since that is a private object - synchronized (principals) { - if (permissions == null) { - permissions = p; - } - } - } - } - - /* [IKVM] */ - private void lazyInitCodeSource() { - if (codesource == null && assembly != null) { - java.net.URL url; - try { - if (false) throw new cli.System.NotSupportedException(); - url = new java.net.URL(assembly.get_EscapedCodeBase()); - } catch (java.net.MalformedURLException _) { - url = null; - } catch (cli.System.NotSupportedException _) { - // dynamic assemblies don't have a codebase - url = null; - } - CodeSource cs = new CodeSource(url, (java.security.cert.Certificate[])null); - // we lock on principals since that is a private object - synchronized (principals) { - if (codesource == null) { - codesource = cs; - } - } - } - } - - /** - * Creates a new ProtectionDomain with the given CodeSource and - * Permissions. If the permissions object is not null, then - * <code>setReadOnly())</code> will be called on the passed in - * Permissions object. The only permissions granted to this domain - * are the ones specified; the current Policy will not be consulted. - * - * @param codesource the codesource associated with this domain - * @param permissions the permissions granted to this domain - */ - public ProtectionDomain(CodeSource codesource, - PermissionCollection permissions) { - this.codesource = codesource; - if (permissions != null) { - this.permissions = permissions; - this.permissions.setReadOnly(); - if (permissions instanceof Permissions && - ((Permissions)permissions).allPermission != null) { - hasAllPerm = true; - } - } - this.classloader = null; - this.principals = new Principal[0]; - staticPermissions = true; - } - - /** - * Creates a new ProtectionDomain qualified by the given CodeSource, - * Permissions, ClassLoader and array of Principals. If the - * permissions object is not null, then <code>setReadOnly()</code> - * will be called on the passed in Permissions object. - * The permissions granted to this domain are dynamic; they include - * both the static permissions passed to this constructor, and any - * permissions granted to this domain by the current Policy at the - * time a permission is checked. - * <p> - * This constructor is typically used by - * {@link SecureClassLoader ClassLoaders} - * and {@link DomainCombiner DomainCombiners} which delegate to - * <code>Policy</code> to actively associate the permissions granted to - * this domain. This constructor affords the - * Policy provider the opportunity to augment the supplied - * PermissionCollection to reflect policy changes. - * <p> - * - * @param codesource the CodeSource associated with this domain - * @param permissions the permissions granted to this domain - * @param classloader the ClassLoader associated with this domain - * @param principals the array of Principals associated with this - * domain. The contents of the array are copied to protect against - * subsequent modification. - * @see Policy#refresh - * @see Policy#getPermissions(ProtectionDomain) - * @since 1.4 - */ - public ProtectionDomain(CodeSource codesource, - PermissionCollection permissions, - ClassLoader classloader, - Principal[] principals) { - this.codesource = codesource; - if (permissions != null) { - this.permissions = permissions; - this.permissions.setReadOnly(); - if (permissions instanceof Permissions && - ((Permissions)permissions).allPermission != null) { - hasAllPerm = true; - } - } - this.classloader = classloader; - this.principals = (principals != null ? principals.clone(): - new Principal[0]); - staticPermissions = false; - } - - /** - * Returns the CodeSource of this domain. - * @return the CodeSource of this domain which may be null. - * @since 1.2 - */ - public final CodeSource getCodeSource() { - lazyInitCodeSource(); - return this.codesource; - } - - - /** - * Returns the ClassLoader of this domain. - * @return the ClassLoader of this domain which may be null. - * - * @since 1.4 - */ - public final ClassLoader getClassLoader() { - lazyInitClassLoader(); - return this.classloader; - } - - - /** - * Returns an array of principals for this domain. - * @return a non-null array of principals for this domain. - * Returns a new array each time this method is called. - * - * @since 1.4 - */ - public final Principal[] getPrincipals() { - return this.principals.clone(); - } - - /** - * Returns the static permissions granted to this domain. - * - * @return the static set of permissions for this domain which may be null. - * @see Policy#refresh - * @see Policy#getPermissions(ProtectionDomain) - */ - public final PermissionCollection getPermissions() { - lazyInitPermissions(); - return permissions; - } - - /** - * Check and see if this ProtectionDomain implies the permissions - * expressed in the Permission object. - * <p> - * The set of permissions evaluated is a function of whether the - * ProtectionDomain was constructed with a static set of permissions - * or it was bound to a dynamically mapped set of permissions. - * <p> - * If the ProtectionDomain was constructed to a - * {@link #ProtectionDomain(CodeSource, PermissionCollection) - * statically bound} PermissionCollection then the permission will - * only be checked against the PermissionCollection supplied at - * construction. - * <p> - * However, if the ProtectionDomain was constructed with - * the constructor variant which supports - * {@link #ProtectionDomain(CodeSource, PermissionCollection, - * ClassLoader, java.security.Principal[]) dynamically binding} - * permissions, then the permission will be checked against the - * combination of the PermissionCollection supplied at construction and - * the current Policy binding. - * <p> - * - * @param permission the Permission object to check. - * - * @return true if "permission" is implicit to this ProtectionDomain. - */ - public boolean implies(Permission permission) { - - if (hasAllPerm) { - // internal permission collection already has AllPermission - - // no need to go to policy - return true; - } - - if (!staticPermissions && - Policy.getPolicyNoCheck().implies(this, permission)) - return true; - if (permissions != null) - return permissions.implies(permission); - - return false; - } - - /** - * Convert a ProtectionDomain to a String. - */ - @Override public String toString() { - lazyInitCodeSource(); - lazyInitClassLoader(); - String pals = "<no principals>"; - if (principals != null && principals.length > 0) { - StringBuilder palBuf = new StringBuilder("(principals "); - - for (int i = 0; i < principals.length; i++) { - palBuf.append(principals[i].getClass().getName() + - " \"" + principals[i].getName() + - "\""); - if (i < principals.length-1) - palBuf.append(",\n"); - else - palBuf.append(")\n"); - } - pals = palBuf.toString(); - } - - // Check if policy is set; we don't want to load - // the policy prematurely here - PermissionCollection pc = Policy.isSet() && seeAllp() ? - mergePermissions(): - getPermissions(); - - return "ProtectionDomain "+ - " "+codesource+"\n"+ - " "+classloader+"\n"+ - " "+pals+"\n"+ - " "+pc+"\n"; - } - - /** - * Return true (merge policy permissions) in the following cases: - * - * . SecurityManager is null - * - * . SecurityManager is not null, - * debug is not null, - * SecurityManager impelmentation is in bootclasspath, - * Policy implementation is in bootclasspath - * (the bootclasspath restrictions avoid recursion) - * - * . SecurityManager is not null, - * debug is null, - * caller has Policy.getPolicy permission - */ - private static boolean seeAllp() { - SecurityManager sm = System.getSecurityManager(); - - if (sm == null) { - return true; - } else { - Debug debug = Debug.getInstance("domain"); - if (debug != null) { - if (sm.getClass().getClassLoader() == null && - Policy.getPolicyNoCheck().getClass().getClassLoader() - == null) { - return true; - } - } else { - try { - sm.checkPermission(SecurityConstants.GET_POLICY_PERMISSION); - return true; - } catch (SecurityException se) { - // fall thru and return false - } - } - } - - return false; - } - - private PermissionCollection mergePermissions() { - lazyInitPermissions(); - if (staticPermissions) - return permissions; - - PermissionCollection perms = - java.security.AccessController.doPrivileged - (new java.security.PrivilegedAction<PermissionCollection>() { - public PermissionCollection run() { - Policy p = Policy.getPolicyNoCheck(); - return p.getPermissions(ProtectionDomain.this); - } - }); - - Permissions mergedPerms = new Permissions(); - int swag = 32; - int vcap = 8; - Enumeration<Permission> e; - List<Permission> pdVector = new ArrayList<>(vcap); - List<Permission> plVector = new ArrayList<>(swag); - - // - // Build a vector of domain permissions for subsequent merge - if (permissions != null) { - synchronized (permissions) { - e = permissions.elements(); - while (e.hasMoreElements()) { - pdVector.add(e.nextElement()); - } - } - } - - // - // Build a vector of Policy permissions for subsequent merge - if (perms != null) { - synchronized (perms) { - e = perms.elements(); - while (e.hasMoreElements()) { - plVector.add(e.nextElement()); - vcap++; - } - } - } - - if (perms != null && permissions != null) { - // - // Weed out the duplicates from the policy. Unless a refresh - // has occured since the pd was consed this should result in - // an empty vector. - synchronized (permissions) { - e = permissions.elements(); // domain vs policy - while (e.hasMoreElements()) { - Permission pdp = e.nextElement(); - Class pdpClass = pdp.getClass(); - String pdpActions = pdp.getActions(); - String pdpName = pdp.getName(); - for (int i = 0; i < plVector.size(); i++) { - Permission pp = plVector.get(i); - if (pdpClass.isInstance(pp)) { - // The equals() method on some permissions - // have some side effects so this manual - // comparison is sufficient. - if (pdpName.equals(pp.getName()) && - pdpActions.equals(pp.getActions())) { - plVector.remove(i); - break; - } - } - } - } - } - } - - if (perms !=null) { - // the order of adding to merged perms and permissions - // needs to preserve the bugfix 4301064 - - for (int i = plVector.size()-1; i >= 0; i--) { - mergedPerms.add(plVector.get(i)); - } - } - if (permissions != null) { - for (int i = pdVector.size()-1; i >= 0; i--) { - mergedPerms.add(pdVector.get(i)); - } - } - - return mergedPerms; - } - - /** - * Used for storing ProtectionDomains as keys in a Map. - */ - final class Key {} - - static { - SharedSecrets.setJavaSecurityProtectionDomainAccess( - new JavaSecurityProtectionDomainAccess() { - public ProtectionDomainCache getProtectionDomainCache() { - return new ProtectionDomainCache() { - private final Map<Key, PermissionCollection> map = - Collections.synchronizedMap - (new WeakHashMap<Key, PermissionCollection>()); - public void put(ProtectionDomain pd, - PermissionCollection pc) { - map.put((pd == null ? null : pd.key), pc); - } - public PermissionCollection get(ProtectionDomain pd) { - return pd == null ? map.get(null) : map.get(pd.key); - } - }; - } - }); - } -} diff --git a/openjdk/java/sql/DriverManager.java b/openjdk/java/sql/DriverManager.java deleted file mode 100644 index 8698345c..00000000 --- a/openjdk/java/sql/DriverManager.java +++ /dev/null @@ -1,624 +0,0 @@ -/* - * 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 - * 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.sql; - -import java.util.Iterator; -import java.util.ServiceLoader; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.concurrent.CopyOnWriteArrayList; -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; - -/** - * <P>The basic service for managing a set of JDBC drivers.<br> - * <B>NOTE:</B> The {@link <code>DataSource</code>} interface, new in the - * JDBC 2.0 API, provides another way to connect to a data source. - * The use of a <code>DataSource</code> object is the preferred means of - * connecting to a data source. - * - * <P>As part of its initialization, the <code>DriverManager</code> class will - * attempt to load the driver classes referenced in the "jdbc.drivers" - * system property. This allows a user to customize the JDBC Drivers - * used by their applications. For example in your - * ~/.hotjava/properties file you might specify: - * <pre> - * <CODE>jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver</CODE> - * </pre> - *<P> The <code>DriverManager</code> methods <code>getConnection</code> and - * <code>getDrivers</code> have been enhanced to support the Java Standard Edition - * <a href="../../../technotes/guides/jar/jar.html#Service%20Provider">Service Provider</a> mechanism. JDBC 4.0 Drivers must - * include the file <code>META-INF/services/java.sql.Driver</code>. This file contains the name of the JDBC drivers - * implementation of <code>java.sql.Driver</code>. For example, to load the <code>my.sql.Driver</code> class, - * the <code>META-INF/services/java.sql.Driver</code> file would contain the entry: - * <pre> - * <code>my.sql.Driver</code> - * </pre> - * - * <P>Applications no longer need to explictly load JDBC drivers using <code>Class.forName()</code>. Existing programs - * which currently load JDBC drivers using <code>Class.forName()</code> will continue to work without - * modification. - * - * <P>When the method <code>getConnection</code> is called, - * the <code>DriverManager</code> will attempt to - * locate a suitable driver from amongst those loaded at - * initialization and those loaded explicitly using the same classloader - * as the current applet or application. - * - * <P> - * Starting with the Java 2 SDK, Standard Edition, version 1.3, a - * logging stream can be set only if the proper - * permission has been granted. Normally this will be done with - * the tool PolicyTool, which can be used to grant <code>permission - * java.sql.SQLPermission "setLog"</code>. - * @see Driver - * @see Connection - */ -public class DriverManager { - - - // List of registered JDBC drivers - private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<DriverInfo>(); - private static volatile int loginTimeout = 0; - private static volatile java.io.PrintWriter logWriter = null; - private static volatile java.io.PrintStream logStream = null; - // Used in println() to synchronize logWriter - private final static Object logSync = new Object(); - - /* Prevent the DriverManager class from being instantiated. */ - private DriverManager(){} - - - /** - * Load the initial JDBC drivers by checking the System property - * jdbc.properties and then use the {@code ServiceLoader} mechanism - */ - static { - loadInitialDrivers(); - println("JDBC DriverManager initialized"); - } - - /** - * The <code>SQLPermission</code> constant that allows the - * setting of the logging stream. - * @since 1.3 - */ - final static SQLPermission SET_LOG_PERMISSION = - new SQLPermission("setLog"); - - //--------------------------JDBC 2.0----------------------------- - - /** - * Retrieves the log writer. - * - * The <code>getLogWriter</code> and <code>setLogWriter</code> - * methods should be used instead - * of the <code>get/setlogStream</code> methods, which are deprecated. - * @return a <code>java.io.PrintWriter</code> object - * @see #setLogWriter - * @since 1.2 - */ - public static java.io.PrintWriter getLogWriter() { - return logWriter; - } - - /** - * Sets the logging/tracing <code>PrintWriter</code> object - * that is used by the <code>DriverManager</code> and all drivers. - * <P> - * There is a minor versioning problem created by the introduction - * of the method <code>setLogWriter</code>. The - * method <code>setLogWriter</code> cannot create a <code>PrintStream</code> object - * that will be returned by <code>getLogStream</code>---the Java platform does - * not provide a backward conversion. As a result, a new application - * that uses <code>setLogWriter</code> and also uses a JDBC 1.0 driver that uses - * <code>getLogStream</code> will likely not see debugging information written - * by that driver. - *<P> - * Starting with the Java 2 SDK, Standard Edition, version 1.3 release, this method checks - * to see that there is an <code>SQLPermission</code> object before setting - * the logging stream. If a <code>SecurityManager</code> exists and its - * <code>checkPermission</code> method denies setting the log writer, this - * method throws a <code>java.lang.SecurityException</code>. - * - * @param out the new logging/tracing <code>PrintStream</code> object; - * <code>null</code> to disable logging and tracing - * @throws SecurityException - * if a security manager exists and its - * <code>checkPermission</code> method denies - * setting the log writer - * - * @see SecurityManager#checkPermission - * @see #getLogWriter - * @since 1.2 - */ - public static void setLogWriter(java.io.PrintWriter out) { - - SecurityManager sec = System.getSecurityManager(); - if (sec != null) { - sec.checkPermission(SET_LOG_PERMISSION); - } - logStream = null; - logWriter = out; - } - - - //--------------------------------------------------------------- - - /** - * Attempts to establish a connection to the given database URL. - * The <code>DriverManager</code> attempts to select an appropriate driver from - * the set of registered JDBC drivers. - * - * @param url a database url of the form - * <code> jdbc:<em>subprotocol</em>:<em>subname</em></code> - * @param info a list of arbitrary string tag/value pairs as - * connection arguments; normally at least a "user" and - * "password" property should be included - * @return a Connection to the URL - * @exception SQLException if a database access error occurs - */ - @CallerSensitive - public static Connection getConnection(String url, - java.util.Properties info) throws SQLException { - return (getConnection(url, info, Reflection.getCallerClass())); - } - - /** - * Attempts to establish a connection to the given database URL. - * The <code>DriverManager</code> attempts to select an appropriate driver from - * the set of registered JDBC drivers. - * - * @param url a database url of the form - * <code>jdbc:<em>subprotocol</em>:<em>subname</em></code> - * @param user the database user on whose behalf the connection is being - * made - * @param password the user's password - * @return a connection to the URL - * @exception SQLException if a database access error occurs - */ - @CallerSensitive - public static Connection getConnection(String url, - String user, String password) throws SQLException { - java.util.Properties info = new java.util.Properties(); - - if (user != null) { - info.put("user", user); - } - if (password != null) { - info.put("password", password); - } - - return (getConnection(url, info, Reflection.getCallerClass())); - } - - /** - * Attempts to establish a connection to the given database URL. - * The <code>DriverManager</code> attempts to select an appropriate driver from - * the set of registered JDBC drivers. - * - * @param url a database url of the form - * <code> jdbc:<em>subprotocol</em>:<em>subname</em></code> - * @return a connection to the URL - * @exception SQLException if a database access error occurs - */ - @CallerSensitive - public static Connection getConnection(String url) - throws SQLException { - - java.util.Properties info = new java.util.Properties(); - return (getConnection(url, info, Reflection.getCallerClass())); - } - - /** - * Attempts to locate a driver that understands the given URL. - * The <code>DriverManager</code> attempts to select an appropriate driver from - * the set of registered JDBC drivers. - * - * @param url a database URL of the form - * <code>jdbc:<em>subprotocol</em>:<em>subname</em></code> - * @return a <code>Driver</code> object representing a driver - * that can connect to the given URL - * @exception SQLException if a database access error occurs - */ - @CallerSensitive - public static Driver getDriver(String url) - throws SQLException { - - println("DriverManager.getDriver(\"" + url + "\")"); - - Class<?> callerClass = Reflection.getCallerClass(); - - // Walk through the loaded registeredDrivers attempting to locate someone - // who understands the given URL. - for (DriverInfo aDriver : registeredDrivers) { - // If the caller does not have permission to load the driver then - // skip it. - if(isDriverAllowed(aDriver.driver, callerClass)) { - try { - if(aDriver.driver.acceptsURL(url)) { - // Success! - println("getDriver returning " + aDriver.driver.getClass().getName()); - return (aDriver.driver); - } - - } catch(SQLException sqe) { - // Drop through and try the next driver. - } - } else { - println(" skipping: " + aDriver.driver.getClass().getName()); - } - - } - - println("getDriver: no suitable driver"); - throw new SQLException("No suitable driver", "08001"); - } - - - /** - * Registers the given driver with the <code>DriverManager</code>. - * A newly-loaded driver class should call - * the method <code>registerDriver</code> to make itself - * known to the <code>DriverManager</code>. - * - * @param driver the new JDBC Driver that is to be registered with the - * <code>DriverManager</code> - * @exception SQLException if a database access error occurs - */ - public static synchronized void registerDriver(java.sql.Driver driver) - throws SQLException { - - /* Register the driver if it has not already been added to our list */ - if(driver != null) { - registeredDrivers.addIfAbsent(new DriverInfo(driver)); - } else { - // This is for compatibility with the original DriverManager - throw new NullPointerException(); - } - - println("registerDriver: " + driver); - - } - - /** - * Drops a driver from the <code>DriverManager</code>'s list. - * Applets can only deregister drivers from their own classloaders. - * - * @param driver the JDBC Driver to drop - * @exception SQLException if a database access error occurs - */ - @CallerSensitive - public static synchronized void deregisterDriver(Driver driver) - throws SQLException { - if (driver == null) { - return; - } - - println("DriverManager.deregisterDriver: " + driver); - - DriverInfo aDriver = new DriverInfo(driver); - if(registeredDrivers.contains(aDriver)) { - if (isDriverAllowed(driver, Reflection.getCallerClass())) { - registeredDrivers.remove(aDriver); - } else { - // If the caller does not have permission to load the driver then - // throw a SecurityException. - throw new SecurityException(); - } - } else { - println(" couldn't find driver to unload"); - } - } - - /** - * Retrieves an Enumeration with all of the currently loaded JDBC drivers - * to which the current caller has access. - * - * <P><B>Note:</B> The classname of a driver can be found using - * <CODE>d.getClass().getName()</CODE> - * - * @return the list of JDBC Drivers loaded by the caller's class loader - */ - @CallerSensitive - public static java.util.Enumeration<Driver> getDrivers() { - java.util.Vector<Driver> result = new java.util.Vector<Driver>(); - - Class<?> callerClass = Reflection.getCallerClass(); - - // Walk through the loaded registeredDrivers. - for(DriverInfo aDriver : registeredDrivers) { - // If the caller does not have permission to load the driver then - // skip it. - if(isDriverAllowed(aDriver.driver, callerClass)) { - result.addElement(aDriver.driver); - } else { - println(" skipping: " + aDriver.getClass().getName()); - } - } - return (result.elements()); - } - - - /** - * Sets the maximum time in seconds that a driver will wait - * while attempting to connect to a database. - * - * @param seconds the login time limit in seconds; zero means there is no limit - * @see #getLoginTimeout - */ - public static void setLoginTimeout(int seconds) { - loginTimeout = seconds; - } - - /** - * Gets the maximum time in seconds that a driver can wait - * when attempting to log in to a database. - * - * @return the driver login time limit in seconds - * @see #setLoginTimeout - */ - public static int getLoginTimeout() { - return (loginTimeout); - } - - /** - * Sets the logging/tracing PrintStream that is used - * by the <code>DriverManager</code> - * and all drivers. - *<P> - * In the Java 2 SDK, Standard Edition, version 1.3 release, this method checks - * to see that there is an <code>SQLPermission</code> object before setting - * the logging stream. If a <code>SecurityManager</code> exists and its - * <code>checkPermission</code> method denies setting the log writer, this - * method throws a <code>java.lang.SecurityException</code>. - * - * @param out the new logging/tracing PrintStream; to disable, set to <code>null</code> - * @deprecated - * @throws SecurityException if a security manager exists and its - * <code>checkPermission</code> method denies setting the log stream - * - * @see SecurityManager#checkPermission - * @see #getLogStream - */ - public static void setLogStream(java.io.PrintStream out) { - - SecurityManager sec = System.getSecurityManager(); - if (sec != null) { - sec.checkPermission(SET_LOG_PERMISSION); - } - - logStream = out; - if ( out != null ) - logWriter = new java.io.PrintWriter(out); - else - logWriter = null; - } - - /** - * Retrieves the logging/tracing PrintStream that is used by the <code>DriverManager</code> - * and all drivers. - * - * @return the logging/tracing PrintStream; if disabled, is <code>null</code> - * @deprecated - * @see #setLogStream - */ - public static java.io.PrintStream getLogStream() { - return logStream; - } - - /** - * Prints a message to the current JDBC log stream. - * - * @param message a log or tracing message - */ - public static void println(String message) { - synchronized (logSync) { - if (logWriter != null) { - logWriter.println(message); - - // automatic flushing is never enabled, so we must do it ourselves - logWriter.flush(); - } - } - } - - //------------------------------------------------------------------------ - - // Indicates whether the class object that would be created if the code calling - // DriverManager is accessible. - private static boolean isDriverAllowed(Driver driver, Class<?> caller) { - ClassLoader callerCL = caller != null ? caller.getClassLoader() : null; - return isDriverAllowed(driver, callerCL); - } - - private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) { - boolean result = false; - if(driver != null) { - Class<?> aClass = null; - try { - aClass = Class.forName(driver.getClass().getName(), true, classLoader); - } catch (Exception ex) { - result = false; - } - - result = ( aClass == driver.getClass() ) ? true : false; - } - - return result; - } - - private static void loadInitialDrivers() { - String drivers; - try { - drivers = AccessController.doPrivileged(new PrivilegedAction<String>() { - public String run() { - return System.getProperty("jdbc.drivers"); - } - }); - } catch (Exception ex) { - drivers = null; - } - // If the driver is packaged as a Service Provider, load it. - // Get all the drivers through the classloader - // exposed as a java.sql.Driver.class service. - // ServiceLoader.load() replaces the sun.misc.Providers() - - AccessController.doPrivileged(new PrivilegedAction<Void>() { - public Void run() { - - ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class); - Iterator driversIterator = loadedDrivers.iterator(); - - /* Load these drivers, so that they can be instantiated. - * It may be the case that the driver class may not be there - * i.e. there may be a packaged driver with the service class - * as implementation of java.sql.Driver but the actual class - * may be missing. In that case a java.util.ServiceConfigurationError - * will be thrown at runtime by the VM trying to locate - * and load the service. - * - * Adding a try catch block to catch those runtime errors - * if driver not available in classpath but it's - * packaged as service and that service is there in classpath. - */ - try{ - while(driversIterator.hasNext()) { - driversIterator.next(); - } - } catch(Throwable t) { - // Do nothing - } - return null; - } - }); - - println("DriverManager.initialize: jdbc.drivers = " + drivers); - - if (drivers == null || drivers.equals("")) { - return; - } - String[] driversList = drivers.split(":"); - println("number of Drivers:" + driversList.length); - for (String aDriver : driversList) { - try { - println("DriverManager.Initialize: loading " + aDriver); - Class.forName(aDriver, true, - ClassLoader.getSystemClassLoader()); - } catch (Exception ex) { - println("DriverManager.Initialize: load failed: " + ex); - } - } - } - - - // Worker method called by the public getConnection() methods. - private static Connection getConnection( - String url, java.util.Properties info, Class<?> caller) throws SQLException { - /* - * When callerCl is null, we should check the application's - * (which is invoking this class indirectly) - * classloader, so that the JDBC driver class outside rt.jar - * can be loaded from here. - */ - ClassLoader callerCL = caller != null ? caller.getClassLoader() : null; - synchronized (DriverManager.class) { - // synchronize loading of the correct classloader. - if (callerCL == null) { - callerCL = Thread.currentThread().getContextClassLoader(); - } - } - - if(url == null) { - throw new SQLException("The url cannot be null", "08001"); - } - - println("DriverManager.getConnection(\"" + url + "\")"); - - // Walk through the loaded registeredDrivers attempting to make a connection. - // Remember the first exception that gets raised so we can reraise it. - SQLException reason = null; - - for(DriverInfo aDriver : registeredDrivers) { - // If the caller does not have permission to load the driver then - // skip it. - if(isDriverAllowed(aDriver.driver, callerCL)) { - try { - println(" trying " + aDriver.driver.getClass().getName()); - Connection con = aDriver.driver.connect(url, info); - if (con != null) { - // Success! - println("getConnection returning " + aDriver.driver.getClass().getName()); - return (con); - } - } catch (SQLException ex) { - if (reason == null) { - reason = ex; - } - } - - } else { - println(" skipping: " + aDriver.getClass().getName()); - } - - } - - // if we got here nobody could connect. - if (reason != null) { - println("getConnection failed: " + reason); - throw reason; - } - - println("getConnection: no suitable driver found for "+ url); - throw new SQLException("No suitable driver found for "+ url, "08001"); - } -} - -/* - * Wrapper class for registered Drivers in order to not expose Driver.equals() - * to avoid the capture of the Driver it being compared to as it might not - * normally have access. - */ -class DriverInfo { - - final Driver driver; - DriverInfo(Driver driver) { - this.driver = driver; - } - - public boolean equals(Object other) { - return (other instanceof DriverInfo) - && this.driver == ((DriverInfo) other).driver; - } - - public int hashCode() { - return driver.hashCode(); - } - - public String toString() { - return ("driver[className=" + driver + "]"); - } -} diff --git a/openjdk/java/util/ResourceBundle.java b/openjdk/java/util/ResourceBundle.java deleted file mode 100644 index 98ee3c51..00000000 --- a/openjdk/java/util/ResourceBundle.java +++ /dev/null @@ -1,2912 +0,0 @@ -/* - * Copyright (c) 1996, 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. - */ - -/* - * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved - * (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved - * - * The original version of this source code and documentation - * is copyrighted and owned by Taligent, Inc., a wholly-owned - * subsidiary of IBM. These materials are provided under terms - * of a License Agreement between Taligent and Sun. This technology - * is protected by multiple US and International patents. - * - * This notice and attribution to Taligent may not be removed. - * Taligent is a registered trademark of Taligent, Inc. - * - */ - -package java.util; - -import java.io.IOException; -import java.io.InputStream; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.SoftReference; -import java.lang.ref.WeakReference; -import java.net.JarURLConnection; -import java.net.URL; -import java.net.URLConnection; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.jar.JarEntry; - -import sun.reflect.CallerSensitive; -import sun.reflect.Reflection; -import sun.util.locale.BaseLocale; -import sun.util.locale.LocaleObjectCache; - - -/** - * - * Resource bundles contain locale-specific objects. When your program needs a - * locale-specific resource, a <code>String</code> for example, your program can - * load it from the resource bundle that is appropriate for the current user's - * locale. In this way, you can write program code that is largely independent - * of the user's locale isolating most, if not all, of the locale-specific - * information in resource bundles. - * - * <p> - * This allows you to write programs that can: - * <UL type=SQUARE> - * <LI> be easily localized, or translated, into different languages - * <LI> handle multiple locales at once - * <LI> be easily modified later to support even more locales - * </UL> - * - * <P> - * Resource bundles belong to families whose members share a common base - * name, but whose names also have additional components that identify - * their locales. For example, the base name of a family of resource - * bundles might be "MyResources". The family should have a default - * resource bundle which simply has the same name as its family - - * "MyResources" - and will be used as the bundle of last resort if a - * specific locale is not supported. The family can then provide as - * many locale-specific members as needed, for example a German one - * named "MyResources_de". - * - * <P> - * Each resource bundle in a family contains the same items, but the items have - * been translated for the locale represented by that resource bundle. - * For example, both "MyResources" and "MyResources_de" may have a - * <code>String</code> that's used on a button for canceling operations. - * In "MyResources" the <code>String</code> may contain "Cancel" and in - * "MyResources_de" it may contain "Abbrechen". - * - * <P> - * If there are different resources for different countries, you - * can make specializations: for example, "MyResources_de_CH" contains objects for - * the German language (de) in Switzerland (CH). If you want to only - * modify some of the resources - * in the specialization, you can do so. - * - * <P> - * When your program needs a locale-specific object, it loads - * the <code>ResourceBundle</code> class using the - * {@link #getBundle(java.lang.String, java.util.Locale) getBundle} - * method: - * <blockquote> - * <pre> - * ResourceBundle myResources = - * ResourceBundle.getBundle("MyResources", currentLocale); - * </pre> - * </blockquote> - * - * <P> - * Resource bundles contain key/value pairs. The keys uniquely - * identify a locale-specific object in the bundle. Here's an - * example of a <code>ListResourceBundle</code> that contains - * two key/value pairs: - * <blockquote> - * <pre> - * public class MyResources extends ListResourceBundle { - * protected Object[][] getContents() { - * return new Object[][] { - * // LOCALIZE THE SECOND STRING OF EACH ARRAY (e.g., "OK") - * {"OkKey", "OK"}, - * {"CancelKey", "Cancel"}, - * // END OF MATERIAL TO LOCALIZE - * }; - * } - * } - * </pre> - * </blockquote> - * Keys are always <code>String</code>s. - * In this example, the keys are "OkKey" and "CancelKey". - * In the above example, the values - * are also <code>String</code>s--"OK" and "Cancel"--but - * they don't have to be. The values can be any type of object. - * - * <P> - * You retrieve an object from resource bundle using the appropriate - * getter method. Because "OkKey" and "CancelKey" - * are both strings, you would use <code>getString</code> to retrieve them: - * <blockquote> - * <pre> - * button1 = new Button(myResources.getString("OkKey")); - * button2 = new Button(myResources.getString("CancelKey")); - * </pre> - * </blockquote> - * The getter methods all require the key as an argument and return - * the object if found. If the object is not found, the getter method - * throws a <code>MissingResourceException</code>. - * - * <P> - * Besides <code>getString</code>, <code>ResourceBundle</code> also provides - * a method for getting string arrays, <code>getStringArray</code>, - * as well as a generic <code>getObject</code> method for any other - * type of object. When using <code>getObject</code>, you'll - * have to cast the result to the appropriate type. For example: - * <blockquote> - * <pre> - * int[] myIntegers = (int[]) myResources.getObject("intList"); - * </pre> - * </blockquote> - * - * <P> - * The Java Platform provides two subclasses of <code>ResourceBundle</code>, - * <code>ListResourceBundle</code> and <code>PropertyResourceBundle</code>, - * that provide a fairly simple way to create resources. - * As you saw briefly in a previous example, <code>ListResourceBundle</code> - * manages its resource as a list of key/value pairs. - * <code>PropertyResourceBundle</code> uses a properties file to manage - * its resources. - * - * <p> - * If <code>ListResourceBundle</code> or <code>PropertyResourceBundle</code> - * do not suit your needs, you can write your own <code>ResourceBundle</code> - * subclass. Your subclasses must override two methods: <code>handleGetObject</code> - * and <code>getKeys()</code>. - * - * <h4>ResourceBundle.Control</h4> - * - * The {@link ResourceBundle.Control} class provides information necessary - * to perform the bundle loading process by the <code>getBundle</code> - * factory methods that take a <code>ResourceBundle.Control</code> - * instance. You can implement your own subclass in order to enable - * non-standard resource bundle formats, change the search strategy, or - * define caching parameters. Refer to the descriptions of the class and the - * {@link #getBundle(String, Locale, ClassLoader, Control) getBundle} - * factory method for details. - * - * <h4>Cache Management</h4> - * - * Resource bundle instances created by the <code>getBundle</code> factory - * methods are cached by default, and the factory methods return the same - * resource bundle instance multiple times if it has been - * cached. <code>getBundle</code> clients may clear the cache, manage the - * lifetime of cached resource bundle instances using time-to-live values, - * or specify not to cache resource bundle instances. Refer to the - * descriptions of the {@linkplain #getBundle(String, Locale, ClassLoader, - * Control) <code>getBundle</code> factory method}, {@link - * #clearCache(ClassLoader) clearCache}, {@link - * Control#getTimeToLive(String, Locale) - * ResourceBundle.Control.getTimeToLive}, and {@link - * Control#needsReload(String, Locale, String, ClassLoader, ResourceBundle, - * long) ResourceBundle.Control.needsReload} for details. - * - * <h4>Example</h4> - * - * The following is a very simple example of a <code>ResourceBundle</code> - * subclass, <code>MyResources</code>, that manages two resources (for a larger number of - * resources you would probably use a <code>Map</code>). - * Notice that you don't need to supply a value if - * a "parent-level" <code>ResourceBundle</code> handles the same - * key with the same value (as for the okKey below). - * <blockquote> - * <pre> - * // default (English language, United States) - * public class MyResources extends ResourceBundle { - * public Object handleGetObject(String key) { - * if (key.equals("okKey")) return "Ok"; - * if (key.equals("cancelKey")) return "Cancel"; - * return null; - * } - * - * public Enumeration<String> getKeys() { - * return Collections.enumeration(keySet()); - * } - * - * // Overrides handleKeySet() so that the getKeys() implementation - * // can rely on the keySet() value. - * protected Set<String> handleKeySet() { - * return new HashSet<String>(Arrays.asList("okKey", "cancelKey")); - * } - * } - * - * // German language - * public class MyResources_de extends MyResources { - * public Object handleGetObject(String key) { - * // don't need okKey, since parent level handles it. - * if (key.equals("cancelKey")) return "Abbrechen"; - * return null; - * } - * - * protected Set<String> handleKeySet() { - * return new HashSet<String>(Arrays.asList("cancelKey")); - * } - * } - * </pre> - * </blockquote> - * You do not have to restrict yourself to using a single family of - * <code>ResourceBundle</code>s. For example, you could have a set of bundles for - * exception messages, <code>ExceptionResources</code> - * (<code>ExceptionResources_fr</code>, <code>ExceptionResources_de</code>, ...), - * and one for widgets, <code>WidgetResource</code> (<code>WidgetResources_fr</code>, - * <code>WidgetResources_de</code>, ...); breaking up the resources however you like. - * - * @see ListResourceBundle - * @see PropertyResourceBundle - * @see MissingResourceException - * @since JDK1.1 - */ -public abstract class ResourceBundle { - - /** initial size of the bundle cache */ - private static final int INITIAL_CACHE_SIZE = 32; - - /** constant indicating that no resource bundle exists */ - private static final ResourceBundle NONEXISTENT_BUNDLE = new ResourceBundle() { - public Enumeration<String> getKeys() { return null; } - protected Object handleGetObject(String key) { return null; } - public String toString() { return "NONEXISTENT_BUNDLE"; } - }; - - - /** - * The cache is a map from cache keys (with bundle base name, locale, and - * class loader) to either a resource bundle or NONEXISTENT_BUNDLE wrapped by a - * BundleReference. - * - * The cache is a ConcurrentMap, allowing the cache to be searched - * concurrently by multiple threads. This will also allow the cache keys - * to be reclaimed along with the ClassLoaders they reference. - * - * This variable would be better named "cache", but we keep the old - * name for compatibility with some workarounds for bug 4212439. - */ - private static final ConcurrentMap<CacheKey, BundleReference> cacheList - = new ConcurrentHashMap<>(INITIAL_CACHE_SIZE); - - /** - * Queue for reference objects referring to class loaders or bundles. - */ - private static final ReferenceQueue referenceQueue = new ReferenceQueue(); - - /** - * The parent bundle of this bundle. - * The parent bundle is searched by {@link #getObject getObject} - * when this bundle does not contain a particular resource. - */ - protected ResourceBundle parent = null; - - /** - * The locale for this bundle. - */ - private Locale locale = null; - - /** - * The base bundle name for this bundle. - */ - private String name; - - /** - * The flag indicating this bundle has expired in the cache. - */ - private volatile boolean expired; - - /** - * The back link to the cache key. null if this bundle isn't in - * the cache (yet) or has expired. - */ - private volatile CacheKey cacheKey; - - /** - * A Set of the keys contained only in this ResourceBundle. - */ - private volatile Set<String> keySet; - - /** - * Sole constructor. (For invocation by subclass constructors, typically - * implicit.) - */ - public ResourceBundle() { - } - - /** - * Gets a string for the given key from this resource bundle or one of its parents. - * Calling this method is equivalent to calling - * <blockquote> - * <code>(String) {@link #getObject(java.lang.String) getObject}(key)</code>. - * </blockquote> - * - * @param key the key for the desired string - * @exception NullPointerException if <code>key</code> is <code>null</code> - * @exception MissingResourceException if no object for the given key can be found - * @exception ClassCastException if the object found for the given key is not a string - * @return the string for the given key - */ - public final String getString(String key) { - return (String) getObject(key); - } - - /** - * Gets a string array for the given key from this resource bundle or one of its parents. - * Calling this method is equivalent to calling - * <blockquote> - * <code>(String[]) {@link #getObject(java.lang.String) getObject}(key)</code>. - * </blockquote> - * - * @param key the key for the desired string array - * @exception NullPointerException if <code>key</code> is <code>null</code> - * @exception MissingResourceException if no object for the given key can be found - * @exception ClassCastException if the object found for the given key is not a string array - * @return the string array for the given key - */ - public final String[] getStringArray(String key) { - return (String[]) getObject(key); - } - - /** - * Gets an object for the given key from this resource bundle or one of its parents. - * This method first tries to obtain the object from this resource bundle using - * {@link #handleGetObject(java.lang.String) handleGetObject}. - * If not successful, and the parent resource bundle is not null, - * it calls the parent's <code>getObject</code> method. - * If still not successful, it throws a MissingResourceException. - * - * @param key the key for the desired object - * @exception NullPointerException if <code>key</code> is <code>null</code> - * @exception MissingResourceException if no object for the given key can be found - * @return the object for the given key - */ - public final Object getObject(String key) { - Object obj = handleGetObject(key); - if (obj == null) { - if (parent != null) { - obj = parent.getObject(key); - } - if (obj == null) - throw new MissingResourceException("Can't find resource for bundle " - +this.getClass().getName() - +", key "+key, - this.getClass().getName(), - key); - } - return obj; - } - - /** - * Returns the locale of this resource bundle. This method can be used after a - * call to getBundle() to determine whether the resource bundle returned really - * corresponds to the requested locale or is a fallback. - * - * @return the locale of this resource bundle - */ - public Locale getLocale() { - return locale; - } - - /* - * Automatic determination of the ClassLoader to be used to load - * resources on behalf of the client. - */ - private static ClassLoader getLoader(Class<?> caller) { - ClassLoader cl = caller == null ? null : caller.getClassLoader(); - if (cl == null) { - // When the caller's loader is the boot class loader, cl is null - // here. In that case, ClassLoader.getSystemClassLoader() may - // return the same class loader that the application is - // using. We therefore use a wrapper ClassLoader to create a - // separate scope for bundles loaded on behalf of the Java - // runtime so that these bundles cannot be returned from the - // cache to the application (5048280). - cl = RBClassLoader.INSTANCE; - } - return cl; - } - - /** - * A wrapper of ClassLoader.getSystemClassLoader(). - */ - private static class RBClassLoader extends ClassLoader { - private static final RBClassLoader INSTANCE = AccessController.doPrivileged( - new PrivilegedAction<RBClassLoader>() { - public RBClassLoader run() { - return new RBClassLoader(); - } - }); - private static final ClassLoader loader = ClassLoader.getSystemClassLoader(); - - private RBClassLoader() { - } - public Class<?> loadClass(String name) throws ClassNotFoundException { - if (loader != null) { - return loader.loadClass(name); - } - return Class.forName(name); - } - public URL getResource(String name) { - if (loader != null) { - return loader.getResource(name); - } - return ClassLoader.getSystemResource(name); - } - public InputStream getResourceAsStream(String name) { - if (loader != null) { - return loader.getResourceAsStream(name); - } - return ClassLoader.getSystemResourceAsStream(name); - } - } - - /** - * Sets the parent bundle of this bundle. - * The parent bundle is searched by {@link #getObject getObject} - * when this bundle does not contain a particular resource. - * - * @param parent this bundle's parent bundle. - */ - protected void setParent(ResourceBundle parent) { - assert parent != NONEXISTENT_BUNDLE; - this.parent = parent; - } - - /** - * Key used for cached resource bundles. The key checks the base - * name, the locale, and the class loader to determine if the - * resource is a match to the requested one. The loader may be - * null, but the base name and the locale must have a non-null - * value. - */ - private static final class CacheKey implements Cloneable { - // These three are the actual keys for lookup in Map. - private String name; - private Locale locale; - private LoaderReference loaderRef; - - // bundle format which is necessary for calling - // Control.needsReload(). - private String format; - - // These time values are in CacheKey so that NONEXISTENT_BUNDLE - // doesn't need to be cloned for caching. - - // The time when the bundle has been loaded - private volatile long loadTime; - - // The time when the bundle expires in the cache, or either - // Control.TTL_DONT_CACHE or Control.TTL_NO_EXPIRATION_CONTROL. - private volatile long expirationTime; - - // Placeholder for an error report by a Throwable - private Throwable cause; - - // Hash code value cache to avoid recalculating the hash code - // of this instance. - private int hashCodeCache; - - CacheKey(String baseName, Locale locale, ClassLoader loader) { - this.name = baseName; - this.locale = locale; - if (loader == null) { - this.loaderRef = null; - } else { - loaderRef = new LoaderReference(loader, referenceQueue, this); - } - calculateHashCode(); - } - - String getName() { - return name; - } - - CacheKey setName(String baseName) { - if (!this.name.equals(baseName)) { - this.name = baseName; - calculateHashCode(); - } - return this; - } - - Locale getLocale() { - return locale; - } - - CacheKey setLocale(Locale locale) { - if (!this.locale.equals(locale)) { - this.locale = locale; - calculateHashCode(); - } - return this; - } - - ClassLoader getLoader() { - return (loaderRef != null) ? loaderRef.get() : null; - } - - public boolean equals(Object other) { - if (this == other) { - return true; - } - try { - final CacheKey otherEntry = (CacheKey)other; - //quick check to see if they are not equal - if (hashCodeCache != otherEntry.hashCodeCache) { - return false; - } - //are the names the same? - if (!name.equals(otherEntry.name)) { - return false; - } - // are the locales the same? - if (!locale.equals(otherEntry.locale)) { - return false; - } - //are refs (both non-null) or (both null)? - if (loaderRef == null) { - return otherEntry.loaderRef == null; - } - ClassLoader loader = loaderRef.get(); - return (otherEntry.loaderRef != null) - // with a null reference we can no longer find - // out which class loader was referenced; so - // treat it as unequal - && (loader != null) - && (loader == otherEntry.loaderRef.get()); - } catch (NullPointerException e) { - } catch (ClassCastException e) { - } - return false; - } - - public int hashCode() { - return hashCodeCache; - } - - private void calculateHashCode() { - hashCodeCache = name.hashCode() << 3; - hashCodeCache ^= locale.hashCode(); - ClassLoader loader = getLoader(); - if (loader != null) { - hashCodeCache ^= loader.hashCode(); - } - } - - public Object clone() { - try { - CacheKey clone = (CacheKey) super.clone(); - if (loaderRef != null) { - clone.loaderRef = new LoaderReference(loaderRef.get(), - referenceQueue, clone); - } - // Clear the reference to a Throwable - clone.cause = null; - return clone; - } catch (CloneNotSupportedException e) { - //this should never happen - throw new InternalError(); - } - } - - String getFormat() { - return format; - } - - void setFormat(String format) { - this.format = format; - } - - private void setCause(Throwable cause) { - if (this.cause == null) { - this.cause = cause; - } else { - // Override the cause if the previous one is - // ClassNotFoundException. - if (this.cause instanceof ClassNotFoundException) { - this.cause = cause; - } - } - } - - private Throwable getCause() { - return cause; - } - - public String toString() { - String l = locale.toString(); - if (l.length() == 0) { - if (locale.getVariant().length() != 0) { - l = "__" + locale.getVariant(); - } else { - l = "\"\""; - } - } - return "CacheKey[" + name + ", lc=" + l + ", ldr=" + getLoader() - + "(format=" + format + ")]"; - } - } - - /** - * The common interface to get a CacheKey in LoaderReference and - * BundleReference. - */ - private static interface CacheKeyReference { - public CacheKey getCacheKey(); - } - - /** - * References to class loaders are weak references, so that they can be - * garbage collected when nobody else is using them. The ResourceBundle - * class has no reason to keep class loaders alive. - */ - private static final class LoaderReference extends WeakReference<ClassLoader> - implements CacheKeyReference { - private CacheKey cacheKey; - - LoaderReference(ClassLoader referent, ReferenceQueue q, CacheKey key) { - super(referent, q); - cacheKey = key; - } - - public CacheKey getCacheKey() { - return cacheKey; - } - } - - /** - * References to bundles are soft references so that they can be garbage - * collected when they have no hard references. - */ - private static final class BundleReference extends SoftReference<ResourceBundle> - implements CacheKeyReference { - private CacheKey cacheKey; - - BundleReference(ResourceBundle referent, ReferenceQueue q, CacheKey key) { - super(referent, q); - cacheKey = key; - } - - public CacheKey getCacheKey() { - return cacheKey; - } - } - - /** - * Gets a resource bundle using the specified base name, the default locale, - * and the caller's class loader. Calling this method is equivalent to calling - * <blockquote> - * <code>getBundle(baseName, Locale.getDefault(), this.getClass().getClassLoader())</code>, - * </blockquote> - * except that <code>getClassLoader()</code> is run with the security - * privileges of <code>ResourceBundle</code>. - * See {@link #getBundle(String, Locale, ClassLoader) getBundle} - * for a complete description of the search and instantiation strategy. - * - * @param baseName the base name of the resource bundle, a fully qualified class name - * @exception java.lang.NullPointerException - * if <code>baseName</code> is <code>null</code> - * @exception MissingResourceException - * if no resource bundle for the specified base name can be found - * @return a resource bundle for the given base name and the default locale - */ - @CallerSensitive - public static final ResourceBundle getBundle(String baseName) - { - return getBundleImpl(baseName, Locale.getDefault(), - /* must determine loader here, else we break stack invariant */ - getLoader(Reflection.getCallerClass()), - Control.INSTANCE); - } - - /** - * Returns a resource bundle using the specified base name, the - * default locale and the specified control. Calling this method - * is equivalent to calling - * <pre> - * getBundle(baseName, Locale.getDefault(), - * this.getClass().getClassLoader(), control), - * </pre> - * except that <code>getClassLoader()</code> is run with the security - * privileges of <code>ResourceBundle</code>. See {@link - * #getBundle(String, Locale, ClassLoader, Control) getBundle} for the - * complete description of the resource bundle loading process with a - * <code>ResourceBundle.Control</code>. - * - * @param baseName - * the base name of the resource bundle, a fully qualified class - * name - * @param control - * the control which gives information for the resource bundle - * loading process - * @return a resource bundle for the given base name and the default - * locale - * @exception NullPointerException - * if <code>baseName</code> or <code>control</code> is - * <code>null</code> - * @exception MissingResourceException - * if no resource bundle for the specified base name can be found - * @exception IllegalArgumentException - * if the given <code>control</code> doesn't perform properly - * (e.g., <code>control.getCandidateLocales</code> returns null.) - * Note that validation of <code>control</code> is performed as - * needed. - * @since 1.6 - */ - @CallerSensitive - public static final ResourceBundle getBundle(String baseName, - Control control) { - return getBundleImpl(baseName, Locale.getDefault(), - /* must determine loader here, else we break stack invariant */ - getLoader(Reflection.getCallerClass()), - control); - } - - /** - * Gets a resource bundle using the specified base name and locale, - * and the caller's class loader. Calling this method is equivalent to calling - * <blockquote> - * <code>getBundle(baseName, locale, this.getClass().getClassLoader())</code>, - * </blockquote> - * except that <code>getClassLoader()</code> is run with the security - * privileges of <code>ResourceBundle</code>. - * See {@link #getBundle(String, Locale, ClassLoader) getBundle} - * for a complete description of the search and instantiation strategy. - * - * @param baseName - * the base name of the resource bundle, a fully qualified class name - * @param locale - * the locale for which a resource bundle is desired - * @exception NullPointerException - * if <code>baseName</code> or <code>locale</code> is <code>null</code> - * @exception MissingResourceException - * if no resource bundle for the specified base name can be found - * @return a resource bundle for the given base name and locale - */ - @CallerSensitive - public static final ResourceBundle getBundle(String baseName, - Locale locale) - { - return getBundleImpl(baseName, locale, - /* must determine loader here, else we break stack invariant */ - getLoader(Reflection.getCallerClass()), - Control.INSTANCE); - } - - /** - * Returns a resource bundle using the specified base name, target - * locale and control, and the caller's class loader. Calling this - * method is equivalent to calling - * <pre> - * getBundle(baseName, targetLocale, this.getClass().getClassLoader(), - * control), - * </pre> - * except that <code>getClassLoader()</code> is run with the security - * privileges of <code>ResourceBundle</code>. See {@link - * #getBundle(String, Locale, ClassLoader, Control) getBundle} for the - * complete description of the resource bundle loading process with a - * <code>ResourceBundle.Control</code>. - * - * @param baseName - * the base name of the resource bundle, a fully qualified - * class name - * @param targetLocale - * the locale for which a resource bundle is desired - * @param control - * the control which gives information for the resource - * bundle loading process - * @return a resource bundle for the given base name and a - * <code>Locale</code> in <code>locales</code> - * @exception NullPointerException - * if <code>baseName</code>, <code>locales</code> or - * <code>control</code> is <code>null</code> - * @exception MissingResourceException - * if no resource bundle for the specified base name in any - * of the <code>locales</code> can be found. - * @exception IllegalArgumentException - * if the given <code>control</code> doesn't perform properly - * (e.g., <code>control.getCandidateLocales</code> returns null.) - * Note that validation of <code>control</code> is performed as - * needed. - * @since 1.6 - */ - @CallerSensitive - public static final ResourceBundle getBundle(String baseName, Locale targetLocale, - Control control) { - return getBundleImpl(baseName, targetLocale, - /* must determine loader here, else we break stack invariant */ - getLoader(Reflection.getCallerClass()), - control); - } - - /** - * Gets a resource bundle using the specified base name, locale, and class - * loader. - * - * <p><a name="default_behavior"/>This method behaves the same as calling - * {@link #getBundle(String, Locale, ClassLoader, Control)} passing a - * default instance of {@link Control}. The following describes this behavior. - * - * <p><code>getBundle</code> uses the base name, the specified locale, and - * the default locale (obtained from {@link java.util.Locale#getDefault() - * Locale.getDefault}) to generate a sequence of <a - * name="candidates"><em>candidate bundle names</em></a>. If the specified - * locale's language, script, country, and variant are all empty strings, - * then the base name is the only candidate bundle name. Otherwise, a list - * of candidate locales is generated from the attribute values of the - * specified locale (language, script, country and variant) and appended to - * the base name. Typically, this will look like the following: - * - * <pre> - * baseName + "_" + language + "_" + script + "_" + country + "_" + variant - * baseName + "_" + language + "_" + script + "_" + country - * baseName + "_" + language + "_" + script - * baseName + "_" + language + "_" + country + "_" + variant - * baseName + "_" + language + "_" + country - * baseName + "_" + language - * </pre> - * - * <p>Candidate bundle names where the final component is an empty string - * are omitted, along with the underscore. For example, if country is an - * empty string, the second and the fifth candidate bundle names above - * would be omitted. Also, if script is an empty string, the candidate names - * including script are omitted. For example, a locale with language "de" - * and variant "JAVA" will produce candidate names with base name - * "MyResource" below. - * - * <pre> - * MyResource_de__JAVA - * MyResource_de - * </pre> - * - * In the case that the variant contains one or more underscores ('_'), a - * sequence of bundle names generated by truncating the last underscore and - * the part following it is inserted after a candidate bundle name with the - * original variant. For example, for a locale with language "en", script - * "Latn, country "US" and variant "WINDOWS_VISTA", and bundle base name - * "MyResource", the list of candidate bundle names below is generated: - * - * <pre> - * MyResource_en_Latn_US_WINDOWS_VISTA - * MyResource_en_Latn_US_WINDOWS - * MyResource_en_Latn_US - * MyResource_en_Latn - * MyResource_en_US_WINDOWS_VISTA - * MyResource_en_US_WINDOWS - * MyResource_en_US - * MyResource_en - * </pre> - * - * <blockquote><b>Note:</b> For some <code>Locale</code>s, the list of - * candidate bundle names contains extra names, or the order of bundle names - * is slightly modified. See the description of the default implementation - * of {@link Control#getCandidateLocales(String, Locale) - * getCandidateLocales} for details.</blockquote> - * - * <p><code>getBundle</code> then iterates over the candidate bundle names - * to find the first one for which it can <em>instantiate</em> an actual - * resource bundle. It uses the default controls' {@link Control#getFormats - * getFormats} method, which generates two bundle names for each generated - * name, the first a class name and the second a properties file name. For - * each candidate bundle name, it attempts to create a resource bundle: - * - * <ul><li>First, it attempts to load a class using the generated class name. - * If such a class can be found and loaded using the specified class - * loader, is assignment compatible with ResourceBundle, is accessible from - * ResourceBundle, and can be instantiated, <code>getBundle</code> creates a - * new instance of this class and uses it as the <em>result resource - * bundle</em>. - * - * <li>Otherwise, <code>getBundle</code> attempts to locate a property - * resource file using the generated properties file name. It generates a - * path name from the candidate bundle name by replacing all "." characters - * with "/" and appending the string ".properties". It attempts to find a - * "resource" with this name using {@link - * java.lang.ClassLoader#getResource(java.lang.String) - * ClassLoader.getResource}. (Note that a "resource" in the sense of - * <code>getResource</code> has nothing to do with the contents of a - * resource bundle, it is just a container of data, such as a file.) If it - * finds a "resource", it attempts to create a new {@link - * PropertyResourceBundle} instance from its contents. If successful, this - * instance becomes the <em>result resource bundle</em>. </ul> - * - * <p>This continues until a result resource bundle is instantiated or the - * list of candidate bundle names is exhausted. If no matching resource - * bundle is found, the default control's {@link Control#getFallbackLocale - * getFallbackLocale} method is called, which returns the current default - * locale. A new sequence of candidate locale names is generated using this - * locale and and searched again, as above. - * - * <p>If still no result bundle is found, the base name alone is looked up. If - * this still fails, a <code>MissingResourceException</code> is thrown. - * - * <p><a name="parent_chain"/> Once a result resource bundle has been found, - * its <em>parent chain</em> is instantiated. If the result bundle already - * has a parent (perhaps because it was returned from a cache) the chain is - * complete. - * - * <p>Otherwise, <code>getBundle</code> examines the remainder of the - * candidate locale list that was used during the pass that generated the - * result resource bundle. (As before, candidate bundle names where the - * final component is an empty string are omitted.) When it comes to the - * end of the candidate list, it tries the plain bundle name. With each of the - * candidate bundle names it attempts to instantiate a resource bundle (first - * looking for a class and then a properties file, as described above). - * - * <p>Whenever it succeeds, it calls the previously instantiated resource - * bundle's {@link #setParent(java.util.ResourceBundle) setParent} method - * with the new resource bundle. This continues until the list of names - * is exhausted or the current bundle already has a non-null parent. - * - * <p>Once the parent chain is complete, the bundle is returned. - * - * <p><b>Note:</b> <code>getBundle</code> caches instantiated resource - * bundles and might return the same resource bundle instance multiple times. - * - * <p><b>Note:</b>The <code>baseName</code> argument should be a fully - * qualified class name. However, for compatibility with earlier versions, - * Sun's Java SE Runtime Environments do not verify this, and so it is - * possible to access <code>PropertyResourceBundle</code>s by specifying a - * path name (using "/") instead of a fully qualified class name (using - * "."). - * - * <p><a name="default_behavior_example"/> - * <strong>Example:</strong> - * <p> - * The following class and property files are provided: - * <pre> - * MyResources.class - * MyResources.properties - * MyResources_fr.properties - * MyResources_fr_CH.class - * MyResources_fr_CH.properties - * MyResources_en.properties - * MyResources_es_ES.class - * </pre> - * - * The contents of all files are valid (that is, public non-abstract - * subclasses of <code>ResourceBundle</code> for the ".class" files, - * syntactically correct ".properties" files). The default locale is - * <code>Locale("en", "GB")</code>. - * - * <p>Calling <code>getBundle</code> with the locale arguments below will - * instantiate resource bundles as follows: - * - * <table> - * <tr><td>Locale("fr", "CH")</td><td>MyResources_fr_CH.class, parent MyResources_fr.properties, parent MyResources.class</td></tr> - * <tr><td>Locale("fr", "FR")</td><td>MyResources_fr.properties, parent MyResources.class</td></tr> - * <tr><td>Locale("de", "DE")</td><td>MyResources_en.properties, parent MyResources.class</td></tr> - * <tr><td>Locale("en", "US")</td><td>MyResources_en.properties, parent MyResources.class</td></tr> - * <tr><td>Locale("es", "ES")</td><td>MyResources_es_ES.class, parent MyResources.class</td></tr> - * </table> - * - * <p>The file MyResources_fr_CH.properties is never used because it is - * hidden by the MyResources_fr_CH.class. Likewise, MyResources.properties - * is also hidden by MyResources.class. - * - * @param baseName the base name of the resource bundle, a fully qualified class name - * @param locale the locale for which a resource bundle is desired - * @param loader the class loader from which to load the resource bundle - * @return a resource bundle for the given base name and locale - * @exception java.lang.NullPointerException - * if <code>baseName</code>, <code>locale</code>, or <code>loader</code> is <code>null</code> - * @exception MissingResourceException - * if no resource bundle for the specified base name can be found - * @since 1.2 - */ - public static ResourceBundle getBundle(String baseName, Locale locale, - ClassLoader loader) - { - if (loader == null) { - throw new NullPointerException(); - } - return getBundleImpl(baseName, locale, loader, Control.INSTANCE); - } - - /** - * Returns a resource bundle using the specified base name, target - * locale, class loader and control. Unlike the {@linkplain - * #getBundle(String, Locale, ClassLoader) <code>getBundle</code> - * factory methods with no <code>control</code> argument}, the given - * <code>control</code> specifies how to locate and instantiate resource - * bundles. Conceptually, the bundle loading process with the given - * <code>control</code> is performed in the following steps. - * - * <p> - * <ol> - * <li>This factory method looks up the resource bundle in the cache for - * the specified <code>baseName</code>, <code>targetLocale</code> and - * <code>loader</code>. If the requested resource bundle instance is - * found in the cache and the time-to-live periods of the instance and - * all of its parent instances have not expired, the instance is returned - * to the caller. Otherwise, this factory method proceeds with the - * loading process below.</li> - * - * <li>The {@link ResourceBundle.Control#getFormats(String) - * control.getFormats} method is called to get resource bundle formats - * to produce bundle or resource names. The strings - * <code>"java.class"</code> and <code>"java.properties"</code> - * designate class-based and {@linkplain PropertyResourceBundle - * property}-based resource bundles, respectively. Other strings - * starting with <code>"java."</code> are reserved for future extensions - * and must not be used for application-defined formats. Other strings - * designate application-defined formats.</li> - * - * <li>The {@link ResourceBundle.Control#getCandidateLocales(String, - * Locale) control.getCandidateLocales} method is called with the target - * locale to get a list of <em>candidate <code>Locale</code>s</em> for - * which resource bundles are searched.</li> - * - * <li>The {@link ResourceBundle.Control#newBundle(String, Locale, - * String, ClassLoader, boolean) control.newBundle} method is called to - * instantiate a <code>ResourceBundle</code> for the base bundle name, a - * candidate locale, and a format. (Refer to the note on the cache - * lookup below.) This step is iterated over all combinations of the - * candidate locales and formats until the <code>newBundle</code> method - * returns a <code>ResourceBundle</code> instance or the iteration has - * used up all the combinations. For example, if the candidate locales - * are <code>Locale("de", "DE")</code>, <code>Locale("de")</code> and - * <code>Locale("")</code> and the formats are <code>"java.class"</code> - * and <code>"java.properties"</code>, then the following is the - * sequence of locale-format combinations to be used to call - * <code>control.newBundle</code>. - * - * <table style="width: 50%; text-align: left; margin-left: 40px;" - * border="0" cellpadding="2" cellspacing="2"> - * <tbody><code> - * <tr> - * <td - * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;">Locale<br> - * </td> - * <td - * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;">format<br> - * </td> - * </tr> - * <tr> - * <td style="vertical-align: top; width: 50%;">Locale("de", "DE")<br> - * </td> - * <td style="vertical-align: top; width: 50%;">java.class<br> - * </td> - * </tr> - * <tr> - * <td style="vertical-align: top; width: 50%;">Locale("de", "DE")</td> - * <td style="vertical-align: top; width: 50%;">java.properties<br> - * </td> - * </tr> - * <tr> - * <td style="vertical-align: top; width: 50%;">Locale("de")</td> - * <td style="vertical-align: top; width: 50%;">java.class</td> - * </tr> - * <tr> - * <td style="vertical-align: top; width: 50%;">Locale("de")</td> - * <td style="vertical-align: top; width: 50%;">java.properties</td> - * </tr> - * <tr> - * <td style="vertical-align: top; width: 50%;">Locale("")<br> - * </td> - * <td style="vertical-align: top; width: 50%;">java.class</td> - * </tr> - * <tr> - * <td style="vertical-align: top; width: 50%;">Locale("")</td> - * <td style="vertical-align: top; width: 50%;">java.properties</td> - * </tr> - * </code></tbody> - * </table> - * </li> - * - * <li>If the previous step has found no resource bundle, proceed to - * Step 6. If a bundle has been found that is a base bundle (a bundle - * for <code>Locale("")</code>), and the candidate locale list only contained - * <code>Locale("")</code>, return the bundle to the caller. If a bundle - * has been found that is a base bundle, but the candidate locale list - * contained locales other than Locale(""), put the bundle on hold and - * proceed to Step 6. If a bundle has been found that is not a base - * bundle, proceed to Step 7.</li> - * - * <li>The {@link ResourceBundle.Control#getFallbackLocale(String, - * Locale) control.getFallbackLocale} method is called to get a fallback - * locale (alternative to the current target locale) to try further - * finding a resource bundle. If the method returns a non-null locale, - * it becomes the next target locale and the loading process starts over - * from Step 3. Otherwise, if a base bundle was found and put on hold in - * a previous Step 5, it is returned to the caller now. Otherwise, a - * MissingResourceException is thrown.</li> - * - * <li>At this point, we have found a resource bundle that's not the - * base bundle. If this bundle set its parent during its instantiation, - * it is returned to the caller. Otherwise, its <a - * href="./ResourceBundle.html#parent_chain">parent chain</a> is - * instantiated based on the list of candidate locales from which it was - * found. Finally, the bundle is returned to the caller.</li> - * </ol> - * - * <p>During the resource bundle loading process above, this factory - * method looks up the cache before calling the {@link - * Control#newBundle(String, Locale, String, ClassLoader, boolean) - * control.newBundle} method. If the time-to-live period of the - * resource bundle found in the cache has expired, the factory method - * calls the {@link ResourceBundle.Control#needsReload(String, Locale, - * String, ClassLoader, ResourceBundle, long) control.needsReload} - * method to determine whether the resource bundle needs to be reloaded. - * If reloading is required, the factory method calls - * <code>control.newBundle</code> to reload the resource bundle. If - * <code>control.newBundle</code> returns <code>null</code>, the factory - * method puts a dummy resource bundle in the cache as a mark of - * nonexistent resource bundles in order to avoid lookup overhead for - * subsequent requests. Such dummy resource bundles are under the same - * expiration control as specified by <code>control</code>. - * - * <p>All resource bundles loaded are cached by default. Refer to - * {@link Control#getTimeToLive(String,Locale) - * control.getTimeToLive} for details. - * - * <p>The following is an example of the bundle loading process with the - * default <code>ResourceBundle.Control</code> implementation. - * - * <p>Conditions: - * <ul> - * <li>Base bundle name: <code>foo.bar.Messages</code> - * <li>Requested <code>Locale</code>: {@link Locale#ITALY}</li> - * <li>Default <code>Locale</code>: {@link Locale#FRENCH}</li> - * <li>Available resource bundles: - * <code>foo/bar/Messages_fr.properties</code> and - * <code>foo/bar/Messages.properties</code></li> - * </ul> - * - * <p>First, <code>getBundle</code> tries loading a resource bundle in - * the following sequence. - * - * <ul> - * <li>class <code>foo.bar.Messages_it_IT</code> - * <li>file <code>foo/bar/Messages_it_IT.properties</code> - * <li>class <code>foo.bar.Messages_it</code></li> - * <li>file <code>foo/bar/Messages_it.properties</code></li> - * <li>class <code>foo.bar.Messages</code></li> - * <li>file <code>foo/bar/Messages.properties</code></li> - * </ul> - * - * <p>At this point, <code>getBundle</code> finds - * <code>foo/bar/Messages.properties</code>, which is put on hold - * because it's the base bundle. <code>getBundle</code> calls {@link - * Control#getFallbackLocale(String, Locale) - * control.getFallbackLocale("foo.bar.Messages", Locale.ITALY)} which - * returns <code>Locale.FRENCH</code>. Next, <code>getBundle</code> - * tries loading a bundle in the following sequence. - * - * <ul> - * <li>class <code>foo.bar.Messages_fr</code></li> - * <li>file <code>foo/bar/Messages_fr.properties</code></li> - * <li>class <code>foo.bar.Messages</code></li> - * <li>file <code>foo/bar/Messages.properties</code></li> - * </ul> - * - * <p><code>getBundle</code> finds - * <code>foo/bar/Messages_fr.properties</code> and creates a - * <code>ResourceBundle</code> instance. Then, <code>getBundle</code> - * sets up its parent chain from the list of the candiate locales. Only - * <code>foo/bar/Messages.properties</code> is found in the list and - * <code>getBundle</code> creates a <code>ResourceBundle</code> instance - * that becomes the parent of the instance for - * <code>foo/bar/Messages_fr.properties</code>. - * - * @param baseName - * the base name of the resource bundle, a fully qualified - * class name - * @param targetLocale - * the locale for which a resource bundle is desired - * @param loader - * the class loader from which to load the resource bundle - * @param control - * the control which gives information for the resource - * bundle loading process - * @return a resource bundle for the given base name and locale - * @exception NullPointerException - * if <code>baseName</code>, <code>targetLocale</code>, - * <code>loader</code>, or <code>control</code> is - * <code>null</code> - * @exception MissingResourceException - * if no resource bundle for the specified base name can be found - * @exception IllegalArgumentException - * if the given <code>control</code> doesn't perform properly - * (e.g., <code>control.getCandidateLocales</code> returns null.) - * Note that validation of <code>control</code> is performed as - * needed. - * @since 1.6 - */ - public static ResourceBundle getBundle(String baseName, Locale targetLocale, - ClassLoader loader, Control control) { - if (loader == null || control == null) { - throw new NullPointerException(); - } - return getBundleImpl(baseName, targetLocale, loader, control); - } - - private static ResourceBundle getBundleImpl(String baseName, Locale locale, - ClassLoader loader, Control control) { - if (locale == null || control == null) { - throw new NullPointerException(); - } - - // We create a CacheKey here for use by this call. The base - // name and loader will never change during the bundle loading - // process. We have to make sure that the locale is set before - // using it as a cache key. - CacheKey cacheKey = new CacheKey(baseName, locale, loader); - ResourceBundle bundle = null; - - // Quick lookup of the cache. - BundleReference bundleRef = cacheList.get(cacheKey); - if (bundleRef != null) { - bundle = bundleRef.get(); - bundleRef = null; - } - - // If this bundle and all of its parents are valid (not expired), - // then return this bundle. If any of the bundles is expired, we - // don't call control.needsReload here but instead drop into the - // complete loading process below. - if (isValidBundle(bundle) && hasValidParentChain(bundle)) { - return bundle; - } - - // No valid bundle was found in the cache, so we need to load the - // resource bundle and its parents. - - boolean isKnownControl = (control == Control.INSTANCE) || - (control instanceof SingleFormatControl); - List<String> formats = control.getFormats(baseName); - if (!isKnownControl && !checkList(formats)) { - throw new IllegalArgumentException("Invalid Control: getFormats"); - } - - ResourceBundle baseBundle = null; - for (Locale targetLocale = locale; - targetLocale != null; - targetLocale = control.getFallbackLocale(baseName, targetLocale)) { - List<Locale> candidateLocales = control.getCandidateLocales(baseName, targetLocale); - if (!isKnownControl && !checkList(candidateLocales)) { - throw new IllegalArgumentException("Invalid Control: getCandidateLocales"); - } - - bundle = findBundle(cacheKey, candidateLocales, formats, 0, control, baseBundle); - - // If the loaded bundle is the base bundle and exactly for the - // requested locale or the only candidate locale, then take the - // bundle as the resulting one. If the loaded bundle is the base - // bundle, it's put on hold until we finish processing all - // fallback locales. - if (isValidBundle(bundle)) { - boolean isBaseBundle = Locale.ROOT.equals(bundle.locale); - if (!isBaseBundle || bundle.locale.equals(locale) - || (candidateLocales.size() == 1 - && bundle.locale.equals(candidateLocales.get(0)))) { - break; - } - - // If the base bundle has been loaded, keep the reference in - // baseBundle so that we can avoid any redundant loading in case - // the control specify not to cache bundles. - if (isBaseBundle && baseBundle == null) { - baseBundle = bundle; - } - } - } - - if (bundle == null) { - if (baseBundle == null) { - throwMissingResourceException(baseName, locale, cacheKey.getCause()); - } - bundle = baseBundle; - } - - return bundle; - } - - /** - * Checks if the given <code>List</code> is not null, not empty, - * not having null in its elements. - */ - private static final boolean checkList(List a) { - boolean valid = (a != null && a.size() != 0); - if (valid) { - int size = a.size(); - for (int i = 0; valid && i < size; i++) { - valid = (a.get(i) != null); - } - } - return valid; - } - - private static final ResourceBundle findBundle(CacheKey cacheKey, - List<Locale> candidateLocales, - List<String> formats, - int index, - Control control, - ResourceBundle baseBundle) { - Locale targetLocale = candidateLocales.get(index); - ResourceBundle parent = null; - if (index != candidateLocales.size() - 1) { - parent = findBundle(cacheKey, candidateLocales, formats, index + 1, - control, baseBundle); - } else if (baseBundle != null && Locale.ROOT.equals(targetLocale)) { - return baseBundle; - } - - // Before we do the real loading work, see whether we need to - // do some housekeeping: If references to class loaders or - // resource bundles have been nulled out, remove all related - // information from the cache. - Object ref; - while ((ref = referenceQueue.poll()) != null) { - cacheList.remove(((CacheKeyReference)ref).getCacheKey()); - } - - // flag indicating the resource bundle has expired in the cache - boolean expiredBundle = false; - - // First, look up the cache to see if it's in the cache, without - // attempting to load bundle. - cacheKey.setLocale(targetLocale); - ResourceBundle bundle = findBundleInCache(cacheKey, control); - if (isValidBundle(bundle)) { - expiredBundle = bundle.expired; - if (!expiredBundle) { - // If its parent is the one asked for by the candidate - // locales (the runtime lookup path), we can take the cached - // one. (If it's not identical, then we'd have to check the - // parent's parents to be consistent with what's been - // requested.) - if (bundle.parent == parent) { - return bundle; - } - // Otherwise, remove the cached one since we can't keep - // the same bundles having different parents. - BundleReference bundleRef = cacheList.get(cacheKey); - if (bundleRef != null && bundleRef.get() == bundle) { - cacheList.remove(cacheKey, bundleRef); - } - } - } - - if (bundle != NONEXISTENT_BUNDLE) { - CacheKey constKey = (CacheKey) cacheKey.clone(); - - try { - bundle = loadBundle(cacheKey, formats, control, expiredBundle); - if (bundle != null) { - if (bundle.parent == null) { - bundle.setParent(parent); - } - bundle.locale = targetLocale; - bundle = putBundleInCache(cacheKey, bundle, control); - return bundle; - } - - // Put NONEXISTENT_BUNDLE in the cache as a mark that there's no bundle - // instance for the locale. - putBundleInCache(cacheKey, NONEXISTENT_BUNDLE, control); - } finally { - if (constKey.getCause() instanceof InterruptedException) { - Thread.currentThread().interrupt(); - } - } - } - return parent; - } - - private static final ResourceBundle loadBundle(CacheKey cacheKey, - List<String> formats, - Control control, - boolean reload) { - - // Here we actually load the bundle in the order of formats - // specified by the getFormats() value. - Locale targetLocale = cacheKey.getLocale(); - - ResourceBundle bundle = null; - int size = formats.size(); - for (int i = 0; i < size; i++) { - String format = formats.get(i); - try { - bundle = control.newBundle(cacheKey.getName(), targetLocale, format, - cacheKey.getLoader(), reload); - } catch (LinkageError error) { - // We need to handle the LinkageError case due to - // inconsistent case-sensitivity in ClassLoader. - // See 6572242 for details. - cacheKey.setCause(error); - } catch (Exception cause) { - cacheKey.setCause(cause); - } - if (bundle != null) { - // Set the format in the cache key so that it can be - // used when calling needsReload later. - cacheKey.setFormat(format); - bundle.name = cacheKey.getName(); - bundle.locale = targetLocale; - // Bundle provider might reuse instances. So we should make - // sure to clear the expired flag here. - bundle.expired = false; - break; - } - } - - return bundle; - } - - private static final boolean isValidBundle(ResourceBundle bundle) { - return bundle != null && bundle != NONEXISTENT_BUNDLE; - } - - /** - * Determines whether any of resource bundles in the parent chain, - * including the leaf, have expired. - */ - private static final boolean hasValidParentChain(ResourceBundle bundle) { - long now = System.currentTimeMillis(); - while (bundle != null) { - if (bundle.expired) { - return false; - } - CacheKey key = bundle.cacheKey; - if (key != null) { - long expirationTime = key.expirationTime; - if (expirationTime >= 0 && expirationTime <= now) { - return false; - } - } - bundle = bundle.parent; - } - return true; - } - - /** - * Throw a MissingResourceException with proper message - */ - private static final void throwMissingResourceException(String baseName, - Locale locale, - Throwable cause) { - // If the cause is a MissingResourceException, avoid creating - // a long chain. (6355009) - if (cause instanceof MissingResourceException) { - cause = null; - } - throw new MissingResourceException("Can't find bundle for base name " - + baseName + ", locale " + locale, - baseName + "_" + locale, // className - "", // key - cause); - } - - /** - * Finds a bundle in the cache. Any expired bundles are marked as - * `expired' and removed from the cache upon return. - * - * @param cacheKey the key to look up the cache - * @param control the Control to be used for the expiration control - * @return the cached bundle, or null if the bundle is not found in the - * cache or its parent has expired. <code>bundle.expire</code> is true - * upon return if the bundle in the cache has expired. - */ - private static final ResourceBundle findBundleInCache(CacheKey cacheKey, - Control control) { - BundleReference bundleRef = cacheList.get(cacheKey); - if (bundleRef == null) { - return null; - } - ResourceBundle bundle = bundleRef.get(); - if (bundle == null) { - return null; - } - ResourceBundle p = bundle.parent; - assert p != NONEXISTENT_BUNDLE; - // If the parent has expired, then this one must also expire. We - // check only the immediate parent because the actual loading is - // done from the root (base) to leaf (child) and the purpose of - // checking is to propagate expiration towards the leaf. For - // example, if the requested locale is ja_JP_JP and there are - // bundles for all of the candidates in the cache, we have a list, - // - // base <- ja <- ja_JP <- ja_JP_JP - // - // If ja has expired, then it will reload ja and the list becomes a - // tree. - // - // base <- ja (new) - // " <- ja (expired) <- ja_JP <- ja_JP_JP - // - // When looking up ja_JP in the cache, it finds ja_JP in the cache - // which references to the expired ja. Then, ja_JP is marked as - // expired and removed from the cache. This will be propagated to - // ja_JP_JP. - // - // Now, it's possible, for example, that while loading new ja_JP, - // someone else has started loading the same bundle and finds the - // base bundle has expired. Then, what we get from the first - // getBundle call includes the expired base bundle. However, if - // someone else didn't start its loading, we wouldn't know if the - // base bundle has expired at the end of the loading process. The - // expiration control doesn't guarantee that the returned bundle and - // its parents haven't expired. - // - // We could check the entire parent chain to see if there's any in - // the chain that has expired. But this process may never end. An - // extreme case would be that getTimeToLive returns 0 and - // needsReload always returns true. - if (p != null && p.expired) { - assert bundle != NONEXISTENT_BUNDLE; - bundle.expired = true; - bundle.cacheKey = null; - cacheList.remove(cacheKey, bundleRef); - bundle = null; - } else { - CacheKey key = bundleRef.getCacheKey(); - long expirationTime = key.expirationTime; - if (!bundle.expired && expirationTime >= 0 && - expirationTime <= System.currentTimeMillis()) { - // its TTL period has expired. - if (bundle != NONEXISTENT_BUNDLE) { - // Synchronize here to call needsReload to avoid - // redundant concurrent calls for the same bundle. - synchronized (bundle) { - expirationTime = key.expirationTime; - if (!bundle.expired && expirationTime >= 0 && - expirationTime <= System.currentTimeMillis()) { - try { - bundle.expired = control.needsReload(key.getName(), - key.getLocale(), - key.getFormat(), - key.getLoader(), - bundle, - key.loadTime); - } catch (Exception e) { - cacheKey.setCause(e); - } - if (bundle.expired) { - // If the bundle needs to be reloaded, then - // remove the bundle from the cache, but - // return the bundle with the expired flag - // on. - bundle.cacheKey = null; - cacheList.remove(cacheKey, bundleRef); - } else { - // Update the expiration control info. and reuse - // the same bundle instance - setExpirationTime(key, control); - } - } - } - } else { - // We just remove NONEXISTENT_BUNDLE from the cache. - cacheList.remove(cacheKey, bundleRef); - bundle = null; - } - } - } - return bundle; - } - - /** - * Put a new bundle in the cache. - * - * @param cacheKey the key for the resource bundle - * @param bundle the resource bundle to be put in the cache - * @return the ResourceBundle for the cacheKey; if someone has put - * the bundle before this call, the one found in the cache is - * returned. - */ - private static final ResourceBundle putBundleInCache(CacheKey cacheKey, - ResourceBundle bundle, - Control control) { - setExpirationTime(cacheKey, control); - if (cacheKey.expirationTime != Control.TTL_DONT_CACHE) { - CacheKey key = (CacheKey) cacheKey.clone(); - BundleReference bundleRef = new BundleReference(bundle, referenceQueue, key); - bundle.cacheKey = key; - - // Put the bundle in the cache if it's not been in the cache. - BundleReference result = cacheList.putIfAbsent(key, bundleRef); - - // If someone else has put the same bundle in the cache before - // us and it has not expired, we should use the one in the cache. - if (result != null) { - ResourceBundle rb = result.get(); - if (rb != null && !rb.expired) { - // Clear the back link to the cache key - bundle.cacheKey = null; - bundle = rb; - // Clear the reference in the BundleReference so that - // it won't be enqueued. - bundleRef.clear(); - } else { - // Replace the invalid (garbage collected or expired) - // instance with the valid one. - cacheList.put(key, bundleRef); - } - } - } - return bundle; - } - - private static final void setExpirationTime(CacheKey cacheKey, Control control) { - long ttl = control.getTimeToLive(cacheKey.getName(), - cacheKey.getLocale()); - if (ttl >= 0) { - // If any expiration time is specified, set the time to be - // expired in the cache. - long now = System.currentTimeMillis(); - cacheKey.loadTime = now; - cacheKey.expirationTime = now + ttl; - } else if (ttl >= Control.TTL_NO_EXPIRATION_CONTROL) { - cacheKey.expirationTime = ttl; - } else { - throw new IllegalArgumentException("Invalid Control: TTL=" + ttl); - } - } - - /** - * Removes all resource bundles from the cache that have been loaded - * using the caller's class loader. - * - * @since 1.6 - * @see ResourceBundle.Control#getTimeToLive(String,Locale) - */ - @CallerSensitive - public static final void clearCache() { - clearCache(getLoader(Reflection.getCallerClass())); - } - - /** - * Removes all resource bundles from the cache that have been loaded - * using the given class loader. - * - * @param loader the class loader - * @exception NullPointerException if <code>loader</code> is null - * @since 1.6 - * @see ResourceBundle.Control#getTimeToLive(String,Locale) - */ - public static final void clearCache(ClassLoader loader) { - if (loader == null) { - throw new NullPointerException(); - } - Set<CacheKey> set = cacheList.keySet(); - for (CacheKey key : set) { - if (key.getLoader() == loader) { - set.remove(key); - } - } - } - - /** - * Gets an object for the given key from this resource bundle. - * Returns null if this resource bundle does not contain an - * object for the given key. - * - * @param key the key for the desired object - * @exception NullPointerException if <code>key</code> is <code>null</code> - * @return the object for the given key, or null - */ - protected abstract Object handleGetObject(String key); - - /** - * Returns an enumeration of the keys. - * - * @return an <code>Enumeration</code> of the keys contained in - * this <code>ResourceBundle</code> and its parent bundles. - */ - public abstract Enumeration<String> getKeys(); - - /** - * Determines whether the given <code>key</code> is contained in - * this <code>ResourceBundle</code> or its parent bundles. - * - * @param key - * the resource <code>key</code> - * @return <code>true</code> if the given <code>key</code> is - * contained in this <code>ResourceBundle</code> or its - * parent bundles; <code>false</code> otherwise. - * @exception NullPointerException - * if <code>key</code> is <code>null</code> - * @since 1.6 - */ - public boolean containsKey(String key) { - if (key == null) { - throw new NullPointerException(); - } - for (ResourceBundle rb = this; rb != null; rb = rb.parent) { - if (rb.handleKeySet().contains(key)) { - return true; - } - } - return false; - } - - /** - * Returns a <code>Set</code> of all keys contained in this - * <code>ResourceBundle</code> and its parent bundles. - * - * @return a <code>Set</code> of all keys contained in this - * <code>ResourceBundle</code> and its parent bundles. - * @since 1.6 - */ - public Set<String> keySet() { - Set<String> keys = new HashSet<>(); - for (ResourceBundle rb = this; rb != null; rb = rb.parent) { - keys.addAll(rb.handleKeySet()); - } - return keys; - } - - /** - * Returns a <code>Set</code> of the keys contained <em>only</em> - * in this <code>ResourceBundle</code>. - * - * <p>The default implementation returns a <code>Set</code> of the - * keys returned by the {@link #getKeys() getKeys} method except - * for the ones for which the {@link #handleGetObject(String) - * handleGetObject} method returns <code>null</code>. Once the - * <code>Set</code> has been created, the value is kept in this - * <code>ResourceBundle</code> in order to avoid producing the - * same <code>Set</code> in subsequent calls. Subclasses can - * override this method for faster handling. - * - * @return a <code>Set</code> of the keys contained only in this - * <code>ResourceBundle</code> - * @since 1.6 - */ - protected Set<String> handleKeySet() { - if (keySet == null) { - synchronized (this) { - if (keySet == null) { - Set<String> keys = new HashSet<>(); - Enumeration<String> enumKeys = getKeys(); - while (enumKeys.hasMoreElements()) { - String key = enumKeys.nextElement(); - if (handleGetObject(key) != null) { - keys.add(key); - } - } - keySet = keys; - } - } - } - return keySet; - } - - - - /** - * <code>ResourceBundle.Control</code> defines a set of callback methods - * that are invoked by the {@link ResourceBundle#getBundle(String, - * Locale, ClassLoader, Control) ResourceBundle.getBundle} factory - * methods during the bundle loading process. In other words, a - * <code>ResourceBundle.Control</code> collaborates with the factory - * methods for loading resource bundles. The default implementation of - * the callback methods provides the information necessary for the - * factory methods to perform the <a - * href="./ResourceBundle.html#default_behavior">default behavior</a>. - * - * <p>In addition to the callback methods, the {@link - * #toBundleName(String, Locale) toBundleName} and {@link - * #toResourceName(String, String) toResourceName} methods are defined - * primarily for convenience in implementing the callback - * methods. However, the <code>toBundleName</code> method could be - * overridden to provide different conventions in the organization and - * packaging of localized resources. The <code>toResourceName</code> - * method is <code>final</code> to avoid use of wrong resource and class - * name separators. - * - * <p>Two factory methods, {@link #getControl(List)} and {@link - * #getNoFallbackControl(List)}, provide - * <code>ResourceBundle.Control</code> instances that implement common - * variations of the default bundle loading process. - * - * <p>The formats returned by the {@link Control#getFormats(String) - * getFormats} method and candidate locales returned by the {@link - * ResourceBundle.Control#getCandidateLocales(String, Locale) - * getCandidateLocales} method must be consistent in all - * <code>ResourceBundle.getBundle</code> invocations for the same base - * bundle. Otherwise, the <code>ResourceBundle.getBundle</code> methods - * may return unintended bundles. For example, if only - * <code>"java.class"</code> is returned by the <code>getFormats</code> - * method for the first call to <code>ResourceBundle.getBundle</code> - * and only <code>"java.properties"</code> for the second call, then the - * second call will return the class-based one that has been cached - * during the first call. - * - * <p>A <code>ResourceBundle.Control</code> instance must be thread-safe - * if it's simultaneously used by multiple threads. - * <code>ResourceBundle.getBundle</code> does not synchronize to call - * the <code>ResourceBundle.Control</code> methods. The default - * implementations of the methods are thread-safe. - * - * <p>Applications can specify <code>ResourceBundle.Control</code> - * instances returned by the <code>getControl</code> factory methods or - * created from a subclass of <code>ResourceBundle.Control</code> to - * customize the bundle loading process. The following are examples of - * changing the default bundle loading process. - * - * <p><b>Example 1</b> - * - * <p>The following code lets <code>ResourceBundle.getBundle</code> look - * up only properties-based resources. - * - * <pre> - * import java.util.*; - * import static java.util.ResourceBundle.Control.*; - * ... - * ResourceBundle bundle = - * ResourceBundle.getBundle("MyResources", new Locale("fr", "CH"), - * ResourceBundle.Control.getControl(FORMAT_PROPERTIES)); - * </pre> - * - * Given the resource bundles in the <a - * href="./ResourceBundle.html#default_behavior_example">example</a> in - * the <code>ResourceBundle.getBundle</code> description, this - * <code>ResourceBundle.getBundle</code> call loads - * <code>MyResources_fr_CH.properties</code> whose parent is - * <code>MyResources_fr.properties</code> whose parent is - * <code>MyResources.properties</code>. (<code>MyResources_fr_CH.properties</code> - * is not hidden, but <code>MyResources_fr_CH.class</code> is.) - * - * <p><b>Example 2</b> - * - * <p>The following is an example of loading XML-based bundles - * using {@link Properties#loadFromXML(java.io.InputStream) - * Properties.loadFromXML}. - * - * <pre> - * ResourceBundle rb = ResourceBundle.getBundle("Messages", - * new ResourceBundle.Control() { - * public List<String> getFormats(String baseName) { - * if (baseName == null) - * throw new NullPointerException(); - * return Arrays.asList("xml"); - * } - * public ResourceBundle newBundle(String baseName, - * Locale locale, - * String format, - * ClassLoader loader, - * boolean reload) - * throws IllegalAccessException, - * InstantiationException, - * IOException { - * if (baseName == null || locale == null - * || format == null || loader == null) - * throw new NullPointerException(); - * ResourceBundle bundle = null; - * if (format.equals("xml")) { - * String bundleName = toBundleName(baseName, locale); - * String resourceName = toResourceName(bundleName, format); - * InputStream stream = null; - * if (reload) { - * URL url = loader.getResource(resourceName); - * if (url != null) { - * URLConnection connection = url.openConnection(); - * if (connection != null) { - * // Disable caches to get fresh data for - * // reloading. - * connection.setUseCaches(false); - * stream = connection.getInputStream(); - * } - * } - * } else { - * stream = loader.getResourceAsStream(resourceName); - * } - * if (stream != null) { - * BufferedInputStream bis = new BufferedInputStream(stream); - * bundle = new XMLResourceBundle(bis); - * bis.close(); - * } - * } - * return bundle; - * } - * }); - * - * ... - * - * private static class XMLResourceBundle extends ResourceBundle { - * private Properties props; - * XMLResourceBundle(InputStream stream) throws IOException { - * props = new Properties(); - * props.loadFromXML(stream); - * } - * protected Object handleGetObject(String key) { - * return props.getProperty(key); - * } - * public Enumeration<String> getKeys() { - * ... - * } - * } - * </pre> - * - * @since 1.6 - */ - public static class Control { - /** - * The default format <code>List</code>, which contains the strings - * <code>"java.class"</code> and <code>"java.properties"</code>, in - * this order. This <code>List</code> is {@linkplain - * Collections#unmodifiableList(List) unmodifiable}. - * - * @see #getFormats(String) - */ - public static final List<String> FORMAT_DEFAULT - = Collections.unmodifiableList(Arrays.asList("java.class", - "java.properties")); - - /** - * The class-only format <code>List</code> containing - * <code>"java.class"</code>. This <code>List</code> is {@linkplain - * Collections#unmodifiableList(List) unmodifiable}. - * - * @see #getFormats(String) - */ - public static final List<String> FORMAT_CLASS - = Collections.unmodifiableList(Arrays.asList("java.class")); - - /** - * The properties-only format <code>List</code> containing - * <code>"java.properties"</code>. This <code>List</code> is - * {@linkplain Collections#unmodifiableList(List) unmodifiable}. - * - * @see #getFormats(String) - */ - public static final List<String> FORMAT_PROPERTIES - = Collections.unmodifiableList(Arrays.asList("java.properties")); - - /** - * The time-to-live constant for not caching loaded resource bundle - * instances. - * - * @see #getTimeToLive(String, Locale) - */ - public static final long TTL_DONT_CACHE = -1; - - /** - * The time-to-live constant for disabling the expiration control - * for loaded resource bundle instances in the cache. - * - * @see #getTimeToLive(String, Locale) - */ - public static final long TTL_NO_EXPIRATION_CONTROL = -2; - - private static final Control INSTANCE = new Control(); - - /** - * Sole constructor. (For invocation by subclass constructors, - * typically implicit.) - */ - protected Control() { - } - - /** - * Returns a <code>ResourceBundle.Control</code> in which the {@link - * #getFormats(String) getFormats} method returns the specified - * <code>formats</code>. The <code>formats</code> must be equal to - * one of {@link Control#FORMAT_PROPERTIES}, {@link - * Control#FORMAT_CLASS} or {@link - * Control#FORMAT_DEFAULT}. <code>ResourceBundle.Control</code> - * instances returned by this method are singletons and thread-safe. - * - * <p>Specifying {@link Control#FORMAT_DEFAULT} is equivalent to - * instantiating the <code>ResourceBundle.Control</code> class, - * except that this method returns a singleton. - * - * @param formats - * the formats to be returned by the - * <code>ResourceBundle.Control.getFormats</code> method - * @return a <code>ResourceBundle.Control</code> supporting the - * specified <code>formats</code> - * @exception NullPointerException - * if <code>formats</code> is <code>null</code> - * @exception IllegalArgumentException - * if <code>formats</code> is unknown - */ - public static final Control getControl(List<String> formats) { - if (formats.equals(Control.FORMAT_PROPERTIES)) { - return SingleFormatControl.PROPERTIES_ONLY; - } - if (formats.equals(Control.FORMAT_CLASS)) { - return SingleFormatControl.CLASS_ONLY; - } - if (formats.equals(Control.FORMAT_DEFAULT)) { - return Control.INSTANCE; - } - throw new IllegalArgumentException(); - } - - /** - * Returns a <code>ResourceBundle.Control</code> in which the {@link - * #getFormats(String) getFormats} method returns the specified - * <code>formats</code> and the {@link - * Control#getFallbackLocale(String, Locale) getFallbackLocale} - * method returns <code>null</code>. The <code>formats</code> must - * be equal to one of {@link Control#FORMAT_PROPERTIES}, {@link - * Control#FORMAT_CLASS} or {@link Control#FORMAT_DEFAULT}. - * <code>ResourceBundle.Control</code> instances returned by this - * method are singletons and thread-safe. - * - * @param formats - * the formats to be returned by the - * <code>ResourceBundle.Control.getFormats</code> method - * @return a <code>ResourceBundle.Control</code> supporting the - * specified <code>formats</code> with no fallback - * <code>Locale</code> support - * @exception NullPointerException - * if <code>formats</code> is <code>null</code> - * @exception IllegalArgumentException - * if <code>formats</code> is unknown - */ - public static final Control getNoFallbackControl(List<String> formats) { - if (formats.equals(Control.FORMAT_DEFAULT)) { - return NoFallbackControl.NO_FALLBACK; - } - if (formats.equals(Control.FORMAT_PROPERTIES)) { - return NoFallbackControl.PROPERTIES_ONLY_NO_FALLBACK; - } - if (formats.equals(Control.FORMAT_CLASS)) { - return NoFallbackControl.CLASS_ONLY_NO_FALLBACK; - } - throw new IllegalArgumentException(); - } - - /** - * Returns a <code>List</code> of <code>String</code>s containing - * formats to be used to load resource bundles for the given - * <code>baseName</code>. The <code>ResourceBundle.getBundle</code> - * factory method tries to load resource bundles with formats in the - * order specified by the list. The list returned by this method - * must have at least one <code>String</code>. The predefined - * formats are <code>"java.class"</code> for class-based resource - * bundles and <code>"java.properties"</code> for {@linkplain - * PropertyResourceBundle properties-based} ones. Strings starting - * with <code>"java."</code> are reserved for future extensions and - * must not be used by application-defined formats. - * - * <p>It is not a requirement to return an immutable (unmodifiable) - * <code>List</code>. However, the returned <code>List</code> must - * not be mutated after it has been returned by - * <code>getFormats</code>. - * - * <p>The default implementation returns {@link #FORMAT_DEFAULT} so - * that the <code>ResourceBundle.getBundle</code> factory method - * looks up first class-based resource bundles, then - * properties-based ones. - * - * @param baseName - * the base name of the resource bundle, a fully qualified class - * name - * @return a <code>List</code> of <code>String</code>s containing - * formats for loading resource bundles. - * @exception NullPointerException - * if <code>baseName</code> is null - * @see #FORMAT_DEFAULT - * @see #FORMAT_CLASS - * @see #FORMAT_PROPERTIES - */ - public List<String> getFormats(String baseName) { - if (baseName == null) { - throw new NullPointerException(); - } - return FORMAT_DEFAULT; - } - - /** - * Returns a <code>List</code> of <code>Locale</code>s as candidate - * locales for <code>baseName</code> and <code>locale</code>. This - * method is called by the <code>ResourceBundle.getBundle</code> - * factory method each time the factory method tries finding a - * resource bundle for a target <code>Locale</code>. - * - * <p>The sequence of the candidate locales also corresponds to the - * runtime resource lookup path (also known as the <I>parent - * chain</I>), if the corresponding resource bundles for the - * candidate locales exist and their parents are not defined by - * loaded resource bundles themselves. The last element of the list - * must be a {@linkplain Locale#ROOT root locale} if it is desired to - * have the base bundle as the terminal of the parent chain. - * - * <p>If the given locale is equal to <code>Locale.ROOT</code> (the - * root locale), a <code>List</code> containing only the root - * <code>Locale</code> must be returned. In this case, the - * <code>ResourceBundle.getBundle</code> factory method loads only - * the base bundle as the resulting resource bundle. - * - * <p>It is not a requirement to return an immutable (unmodifiable) - * <code>List</code>. However, the returned <code>List</code> must not - * be mutated after it has been returned by - * <code>getCandidateLocales</code>. - * - * <p>The default implementation returns a <code>List</code> containing - * <code>Locale</code>s using the rules described below. In the - * description below, <em>L</em>, <em>S</em>, <em>C</em> and <em>V</em> - * respectively represent non-empty language, script, country, and - * variant. For example, [<em>L</em>, <em>C</em>] represents a - * <code>Locale</code> that has non-empty values only for language and - * country. The form <em>L</em>("xx") represents the (non-empty) - * language value is "xx". For all cases, <code>Locale</code>s whose - * final component values are empty strings are omitted. - * - * <ol><li>For an input <code>Locale</code> with an empty script value, - * append candidate <code>Locale</code>s by omitting the final component - * one by one as below: - * - * <ul> - * <li> [<em>L</em>, <em>C</em>, <em>V</em>] - * <li> [<em>L</em>, <em>C</em>] - * <li> [<em>L</em>] - * <li> <code>Locale.ROOT</code> - * </ul> - * - * <li>For an input <code>Locale</code> with a non-empty script value, - * append candidate <code>Locale</code>s by omitting the final component - * up to language, then append candidates generated from the - * <code>Locale</code> with country and variant restored: - * - * <ul> - * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V</em>] - * <li> [<em>L</em>, <em>S</em>, <em>C</em>] - * <li> [<em>L</em>, <em>S</em>] - * <li> [<em>L</em>, <em>C</em>, <em>V</em>] - * <li> [<em>L</em>, <em>C</em>] - * <li> [<em>L</em>] - * <li> <code>Locale.ROOT</code> - * </ul> - * - * <li>For an input <code>Locale</code> with a variant value consisting - * of multiple subtags separated by underscore, generate candidate - * <code>Locale</code>s by omitting the variant subtags one by one, then - * insert them after every occurence of <code> Locale</code>s with the - * full variant value in the original list. For example, if the - * the variant consists of two subtags <em>V1</em> and <em>V2</em>: - * - * <ul> - * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>, <em>V2</em>] - * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>] - * <li> [<em>L</em>, <em>S</em>, <em>C</em>] - * <li> [<em>L</em>, <em>S</em>] - * <li> [<em>L</em>, <em>C</em>, <em>V1</em>, <em>V2</em>] - * <li> [<em>L</em>, <em>C</em>, <em>V1</em>] - * <li> [<em>L</em>, <em>C</em>] - * <li> [<em>L</em>] - * <li> <code>Locale.ROOT</code> - * </ul> - * - * <li>Special cases for Chinese. When an input <code>Locale</code> has the - * language "zh" (Chinese) and an empty script value, either "Hans" (Simplified) or - * "Hant" (Traditional) might be supplied, depending on the country. - * When the country is "CN" (China) or "SG" (Singapore), "Hans" is supplied. - * When the country is "HK" (Hong Kong SAR China), "MO" (Macau SAR China), - * or "TW" (Taiwan), "Hant" is supplied. For all other countries or when the country - * is empty, no script is supplied. For example, for <code>Locale("zh", "CN") - * </code>, the candidate list will be: - * <ul> - * <li> [<em>L</em>("zh"), <em>S</em>("Hans"), <em>C</em>("CN")] - * <li> [<em>L</em>("zh"), <em>S</em>("Hans")] - * <li> [<em>L</em>("zh"), <em>C</em>("CN")] - * <li> [<em>L</em>("zh")] - * <li> <code>Locale.ROOT</code> - * </ul> - * - * For <code>Locale("zh", "TW")</code>, the candidate list will be: - * <ul> - * <li> [<em>L</em>("zh"), <em>S</em>("Hant"), <em>C</em>("TW")] - * <li> [<em>L</em>("zh"), <em>S</em>("Hant")] - * <li> [<em>L</em>("zh"), <em>C</em>("TW")] - * <li> [<em>L</em>("zh")] - * <li> <code>Locale.ROOT</code> - * </ul> - * - * <li>Special cases for Norwegian. Both <code>Locale("no", "NO", - * "NY")</code> and <code>Locale("nn", "NO")</code> represent Norwegian - * Nynorsk. When a locale's language is "nn", the standard candidate - * list is generated up to [<em>L</em>("nn")], and then the following - * candidates are added: - * - * <ul><li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("NY")] - * <li> [<em>L</em>("no"), <em>C</em>("NO")] - * <li> [<em>L</em>("no")] - * <li> <code>Locale.ROOT</code> - * </ul> - * - * If the locale is exactly <code>Locale("no", "NO", "NY")</code>, it is first - * converted to <code>Locale("nn", "NO")</code> and then the above procedure is - * followed. - * - * <p>Also, Java treats the language "no" as a synonym of Norwegian - * Bokmål "nb". Except for the single case <code>Locale("no", - * "NO", "NY")</code> (handled above), when an input <code>Locale</code> - * has language "no" or "nb", candidate <code>Locale</code>s with - * language code "no" and "nb" are interleaved, first using the - * requested language, then using its synonym. For example, - * <code>Locale("nb", "NO", "POSIX")</code> generates the following - * candidate list: - * - * <ul> - * <li> [<em>L</em>("nb"), <em>C</em>("NO"), <em>V</em>("POSIX")] - * <li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("POSIX")] - * <li> [<em>L</em>("nb"), <em>C</em>("NO")] - * <li> [<em>L</em>("no"), <em>C</em>("NO")] - * <li> [<em>L</em>("nb")] - * <li> [<em>L</em>("no")] - * <li> <code>Locale.ROOT</code> - * </ul> - * - * <code>Locale("no", "NO", "POSIX")</code> would generate the same list - * except that locales with "no" would appear before the corresponding - * locales with "nb".</li> - * - * </li> - * </ol> - * - * <p>The default implementation uses an {@link ArrayList} that - * overriding implementations may modify before returning it to the - * caller. However, a subclass must not modify it after it has - * been returned by <code>getCandidateLocales</code>. - * - * <p>For example, if the given <code>baseName</code> is "Messages" - * and the given <code>locale</code> is - * <code>Locale("ja", "", "XX")</code>, then a - * <code>List</code> of <code>Locale</code>s: - * <pre> - * Locale("ja", "", "XX") - * Locale("ja") - * Locale.ROOT - * </pre> - * is returned. And if the resource bundles for the "ja" and - * "" <code>Locale</code>s are found, then the runtime resource - * lookup path (parent chain) is: - * <pre> - * Messages_ja -> Messages - * </pre> - * - * @param baseName - * the base name of the resource bundle, a fully - * qualified class name - * @param locale - * the locale for which a resource bundle is desired - * @return a <code>List</code> of candidate - * <code>Locale</code>s for the given <code>locale</code> - * @exception NullPointerException - * if <code>baseName</code> or <code>locale</code> is - * <code>null</code> - */ - public List<Locale> getCandidateLocales(String baseName, Locale locale) { - if (baseName == null) { - throw new NullPointerException(); - } - return new ArrayList<>(CANDIDATES_CACHE.get(locale.getBaseLocale())); - } - - private static final CandidateListCache CANDIDATES_CACHE = new CandidateListCache(); - - private static class CandidateListCache extends LocaleObjectCache<BaseLocale, List<Locale>> { - protected List<Locale> createObject(BaseLocale base) { - String language = base.getLanguage(); - String script = base.getScript(); - String region = base.getRegion(); - String variant = base.getVariant(); - - // Special handling for Norwegian - boolean isNorwegianBokmal = false; - boolean isNorwegianNynorsk = false; - if (language.equals("no")) { - if (region.equals("NO") && variant.equals("NY")) { - variant = ""; - isNorwegianNynorsk = true; - } else { - isNorwegianBokmal = true; - } - } - if (language.equals("nb") || isNorwegianBokmal) { - List<Locale> tmpList = getDefaultList("nb", script, region, variant); - // Insert a locale replacing "nb" with "no" for every list entry - List<Locale> bokmalList = new LinkedList<>(); - for (Locale l : tmpList) { - bokmalList.add(l); - if (l.getLanguage().length() == 0) { - break; - } - bokmalList.add(Locale.getInstance("no", l.getScript(), l.getCountry(), - l.getVariant(), null)); - } - return bokmalList; - } else if (language.equals("nn") || isNorwegianNynorsk) { - // Insert no_NO_NY, no_NO, no after nn - List<Locale> nynorskList = getDefaultList("nn", script, region, variant); - int idx = nynorskList.size() - 1; - nynorskList.add(idx++, Locale.getInstance("no", "NO", "NY")); - nynorskList.add(idx++, Locale.getInstance("no", "NO", "")); - nynorskList.add(idx++, Locale.getInstance("no", "", "")); - return nynorskList; - } - // Special handling for Chinese - else if (language.equals("zh")) { - if (script.length() == 0 && region.length() > 0) { - // Supply script for users who want to use zh_Hans/zh_Hant - // as bundle names (recommended for Java7+) - if (region.equals("TW") || region.equals("HK") || region.equals("MO")) { - script = "Hant"; - } else if (region.equals("CN") || region.equals("SG")) { - script = "Hans"; - } - } else if (script.length() > 0 && region.length() == 0) { - // Supply region(country) for users who still package Chinese - // bundles using old convension. - if (script.equals("Hans")) { - region = "CN"; - } else if (script.equals("Hant")) { - region = "TW"; - } - } - } - - return getDefaultList(language, script, region, variant); - } - - private static List<Locale> getDefaultList(String language, String script, String region, String variant) { - List<String> variants = null; - - if (variant.length() > 0) { - variants = new LinkedList<>(); - int idx = variant.length(); - while (idx != -1) { - variants.add(variant.substring(0, idx)); - idx = variant.lastIndexOf('_', --idx); - } - } - - List<Locale> list = new LinkedList<>(); - - if (variants != null) { - for (String v : variants) { - list.add(Locale.getInstance(language, script, region, v, null)); - } - } - if (region.length() > 0) { - list.add(Locale.getInstance(language, script, region, "", null)); - } - if (script.length() > 0) { - list.add(Locale.getInstance(language, script, "", "", null)); - - // With script, after truncating variant, region and script, - // start over without script. - if (variants != null) { - for (String v : variants) { - list.add(Locale.getInstance(language, "", region, v, null)); - } - } - if (region.length() > 0) { - list.add(Locale.getInstance(language, "", region, "", null)); - } - } - if (language.length() > 0) { - list.add(Locale.getInstance(language, "", "", "", null)); - } - // Add root locale at the end - list.add(Locale.ROOT); - - return list; - } - } - - /** - * Returns a <code>Locale</code> to be used as a fallback locale for - * further resource bundle searches by the - * <code>ResourceBundle.getBundle</code> factory method. This method - * is called from the factory method every time when no resulting - * resource bundle has been found for <code>baseName</code> and - * <code>locale</code>, where locale is either the parameter for - * <code>ResourceBundle.getBundle</code> or the previous fallback - * locale returned by this method. - * - * <p>The method returns <code>null</code> if no further fallback - * search is desired. - * - * <p>The default implementation returns the {@linkplain - * Locale#getDefault() default <code>Locale</code>} if the given - * <code>locale</code> isn't the default one. Otherwise, - * <code>null</code> is returned. - * - * @param baseName - * the base name of the resource bundle, a fully - * qualified class name for which - * <code>ResourceBundle.getBundle</code> has been - * unable to find any resource bundles (except for the - * base bundle) - * @param locale - * the <code>Locale</code> for which - * <code>ResourceBundle.getBundle</code> has been - * unable to find any resource bundles (except for the - * base bundle) - * @return a <code>Locale</code> for the fallback search, - * or <code>null</code> if no further fallback search - * is desired. - * @exception NullPointerException - * if <code>baseName</code> or <code>locale</code> - * is <code>null</code> - */ - public Locale getFallbackLocale(String baseName, Locale locale) { - if (baseName == null) { - throw new NullPointerException(); - } - Locale defaultLocale = Locale.getDefault(); - return locale.equals(defaultLocale) ? null : defaultLocale; - } - - /** - * Instantiates a resource bundle for the given bundle name of the - * given format and locale, using the given class loader if - * necessary. This method returns <code>null</code> if there is no - * resource bundle available for the given parameters. If a resource - * bundle can't be instantiated due to an unexpected error, the - * error must be reported by throwing an <code>Error</code> or - * <code>Exception</code> rather than simply returning - * <code>null</code>. - * - * <p>If the <code>reload</code> flag is <code>true</code>, it - * indicates that this method is being called because the previously - * loaded resource bundle has expired. - * - * <p>The default implementation instantiates a - * <code>ResourceBundle</code> as follows. - * - * <ul> - * - * <li>The bundle name is obtained by calling {@link - * #toBundleName(String, Locale) toBundleName(baseName, - * locale)}.</li> - * - * <li>If <code>format</code> is <code>"java.class"</code>, the - * {@link Class} specified by the bundle name is loaded by calling - * {@link ClassLoader#loadClass(String)}. Then, a - * <code>ResourceBundle</code> is instantiated by calling {@link - * Class#newInstance()}. Note that the <code>reload</code> flag is - * ignored for loading class-based resource bundles in this default - * implementation.</li> - * - * <li>If <code>format</code> is <code>"java.properties"</code>, - * {@link #toResourceName(String, String) toResourceName(bundlename, - * "properties")} is called to get the resource name. - * If <code>reload</code> is <code>true</code>, {@link - * ClassLoader#getResource(String) load.getResource} is called - * to get a {@link URL} for creating a {@link - * URLConnection}. This <code>URLConnection</code> is used to - * {@linkplain URLConnection#setUseCaches(boolean) disable the - * caches} of the underlying resource loading layers, - * and to {@linkplain URLConnection#getInputStream() get an - * <code>InputStream</code>}. - * Otherwise, {@link ClassLoader#getResourceAsStream(String) - * loader.getResourceAsStream} is called to get an {@link - * InputStream}. Then, a {@link - * PropertyResourceBundle} is constructed with the - * <code>InputStream</code>.</li> - * - * <li>If <code>format</code> is neither <code>"java.class"</code> - * nor <code>"java.properties"</code>, an - * <code>IllegalArgumentException</code> is thrown.</li> - * - * </ul> - * - * @param baseName - * the base bundle name of the resource bundle, a fully - * qualified class name - * @param locale - * the locale for which the resource bundle should be - * instantiated - * @param format - * the resource bundle format to be loaded - * @param loader - * the <code>ClassLoader</code> to use to load the bundle - * @param reload - * the flag to indicate bundle reloading; <code>true</code> - * if reloading an expired resource bundle, - * <code>false</code> otherwise - * @return the resource bundle instance, - * or <code>null</code> if none could be found. - * @exception NullPointerException - * if <code>bundleName</code>, <code>locale</code>, - * <code>format</code>, or <code>loader</code> is - * <code>null</code>, or if <code>null</code> is returned by - * {@link #toBundleName(String, Locale) toBundleName} - * @exception IllegalArgumentException - * if <code>format</code> is unknown, or if the resource - * found for the given parameters contains malformed data. - * @exception ClassCastException - * if the loaded class cannot be cast to <code>ResourceBundle</code> - * @exception IllegalAccessException - * if the class or its nullary constructor is not - * accessible. - * @exception InstantiationException - * if the instantiation of a class fails for some other - * reason. - * @exception ExceptionInInitializerError - * if the initialization provoked by this method fails. - * @exception SecurityException - * If a security manager is present and creation of new - * instances is denied. See {@link Class#newInstance()} - * for details. - * @exception IOException - * if an error occurred when reading resources using - * any I/O operations - */ - public ResourceBundle newBundle(String baseName, Locale locale, String format, - ClassLoader loader, boolean reload) - throws IllegalAccessException, InstantiationException, IOException { - String bundleName = toBundleName(baseName, locale); - ResourceBundle bundle = null; - if (format.equals("java.class")) { - try { - Class<? extends ResourceBundle> bundleClass - = (Class<? extends ResourceBundle>)loader.loadClass(bundleName); - - // If the class isn't a ResourceBundle subclass, throw a - // ClassCastException. - if (ResourceBundle.class.isAssignableFrom(bundleClass)) { - bundle = bundleClass.newInstance(); - } else { - throw new ClassCastException(bundleClass.getName() - + " cannot be cast to ResourceBundle"); - } - } catch (ClassNotFoundException e) { - } - } else if (format.equals("java.properties")) { - final String resourceName = toResourceName(bundleName, "properties"); - final ClassLoader classLoader = loader; - final boolean reloadFlag = reload; - InputStream stream = null; - try { - stream = AccessController.doPrivileged( - new PrivilegedExceptionAction<InputStream>() { - public InputStream run() throws IOException { - InputStream is = null; - if (reloadFlag) { - URL url = classLoader.getResource(resourceName); - if (url != null) { - URLConnection connection = url.openConnection(); - if (connection != null) { - // Disable caches to get fresh data for - // reloading. - connection.setUseCaches(false); - is = connection.getInputStream(); - } - } - } else { - is = classLoader.getResourceAsStream(resourceName); - } - return is; - } - }); - } catch (PrivilegedActionException e) { - throw (IOException) e.getException(); - } - if (stream != null) { - try { - bundle = new PropertyResourceBundle(stream); - } finally { - stream.close(); - } - } - } else { - throw new IllegalArgumentException("unknown format: " + format); - } - return bundle; - } - - /** - * Returns the time-to-live (TTL) value for resource bundles that - * are loaded under this - * <code>ResourceBundle.Control</code>. Positive time-to-live values - * specify the number of milliseconds a bundle can remain in the - * cache without being validated against the source data from which - * it was constructed. The value 0 indicates that a bundle must be - * validated each time it is retrieved from the cache. {@link - * #TTL_DONT_CACHE} specifies that loaded resource bundles are not - * put in the cache. {@link #TTL_NO_EXPIRATION_CONTROL} specifies - * that loaded resource bundles are put in the cache with no - * expiration control. - * - * <p>The expiration affects only the bundle loading process by the - * <code>ResourceBundle.getBundle</code> factory method. That is, - * if the factory method finds a resource bundle in the cache that - * has expired, the factory method calls the {@link - * #needsReload(String, Locale, String, ClassLoader, ResourceBundle, - * long) needsReload} method to determine whether the resource - * bundle needs to be reloaded. If <code>needsReload</code> returns - * <code>true</code>, the cached resource bundle instance is removed - * from the cache. Otherwise, the instance stays in the cache, - * updated with the new TTL value returned by this method. - * - * <p>All cached resource bundles are subject to removal from the - * cache due to memory constraints of the runtime environment. - * Returning a large positive value doesn't mean to lock loaded - * resource bundles in the cache. - * - * <p>The default implementation returns {@link #TTL_NO_EXPIRATION_CONTROL}. - * - * @param baseName - * the base name of the resource bundle for which the - * expiration value is specified. - * @param locale - * the locale of the resource bundle for which the - * expiration value is specified. - * @return the time (0 or a positive millisecond offset from the - * cached time) to get loaded bundles expired in the cache, - * {@link #TTL_NO_EXPIRATION_CONTROL} to disable the - * expiration control, or {@link #TTL_DONT_CACHE} to disable - * caching. - * @exception NullPointerException - * if <code>baseName</code> or <code>locale</code> is - * <code>null</code> - */ - public long getTimeToLive(String baseName, Locale locale) { - if (baseName == null || locale == null) { - throw new NullPointerException(); - } - return TTL_NO_EXPIRATION_CONTROL; - } - - /** - * Determines if the expired <code>bundle</code> in the cache needs - * to be reloaded based on the loading time given by - * <code>loadTime</code> or some other criteria. The method returns - * <code>true</code> if reloading is required; <code>false</code> - * otherwise. <code>loadTime</code> is a millisecond offset since - * the <a href="Calendar.html#Epoch"> <code>Calendar</code> - * Epoch</a>. - * - * The calling <code>ResourceBundle.getBundle</code> factory method - * calls this method on the <code>ResourceBundle.Control</code> - * instance used for its current invocation, not on the instance - * used in the invocation that originally loaded the resource - * bundle. - * - * <p>The default implementation compares <code>loadTime</code> and - * the last modified time of the source data of the resource - * bundle. If it's determined that the source data has been modified - * since <code>loadTime</code>, <code>true</code> is - * returned. Otherwise, <code>false</code> is returned. This - * implementation assumes that the given <code>format</code> is the - * same string as its file suffix if it's not one of the default - * formats, <code>"java.class"</code> or - * <code>"java.properties"</code>. - * - * @param baseName - * the base bundle name of the resource bundle, a - * fully qualified class name - * @param locale - * the locale for which the resource bundle - * should be instantiated - * @param format - * the resource bundle format to be loaded - * @param loader - * the <code>ClassLoader</code> to use to load the bundle - * @param bundle - * the resource bundle instance that has been expired - * in the cache - * @param loadTime - * the time when <code>bundle</code> was loaded and put - * in the cache - * @return <code>true</code> if the expired bundle needs to be - * reloaded; <code>false</code> otherwise. - * @exception NullPointerException - * if <code>baseName</code>, <code>locale</code>, - * <code>format</code>, <code>loader</code>, or - * <code>bundle</code> is <code>null</code> - */ - public boolean needsReload(String baseName, Locale locale, - String format, ClassLoader loader, - ResourceBundle bundle, long loadTime) { - if (bundle == null) { - throw new NullPointerException(); - } - if (format.equals("java.class") || format.equals("java.properties")) { - format = format.substring(5); - } - boolean result = false; - try { - String resourceName = toResourceName(toBundleName(baseName, locale), format); - URL url = loader.getResource(resourceName); - if (url != null) { - long lastModified = 0; - URLConnection connection = url.openConnection(); - if (connection != null) { - // disable caches to get the correct data - connection.setUseCaches(false); - if (connection instanceof JarURLConnection) { - JarEntry ent = ((JarURLConnection)connection).getJarEntry(); - if (ent != null) { - lastModified = ent.getTime(); - if (lastModified == -1) { - lastModified = 0; - } - } - } else { - lastModified = connection.getLastModified(); - } - } - result = lastModified >= loadTime; - } - } catch (NullPointerException npe) { - throw npe; - } catch (Exception e) { - // ignore other exceptions - } - return result; - } - - /** - * Converts the given <code>baseName</code> and <code>locale</code> - * to the bundle name. This method is called from the default - * implementation of the {@link #newBundle(String, Locale, String, - * ClassLoader, boolean) newBundle} and {@link #needsReload(String, - * Locale, String, ClassLoader, ResourceBundle, long) needsReload} - * methods. - * - * <p>This implementation returns the following value: - * <pre> - * baseName + "_" + language + "_" + script + "_" + country + "_" + variant - * </pre> - * where <code>language</code>, <code>script</code>, <code>country</code>, - * and <code>variant</code> are the language, script, country, and variant - * values of <code>locale</code>, respectively. Final component values that - * are empty Strings are omitted along with the preceding '_'. When the - * script is empty, the script value is ommitted along with the preceding '_'. - * If all of the values are empty strings, then <code>baseName</code> - * is returned. - * - * <p>For example, if <code>baseName</code> is - * <code>"baseName"</code> and <code>locale</code> is - * <code>Locale("ja", "", "XX")</code>, then - * <code>"baseName_ja_ _XX"</code> is returned. If the given - * locale is <code>Locale("en")</code>, then - * <code>"baseName_en"</code> is returned. - * - * <p>Overriding this method allows applications to use different - * conventions in the organization and packaging of localized - * resources. - * - * @param baseName - * the base name of the resource bundle, a fully - * qualified class name - * @param locale - * the locale for which a resource bundle should be - * loaded - * @return the bundle name for the resource bundle - * @exception NullPointerException - * if <code>baseName</code> or <code>locale</code> - * is <code>null</code> - */ - public String toBundleName(String baseName, Locale locale) { - if (locale == Locale.ROOT) { - return baseName; - } - - String language = locale.getLanguage(); - String script = locale.getScript(); - String country = locale.getCountry(); - String variant = locale.getVariant(); - - if (language == "" && country == "" && variant == "") { - return baseName; - } - - StringBuilder sb = new StringBuilder(baseName); - sb.append('_'); - if (script != "") { - if (variant != "") { - sb.append(language).append('_').append(script).append('_').append(country).append('_').append(variant); - } else if (country != "") { - sb.append(language).append('_').append(script).append('_').append(country); - } else { - sb.append(language).append('_').append(script); - } - } else { - if (variant != "") { - sb.append(language).append('_').append(country).append('_').append(variant); - } else if (country != "") { - sb.append(language).append('_').append(country); - } else { - sb.append(language); - } - } - return sb.toString(); - - } - - /** - * Converts the given <code>bundleName</code> to the form required - * by the {@link ClassLoader#getResource ClassLoader.getResource} - * method by replacing all occurrences of <code>'.'</code> in - * <code>bundleName</code> with <code>'/'</code> and appending a - * <code>'.'</code> and the given file <code>suffix</code>. For - * example, if <code>bundleName</code> is - * <code>"foo.bar.MyResources_ja_JP"</code> and <code>suffix</code> - * is <code>"properties"</code>, then - * <code>"foo/bar/MyResources_ja_JP.properties"</code> is returned. - * - * @param bundleName - * the bundle name - * @param suffix - * the file type suffix - * @return the converted resource name - * @exception NullPointerException - * if <code>bundleName</code> or <code>suffix</code> - * is <code>null</code> - */ - public final String toResourceName(String bundleName, String suffix) { - StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length()); - sb.append(bundleName.replace('.', '/')).append('.').append(suffix); - return sb.toString(); - } - } - - private static class SingleFormatControl extends Control { - private static final Control PROPERTIES_ONLY - = new SingleFormatControl(FORMAT_PROPERTIES); - - private static final Control CLASS_ONLY - = new SingleFormatControl(FORMAT_CLASS); - - private final List<String> formats; - - protected SingleFormatControl(List<String> formats) { - this.formats = formats; - } - - public List<String> getFormats(String baseName) { - if (baseName == null) { - throw new NullPointerException(); - } - return formats; - } - } - - private static final class NoFallbackControl extends SingleFormatControl { - private static final Control NO_FALLBACK - = new NoFallbackControl(FORMAT_DEFAULT); - - private static final Control PROPERTIES_ONLY_NO_FALLBACK - = new NoFallbackControl(FORMAT_PROPERTIES); - - private static final Control CLASS_ONLY_NO_FALLBACK - = new NoFallbackControl(FORMAT_CLASS); - - protected NoFallbackControl(List<String> formats) { - super(formats); - } - - public Locale getFallbackLocale(String baseName, Locale locale) { - if (baseName == null || locale == null) { - throw new NullPointerException(); - } - return null; - } - } -} diff --git a/openjdk/java/util/TimeZone.java b/openjdk/java/util/TimeZone.java deleted file mode 100644 index 63f1028c..00000000 --- a/openjdk/java/util/TimeZone.java +++ /dev/null @@ -1,922 +0,0 @@ -/* - * 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 - * 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. - */ - -/* - * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved - * (C) Copyright IBM Corp. 1996 - All Rights Reserved - * - * The original version of this source code and documentation is copyrighted - * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These - * materials are provided under terms of a License Agreement between Taligent - * and Sun. This technology is protected by multiple US and International - * patents. This notice and attribution to Taligent may not be removed. - * Taligent is a registered trademark of Taligent, Inc. - * - */ - -package java.util; - -import java.io.Serializable; -import java.lang.ref.SoftReference; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.concurrent.ConcurrentHashMap; -import sun.misc.SharedSecrets; -import sun.misc.JavaAWTAccess; -import sun.security.action.GetPropertyAction; -import sun.util.TimeZoneNameUtility; -import sun.util.calendar.ZoneInfo; -import sun.util.calendar.ZoneInfoFile; - -/** - * <code>TimeZone</code> represents a time zone offset, and also figures out daylight - * savings. - * - * <p> - * Typically, you get a <code>TimeZone</code> using <code>getDefault</code> - * which creates a <code>TimeZone</code> based on the time zone where the program - * is running. For example, for a program running in Japan, <code>getDefault</code> - * creates a <code>TimeZone</code> object based on Japanese Standard Time. - * - * <p> - * You can also get a <code>TimeZone</code> using <code>getTimeZone</code> - * along with a time zone ID. For instance, the time zone ID for the - * U.S. Pacific Time zone is "America/Los_Angeles". So, you can get a - * U.S. Pacific Time <code>TimeZone</code> object with: - * <blockquote><pre> - * TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles"); - * </pre></blockquote> - * You can use the <code>getAvailableIDs</code> method to iterate through - * all the supported time zone IDs. You can then choose a - * supported ID to get a <code>TimeZone</code>. - * If the time zone you want is not represented by one of the - * supported IDs, then a custom time zone ID can be specified to - * produce a TimeZone. The syntax of a custom time zone ID is: - * - * <blockquote><pre> - * <a name="CustomID"><i>CustomID:</i></a> - * <code>GMT</code> <i>Sign</i> <i>Hours</i> <code>:</code> <i>Minutes</i> - * <code>GMT</code> <i>Sign</i> <i>Hours</i> <i>Minutes</i> - * <code>GMT</code> <i>Sign</i> <i>Hours</i> - * <i>Sign:</i> one of - * <code>+ -</code> - * <i>Hours:</i> - * <i>Digit</i> - * <i>Digit</i> <i>Digit</i> - * <i>Minutes:</i> - * <i>Digit</i> <i>Digit</i> - * <i>Digit:</i> one of - * <code>0 1 2 3 4 5 6 7 8 9</code> - * </pre></blockquote> - * - * <i>Hours</i> must be between 0 to 23 and <i>Minutes</i> must be - * between 00 to 59. For example, "GMT+10" and "GMT+0010" mean ten - * hours and ten minutes ahead of GMT, respectively. - * <p> - * The format is locale independent and digits must be taken from the - * Basic Latin block of the Unicode standard. No daylight saving time - * transition schedule can be specified with a custom time zone ID. If - * the specified string doesn't match the syntax, <code>"GMT"</code> - * is used. - * <p> - * When creating a <code>TimeZone</code>, the specified custom time - * zone ID is normalized in the following syntax: - * <blockquote><pre> - * <a name="NormalizedCustomID"><i>NormalizedCustomID:</i></a> - * <code>GMT</code> <i>Sign</i> <i>TwoDigitHours</i> <code>:</code> <i>Minutes</i> - * <i>Sign:</i> one of - * <code>+ -</code> - * <i>TwoDigitHours:</i> - * <i>Digit</i> <i>Digit</i> - * <i>Minutes:</i> - * <i>Digit</i> <i>Digit</i> - * <i>Digit:</i> one of - * <code>0 1 2 3 4 5 6 7 8 9</code> - * </pre></blockquote> - * For example, TimeZone.getTimeZone("GMT-8").getID() returns "GMT-08:00". - * - * <h4>Three-letter time zone IDs</h4> - * - * For compatibility with JDK 1.1.x, some other three-letter time zone IDs - * (such as "PST", "CTT", "AST") are also supported. However, <strong>their - * use is deprecated</strong> because the same abbreviation is often used - * for multiple time zones (for example, "CST" could be U.S. "Central Standard - * Time" and "China Standard Time"), and the Java platform can then only - * recognize one of them. - * - * - * @see Calendar - * @see GregorianCalendar - * @see SimpleTimeZone - * @author Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu - * @since JDK1.1 - */ -abstract public class TimeZone implements Serializable, Cloneable { - /** - * Sole constructor. (For invocation by subclass constructors, typically - * implicit.) - */ - public TimeZone() { - } - - /** - * A style specifier for <code>getDisplayName()</code> indicating - * a short name, such as "PST." - * @see #LONG - * @since 1.2 - */ - public static final int SHORT = 0; - - /** - * A style specifier for <code>getDisplayName()</code> indicating - * a long name, such as "Pacific Standard Time." - * @see #SHORT - * @since 1.2 - */ - public static final int LONG = 1; - - // Constants used internally; unit is milliseconds - private static final int ONE_MINUTE = 60*1000; - private static final int ONE_HOUR = 60*ONE_MINUTE; - private static final int ONE_DAY = 24*ONE_HOUR; - - // Proclaim serialization compatibility with JDK 1.1 - static final long serialVersionUID = 3581463369166924961L; - - /** - * Gets the time zone offset, for current date, modified in case of - * daylight savings. This is the offset to add to UTC to get local time. - * <p> - * This method returns a historically correct offset if an - * underlying <code>TimeZone</code> implementation subclass - * supports historical Daylight Saving Time schedule and GMT - * offset changes. - * - * @param era the era of the given date. - * @param year the year in the given date. - * @param month the month in the given date. - * Month is 0-based. e.g., 0 for January. - * @param day the day-in-month of the given date. - * @param dayOfWeek the day-of-week of the given date. - * @param milliseconds the milliseconds in day in <em>standard</em> - * local time. - * - * @return the offset in milliseconds to add to GMT to get local time. - * - * @see Calendar#ZONE_OFFSET - * @see Calendar#DST_OFFSET - */ - public abstract int getOffset(int era, int year, int month, int day, - int dayOfWeek, int milliseconds); - - /** - * Returns the offset of this time zone from UTC at the specified - * date. If Daylight Saving Time is in effect at the specified - * date, the offset value is adjusted with the amount of daylight - * saving. - * <p> - * This method returns a historically correct offset value if an - * underlying TimeZone implementation subclass supports historical - * Daylight Saving Time schedule and GMT offset changes. - * - * @param date the date represented in milliseconds since January 1, 1970 00:00:00 GMT - * @return the amount of time in milliseconds to add to UTC to get local time. - * - * @see Calendar#ZONE_OFFSET - * @see Calendar#DST_OFFSET - * @since 1.4 - */ - public int getOffset(long date) { - if (inDaylightTime(new Date(date))) { - return getRawOffset() + getDSTSavings(); - } - return getRawOffset(); - } - - /** - * Gets the raw GMT offset and the amount of daylight saving of this - * time zone at the given time. - * @param date the milliseconds (since January 1, 1970, - * 00:00:00.000 GMT) at which the time zone offset and daylight - * saving amount are found - * @param offset an array of int where the raw GMT offset - * (offset[0]) and daylight saving amount (offset[1]) are stored, - * or null if those values are not needed. The method assumes that - * the length of the given array is two or larger. - * @return the total amount of the raw GMT offset and daylight - * saving at the specified date. - * - * @see Calendar#ZONE_OFFSET - * @see Calendar#DST_OFFSET - */ - int getOffsets(long date, int[] offsets) { - int rawoffset = getRawOffset(); - int dstoffset = 0; - if (inDaylightTime(new Date(date))) { - dstoffset = getDSTSavings(); - } - if (offsets != null) { - offsets[0] = rawoffset; - offsets[1] = dstoffset; - } - return rawoffset + dstoffset; - } - - /** - * Sets the base time zone offset to GMT. - * This is the offset to add to UTC to get local time. - * <p> - * If an underlying <code>TimeZone</code> implementation subclass - * supports historical GMT offset changes, the specified GMT - * offset is set as the latest GMT offset and the difference from - * the known latest GMT offset value is used to adjust all - * historical GMT offset values. - * - * @param offsetMillis the given base time zone offset to GMT. - */ - abstract public void setRawOffset(int offsetMillis); - - /** - * Returns the amount of time in milliseconds to add to UTC to get - * standard time in this time zone. Because this value is not - * affected by daylight saving time, it is called <I>raw - * offset</I>. - * <p> - * If an underlying <code>TimeZone</code> implementation subclass - * supports historical GMT offset changes, the method returns the - * raw offset value of the current date. In Honolulu, for example, - * its raw offset changed from GMT-10:30 to GMT-10:00 in 1947, and - * this method always returns -36000000 milliseconds (i.e., -10 - * hours). - * - * @return the amount of raw offset time in milliseconds to add to UTC. - * @see Calendar#ZONE_OFFSET - */ - public abstract int getRawOffset(); - - /** - * Gets the ID of this time zone. - * @return the ID of this time zone. - */ - public String getID() - { - return ID; - } - - /** - * Sets the time zone ID. This does not change any other data in - * the time zone object. - * @param ID the new time zone ID. - */ - public void setID(String ID) - { - if (ID == null) { - throw new NullPointerException(); - } - this.ID = ID; - } - - /** - * Returns a long standard time name of this {@code TimeZone} suitable for - * presentation to the user in the default locale. - * - * <p>This method is equivalent to: - * <pre><blockquote> - * getDisplayName(false, {@link #LONG}, - * Locale.getDefault({@link Locale.Category#DISPLAY})) - * </blockquote></pre> - * - * @return the human-readable name of this time zone in the default locale. - * @since 1.2 - * @see #getDisplayName(boolean, int, Locale) - * @see Locale#getDefault(Locale.Category) - * @see Locale.Category - */ - public final String getDisplayName() { - return getDisplayName(false, LONG, - Locale.getDefault(Locale.Category.DISPLAY)); - } - - /** - * Returns a long standard time name of this {@code TimeZone} suitable for - * presentation to the user in the specified {@code locale}. - * - * <p>This method is equivalent to: - * <pre><blockquote> - * getDisplayName(false, {@link #LONG}, locale) - * </blockquote></pre> - * - * @param locale the locale in which to supply the display name. - * @return the human-readable name of this time zone in the given locale. - * @exception NullPointerException if {@code locale} is {@code null}. - * @since 1.2 - * @see #getDisplayName(boolean, int, Locale) - */ - public final String getDisplayName(Locale locale) { - return getDisplayName(false, LONG, locale); - } - - /** - * Returns a name in the specified {@code style} of this {@code TimeZone} - * suitable for presentation to the user in the default locale. If the - * specified {@code daylight} is {@code true}, a Daylight Saving Time name - * is returned (even if this {@code TimeZone} doesn't observe Daylight Saving - * Time). Otherwise, a Standard Time name is returned. - * - * <p>This method is equivalent to: - * <pre><blockquote> - * getDisplayName(daylight, style, - * Locale.getDefault({@link Locale.Category#DISPLAY})) - * </blockquote></pre> - * - * @param daylight {@code true} specifying a Daylight Saving Time name, or - * {@code false} specifying a Standard Time name - * @param style either {@link #LONG} or {@link #SHORT} - * @return the human-readable name of this time zone in the default locale. - * @exception IllegalArgumentException if {@code style} is invalid. - * @since 1.2 - * @see #getDisplayName(boolean, int, Locale) - * @see Locale#getDefault(Locale.Category) - * @see Locale.Category - * @see java.text.DateFormatSymbols#getZoneStrings() - */ - public final String getDisplayName(boolean daylight, int style) { - return getDisplayName(daylight, style, - Locale.getDefault(Locale.Category.DISPLAY)); - } - - /** - * Returns a name in the specified {@code style} of this {@code TimeZone} - * suitable for presentation to the user in the specified {@code - * locale}. If the specified {@code daylight} is {@code true}, a Daylight - * Saving Time name is returned (even if this {@code TimeZone} doesn't - * observe Daylight Saving Time). Otherwise, a Standard Time name is - * returned. - * - * <p>When looking up a time zone name, the {@linkplain - * ResourceBundle.Control#getCandidateLocales(String,Locale) default - * <code>Locale</code> search path of <code>ResourceBundle</code>} derived - * from the specified {@code locale} is used. (No {@linkplain - * ResourceBundle.Control#getFallbackLocale(String,Locale) fallback - * <code>Locale</code>} search is performed.) If a time zone name in any - * {@code Locale} of the search path, including {@link Locale#ROOT}, is - * found, the name is returned. Otherwise, a string in the - * <a href="#NormalizedCustomID">normalized custom ID format</a> is returned. - * - * @param daylight {@code true} specifying a Daylight Saving Time name, or - * {@code false} specifying a Standard Time name - * @param style either {@link #LONG} or {@link #SHORT} - * @param locale the locale in which to supply the display name. - * @return the human-readable name of this time zone in the given locale. - * @exception IllegalArgumentException if {@code style} is invalid. - * @exception NullPointerException if {@code locale} is {@code null}. - * @since 1.2 - * @see java.text.DateFormatSymbols#getZoneStrings() - */ - public String getDisplayName(boolean daylight, int style, Locale locale) { - if (style != SHORT && style != LONG) { - throw new IllegalArgumentException("Illegal style: " + style); - } - - String id = getID(); - String[] names = getDisplayNames(id, locale); - if (names == null) { - if (id.startsWith("GMT")) { - char sign = id.charAt(3); - if (sign == '+' || sign == '-') { - return id; - } - } - int offset = getRawOffset(); - if (daylight) { - offset += getDSTSavings(); - } - return ZoneInfoFile.toCustomID(offset); - } - - int index = daylight ? 3 : 1; - if (style == SHORT) { - index++; - } - return names[index]; - } - - private static class DisplayNames { - // Cache for managing display names per timezone per locale - // The structure is: - // Map(key=id, value=SoftReference(Map(key=locale, value=displaynames))) - private static final Map<String, SoftReference<Map<Locale, String[]>>> CACHE = - new ConcurrentHashMap<String, SoftReference<Map<Locale, String[]>>>(); - } - - private static final String[] getDisplayNames(String id, Locale locale) { - Map<String, SoftReference<Map<Locale, String[]>>> displayNames = DisplayNames.CACHE; - - SoftReference<Map<Locale, String[]>> ref = displayNames.get(id); - if (ref != null) { - Map<Locale, String[]> perLocale = ref.get(); - if (perLocale != null) { - String[] names = perLocale.get(locale); - if (names != null) { - return names; - } - names = TimeZoneNameUtility.retrieveDisplayNames(id, locale); - if (names != null) { - perLocale.put(locale, names); - } - return names; - } - } - - String[] names = TimeZoneNameUtility.retrieveDisplayNames(id, locale); - if (names != null) { - Map<Locale, String[]> perLocale = new ConcurrentHashMap<Locale, String[]>(); - perLocale.put(locale, names); - ref = new SoftReference<Map<Locale, String[]>>(perLocale); - displayNames.put(id, ref); - } - return names; - } - - /** - * Returns the amount of time to be added to local standard time - * to get local wall clock time. - * - * <p>The default implementation returns 3600000 milliseconds - * (i.e., one hour) if a call to {@link #useDaylightTime()} - * returns {@code true}. Otherwise, 0 (zero) is returned. - * - * <p>If an underlying {@code TimeZone} implementation subclass - * supports historical and future Daylight Saving Time schedule - * changes, this method returns the amount of saving time of the - * last known Daylight Saving Time rule that can be a future - * prediction. - * - * <p>If the amount of saving time at any given time stamp is - * required, construct a {@link Calendar} with this {@code - * TimeZone} and the time stamp, and call {@link Calendar#get(int) - * Calendar.get}{@code (}{@link Calendar#DST_OFFSET}{@code )}. - * - * @return the amount of saving time in milliseconds - * @since 1.4 - * @see #inDaylightTime(Date) - * @see #getOffset(long) - * @see #getOffset(int,int,int,int,int,int) - * @see Calendar#ZONE_OFFSET - */ - public int getDSTSavings() { - if (useDaylightTime()) { - return 3600000; - } - return 0; - } - - /** - * Queries if this {@code TimeZone} uses Daylight Saving Time. - * - * <p>If an underlying {@code TimeZone} implementation subclass - * supports historical and future Daylight Saving Time schedule - * changes, this method refers to the last known Daylight Saving Time - * rule that can be a future prediction and may not be the same as - * the current rule. Consider calling {@link #observesDaylightTime()} - * if the current rule should also be taken into account. - * - * @return {@code true} if this {@code TimeZone} uses Daylight Saving Time, - * {@code false}, otherwise. - * @see #inDaylightTime(Date) - * @see Calendar#DST_OFFSET - */ - public abstract boolean useDaylightTime(); - - /** - * Returns {@code true} if this {@code TimeZone} is currently in - * Daylight Saving Time, or if a transition from Standard Time to - * Daylight Saving Time occurs at any future time. - * - * <p>The default implementation returns {@code true} if - * {@code useDaylightTime()} or {@code inDaylightTime(new Date())} - * returns {@code true}. - * - * @return {@code true} if this {@code TimeZone} is currently in - * Daylight Saving Time, or if a transition from Standard Time to - * Daylight Saving Time occurs at any future time; {@code false} - * otherwise. - * @since 1.7 - * @see #useDaylightTime() - * @see #inDaylightTime(Date) - * @see Calendar#DST_OFFSET - */ - public boolean observesDaylightTime() { - return useDaylightTime() || inDaylightTime(new Date()); - } - - /** - * Queries if the given {@code date} is in Daylight Saving Time in - * this time zone. - * - * @param date the given Date. - * @return {@code true} if the given date is in Daylight Saving Time, - * {@code false}, otherwise. - */ - abstract public boolean inDaylightTime(Date date); - - /** - * Gets the <code>TimeZone</code> for the given ID. - * - * @param ID the ID for a <code>TimeZone</code>, either an abbreviation - * such as "PST", a full name such as "America/Los_Angeles", or a custom - * ID such as "GMT-8:00". Note that the support of abbreviations is - * for JDK 1.1.x compatibility only and full names should be used. - * - * @return the specified <code>TimeZone</code>, or the GMT zone if the given ID - * cannot be understood. - */ - public static synchronized TimeZone getTimeZone(String ID) { - return getTimeZone(ID, true); - } - - private static TimeZone getTimeZone(String ID, boolean fallback) { - TimeZone tz = ZoneInfo.getTimeZone(ID); - if (tz == null) { - tz = parseCustomTimeZone(ID); - if (tz == null && fallback) { - tz = new ZoneInfo(GMT_ID, 0); - } - } - return tz; - } - - /** - * Gets the available IDs according to the given time zone offset in milliseconds. - * - * @param rawOffset the given time zone GMT offset in milliseconds. - * @return an array of IDs, where the time zone for that ID has - * the specified GMT offset. For example, "America/Phoenix" and "America/Denver" - * both have GMT-07:00, but differ in daylight saving behavior. - * @see #getRawOffset() - */ - public static synchronized String[] getAvailableIDs(int rawOffset) { - return ZoneInfo.getAvailableIDs(rawOffset); - } - - /** - * Gets all the available IDs supported. - * @return an array of IDs. - */ - public static synchronized String[] getAvailableIDs() { - return ZoneInfo.getAvailableIDs(); - } - - /** - * Gets the platform defined TimeZone ID. - **/ - private static native String getSystemTimeZoneID(String javaHome, - String country); - - /** - * Gets the custom time zone ID based on the GMT offset of the - * platform. (e.g., "GMT+08:00") - */ - private static native String getSystemGMTOffsetID(); - - /** - * Gets the default <code>TimeZone</code> for this host. - * The source of the default <code>TimeZone</code> - * may vary with implementation. - * @return a default <code>TimeZone</code>. - * @see #setDefault - */ - public static TimeZone getDefault() { - return (TimeZone) getDefaultRef().clone(); - } - - /** - * Returns the reference to the default TimeZone object. This - * method doesn't create a clone. - */ - static TimeZone getDefaultRef() { - TimeZone defaultZone = getDefaultInAppContext(); - if (defaultZone == null) { - defaultZone = defaultTimeZone; - if (defaultZone == null) { - // Need to initialize the default time zone. - defaultZone = setDefaultZone(); - assert defaultZone != null; - } - } - // Don't clone here. - return defaultZone; - } - - private static synchronized TimeZone setDefaultZone() { - TimeZone tz = null; - // get the time zone ID from the system properties - String zoneID = AccessController.doPrivileged( - new GetPropertyAction("user.timezone")); - - // if the time zone ID is not set (yet), perform the - // platform to Java time zone ID mapping. - if (zoneID == null || zoneID.equals("")) { - String country = AccessController.doPrivileged( - new GetPropertyAction("user.country")); - String javaHome = AccessController.doPrivileged( - new GetPropertyAction("java.home")); - try { - zoneID = getSystemTimeZoneID(javaHome, country); - if (zoneID == null) { - zoneID = GMT_ID; - } - } catch (NullPointerException e) { - zoneID = GMT_ID; - } - } - - // Get the time zone for zoneID. But not fall back to - // "GMT" here. - tz = getTimeZone(zoneID, false); - - if (tz == null) { - // If the given zone ID is unknown in Java, try to - // get the GMT-offset-based time zone ID, - // a.k.a. custom time zone ID (e.g., "GMT-08:00"). - String gmtOffsetID = getSystemGMTOffsetID(); - if (gmtOffsetID != null) { - zoneID = gmtOffsetID; - } - tz = getTimeZone(zoneID, true); - } - assert tz != null; - - final String id = zoneID; - AccessController.doPrivileged(new PrivilegedAction<Object>() { - public Object run() { - System.setProperty("user.timezone", id); - return null; - } - }); - - defaultTimeZone = tz; - return tz; - } - - private static boolean hasPermission() { - boolean hasPermission = true; - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - try { - sm.checkPermission(new PropertyPermission - ("user.timezone", "write")); - } catch (SecurityException e) { - hasPermission = false; - } - } - return hasPermission; - } - - /** - * Sets the <code>TimeZone</code> that is - * returned by the <code>getDefault</code> method. If <code>zone</code> - * is null, reset the default to the value it had originally when the - * VM first started. - * @param zone the new default time zone - * @see #getDefault - */ - public static void setDefault(TimeZone zone) - { - if (hasPermission()) { - synchronized (TimeZone.class) { - defaultTimeZone = zone; - setDefaultInAppContext(null); - } - } else { - setDefaultInAppContext(zone); - } - } - - /** - * Returns the default TimeZone in an AppContext if any AppContext - * has ever used. null is returned if any AppContext hasn't been - * used or if the AppContext doesn't have the default TimeZone. - * - * Note that javaAWTAccess may be null if sun.awt.AppContext class hasn't - * been loaded. If so, it implies that AWTSecurityManager is not our - * SecurityManager and we can use a local static variable. - * This works around a build time issue. - */ - private static TimeZone getDefaultInAppContext() { - // JavaAWTAccess provides access implementation-private methods without using reflection. - JavaAWTAccess javaAWTAccess = SharedSecrets.getJavaAWTAccess(); - if (javaAWTAccess == null) { - return mainAppContextDefault; - } else { - if (!javaAWTAccess.isDisposed()) { - TimeZone tz = (TimeZone) - javaAWTAccess.get(TimeZone.class); - if (tz == null && javaAWTAccess.isMainAppContext()) { - return mainAppContextDefault; - } else { - return tz; - } - } - } - return null; - } - - /** - * Sets the default TimeZone in the AppContext to the given - * tz. null is handled special: do nothing if any AppContext - * hasn't been used, remove the default TimeZone in the - * AppContext otherwise. - * - * Note that javaAWTAccess may be null if sun.awt.AppContext class hasn't - * been loaded. If so, it implies that AWTSecurityManager is not our - * SecurityManager and we can use a local static variable. - * This works around a build time issue. - */ - private static void setDefaultInAppContext(TimeZone tz) { - // JavaAWTAccess provides access implementation-private methods without using reflection. - JavaAWTAccess javaAWTAccess = SharedSecrets.getJavaAWTAccess(); - if (javaAWTAccess == null) { - mainAppContextDefault = tz; - } else { - if (!javaAWTAccess.isDisposed()) { - javaAWTAccess.put(TimeZone.class, tz); - if (javaAWTAccess.isMainAppContext()) { - mainAppContextDefault = null; - } - } - } - } - - /** - * Returns true if this zone has the same rule and offset as another zone. - * That is, if this zone differs only in ID, if at all. Returns false - * if the other zone is null. - * @param other the <code>TimeZone</code> object to be compared with - * @return true if the other zone is not null and is the same as this one, - * with the possible exception of the ID - * @since 1.2 - */ - public boolean hasSameRules(TimeZone other) { - return other != null && getRawOffset() == other.getRawOffset() && - useDaylightTime() == other.useDaylightTime(); - } - - /** - * Creates a copy of this <code>TimeZone</code>. - * - * @return a clone of this <code>TimeZone</code> - */ - public Object clone() - { - try { - TimeZone other = (TimeZone) super.clone(); - other.ID = ID; - return other; - } catch (CloneNotSupportedException e) { - throw new InternalError(); - } - } - - /** - * The null constant as a TimeZone. - */ - static final TimeZone NO_TIMEZONE = null; - - // =======================privates=============================== - - /** - * The string identifier of this <code>TimeZone</code>. This is a - * programmatic identifier used internally to look up <code>TimeZone</code> - * objects from the system table and also to map them to their localized - * display names. <code>ID</code> values are unique in the system - * table but may not be for dynamically created zones. - * @serial - */ - private String ID; - private static volatile TimeZone defaultTimeZone; - - static final String GMT_ID = "GMT"; - private static final int GMT_ID_LENGTH = 3; - - // a static TimeZone we can reference if no AppContext is in place - private static volatile TimeZone mainAppContextDefault; - - /** - * Parses a custom time zone identifier and returns a corresponding zone. - * This method doesn't support the RFC 822 time zone format. (e.g., +hhmm) - * - * @param id a string of the <a href="#CustomID">custom ID form</a>. - * @return a newly created TimeZone with the given offset and - * no daylight saving time, or null if the id cannot be parsed. - */ - private static final TimeZone parseCustomTimeZone(String id) { - int length; - - // Error if the length of id isn't long enough or id doesn't - // start with "GMT". - if ((length = id.length()) < (GMT_ID_LENGTH + 2) || - id.indexOf(GMT_ID) != 0) { - return null; - } - - ZoneInfo zi; - - // First, we try to find it in the cache with the given - // id. Even the id is not normalized, the returned ZoneInfo - // should have its normalized id. - zi = ZoneInfoFile.getZoneInfo(id); - if (zi != null) { - return zi; - } - - int index = GMT_ID_LENGTH; - boolean negative = false; - char c = id.charAt(index++); - if (c == '-') { - negative = true; - } else if (c != '+') { - return null; - } - - int hours = 0; - int num = 0; - int countDelim = 0; - int len = 0; - while (index < length) { - c = id.charAt(index++); - if (c == ':') { - if (countDelim > 0) { - return null; - } - if (len > 2) { - return null; - } - hours = num; - countDelim++; - num = 0; - len = 0; - continue; - } - if (c < '0' || c > '9') { - return null; - } - num = num * 10 + (c - '0'); - len++; - } - if (index != length) { - return null; - } - if (countDelim == 0) { - if (len <= 2) { - hours = num; - num = 0; - } else { - hours = num / 100; - num %= 100; - } - } else { - if (len != 2) { - return null; - } - } - if (hours > 23 || num > 59) { - return null; - } - int gmtOffset = (hours * 60 + num) * 60 * 1000; - - if (gmtOffset == 0) { - zi = ZoneInfoFile.getZoneInfo(GMT_ID); - if (negative) { - zi.setID("GMT-00:00"); - } else { - zi.setID("GMT+00:00"); - } - } else { - zi = ZoneInfoFile.getCustomTimeZone(id, negative ? -gmtOffset : gmtOffset); - } - return zi; - } -} diff --git a/openjdk/java/util/concurrent/ForkJoinPool.java b/openjdk/java/util/concurrent/ForkJoinPool.java deleted file mode 100644 index 4b157962..00000000 --- a/openjdk/java/util/concurrent/ForkJoinPool.java +++ /dev/null @@ -1,3363 +0,0 @@ -/* - * 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. - */ - -/* - * This file is available under and governed by the GNU General Public - * License version 2 only, as published by the Free Software Foundation. - * However, the following notice accompanied the original version of this - * file: - * - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/publicdomain/zero/1.0/ - */ - -package java.util.concurrent; - -import java.lang.Thread.UncaughtExceptionHandler; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.AbstractExecutorService; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.RunnableFuture; -import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.TimeUnit; -import java.security.AccessControlContext; -import java.security.ProtectionDomain; -import java.security.Permissions; - -/** - * An {@link ExecutorService} for running {@link ForkJoinTask}s. - * A {@code ForkJoinPool} provides the entry point for submissions - * from non-{@code ForkJoinTask} clients, as well as management and - * monitoring operations. - * - * <p>A {@code ForkJoinPool} differs from other kinds of {@link - * ExecutorService} mainly by virtue of employing - * <em>work-stealing</em>: all threads in the pool attempt to find and - * execute tasks submitted to the pool and/or created by other active - * tasks (eventually blocking waiting for work if none exist). This - * enables efficient processing when most tasks spawn other subtasks - * (as do most {@code ForkJoinTask}s), as well as when many small - * tasks are submitted to the pool from external clients. Especially - * when setting <em>asyncMode</em> to true in constructors, {@code - * ForkJoinPool}s may also be appropriate for use with event-style - * tasks that are never joined. - * - * <p>A static {@link #commonPool()} is available and appropriate for - * most applications. The common pool is used by any ForkJoinTask that - * is not explicitly submitted to a specified pool. Using the common - * pool normally reduces resource usage (its threads are slowly - * reclaimed during periods of non-use, and reinstated upon subsequent - * use). - * - * <p>For applications that require separate or custom pools, a {@code - * ForkJoinPool} may be constructed with a given target parallelism - * level; by default, equal to the number of available processors. The - * pool attempts to maintain enough active (or available) threads by - * dynamically adding, suspending, or resuming internal worker - * threads, even if some tasks are stalled waiting to join others. - * However, no such adjustments are guaranteed in the face of blocked - * I/O or other unmanaged synchronization. The nested {@link - * ManagedBlocker} interface enables extension of the kinds of - * synchronization accommodated. - * - * <p>In addition to execution and lifecycle control methods, this - * class provides status check methods (for example - * {@link #getStealCount}) that are intended to aid in developing, - * tuning, and monitoring fork/join applications. Also, method - * {@link #toString} returns indications of pool state in a - * convenient form for informal monitoring. - * - * <p>As is the case with other ExecutorServices, there are three - * main task execution methods summarized in the following table. - * These are designed to be used primarily by clients not already - * engaged in fork/join computations in the current pool. The main - * forms of these methods accept instances of {@code ForkJoinTask}, - * but overloaded forms also allow mixed execution of plain {@code - * Runnable}- or {@code Callable}- based activities as well. However, - * tasks that are already executing in a pool should normally instead - * use the within-computation forms listed in the table unless using - * async event-style tasks that are not usually joined, in which case - * there is little difference among choice of methods. - * - * <table BORDER CELLPADDING=3 CELLSPACING=1> - * <caption>Summary of task execution methods</caption> - * <tr> - * <td></td> - * <td ALIGN=CENTER> <b>Call from non-fork/join clients</b></td> - * <td ALIGN=CENTER> <b>Call from within fork/join computations</b></td> - * </tr> - * <tr> - * <td> <b>Arrange async execution</b></td> - * <td> {@link #execute(ForkJoinTask)}</td> - * <td> {@link ForkJoinTask#fork}</td> - * </tr> - * <tr> - * <td> <b>Await and obtain result</b></td> - * <td> {@link #invoke(ForkJoinTask)}</td> - * <td> {@link ForkJoinTask#invoke}</td> - * </tr> - * <tr> - * <td> <b>Arrange exec and obtain Future</b></td> - * <td> {@link #submit(ForkJoinTask)}</td> - * <td> {@link ForkJoinTask#fork} (ForkJoinTasks <em>are</em> Futures)</td> - * </tr> - * </table> - * - * <p>The common pool is by default constructed with default - * parameters, but these may be controlled by setting three - * {@linkplain System#getProperty system properties}: - * <ul> - * <li>{@code java.util.concurrent.ForkJoinPool.common.parallelism} - * - the parallelism level, a non-negative integer - * <li>{@code java.util.concurrent.ForkJoinPool.common.threadFactory} - * - the class name of a {@link ForkJoinWorkerThreadFactory} - * <li>{@code java.util.concurrent.ForkJoinPool.common.exceptionHandler} - * - the class name of a {@link UncaughtExceptionHandler} - * </ul> - * If a {@link SecurityManager} is present and no factory is - * specified, then the default pool uses a factory supplying - * threads that have no {@link Permissions} enabled. - * The system class loader is used to load these classes. - * Upon any error in establishing these settings, default parameters - * are used. It is possible to disable or limit the use of threads in - * the common pool by setting the parallelism property to zero, and/or - * using a factory that may return {@code null}. However doing so may - * cause unjoined tasks to never be executed. - * - * <p><b>Implementation notes</b>: This implementation restricts the - * maximum number of running threads to 32767. Attempts to create - * pools with greater than the maximum number result in - * {@code IllegalArgumentException}. - * - * <p>This implementation rejects submitted tasks (that is, by throwing - * {@link RejectedExecutionException}) only when the pool is shut down - * or internal resources have been exhausted. - * - * @since 1.7 - * @author Doug Lea - */ -@sun.misc.Contended -public class ForkJoinPool extends AbstractExecutorService { - - /* - * Implementation Overview - * - * This class and its nested classes provide the main - * functionality and control for a set of worker threads: - * Submissions from non-FJ threads enter into submission queues. - * Workers take these tasks and typically split them into subtasks - * that may be stolen by other workers. Preference rules give - * first priority to processing tasks from their own queues (LIFO - * or FIFO, depending on mode), then to randomized FIFO steals of - * tasks in other queues. - * - * WorkQueues - * ========== - * - * Most operations occur within work-stealing queues (in nested - * class WorkQueue). These are special forms of Deques that - * support only three of the four possible end-operations -- push, - * pop, and poll (aka steal), under the further constraints that - * push and pop are called only from the owning thread (or, as - * extended here, under a lock), while poll may be called from - * other threads. (If you are unfamiliar with them, you probably - * want to read Herlihy and Shavit's book "The Art of - * Multiprocessor programming", chapter 16 describing these in - * more detail before proceeding.) The main work-stealing queue - * design is roughly similar to those in the papers "Dynamic - * Circular Work-Stealing Deque" by Chase and Lev, SPAA 2005 - * (http://research.sun.com/scalable/pubs/index.html) and - * "Idempotent work stealing" by Michael, Saraswat, and Vechev, - * PPoPP 2009 (http://portal.acm.org/citation.cfm?id=1504186). - * See also "Correct and Efficient Work-Stealing for Weak Memory - * Models" by Le, Pop, Cohen, and Nardelli, PPoPP 2013 - * (http://www.di.ens.fr/~zappa/readings/ppopp13.pdf) for an - * analysis of memory ordering (atomic, volatile etc) issues. The - * main differences ultimately stem from GC requirements that we - * null out taken slots as soon as we can, to maintain as small a - * footprint as possible even in programs generating huge numbers - * of tasks. To accomplish this, we shift the CAS arbitrating pop - * vs poll (steal) from being on the indices ("base" and "top") to - * the slots themselves. So, both a successful pop and poll - * mainly entail a CAS of a slot from non-null to null. Because - * we rely on CASes of references, we do not need tag bits on base - * or top. They are simple ints as used in any circular - * array-based queue (see for example ArrayDeque). Updates to the - * indices must still be ordered in a way that guarantees that top - * == base means the queue is empty, but otherwise may err on the - * side of possibly making the queue appear nonempty when a push, - * pop, or poll have not fully committed. Note that this means - * that the poll operation, considered individually, is not - * wait-free. One thief cannot successfully continue until another - * in-progress one (or, if previously empty, a push) completes. - * However, in the aggregate, we ensure at least probabilistic - * non-blockingness. If an attempted steal fails, a thief always - * chooses a different random victim target to try next. So, in - * order for one thief to progress, it suffices for any - * in-progress poll or new push on any empty queue to - * complete. (This is why we normally use method pollAt and its - * variants that try once at the apparent base index, else - * consider alternative actions, rather than method poll.) - * - * This approach also enables support of a user mode in which local - * task processing is in FIFO, not LIFO order, simply by using - * poll rather than pop. This can be useful in message-passing - * frameworks in which tasks are never joined. However neither - * mode considers affinities, loads, cache localities, etc, so - * rarely provide the best possible performance on a given - * machine, but portably provide good throughput by averaging over - * these factors. (Further, even if we did try to use such - * information, we do not usually have a basis for exploiting it. - * For example, some sets of tasks profit from cache affinities, - * but others are harmed by cache pollution effects.) - * - * WorkQueues are also used in a similar way for tasks submitted - * to the pool. We cannot mix these tasks in the same queues used - * for work-stealing (this would contaminate lifo/fifo - * processing). Instead, we randomly associate submission queues - * with submitting threads, using a form of hashing. The - * ThreadLocalRandom probe value serves as a hash code for - * choosing existing queues, and may be randomly repositioned upon - * contention with other submitters. In essence, submitters act - * like workers except that they are restricted to executing local - * tasks that they submitted (or in the case of CountedCompleters, - * others with the same root task). However, because most - * shared/external queue operations are more expensive than - * internal, and because, at steady state, external submitters - * will compete for CPU with workers, ForkJoinTask.join and - * related methods disable them from repeatedly helping to process - * tasks if all workers are active. Insertion of tasks in shared - * mode requires a lock (mainly to protect in the case of - * resizing) but we use only a simple spinlock (using bits in - * field qlock), because submitters encountering a busy queue move - * on to try or create other queues -- they block only when - * creating and registering new queues. - * - * Management - * ========== - * - * The main throughput advantages of work-stealing stem from - * decentralized control -- workers mostly take tasks from - * themselves or each other. We cannot negate this in the - * implementation of other management responsibilities. The main - * tactic for avoiding bottlenecks is packing nearly all - * essentially atomic control state into two volatile variables - * that are by far most often read (not written) as status and - * consistency checks. - * - * Field "ctl" contains 64 bits holding all the information needed - * to atomically decide to add, inactivate, enqueue (on an event - * queue), dequeue, and/or re-activate workers. To enable this - * packing, we restrict maximum parallelism to (1<<15)-1 (which is - * far in excess of normal operating range) to allow ids, counts, - * and their negations (used for thresholding) to fit into 16bit - * fields. - * - * Field "plock" is a form of sequence lock with a saturating - * shutdown bit (similarly for per-queue "qlocks"), mainly - * protecting updates to the workQueues array, as well as to - * enable shutdown. When used as a lock, it is normally only very - * briefly held, so is nearly always available after at most a - * brief spin, but we use a monitor-based backup strategy to - * block when needed. - * - * Recording WorkQueues. WorkQueues are recorded in the - * "workQueues" array that is created upon first use and expanded - * if necessary. Updates to the array while recording new workers - * and unrecording terminated ones are protected from each other - * by a lock but the array is otherwise concurrently readable, and - * accessed directly. To simplify index-based operations, the - * array size is always a power of two, and all readers must - * tolerate null slots. Worker queues are at odd indices. Shared - * (submission) queues are at even indices, up to a maximum of 64 - * slots, to limit growth even if array needs to expand to add - * more workers. Grouping them together in this way simplifies and - * speeds up task scanning. - * - * All worker thread creation is on-demand, triggered by task - * submissions, replacement of terminated workers, and/or - * compensation for blocked workers. However, all other support - * code is set up to work with other policies. To ensure that we - * do not hold on to worker references that would prevent GC, ALL - * accesses to workQueues are via indices into the workQueues - * array (which is one source of some of the messy code - * constructions here). In essence, the workQueues array serves as - * a weak reference mechanism. Thus for example the wait queue - * field of ctl stores indices, not references. Access to the - * workQueues in associated methods (for example signalWork) must - * both index-check and null-check the IDs. All such accesses - * ignore bad IDs by returning out early from what they are doing, - * since this can only be associated with termination, in which - * case it is OK to give up. All uses of the workQueues array - * also check that it is non-null (even if previously - * non-null). This allows nulling during termination, which is - * currently not necessary, but remains an option for - * resource-revocation-based shutdown schemes. It also helps - * reduce JIT issuance of uncommon-trap code, which tends to - * unnecessarily complicate control flow in some methods. - * - * Event Queuing. Unlike HPC work-stealing frameworks, we cannot - * let workers spin indefinitely scanning for tasks when none can - * be found immediately, and we cannot start/resume workers unless - * there appear to be tasks available. On the other hand, we must - * quickly prod them into action when new tasks are submitted or - * generated. In many usages, ramp-up time to activate workers is - * the main limiting factor in overall performance (this is - * compounded at program start-up by JIT compilation and - * allocation). So we try to streamline this as much as possible. - * We park/unpark workers after placing in an event wait queue - * when they cannot find work. This "queue" is actually a simple - * Treiber stack, headed by the "id" field of ctl, plus a 15bit - * counter value (that reflects the number of times a worker has - * been inactivated) to avoid ABA effects (we need only as many - * version numbers as worker threads). Successors are held in - * field WorkQueue.nextWait. Queuing deals with several intrinsic - * races, mainly that a task-producing thread can miss seeing (and - * signalling) another thread that gave up looking for work but - * has not yet entered the wait queue. We solve this by requiring - * a full sweep of all workers (via repeated calls to method - * scan()) both before and after a newly waiting worker is added - * to the wait queue. Because enqueued workers may actually be - * rescanning rather than waiting, we set and clear the "parker" - * field of WorkQueues to reduce unnecessary calls to unpark. - * (This requires a secondary recheck to avoid missed signals.) - * Note the unusual conventions about Thread.interrupts - * surrounding parking and other blocking: Because interrupts are - * used solely to alert threads to check termination, which is - * checked anyway upon blocking, we clear status (using - * Thread.interrupted) before any call to park, so that park does - * not immediately return due to status being set via some other - * unrelated call to interrupt in user code. - * - * Signalling. We create or wake up workers only when there - * appears to be at least one task they might be able to find and - * execute. When a submission is added or another worker adds a - * task to a queue that has fewer than two tasks, they signal - * waiting workers (or trigger creation of new ones if fewer than - * the given parallelism level -- signalWork). These primary - * signals are buttressed by others whenever other threads remove - * a task from a queue and notice that there are other tasks there - * as well. So in general, pools will be over-signalled. On most - * platforms, signalling (unpark) overhead time is noticeably - * long, and the time between signalling a thread and it actually - * making progress can be very noticeably long, so it is worth - * offloading these delays from critical paths as much as - * possible. Additionally, workers spin-down gradually, by staying - * alive so long as they see the ctl state changing. Similar - * stability-sensing techniques are also used before blocking in - * awaitJoin and helpComplete. - * - * Trimming workers. To release resources after periods of lack of - * use, a worker starting to wait when the pool is quiescent will - * time out and terminate if the pool has remained quiescent for a - * given period -- a short period if there are more threads than - * parallelism, longer as the number of threads decreases. This - * will slowly propagate, eventually terminating all workers after - * periods of non-use. - * - * Shutdown and Termination. A call to shutdownNow atomically sets - * a plock bit and then (non-atomically) sets each worker's - * qlock status, cancels all unprocessed tasks, and wakes up - * all waiting workers. Detecting whether termination should - * commence after a non-abrupt shutdown() call requires more work - * and bookkeeping. We need consensus about quiescence (i.e., that - * there is no more work). The active count provides a primary - * indication but non-abrupt shutdown still requires a rechecking - * scan for any workers that are inactive but not queued. - * - * Joining Tasks - * ============= - * - * Any of several actions may be taken when one worker is waiting - * to join a task stolen (or always held) by another. Because we - * are multiplexing many tasks on to a pool of workers, we can't - * just let them block (as in Thread.join). We also cannot just - * reassign the joiner's run-time stack with another and replace - * it later, which would be a form of "continuation", that even if - * possible is not necessarily a good idea since we sometimes need - * both an unblocked task and its continuation to progress. - * Instead we combine two tactics: - * - * Helping: Arranging for the joiner to execute some task that it - * would be running if the steal had not occurred. - * - * Compensating: Unless there are already enough live threads, - * method tryCompensate() may create or re-activate a spare - * thread to compensate for blocked joiners until they unblock. - * - * A third form (implemented in tryRemoveAndExec) amounts to - * helping a hypothetical compensator: If we can readily tell that - * a possible action of a compensator is to steal and execute the - * task being joined, the joining thread can do so directly, - * without the need for a compensation thread (although at the - * expense of larger run-time stacks, but the tradeoff is - * typically worthwhile). - * - * The ManagedBlocker extension API can't use helping so relies - * only on compensation in method awaitBlocker. - * - * The algorithm in tryHelpStealer entails a form of "linear" - * helping: Each worker records (in field currentSteal) the most - * recent task it stole from some other worker. Plus, it records - * (in field currentJoin) the task it is currently actively - * joining. Method tryHelpStealer uses these markers to try to - * find a worker to help (i.e., steal back a task from and execute - * it) that could hasten completion of the actively joined task. - * In essence, the joiner executes a task that would be on its own - * local deque had the to-be-joined task not been stolen. This may - * be seen as a conservative variant of the approach in Wagner & - * Calder "Leapfrogging: a portable technique for implementing - * efficient futures" SIGPLAN Notices, 1993 - * (http://portal.acm.org/citation.cfm?id=155354). It differs in - * that: (1) We only maintain dependency links across workers upon - * steals, rather than use per-task bookkeeping. This sometimes - * requires a linear scan of workQueues array to locate stealers, - * but often doesn't because stealers leave hints (that may become - * stale/wrong) of where to locate them. It is only a hint - * because a worker might have had multiple steals and the hint - * records only one of them (usually the most current). Hinting - * isolates cost to when it is needed, rather than adding to - * per-task overhead. (2) It is "shallow", ignoring nesting and - * potentially cyclic mutual steals. (3) It is intentionally - * racy: field currentJoin is updated only while actively joining, - * which means that we miss links in the chain during long-lived - * tasks, GC stalls etc (which is OK since blocking in such cases - * is usually a good idea). (4) We bound the number of attempts - * to find work (see MAX_HELP) and fall back to suspending the - * worker and if necessary replacing it with another. - * - * Helping actions for CountedCompleters are much simpler: Method - * helpComplete can take and execute any task with the same root - * as the task being waited on. However, this still entails some - * traversal of completer chains, so is less efficient than using - * CountedCompleters without explicit joins. - * - * It is impossible to keep exactly the target parallelism number - * of threads running at any given time. Determining the - * existence of conservatively safe helping targets, the - * availability of already-created spares, and the apparent need - * to create new spares are all racy, so we rely on multiple - * retries of each. Compensation in the apparent absence of - * helping opportunities is challenging to control on JVMs, where - * GC and other activities can stall progress of tasks that in - * turn stall out many other dependent tasks, without us being - * able to determine whether they will ever require compensation. - * Even though work-stealing otherwise encounters little - * degradation in the presence of more threads than cores, - * aggressively adding new threads in such cases entails risk of - * unwanted positive feedback control loops in which more threads - * cause more dependent stalls (as well as delayed progress of - * unblocked threads to the point that we know they are available) - * leading to more situations requiring more threads, and so - * on. This aspect of control can be seen as an (analytically - * intractable) game with an opponent that may choose the worst - * (for us) active thread to stall at any time. We take several - * precautions to bound losses (and thus bound gains), mainly in - * methods tryCompensate and awaitJoin. - * - * Common Pool - * =========== - * - * The static common pool always exists after static - * initialization. Since it (or any other created pool) need - * never be used, we minimize initial construction overhead and - * footprint to the setup of about a dozen fields, with no nested - * allocation. Most bootstrapping occurs within method - * fullExternalPush during the first submission to the pool. - * - * When external threads submit to the common pool, they can - * perform subtask processing (see externalHelpJoin and related - * methods). This caller-helps policy makes it sensible to set - * common pool parallelism level to one (or more) less than the - * total number of available cores, or even zero for pure - * caller-runs. We do not need to record whether external - * submissions are to the common pool -- if not, externalHelpJoin - * returns quickly (at the most helping to signal some common pool - * workers). These submitters would otherwise be blocked waiting - * for completion, so the extra effort (with liberally sprinkled - * task status checks) in inapplicable cases amounts to an odd - * form of limited spin-wait before blocking in ForkJoinTask.join. - * - * As a more appropriate default in managed environments, unless - * overridden by system properties, we use workers of subclass - * InnocuousForkJoinWorkerThread when there is a SecurityManager - * present. These workers have no permissions set, do not belong - * to any user-defined ThreadGroup, and erase all ThreadLocals - * after executing any top-level task (see WorkQueue.runTask). The - * associated mechanics (mainly in ForkJoinWorkerThread) may be - * JVM-dependent and must access particular Thread class fields to - * achieve this effect. - * - * Style notes - * =========== - * - * There is a lot of representation-level coupling among classes - * ForkJoinPool, ForkJoinWorkerThread, and ForkJoinTask. The - * fields of WorkQueue maintain data structures managed by - * ForkJoinPool, so are directly accessed. There is little point - * trying to reduce this, since any associated future changes in - * representations will need to be accompanied by algorithmic - * changes anyway. Several methods intrinsically sprawl because - * they must accumulate sets of consistent reads of volatiles held - * in local variables. Methods signalWork() and scan() are the - * main bottlenecks, so are especially heavily - * micro-optimized/mangled. There are lots of inline assignments - * (of form "while ((local = field) != 0)") which are usually the - * simplest way to ensure the required read orderings (which are - * sometimes critical). This leads to a "C"-like style of listing - * declarations of these locals at the heads of methods or blocks. - * There are several occurrences of the unusual "do {} while - * (!cas...)" which is the simplest way to force an update of a - * CAS'ed variable. There are also other coding oddities (including - * several unnecessary-looking hoisted null checks) that help - * some methods perform reasonably even when interpreted (not - * compiled). - * - * The order of declarations in this file is: - * (1) Static utility functions - * (2) Nested (static) classes - * (3) Static fields - * (4) Fields, along with constants used when unpacking some of them - * (5) Internal control methods - * (6) Callbacks and other support for ForkJoinTask methods - * (7) Exported methods - * (8) Static block initializing statics in minimally dependent order - */ - - // Static utilities - - /** - * If there is a security manager, makes sure caller has - * permission to modify threads. - */ - private static void checkPermission() { - SecurityManager security = System.getSecurityManager(); - if (security != null) - security.checkPermission(modifyThreadPermission); - } - - // Nested classes - - /** - * Factory for creating new {@link ForkJoinWorkerThread}s. - * A {@code ForkJoinWorkerThreadFactory} must be defined and used - * for {@code ForkJoinWorkerThread} subclasses that extend base - * functionality or initialize threads with different contexts. - */ - public static interface ForkJoinWorkerThreadFactory { - /** - * Returns a new worker thread operating in the given pool. - * - * @param pool the pool this thread works in - * @return the new worker thread - * @throws NullPointerException if the pool is null - */ - public ForkJoinWorkerThread newThread(ForkJoinPool pool); - } - - /** - * Default ForkJoinWorkerThreadFactory implementation; creates a - * new ForkJoinWorkerThread. - */ - static final class DefaultForkJoinWorkerThreadFactory - implements ForkJoinWorkerThreadFactory { - public final ForkJoinWorkerThread newThread(ForkJoinPool pool) { - return new ForkJoinWorkerThread(pool); - } - } - - /** - * Class for artificial tasks that are used to replace the target - * of local joins if they are removed from an interior queue slot - * in WorkQueue.tryRemoveAndExec. We don't need the proxy to - * actually do anything beyond having a unique identity. - */ - static final class EmptyTask extends ForkJoinTask<Void> { - private static final long serialVersionUID = -7721805057305804111L; - EmptyTask() { status = ForkJoinTask.NORMAL; } // force done - public final Void getRawResult() { return null; } - public final void setRawResult(Void x) {} - public final boolean exec() { return true; } - } - - /** - * Queues supporting work-stealing as well as external task - * submission. See above for main rationale and algorithms. - * Implementation relies heavily on "Unsafe" intrinsics - * and selective use of "volatile": - * - * Field "base" is the index (mod array.length) of the least valid - * queue slot, which is always the next position to steal (poll) - * from if nonempty. Reads and writes require volatile orderings - * but not CAS, because updates are only performed after slot - * CASes. - * - * Field "top" is the index (mod array.length) of the next queue - * slot to push to or pop from. It is written only by owner thread - * for push, or under lock for external/shared push, and accessed - * by other threads only after reading (volatile) base. Both top - * and base are allowed to wrap around on overflow, but (top - - * base) (or more commonly -(base - top) to force volatile read of - * base before top) still estimates size. The lock ("qlock") is - * forced to -1 on termination, causing all further lock attempts - * to fail. (Note: we don't need CAS for termination state because - * upon pool shutdown, all shared-queues will stop being used - * anyway.) Nearly all lock bodies are set up so that exceptions - * within lock bodies are "impossible" (modulo JVM errors that - * would cause failure anyway.) - * - * The array slots are read and written using the emulation of - * volatiles/atomics provided by Unsafe. Insertions must in - * general use putOrderedObject as a form of releasing store to - * ensure that all writes to the task object are ordered before - * its publication in the queue. All removals entail a CAS to - * null. The array is always a power of two. To ensure safety of - * Unsafe array operations, all accesses perform explicit null - * checks and implicit bounds checks via power-of-two masking. - * - * In addition to basic queuing support, this class contains - * fields described elsewhere to control execution. It turns out - * to work better memory-layout-wise to include them in this class - * rather than a separate class. - * - * Performance on most platforms is very sensitive to placement of - * instances of both WorkQueues and their arrays -- we absolutely - * do not want multiple WorkQueue instances or multiple queue - * arrays sharing cache lines. (It would be best for queue objects - * and their arrays to share, but there is nothing available to - * help arrange that). The @Contended annotation alerts JVMs to - * try to keep instances apart. - */ - @sun.misc.Contended - static final class WorkQueue { - /** - * Capacity of work-stealing queue array upon initialization. - * Must be a power of two; at least 4, but should be larger to - * reduce or eliminate cacheline sharing among queues. - * Currently, it is much larger, as a partial workaround for - * the fact that JVMs often place arrays in locations that - * share GC bookkeeping (especially cardmarks) such that - * per-write accesses encounter serious memory contention. - */ - static final int INITIAL_QUEUE_CAPACITY = 1 << 13; - - /** - * Maximum size for queue arrays. Must be a power of two less - * than or equal to 1 << (31 - width of array entry) to ensure - * lack of wraparound of index calculations, but defined to a - * value a bit less than this to help users trap runaway - * programs before saturating systems. - */ - static final int MAXIMUM_QUEUE_CAPACITY = 1 << 26; // 64M - - volatile int eventCount; // encoded inactivation count; < 0 if inactive - int nextWait; // encoded record of next event waiter - int nsteals; // number of steals - int hint; // steal index hint - short poolIndex; // index of this queue in pool - final short mode; // 0: lifo, > 0: fifo, < 0: shared - volatile int qlock; // 1: locked, -1: terminate; else 0 - volatile int base; // index of next slot for poll - int top; // index of next slot for push - ForkJoinTask<?>[] array; // the elements (initially unallocated) - final ForkJoinPool pool; // the containing pool (may be null) - final ForkJoinWorkerThread owner; // owning thread or null if shared - volatile Thread parker; // == owner during call to park; else null - volatile ForkJoinTask<?> currentJoin; // task being joined in awaitJoin - ForkJoinTask<?> currentSteal; // current non-local task being executed - - WorkQueue(ForkJoinPool pool, ForkJoinWorkerThread owner, int mode, - int seed) { - this.pool = pool; - this.owner = owner; - this.mode = (short)mode; - this.hint = seed; // store initial seed for runWorker - // Place indices in the center of array (that is not yet allocated) - base = top = INITIAL_QUEUE_CAPACITY >>> 1; - } - - /** - * Returns the approximate number of tasks in the queue. - */ - final int queueSize() { - int n = base - top; // non-owner callers must read base first - return (n >= 0) ? 0 : -n; // ignore transient negative - } - - /** - * Provides a more accurate estimate of whether this queue has - * any tasks than does queueSize, by checking whether a - * near-empty queue has at least one unclaimed task. - */ - final boolean isEmpty() { - ForkJoinTask<?>[] a; int m, s; - int n = base - (s = top); - return (n >= 0 || - (n == -1 && - ((a = array) == null || - (m = a.length - 1) < 0 || - U.getObject - (a, (long)((m & (s - 1)) << ASHIFT) + ABASE) == null))); - } - - /** - * Pushes a task. Call only by owner in unshared queues. (The - * shared-queue version is embedded in method externalPush.) - * - * @param task the task. Caller must ensure non-null. - * @throws RejectedExecutionException if array cannot be resized - */ - final void push(ForkJoinTask<?> task) { - ForkJoinTask<?>[] a; ForkJoinPool p; - int s = top, n; - if ((a = array) != null) { // ignore if queue removed - int m = a.length - 1; - U.putOrderedObject(a, ((m & s) << ASHIFT) + ABASE, task); - if ((n = (top = s + 1) - base) <= 2) - (p = pool).signalWork(p.workQueues, this); - else if (n >= m) - growArray(); - } - } - - /** - * Initializes or doubles the capacity of array. Call either - * by owner or with lock held -- it is OK for base, but not - * top, to move while resizings are in progress. - */ - final ForkJoinTask<?>[] growArray() { - ForkJoinTask<?>[] oldA = array; - int size = oldA != null ? oldA.length << 1 : INITIAL_QUEUE_CAPACITY; - if (size > MAXIMUM_QUEUE_CAPACITY) - throw new RejectedExecutionException("Queue capacity exceeded"); - int oldMask, t, b; - ForkJoinTask<?>[] a = array = new ForkJoinTask<?>[size]; - if (oldA != null && (oldMask = oldA.length - 1) >= 0 && - (t = top) - (b = base) > 0) { - int mask = size - 1; - do { - ForkJoinTask<?> x; - int oldj = ((b & oldMask) << ASHIFT) + ABASE; - int j = ((b & mask) << ASHIFT) + ABASE; - x = (ForkJoinTask<?>)U.getObjectVolatile(oldA, oldj); - if (x != null && - U.compareAndSwapObject(oldA, oldj, x, null)) - U.putObjectVolatile(a, j, x); - } while (++b != t); - } - return a; - } - - /** - * Takes next task, if one exists, in LIFO order. Call only - * by owner in unshared queues. - */ - final ForkJoinTask<?> pop() { - ForkJoinTask<?>[] a; ForkJoinTask<?> t; int m; - if ((a = array) != null && (m = a.length - 1) >= 0) { - for (int s; (s = top - 1) - base >= 0;) { - long j = ((m & s) << ASHIFT) + ABASE; - if ((t = (ForkJoinTask<?>)U.getObject(a, j)) == null) - break; - if (U.compareAndSwapObject(a, j, t, null)) { - top = s; - return t; - } - } - } - return null; - } - - /** - * Takes a task in FIFO order if b is base of queue and a task - * can be claimed without contention. Specialized versions - * appear in ForkJoinPool methods scan and tryHelpStealer. - */ - final ForkJoinTask<?> pollAt(int b) { - ForkJoinTask<?> t; ForkJoinTask<?>[] a; - if ((a = array) != null) { - int j = (((a.length - 1) & b) << ASHIFT) + ABASE; - if ((t = (ForkJoinTask<?>)U.getObjectVolatile(a, j)) != null && - base == b && U.compareAndSwapObject(a, j, t, null)) { - base = b + 1; - return t; - } - } - return null; - } - - /** - * Takes next task, if one exists, in FIFO order. - */ - final ForkJoinTask<?> poll() { - ForkJoinTask<?>[] a; int b; ForkJoinTask<?> t; - while ((b = base) - top < 0 && (a = array) != null) { - int j = (((a.length - 1) & b) << ASHIFT) + ABASE; - t = (ForkJoinTask<?>)U.getObjectVolatile(a, j); - if (t != null) { - if (U.compareAndSwapObject(a, j, t, null)) { - base = b + 1; - return t; - } - } - else if (base == b) { - if (b + 1 == top) - break; - Thread.yield(); // wait for lagging update (very rare) - } - } - return null; - } - - /** - * Takes next task, if one exists, in order specified by mode. - */ - final ForkJoinTask<?> nextLocalTask() { - return mode == 0 ? pop() : poll(); - } - - /** - * Returns next task, if one exists, in order specified by mode. - */ - final ForkJoinTask<?> peek() { - ForkJoinTask<?>[] a = array; int m; - if (a == null || (m = a.length - 1) < 0) - return null; - int i = mode == 0 ? top - 1 : base; - int j = ((i & m) << ASHIFT) + ABASE; - return (ForkJoinTask<?>)U.getObjectVolatile(a, j); - } - - /** - * Pops the given task only if it is at the current top. - * (A shared version is available only via FJP.tryExternalUnpush) - */ - final boolean tryUnpush(ForkJoinTask<?> t) { - ForkJoinTask<?>[] a; int s; - if ((a = array) != null && (s = top) != base && - U.compareAndSwapObject - (a, (((a.length - 1) & --s) << ASHIFT) + ABASE, t, null)) { - top = s; - return true; - } - return false; - } - - /** - * Removes and cancels all known tasks, ignoring any exceptions. - */ - final void cancelAll() { - ForkJoinTask.cancelIgnoringExceptions(currentJoin); - ForkJoinTask.cancelIgnoringExceptions(currentSteal); - for (ForkJoinTask<?> t; (t = poll()) != null; ) - ForkJoinTask.cancelIgnoringExceptions(t); - } - - // Specialized execution methods - - /** - * Polls and runs tasks until empty. - */ - final void pollAndExecAll() { - for (ForkJoinTask<?> t; (t = poll()) != null;) - t.doExec(); - } - - /** - * Executes a top-level task and any local tasks remaining - * after execution. - */ - final void runTask(ForkJoinTask<?> task) { - if ((currentSteal = task) != null) { - ForkJoinWorkerThread thread; - task.doExec(); - ForkJoinTask<?>[] a = array; - int md = mode; - ++nsteals; - currentSteal = null; - if (md != 0) - pollAndExecAll(); - else if (a != null) { - int s, m = a.length - 1; - ForkJoinTask<?> t; - while ((s = top - 1) - base >= 0 && - (t = (ForkJoinTask<?>)U.getAndSetObject - (a, ((m & s) << ASHIFT) + ABASE, null)) != null) { - top = s; - t.doExec(); - } - } - if ((thread = owner) != null) // no need to do in finally clause - thread.afterTopLevelExec(); - } - } - - /** - * If present, removes from queue and executes the given task, - * or any other cancelled task. Returns (true) on any CAS - * or consistency check failure so caller can retry. - * - * @return false if no progress can be made, else true - */ - final boolean tryRemoveAndExec(ForkJoinTask<?> task) { - boolean stat; - ForkJoinTask<?>[] a; int m, s, b, n; - if (task != null && (a = array) != null && (m = a.length - 1) >= 0 && - (n = (s = top) - (b = base)) > 0) { - boolean removed = false, empty = true; - stat = true; - for (ForkJoinTask<?> t;;) { // traverse from s to b - long j = ((--s & m) << ASHIFT) + ABASE; - t = (ForkJoinTask<?>)U.getObject(a, j); - if (t == null) // inconsistent length - break; - else if (t == task) { - if (s + 1 == top) { // pop - if (!U.compareAndSwapObject(a, j, task, null)) - break; - top = s; - removed = true; - } - else if (base == b) // replace with proxy - removed = U.compareAndSwapObject(a, j, task, - new EmptyTask()); - break; - } - else if (t.status >= 0) - empty = false; - else if (s + 1 == top) { // pop and throw away - if (U.compareAndSwapObject(a, j, t, null)) - top = s; - break; - } - if (--n == 0) { - if (!empty && base == b) - stat = false; - break; - } - } - if (removed) - task.doExec(); - } - else - stat = false; - return stat; - } - - /** - * Tries to poll for and execute the given task or any other - * task in its CountedCompleter computation. - */ - final boolean pollAndExecCC(CountedCompleter<?> root) { - ForkJoinTask<?>[] a; int b; Object o; CountedCompleter<?> t, r; - if ((b = base) - top < 0 && (a = array) != null) { - long j = (((a.length - 1) & b) << ASHIFT) + ABASE; - if ((o = U.getObjectVolatile(a, j)) == null) - return true; // retry - if (o instanceof CountedCompleter) { - for (t = (CountedCompleter<?>)o, r = t;;) { - if (r == root) { - if (base == b && - U.compareAndSwapObject(a, j, t, null)) { - base = b + 1; - t.doExec(); - } - return true; - } - else if ((r = r.completer) == null) - break; // not part of root computation - } - } - } - return false; - } - - /** - * Tries to pop and execute the given task or any other task - * in its CountedCompleter computation. - */ - final boolean externalPopAndExecCC(CountedCompleter<?> root) { - ForkJoinTask<?>[] a; int s; Object o; CountedCompleter<?> t, r; - if (base - (s = top) < 0 && (a = array) != null) { - long j = (((a.length - 1) & (s - 1)) << ASHIFT) + ABASE; - if ((o = U.getObject(a, j)) instanceof CountedCompleter) { - for (t = (CountedCompleter<?>)o, r = t;;) { - if (r == root) { - if (compareAndSwapIntQlock(0, 1)) { - if (top == s && array == a && - U.compareAndSwapObject(a, j, t, null)) { - top = s - 1; - qlock = 0; - t.doExec(); - } - else - qlock = 0; - } - return true; - } - else if ((r = r.completer) == null) - break; - } - } - } - return false; - } - - /** - * Internal version - */ - final boolean internalPopAndExecCC(CountedCompleter<?> root) { - ForkJoinTask<?>[] a; int s; Object o; CountedCompleter<?> t, r; - if (base - (s = top) < 0 && (a = array) != null) { - long j = (((a.length - 1) & (s - 1)) << ASHIFT) + ABASE; - if ((o = U.getObject(a, j)) instanceof CountedCompleter) { - for (t = (CountedCompleter<?>)o, r = t;;) { - if (r == root) { - if (U.compareAndSwapObject(a, j, t, null)) { - top = s - 1; - t.doExec(); - } - return true; - } - else if ((r = r.completer) == null) - break; - } - } - } - return false; - } - - /** - * Returns true if owned and not known to be blocked. - */ - final boolean isApparentlyUnblocked() { - Thread wt; Thread.State s; - return (eventCount >= 0 && - (wt = owner) != null && - (s = wt.getState()) != Thread.State.BLOCKED && - s != Thread.State.WAITING && - s != Thread.State.TIMED_WAITING); - } - - @ikvm.internal.InterlockedCompareAndSet("qlock") - final native boolean compareAndSwapIntQlock(int expect, int update); - - // Unsafe mechanics - private static final sun.misc.Unsafe U; - private static final int ABASE; - private static final int ASHIFT; - static { - try { - U = sun.misc.Unsafe.getUnsafe(); - Class<?> ak = ForkJoinTask[].class; - ABASE = U.arrayBaseOffset(ak); - int scale = U.arrayIndexScale(ak); - if ((scale & (scale - 1)) != 0) - throw new Error("data type scale not a power of two"); - ASHIFT = 31 - Integer.numberOfLeadingZeros(scale); - } catch (Exception e) { - throw new Error(e); - } - } - } - - // static fields (initialized in static initializer below) - - /** - * Creates a new ForkJoinWorkerThread. This factory is used unless - * overridden in ForkJoinPool constructors. - */ - public static final ForkJoinWorkerThreadFactory - defaultForkJoinWorkerThreadFactory; - - /** - * Permission required for callers of methods that may start or - * kill threads. - */ - private static final RuntimePermission modifyThreadPermission; - - /** - * Common (static) pool. Non-null for public use unless a static - * construction exception, but internal usages null-check on use - * to paranoically avoid potential initialization circularities - * as well as to simplify generated code. - */ - static final ForkJoinPool common; - - /** - * Common pool parallelism. To allow simpler use and management - * when common pool threads are disabled, we allow the underlying - * common.parallelism field to be zero, but in that case still report - * parallelism as 1 to reflect resulting caller-runs mechanics. - */ - static final int commonParallelism; - - /** - * Sequence number for creating workerNamePrefix. - */ - private static int poolNumberSequence; - - /** - * Returns the next sequence number. We don't expect this to - * ever contend, so use simple builtin sync. - */ - private static final synchronized int nextPoolId() { - return ++poolNumberSequence; - } - - // static constants - - /** - * Initial timeout value (in nanoseconds) for the thread - * triggering quiescence to park waiting for new work. On timeout, - * the thread will instead try to shrink the number of - * workers. The value should be large enough to avoid overly - * aggressive shrinkage during most transient stalls (long GCs - * etc). - */ - private static final long IDLE_TIMEOUT = 2000L * 1000L * 1000L; // 2sec - - /** - * Timeout value when there are more threads than parallelism level - */ - private static final long FAST_IDLE_TIMEOUT = 200L * 1000L * 1000L; - - /** - * Tolerance for idle timeouts, to cope with timer undershoots - */ - private static final long TIMEOUT_SLOP = 2000000L; - - /** - * The maximum stolen->joining link depth allowed in method - * tryHelpStealer. Must be a power of two. Depths for legitimate - * chains are unbounded, but we use a fixed constant to avoid - * (otherwise unchecked) cycles and to bound staleness of - * traversal parameters at the expense of sometimes blocking when - * we could be helping. - */ - private static final int MAX_HELP = 64; - - /** - * Increment for seed generators. See class ThreadLocal for - * explanation. - */ - private static final int SEED_INCREMENT = 0x9e3779b9; - - /* - * Bits and masks for control variables - * - * Field ctl is a long packed with: - * AC: Number of active running workers minus target parallelism (16 bits) - * TC: Number of total workers minus target parallelism (16 bits) - * ST: true if pool is terminating (1 bit) - * EC: the wait count of top waiting thread (15 bits) - * ID: poolIndex of top of Treiber stack of waiters (16 bits) - * - * When convenient, we can extract the upper 32 bits of counts and - * the lower 32 bits of queue state, u = (int)(ctl >>> 32) and e = - * (int)ctl. The ec field is never accessed alone, but always - * together with id and st. The offsets of counts by the target - * parallelism and the positionings of fields makes it possible to - * perform the most common checks via sign tests of fields: When - * ac is negative, there are not enough active workers, when tc is - * negative, there are not enough total workers, and when e is - * negative, the pool is terminating. To deal with these possibly - * negative fields, we use casts in and out of "short" and/or - * signed shifts to maintain signedness. - * - * When a thread is queued (inactivated), its eventCount field is - * set negative, which is the only way to tell if a worker is - * prevented from executing tasks, even though it must continue to - * scan for them to avoid queuing races. Note however that - * eventCount updates lag releases so usage requires care. - * - * Field plock is an int packed with: - * SHUTDOWN: true if shutdown is enabled (1 bit) - * SEQ: a sequence lock, with PL_LOCK bit set if locked (30 bits) - * SIGNAL: set when threads may be waiting on the lock (1 bit) - * - * The sequence number enables simple consistency checks: - * Staleness of read-only operations on the workQueues array can - * be checked by comparing plock before vs after the reads. - */ - - // bit positions/shifts for fields - private static final int AC_SHIFT = 48; - private static final int TC_SHIFT = 32; - private static final int ST_SHIFT = 31; - private static final int EC_SHIFT = 16; - - // bounds - private static final int SMASK = 0xffff; // short bits - private static final int MAX_CAP = 0x7fff; // max #workers - 1 - private static final int EVENMASK = 0xfffe; // even short bits - private static final int SQMASK = 0x007e; // max 64 (even) slots - private static final int SHORT_SIGN = 1 << 15; - private static final int INT_SIGN = 1 << 31; - - // masks - private static final long STOP_BIT = 0x0001L << ST_SHIFT; - private static final long AC_MASK = ((long)SMASK) << AC_SHIFT; - private static final long TC_MASK = ((long)SMASK) << TC_SHIFT; - - // units for incrementing and decrementing - private static final long TC_UNIT = 1L << TC_SHIFT; - private static final long AC_UNIT = 1L << AC_SHIFT; - - // masks and units for dealing with u = (int)(ctl >>> 32) - private static final int UAC_SHIFT = AC_SHIFT - 32; - private static final int UTC_SHIFT = TC_SHIFT - 32; - private static final int UAC_MASK = SMASK << UAC_SHIFT; - private static final int UTC_MASK = SMASK << UTC_SHIFT; - private static final int UAC_UNIT = 1 << UAC_SHIFT; - private static final int UTC_UNIT = 1 << UTC_SHIFT; - - // masks and units for dealing with e = (int)ctl - private static final int E_MASK = 0x7fffffff; // no STOP_BIT - private static final int E_SEQ = 1 << EC_SHIFT; - - // plock bits - private static final int SHUTDOWN = 1 << 31; - private static final int PL_LOCK = 2; - private static final int PL_SIGNAL = 1; - private static final int PL_SPINS = 1 << 8; - - // access mode for WorkQueue - static final int LIFO_QUEUE = 0; - static final int FIFO_QUEUE = 1; - static final int SHARED_QUEUE = -1; - - // Instance fields - volatile long stealCount; // collects worker counts - volatile long ctl; // main pool control - volatile int plock; // shutdown status and seqLock - volatile int indexSeed; // worker/submitter index seed - final short parallelism; // parallelism level - final short mode; // LIFO/FIFO - WorkQueue[] workQueues; // main registry - final ForkJoinWorkerThreadFactory factory; - final UncaughtExceptionHandler ueh; // per-worker UEH - final String workerNamePrefix; // to create worker name string - - /** - * Acquires the plock lock to protect worker array and related - * updates. This method is called only if an initial CAS on plock - * fails. This acts as a spinlock for normal cases, but falls back - * to builtin monitor to block when (rarely) needed. This would be - * a terrible idea for a highly contended lock, but works fine as - * a more conservative alternative to a pure spinlock. - */ - private int acquirePlock() { - int spins = PL_SPINS, ps, nps; - for (;;) { - if (((ps = plock) & PL_LOCK) == 0 && - compareAndSwapIntPlock(ps, nps = ps + PL_LOCK)) - return nps; - else if (spins >= 0) { - if (ThreadLocalRandom.nextSecondarySeed() >= 0) - --spins; - } - else if (compareAndSwapIntPlock(ps, ps | PL_SIGNAL)) { - synchronized (this) { - if ((plock & PL_SIGNAL) != 0) { - try { - wait(); - } catch (InterruptedException ie) { - try { - Thread.currentThread().interrupt(); - } catch (SecurityException ignore) { - } - } - } - else - notifyAll(); - } - } - } - } - - /** - * Unlocks and signals any thread waiting for plock. Called only - * when CAS of seq value for unlock fails. - */ - private void releasePlock(int ps) { - plock = ps; - synchronized (this) { notifyAll(); } - } - - /** - * Tries to create and start one worker if fewer than target - * parallelism level exist. Adjusts counts etc on failure. - */ - private void tryAddWorker() { - long c; int u, e; - while ((u = (int)((c = ctl) >>> 32)) < 0 && - (u & SHORT_SIGN) != 0 && (e = (int)c) >= 0) { - long nc = ((long)(((u + UTC_UNIT) & UTC_MASK) | - ((u + UAC_UNIT) & UAC_MASK)) << 32) | (long)e; - if (compareAndSwapLongCtl(c, nc)) { - ForkJoinWorkerThreadFactory fac; - Throwable ex = null; - ForkJoinWorkerThread wt = null; - try { - if ((fac = factory) != null && - (wt = fac.newThread(this)) != null) { - wt.start(); - break; - } - } catch (Throwable rex) { - ex = rex; - } - deregisterWorker(wt, ex); - break; - } - } - } - - // Registering and deregistering workers - - /** - * Callback from ForkJoinWorkerThread to establish and record its - * WorkQueue. To avoid scanning bias due to packing entries in - * front of the workQueues array, we treat the array as a simple - * power-of-two hash table using per-thread seed as hash, - * expanding as needed. - * - * @param wt the worker thread - * @return the worker's queue - */ - final WorkQueue registerWorker(ForkJoinWorkerThread wt) { - UncaughtExceptionHandler handler; WorkQueue[] ws; int s, ps; - wt.setDaemon(true); - if ((handler = ueh) != null) - wt.setUncaughtExceptionHandler(handler); - do {} while (!compareAndSwapIntIndexSeed(s = indexSeed, - s += SEED_INCREMENT) || - s == 0); // skip 0 - WorkQueue w = new WorkQueue(this, wt, mode, s); - if (((ps = plock) & PL_LOCK) != 0 || - !compareAndSwapIntPlock(ps, ps += PL_LOCK)) - ps = acquirePlock(); - int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN); - try { - if ((ws = workQueues) != null) { // skip if shutting down - int n = ws.length, m = n - 1; - int r = (s << 1) | 1; // use odd-numbered indices - if (ws[r &= m] != null) { // collision - int probes = 0; // step by approx half size - int step = (n <= 4) ? 2 : ((n >>> 1) & EVENMASK) + 2; - while (ws[r = (r + step) & m] != null) { - if (++probes >= n) { - workQueues = ws = Arrays.copyOf(ws, n <<= 1); - m = n - 1; - probes = 0; - } - } - } - w.poolIndex = (short)r; - w.eventCount = r; // volatile write orders - ws[r] = w; - } - } finally { - if (!compareAndSwapIntPlock(ps, nps)) - releasePlock(nps); - } - wt.setName(workerNamePrefix.concat(Integer.toString(w.poolIndex >>> 1))); - return w; - } - - /** - * Final callback from terminating worker, as well as upon failure - * to construct or start a worker. Removes record of worker from - * array, and adjusts counts. If pool is shutting down, tries to - * complete termination. - * - * @param wt the worker thread, or null if construction failed - * @param ex the exception causing failure, or null if none - */ - final void deregisterWorker(ForkJoinWorkerThread wt, Throwable ex) { - WorkQueue w = null; - if (wt != null && (w = wt.workQueue) != null) { - int ps; - w.qlock = -1; // ensure set - getAndAddLongStealCount(w.nsteals); // collect steals - if (((ps = plock) & PL_LOCK) != 0 || - !compareAndSwapIntPlock(ps, ps += PL_LOCK)) - ps = acquirePlock(); - int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN); - try { - int idx = w.poolIndex; - WorkQueue[] ws = workQueues; - if (ws != null && idx >= 0 && idx < ws.length && ws[idx] == w) - ws[idx] = null; - } finally { - if (!compareAndSwapIntPlock(ps, nps)) - releasePlock(nps); - } - } - - long c; // adjust ctl counts - do {} while (!compareAndSwapLongCtl - (c = ctl, (((c - AC_UNIT) & AC_MASK) | - ((c - TC_UNIT) & TC_MASK) | - (c & ~(AC_MASK|TC_MASK))))); - - if (!tryTerminate(false, false) && w != null && w.array != null) { - w.cancelAll(); // cancel remaining tasks - WorkQueue[] ws; WorkQueue v; Thread p; int u, i, e; - while ((u = (int)((c = ctl) >>> 32)) < 0 && (e = (int)c) >= 0) { - if (e > 0) { // activate or create replacement - if ((ws = workQueues) == null || - (i = e & SMASK) >= ws.length || - (v = ws[i]) == null) - break; - long nc = (((long)(v.nextWait & E_MASK)) | - ((long)(u + UAC_UNIT) << 32)); - if (v.eventCount != (e | INT_SIGN)) - break; - if (compareAndSwapLongCtl(c, nc)) { - v.eventCount = (e + E_SEQ) & E_MASK; - if ((p = v.parker) != null) - U.unpark(p); - break; - } - } - else { - if ((short)u < 0) - tryAddWorker(); - break; - } - } - } - if (ex == null) // help clean refs on way out - ForkJoinTask.helpExpungeStaleExceptions(); - else // rethrow - ForkJoinTask.rethrow(ex); - } - - // Submissions - - /** - * Unless shutting down, adds the given task to a submission queue - * at submitter's current queue index (modulo submission - * range). Only the most common path is directly handled in this - * method. All others are relayed to fullExternalPush. - * - * @param task the task. Caller must ensure non-null. - */ - final void externalPush(ForkJoinTask<?> task) { - WorkQueue q; int m, s, n, am; ForkJoinTask<?>[] a; - int r = ThreadLocalRandom.getProbe(); - int ps = plock; - WorkQueue[] ws = workQueues; - if (ps > 0 && ws != null && (m = (ws.length - 1)) >= 0 && - (q = ws[m & r & SQMASK]) != null && r != 0 && - q.compareAndSwapIntQlock(0, 1)) { // lock - if ((a = q.array) != null && - (am = a.length - 1) > (n = (s = q.top) - q.base)) { - int j = ((am & s) << ASHIFT) + ABASE; - U.putOrderedObject(a, j, task); - q.top = s + 1; // push on to deque - q.qlock = 0; - if (n <= 1) - signalWork(ws, q); - return; - } - q.qlock = 0; - } - fullExternalPush(task); - } - - /** - * Full version of externalPush. This method is called, among - * other times, upon the first submission of the first task to the - * pool, so must perform secondary initialization. It also - * detects first submission by an external thread by looking up - * its ThreadLocal, and creates a new shared queue if the one at - * index if empty or contended. The plock lock body must be - * exception-free (so no try/finally) so we optimistically - * allocate new queues outside the lock and throw them away if - * (very rarely) not needed. - * - * Secondary initialization occurs when plock is zero, to create - * workQueue array and set plock to a valid value. This lock body - * must also be exception-free. Because the plock seq value can - * eventually wrap around zero, this method harmlessly fails to - * reinitialize if workQueues exists, while still advancing plock. - */ - private void fullExternalPush(ForkJoinTask<?> task) { - int r; - if ((r = ThreadLocalRandom.getProbe()) == 0) { - ThreadLocalRandom.localInit(); - r = ThreadLocalRandom.getProbe(); - } - for (;;) { - WorkQueue[] ws; WorkQueue q; int ps, m, k; - boolean move = false; - if ((ps = plock) < 0) - throw new RejectedExecutionException(); - else if (ps == 0 || (ws = workQueues) == null || - (m = ws.length - 1) < 0) { // initialize workQueues - int p = parallelism; // find power of two table size - int n = (p > 1) ? p - 1 : 1; // ensure at least 2 slots - n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; - n |= n >>> 8; n |= n >>> 16; n = (n + 1) << 1; - WorkQueue[] nws = ((ws = workQueues) == null || ws.length == 0 ? - new WorkQueue[n] : null); - if (((ps = plock) & PL_LOCK) != 0 || - !compareAndSwapIntPlock(ps, ps += PL_LOCK)) - ps = acquirePlock(); - if (((ws = workQueues) == null || ws.length == 0) && nws != null) - workQueues = nws; - int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN); - if (!compareAndSwapIntPlock(ps, nps)) - releasePlock(nps); - } - else if ((q = ws[k = r & m & SQMASK]) != null) { - if (q.qlock == 0 && q.compareAndSwapIntQlock(0, 1)) { - ForkJoinTask<?>[] a = q.array; - int s = q.top; - boolean submitted = false; - try { // locked version of push - if ((a != null && a.length > s + 1 - q.base) || - (a = q.growArray()) != null) { // must presize - int j = (((a.length - 1) & s) << ASHIFT) + ABASE; - U.putOrderedObject(a, j, task); - q.top = s + 1; - submitted = true; - } - } finally { - q.qlock = 0; // unlock - } - if (submitted) { - signalWork(ws, q); - return; - } - } - move = true; // move on failure - } - else if (((ps = plock) & PL_LOCK) == 0) { // create new queue - q = new WorkQueue(this, null, SHARED_QUEUE, r); - q.poolIndex = (short)k; - if (((ps = plock) & PL_LOCK) != 0 || - !compareAndSwapIntPlock(ps, ps += PL_LOCK)) - ps = acquirePlock(); - if ((ws = workQueues) != null && k < ws.length && ws[k] == null) - ws[k] = q; - int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN); - if (!compareAndSwapIntPlock(ps, nps)) - releasePlock(nps); - } - else - move = true; // move if busy - if (move) - r = ThreadLocalRandom.advanceProbe(r); - } - } - - // Maintaining ctl counts - - /** - * Increments active count; mainly called upon return from blocking. - */ - final void incrementActiveCount() { - long c; - do {} while (!compareAndSwapLongCtl - (c = ctl, ((c & ~AC_MASK) | - ((c & AC_MASK) + AC_UNIT)))); - } - - /** - * Tries to create or activate a worker if too few are active. - * - * @param ws the worker array to use to find signallees - * @param q if non-null, the queue holding tasks to be processed - */ - final void signalWork(WorkQueue[] ws, WorkQueue q) { - for (;;) { - long c; int e, u, i; WorkQueue w; Thread p; - if ((u = (int)((c = ctl) >>> 32)) >= 0) - break; - if ((e = (int)c) <= 0) { - if ((short)u < 0) - tryAddWorker(); - break; - } - if (ws == null || ws.length <= (i = e & SMASK) || - (w = ws[i]) == null) - break; - long nc = (((long)(w.nextWait & E_MASK)) | - ((long)(u + UAC_UNIT)) << 32); - int ne = (e + E_SEQ) & E_MASK; - if (w.eventCount == (e | INT_SIGN) && - compareAndSwapLongCtl(c, nc)) { - w.eventCount = ne; - if ((p = w.parker) != null) - U.unpark(p); - break; - } - if (q != null && q.base >= q.top) - break; - } - } - - // Scanning for tasks - - /** - * Top-level runloop for workers, called by ForkJoinWorkerThread.run. - */ - final void runWorker(WorkQueue w) { - w.growArray(); // allocate queue - for (int r = w.hint; scan(w, r) == 0; ) { - r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift - } - } - - /** - * Scans for and, if found, runs one task, else possibly - * inactivates the worker. This method operates on single reads of - * volatile state and is designed to be re-invoked continuously, - * in part because it returns upon detecting inconsistencies, - * contention, or state changes that indicate possible success on - * re-invocation. - * - * The scan searches for tasks across queues starting at a random - * index, checking each at least twice. The scan terminates upon - * either finding a non-empty queue, or completing the sweep. If - * the worker is not inactivated, it takes and runs a task from - * this queue. Otherwise, if not activated, it tries to activate - * itself or some other worker by signalling. On failure to find a - * task, returns (for retry) if pool state may have changed during - * an empty scan, or tries to inactivate if active, else possibly - * blocks or terminates via method awaitWork. - * - * @param w the worker (via its WorkQueue) - * @param r a random seed - * @return worker qlock status if would have waited, else 0 - */ - private final int scan(WorkQueue w, int r) { - WorkQueue[] ws; int m; - long c = ctl; // for consistency check - if ((ws = workQueues) != null && (m = ws.length - 1) >= 0 && w != null) { - for (int j = m + m + 1, ec = w.eventCount;;) { - WorkQueue q; int b, e; ForkJoinTask<?>[] a; ForkJoinTask<?> t; - if ((q = ws[(r - j) & m]) != null && - (b = q.base) - q.top < 0 && (a = q.array) != null) { - long i = (((a.length - 1) & b) << ASHIFT) + ABASE; - if ((t = ((ForkJoinTask<?>) - U.getObjectVolatile(a, i))) != null) { - if (ec < 0) - helpRelease(c, ws, w, q, b); - else if (q.base == b && - U.compareAndSwapObject(a, i, t, null)) { - q.base = b + 1; - if ((b + 1) - q.top < 0) - signalWork(ws, q); - w.runTask(t); - } - } - break; - } - else if (--j < 0) { - if ((ec | (e = (int)c)) < 0) // inactive or terminating - return awaitWork(w, c, ec); - else if (ctl == c) { // try to inactivate and enqueue - long nc = (long)ec | ((c - AC_UNIT) & (AC_MASK|TC_MASK)); - w.nextWait = e; - w.eventCount = ec | INT_SIGN; - if (!compareAndSwapLongCtl(c, nc)) - w.eventCount = ec; // back out - } - break; - } - } - } - return 0; - } - - /** - * A continuation of scan(), possibly blocking or terminating - * worker w. Returns without blocking if pool state has apparently - * changed since last invocation. Also, if inactivating w has - * caused the pool to become quiescent, checks for pool - * termination, and, so long as this is not the only worker, waits - * for event for up to a given duration. On timeout, if ctl has - * not changed, terminates the worker, which will in turn wake up - * another worker to possibly repeat this process. - * - * @param w the calling worker - * @param c the ctl value on entry to scan - * @param ec the worker's eventCount on entry to scan - */ - private final int awaitWork(WorkQueue w, long c, int ec) { - int stat, ns; long parkTime, deadline; - if ((stat = w.qlock) >= 0 && w.eventCount == ec && ctl == c && - !Thread.interrupted()) { - int e = (int)c; - int u = (int)(c >>> 32); - int d = (u >> UAC_SHIFT) + parallelism; // active count - - if (e < 0 || (d <= 0 && tryTerminate(false, false))) - stat = w.qlock = -1; // pool is terminating - else if ((ns = w.nsteals) != 0) { // collect steals and retry - w.nsteals = 0; - getAndAddLongStealCount((long)ns); - } - else { - long pc = ((d > 0 || ec != (e | INT_SIGN)) ? 0L : - ((long)(w.nextWait & E_MASK)) | // ctl to restore - ((long)(u + UAC_UNIT)) << 32); - if (pc != 0L) { // timed wait if last waiter - int dc = -(short)(c >>> TC_SHIFT); - parkTime = (dc < 0 ? FAST_IDLE_TIMEOUT: - (dc + 1) * IDLE_TIMEOUT); - deadline = System.nanoTime() + parkTime - TIMEOUT_SLOP; - } - else - parkTime = deadline = 0L; - if (w.eventCount == ec && ctl == c) { - Thread wt = Thread.currentThread(); - wt.parkBlocker = this; - w.parker = wt; // emulate LockSupport.park - if (w.eventCount == ec && ctl == c) - U.park(false, parkTime); // must recheck before park - w.parker = null; - wt.parkBlocker = null; - if (parkTime != 0L && ctl == c && - deadline - System.nanoTime() <= 0L && - compareAndSwapLongCtl(c, pc)) - stat = w.qlock = -1; // shrink pool - } - } - } - return stat; - } - - /** - * Possibly releases (signals) a worker. Called only from scan() - * when a worker with apparently inactive status finds a non-empty - * queue. This requires revalidating all of the associated state - * from caller. - */ - private final void helpRelease(long c, WorkQueue[] ws, WorkQueue w, - WorkQueue q, int b) { - WorkQueue v; int e, i; Thread p; - if (w != null && w.eventCount < 0 && (e = (int)c) > 0 && - ws != null && ws.length > (i = e & SMASK) && - (v = ws[i]) != null && ctl == c) { - long nc = (((long)(v.nextWait & E_MASK)) | - ((long)((int)(c >>> 32) + UAC_UNIT)) << 32); - int ne = (e + E_SEQ) & E_MASK; - if (q != null && q.base == b && w.eventCount < 0 && - v.eventCount == (e | INT_SIGN) && - compareAndSwapLongCtl(c, nc)) { - v.eventCount = ne; - if ((p = v.parker) != null) - U.unpark(p); - } - } - } - - /** - * Tries to locate and execute tasks for a stealer of the given - * task, or in turn one of its stealers, Traces currentSteal -> - * currentJoin links looking for a thread working on a descendant - * of the given task and with a non-empty queue to steal back and - * execute tasks from. The first call to this method upon a - * waiting join will often entail scanning/search, (which is OK - * because the joiner has nothing better to do), but this method - * leaves hints in workers to speed up subsequent calls. The - * implementation is very branchy to cope with potential - * inconsistencies or loops encountering chains that are stale, - * unknown, or so long that they are likely cyclic. - * - * @param joiner the joining worker - * @param task the task to join - * @return 0 if no progress can be made, negative if task - * known complete, else positive - */ - private int tryHelpStealer(WorkQueue joiner, ForkJoinTask<?> task) { - int stat = 0, steps = 0; // bound to avoid cycles - if (task != null && joiner != null && - joiner.base - joiner.top >= 0) { // hoist checks - restart: for (;;) { - ForkJoinTask<?> subtask = task; // current target - for (WorkQueue j = joiner, v;;) { // v is stealer of subtask - WorkQueue[] ws; int m, s, h; - if ((s = task.status) < 0) { - stat = s; - break restart; - } - if ((ws = workQueues) == null || (m = ws.length - 1) <= 0) - break restart; // shutting down - if ((v = ws[h = (j.hint | 1) & m]) == null || - v.currentSteal != subtask) { - for (int origin = h;;) { // find stealer - if (((h = (h + 2) & m) & 15) == 1 && - (subtask.status < 0 || j.currentJoin != subtask)) - continue restart; // occasional staleness check - if ((v = ws[h]) != null && - v.currentSteal == subtask) { - j.hint = h; // save hint - break; - } - if (h == origin) - break restart; // cannot find stealer - } - } - for (;;) { // help stealer or descend to its stealer - ForkJoinTask<?>[] a; int b; - if (subtask.status < 0) // surround probes with - continue restart; // consistency checks - if ((b = v.base) - v.top < 0 && (a = v.array) != null) { - int i = (((a.length - 1) & b) << ASHIFT) + ABASE; - ForkJoinTask<?> t = - (ForkJoinTask<?>)U.getObjectVolatile(a, i); - if (subtask.status < 0 || j.currentJoin != subtask || - v.currentSteal != subtask) - continue restart; // stale - stat = 1; // apparent progress - if (v.base == b) { - if (t == null) - break restart; - if (U.compareAndSwapObject(a, i, t, null)) { - v.base = b + 1; - ForkJoinTask<?> ps = joiner.currentSteal; - int jt = joiner.top; - do { - joiner.currentSteal = t; - t.doExec(); // clear local tasks too - } while (task.status >= 0 && - joiner.top != jt && - (t = joiner.pop()) != null); - joiner.currentSteal = ps; - break restart; - } - } - } - else { // empty -- try to descend - ForkJoinTask<?> next = v.currentJoin; - if (subtask.status < 0 || j.currentJoin != subtask || - v.currentSteal != subtask) - continue restart; // stale - else if (next == null || ++steps == MAX_HELP) - break restart; // dead-end or maybe cyclic - else { - subtask = next; - j = v; - break; - } - } - } - } - } - } - return stat; - } - - /** - * Analog of tryHelpStealer for CountedCompleters. Tries to steal - * and run tasks within the target's computation. - * - * @param task the task to join - * @param maxTasks the maximum number of other tasks to run - */ - final int helpComplete(WorkQueue joiner, CountedCompleter<?> task, - int maxTasks) { - WorkQueue[] ws; int m; - int s = 0; - if ((ws = workQueues) != null && (m = ws.length - 1) >= 0 && - joiner != null && task != null) { - int j = joiner.poolIndex; - int scans = m + m + 1; - long c = 0L; // for stability check - for (int k = scans; ; j += 2) { - WorkQueue q; - if ((s = task.status) < 0) - break; - else if (joiner.internalPopAndExecCC(task)) { - if (--maxTasks <= 0) { - s = task.status; - break; - } - k = scans; - } - else if ((s = task.status) < 0) - break; - else if ((q = ws[j & m]) != null && q.pollAndExecCC(task)) { - if (--maxTasks <= 0) { - s = task.status; - break; - } - k = scans; - } - else if (--k < 0) { - if (c == (c = ctl)) - break; - k = scans; - } - } - } - return s; - } - - /** - * Tries to decrement active count (sometimes implicitly) and - * possibly release or create a compensating worker in preparation - * for blocking. Fails on contention or termination. Otherwise, - * adds a new thread if no idle workers are available and pool - * may become starved. - * - * @param c the assumed ctl value - */ - final boolean tryCompensate(long c) { - WorkQueue[] ws = workQueues; - int pc = parallelism, e = (int)c, m, tc; - if (ws != null && (m = ws.length - 1) >= 0 && e >= 0 && ctl == c) { - WorkQueue w = ws[e & m]; - if (e != 0 && w != null) { - Thread p; - long nc = ((long)(w.nextWait & E_MASK) | - (c & (AC_MASK|TC_MASK))); - int ne = (e + E_SEQ) & E_MASK; - if (w.eventCount == (e | INT_SIGN) && - compareAndSwapLongCtl(c, nc)) { - w.eventCount = ne; - if ((p = w.parker) != null) - U.unpark(p); - return true; // replace with idle worker - } - } - else if ((tc = (short)(c >>> TC_SHIFT)) >= 0 && - (int)(c >> AC_SHIFT) + pc > 1) { - long nc = ((c - AC_UNIT) & AC_MASK) | (c & ~AC_MASK); - if (compareAndSwapLongCtl(c, nc)) - return true; // no compensation - } - else if (tc + pc < MAX_CAP) { - long nc = ((c + TC_UNIT) & TC_MASK) | (c & ~TC_MASK); - if (compareAndSwapLongCtl(c, nc)) { - ForkJoinWorkerThreadFactory fac; - Throwable ex = null; - ForkJoinWorkerThread wt = null; - try { - if ((fac = factory) != null && - (wt = fac.newThread(this)) != null) { - wt.start(); - return true; - } - } catch (Throwable rex) { - ex = rex; - } - deregisterWorker(wt, ex); // clean up and return false - } - } - } - return false; - } - - /** - * Helps and/or blocks until the given task is done. - * - * @param joiner the joining worker - * @param task the task - * @return task status on exit - */ - final int awaitJoin(WorkQueue joiner, ForkJoinTask<?> task) { - int s = 0; - if (task != null && (s = task.status) >= 0 && joiner != null) { - ForkJoinTask<?> prevJoin = joiner.currentJoin; - joiner.currentJoin = task; - do {} while (joiner.tryRemoveAndExec(task) && // process local tasks - (s = task.status) >= 0); - if (s >= 0 && (task instanceof CountedCompleter)) - s = helpComplete(joiner, (CountedCompleter<?>)task, Integer.MAX_VALUE); - long cc = 0; // for stability checks - while (s >= 0 && (s = task.status) >= 0) { - if ((s = tryHelpStealer(joiner, task)) == 0 && - (s = task.status) >= 0) { - if (!tryCompensate(cc)) - cc = ctl; - else { - if (task.trySetSignal() && (s = task.status) >= 0) { - synchronized (task) { - if (task.status >= 0) { - try { // see ForkJoinTask - task.wait(); // for explanation - } catch (InterruptedException ie) { - } - } - else - task.notifyAll(); - } - } - long c; // reactivate - do {} while (!compareAndSwapLongCtl - (c = ctl, - ((c & ~AC_MASK) | - ((c & AC_MASK) + AC_UNIT)))); - } - } - } - joiner.currentJoin = prevJoin; - } - return s; - } - - /** - * Stripped-down variant of awaitJoin used by timed joins. Tries - * to help join only while there is continuous progress. (Caller - * will then enter a timed wait.) - * - * @param joiner the joining worker - * @param task the task - */ - final void helpJoinOnce(WorkQueue joiner, ForkJoinTask<?> task) { - int s; - if (joiner != null && task != null && (s = task.status) >= 0) { - ForkJoinTask<?> prevJoin = joiner.currentJoin; - joiner.currentJoin = task; - do {} while (joiner.tryRemoveAndExec(task) && // process local tasks - (s = task.status) >= 0); - if (s >= 0) { - if (task instanceof CountedCompleter) - helpComplete(joiner, (CountedCompleter<?>)task, Integer.MAX_VALUE); - do {} while (task.status >= 0 && - tryHelpStealer(joiner, task) > 0); - } - joiner.currentJoin = prevJoin; - } - } - - /** - * Returns a (probably) non-empty steal queue, if one is found - * during a scan, else null. This method must be retried by - * caller if, by the time it tries to use the queue, it is empty. - */ - private WorkQueue findNonEmptyStealQueue() { - int r = ThreadLocalRandom.nextSecondarySeed(); - for (;;) { - int ps = plock, m; WorkQueue[] ws; WorkQueue q; - if ((ws = workQueues) != null && (m = ws.length - 1) >= 0) { - for (int j = (m + 1) << 2; j >= 0; --j) { - if ((q = ws[(((r - j) << 1) | 1) & m]) != null && - q.base - q.top < 0) - return q; - } - } - if (plock == ps) - return null; - } - } - - /** - * Runs tasks until {@code isQuiescent()}. We piggyback on - * active count ctl maintenance, but rather than blocking - * when tasks cannot be found, we rescan until all others cannot - * find tasks either. - */ - final void helpQuiescePool(WorkQueue w) { - ForkJoinTask<?> ps = w.currentSteal; - for (boolean active = true;;) { - long c; WorkQueue q; ForkJoinTask<?> t; int b; - while ((t = w.nextLocalTask()) != null) - t.doExec(); - if ((q = findNonEmptyStealQueue()) != null) { - if (!active) { // re-establish active count - active = true; - do {} while (!compareAndSwapLongCtl - (c = ctl, - ((c & ~AC_MASK) | - ((c & AC_MASK) + AC_UNIT)))); - } - if ((b = q.base) - q.top < 0 && (t = q.pollAt(b)) != null) - w.runTask(t); - } - else if (active) { // decrement active count without queuing - long nc = ((c = ctl) & ~AC_MASK) | ((c & AC_MASK) - AC_UNIT); - if ((int)(nc >> AC_SHIFT) + parallelism == 0) - break; // bypass decrement-then-increment - if (compareAndSwapLongCtl(c, nc)) - active = false; - } - else if ((int)((c = ctl) >> AC_SHIFT) + parallelism <= 0 && - compareAndSwapLongCtl - (c, ((c & ~AC_MASK) | - ((c & AC_MASK) + AC_UNIT)))) - break; - } - } - - /** - * Gets and removes a local or stolen task for the given worker. - * - * @return a task, if available - */ - final ForkJoinTask<?> nextTaskFor(WorkQueue w) { - for (ForkJoinTask<?> t;;) { - WorkQueue q; int b; - if ((t = w.nextLocalTask()) != null) - return t; - if ((q = findNonEmptyStealQueue()) == null) - return null; - if ((b = q.base) - q.top < 0 && (t = q.pollAt(b)) != null) - return t; - } - } - - /** - * Returns a cheap heuristic guide for task partitioning when - * programmers, frameworks, tools, or languages have little or no - * idea about task granularity. In essence by offering this - * method, we ask users only about tradeoffs in overhead vs - * expected throughput and its variance, rather than how finely to - * partition tasks. - * - * In a steady state strict (tree-structured) computation, each - * thread makes available for stealing enough tasks for other - * threads to remain active. Inductively, if all threads play by - * the same rules, each thread should make available only a - * constant number of tasks. - * - * The minimum useful constant is just 1. But using a value of 1 - * would require immediate replenishment upon each steal to - * maintain enough tasks, which is infeasible. Further, - * partitionings/granularities of offered tasks should minimize - * steal rates, which in general means that threads nearer the top - * of computation tree should generate more than those nearer the - * bottom. In perfect steady state, each thread is at - * approximately the same level of computation tree. However, - * producing extra tasks amortizes the uncertainty of progress and - * diffusion assumptions. - * - * So, users will want to use values larger (but not much larger) - * than 1 to both smooth over transient shortages and hedge - * against uneven progress; as traded off against the cost of - * extra task overhead. We leave the user to pick a threshold - * value to compare with the results of this call to guide - * decisions, but recommend values such as 3. - * - * When all threads are active, it is on average OK to estimate - * surplus strictly locally. In steady-state, if one thread is - * maintaining say 2 surplus tasks, then so are others. So we can - * just use estimated queue length. However, this strategy alone - * leads to serious mis-estimates in some non-steady-state - * conditions (ramp-up, ramp-down, other stalls). We can detect - * many of these by further considering the number of "idle" - * threads, that are known to have zero queued tasks, so - * compensate by a factor of (#idle/#active) threads. - * - * Note: The approximation of #busy workers as #active workers is - * not very good under current signalling scheme, and should be - * improved. - */ - static int getSurplusQueuedTaskCount() { - Thread t; ForkJoinWorkerThread wt; ForkJoinPool pool; WorkQueue q; - if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)) { - int p = (pool = (wt = (ForkJoinWorkerThread)t).pool).parallelism; - int n = (q = wt.workQueue).top - q.base; - int a = (int)(pool.ctl >> AC_SHIFT) + p; - return n - (a > (p >>>= 1) ? 0 : - a > (p >>>= 1) ? 1 : - a > (p >>>= 1) ? 2 : - a > (p >>>= 1) ? 4 : - 8); - } - return 0; - } - - // Termination - - /** - * Possibly initiates and/or completes termination. The caller - * triggering termination runs three passes through workQueues: - * (0) Setting termination status, followed by wakeups of queued - * workers; (1) cancelling all tasks; (2) interrupting lagging - * threads (likely in external tasks, but possibly also blocked in - * joins). Each pass repeats previous steps because of potential - * lagging thread creation. - * - * @param now if true, unconditionally terminate, else only - * if no work and no active workers - * @param enable if true, enable shutdown when next possible - * @return true if now terminating or terminated - */ - private boolean tryTerminate(boolean now, boolean enable) { - int ps; - if (this == common) // cannot shut down - return false; - if ((ps = plock) >= 0) { // enable by setting plock - if (!enable) - return false; - if ((ps & PL_LOCK) != 0 || - !compareAndSwapIntPlock(ps, ps += PL_LOCK)) - ps = acquirePlock(); - int nps = ((ps + PL_LOCK) & ~SHUTDOWN) | SHUTDOWN; - if (!compareAndSwapIntPlock(ps, nps)) - releasePlock(nps); - } - for (long c;;) { - if (((c = ctl) & STOP_BIT) != 0) { // already terminating - if ((short)(c >>> TC_SHIFT) + parallelism <= 0) { - synchronized (this) { - notifyAll(); // signal when 0 workers - } - } - return true; - } - if (!now) { // check if idle & no tasks - WorkQueue[] ws; WorkQueue w; - if ((int)(c >> AC_SHIFT) + parallelism > 0) - return false; - if ((ws = workQueues) != null) { - for (int i = 0; i < ws.length; ++i) { - if ((w = ws[i]) != null && - (!w.isEmpty() || - ((i & 1) != 0 && w.eventCount >= 0))) { - signalWork(ws, w); - return false; - } - } - } - } - if (compareAndSwapLongCtl(c, c | STOP_BIT)) { - for (int pass = 0; pass < 3; ++pass) { - WorkQueue[] ws; WorkQueue w; Thread wt; - if ((ws = workQueues) != null) { - int n = ws.length; - for (int i = 0; i < n; ++i) { - if ((w = ws[i]) != null) { - w.qlock = -1; - if (pass > 0) { - w.cancelAll(); - if (pass > 1 && (wt = w.owner) != null) { - if (!wt.isInterrupted()) { - try { - wt.interrupt(); - } catch (Throwable ignore) { - } - } - U.unpark(wt); - } - } - } - } - // Wake up workers parked on event queue - int i, e; long cc; Thread p; - while ((e = (int)(cc = ctl) & E_MASK) != 0 && - (i = e & SMASK) < n && i >= 0 && - (w = ws[i]) != null) { - long nc = ((long)(w.nextWait & E_MASK) | - ((cc + AC_UNIT) & AC_MASK) | - (cc & (TC_MASK|STOP_BIT))); - if (w.eventCount == (e | INT_SIGN) && - compareAndSwapLongCtl(cc, nc)) { - w.eventCount = (e + E_SEQ) & E_MASK; - w.qlock = -1; - if ((p = w.parker) != null) - U.unpark(p); - } - } - } - } - } - } - } - - // external operations on common pool - - /** - * Returns common pool queue for a thread that has submitted at - * least one task. - */ - static WorkQueue commonSubmitterQueue() { - ForkJoinPool p; WorkQueue[] ws; int m, z; - return ((z = ThreadLocalRandom.getProbe()) != 0 && - (p = common) != null && - (ws = p.workQueues) != null && - (m = ws.length - 1) >= 0) ? - ws[m & z & SQMASK] : null; - } - - /** - * Tries to pop the given task from submitter's queue in common pool. - */ - final boolean tryExternalUnpush(ForkJoinTask<?> task) { - WorkQueue joiner; ForkJoinTask<?>[] a; int m, s; - WorkQueue[] ws = workQueues; - int z = ThreadLocalRandom.getProbe(); - boolean popped = false; - if (ws != null && (m = ws.length - 1) >= 0 && - (joiner = ws[z & m & SQMASK]) != null && - joiner.base != (s = joiner.top) && - (a = joiner.array) != null) { - long j = (((a.length - 1) & (s - 1)) << ASHIFT) + ABASE; - if (U.getObject(a, j) == task && - joiner.compareAndSwapIntQlock(0, 1)) { - if (joiner.top == s && joiner.array == a && - U.compareAndSwapObject(a, j, task, null)) { - joiner.top = s - 1; - popped = true; - } - joiner.qlock = 0; - } - } - return popped; - } - - final int externalHelpComplete(CountedCompleter<?> task, int maxTasks) { - WorkQueue joiner; int m; - WorkQueue[] ws = workQueues; - int j = ThreadLocalRandom.getProbe(); - int s = 0; - if (ws != null && (m = ws.length - 1) >= 0 && - (joiner = ws[j & m & SQMASK]) != null && task != null) { - int scans = m + m + 1; - long c = 0L; // for stability check - j |= 1; // poll odd queues - for (int k = scans; ; j += 2) { - WorkQueue q; - if ((s = task.status) < 0) - break; - else if (joiner.externalPopAndExecCC(task)) { - if (--maxTasks <= 0) { - s = task.status; - break; - } - k = scans; - } - else if ((s = task.status) < 0) - break; - else if ((q = ws[j & m]) != null && q.pollAndExecCC(task)) { - if (--maxTasks <= 0) { - s = task.status; - break; - } - k = scans; - } - else if (--k < 0) { - if (c == (c = ctl)) - break; - k = scans; - } - } - } - return s; - } - - // Exported methods - - // Constructors - - /** - * Creates a {@code ForkJoinPool} with parallelism equal to {@link - * java.lang.Runtime#availableProcessors}, using the {@linkplain - * #defaultForkJoinWorkerThreadFactory default thread factory}, - * no UncaughtExceptionHandler, and non-async LIFO processing mode. - * - * @throws SecurityException if a security manager exists and - * the caller is not permitted to modify threads - * because it does not hold {@link - * java.lang.RuntimePermission}{@code ("modifyThread")} - */ - public ForkJoinPool() { - this(Math.min(MAX_CAP, Runtime.getRuntime().availableProcessors()), - defaultForkJoinWorkerThreadFactory, null, false); - } - - /** - * Creates a {@code ForkJoinPool} with the indicated parallelism - * level, the {@linkplain - * #defaultForkJoinWorkerThreadFactory default thread factory}, - * no UncaughtExceptionHandler, and non-async LIFO processing mode. - * - * @param parallelism the parallelism level - * @throws IllegalArgumentException if parallelism less than or - * equal to zero, or greater than implementation limit - * @throws SecurityException if a security manager exists and - * the caller is not permitted to modify threads - * because it does not hold {@link - * java.lang.RuntimePermission}{@code ("modifyThread")} - */ - public ForkJoinPool(int parallelism) { - this(parallelism, defaultForkJoinWorkerThreadFactory, null, false); - } - - /** - * Creates a {@code ForkJoinPool} with the given parameters. - * - * @param parallelism the parallelism level. For default value, - * use {@link java.lang.Runtime#availableProcessors}. - * @param factory the factory for creating new threads. For default value, - * use {@link #defaultForkJoinWorkerThreadFactory}. - * @param handler the handler for internal worker threads that - * terminate due to unrecoverable errors encountered while executing - * tasks. For default value, use {@code null}. - * @param asyncMode if true, - * establishes local first-in-first-out scheduling mode for forked - * tasks that are never joined. This mode may be more appropriate - * than default locally stack-based mode in applications in which - * worker threads only process event-style asynchronous tasks. - * For default value, use {@code false}. - * @throws IllegalArgumentException if parallelism less than or - * equal to zero, or greater than implementation limit - * @throws NullPointerException if the factory is null - * @throws SecurityException if a security manager exists and - * the caller is not permitted to modify threads - * because it does not hold {@link - * java.lang.RuntimePermission}{@code ("modifyThread")} - */ - public ForkJoinPool(int parallelism, - ForkJoinWorkerThreadFactory factory, - UncaughtExceptionHandler handler, - boolean asyncMode) { - this(checkParallelism(parallelism), - checkFactory(factory), - handler, - (asyncMode ? FIFO_QUEUE : LIFO_QUEUE), - "ForkJoinPool-" + nextPoolId() + "-worker-"); - checkPermission(); - } - - private static int checkParallelism(int parallelism) { - if (parallelism <= 0 || parallelism > MAX_CAP) - throw new IllegalArgumentException(); - return parallelism; - } - - private static ForkJoinWorkerThreadFactory checkFactory - (ForkJoinWorkerThreadFactory factory) { - if (factory == null) - throw new NullPointerException(); - return factory; - } - - /** - * Creates a {@code ForkJoinPool} with the given parameters, without - * any security checks or parameter validation. Invoked directly by - * makeCommonPool. - */ - private ForkJoinPool(int parallelism, - ForkJoinWorkerThreadFactory factory, - UncaughtExceptionHandler handler, - int mode, - String workerNamePrefix) { - this.workerNamePrefix = workerNamePrefix; - this.factory = factory; - this.ueh = handler; - this.mode = (short)mode; - this.parallelism = (short)parallelism; - long np = (long)(-parallelism); // offset ctl counts - this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK); - } - - /** - * Returns the common pool instance. This pool is statically - * constructed; its run state is unaffected by attempts to {@link - * #shutdown} or {@link #shutdownNow}. However this pool and any - * ongoing processing are automatically terminated upon program - * {@link System#exit}. Any program that relies on asynchronous - * task processing to complete before program termination should - * invoke {@code commonPool().}{@link #awaitQuiescence awaitQuiescence}, - * before exit. - * - * @return the common pool instance - * @since 1.8 - */ - public static ForkJoinPool commonPool() { - // assert common != null : "static init error"; - return common; - } - - // Execution methods - - /** - * Performs the given task, returning its result upon completion. - * If the computation encounters an unchecked Exception or Error, - * it is rethrown as the outcome of this invocation. Rethrown - * exceptions behave in the same way as regular exceptions, but, - * when possible, contain stack traces (as displayed for example - * using {@code ex.printStackTrace()}) of both the current thread - * as well as the thread actually encountering the exception; - * minimally only the latter. - * - * @param task the task - * @param <T> the type of the task's result - * @return the task's result - * @throws NullPointerException if the task is null - * @throws RejectedExecutionException if the task cannot be - * scheduled for execution - */ - public <T> T invoke(ForkJoinTask<T> task) { - if (task == null) - throw new NullPointerException(); - externalPush(task); - return task.join(); - } - - /** - * Arranges for (asynchronous) execution of the given task. - * - * @param task the task - * @throws NullPointerException if the task is null - * @throws RejectedExecutionException if the task cannot be - * scheduled for execution - */ - public void execute(ForkJoinTask<?> task) { - if (task == null) - throw new NullPointerException(); - externalPush(task); - } - - // AbstractExecutorService methods - - /** - * @throws NullPointerException if the task is null - * @throws RejectedExecutionException if the task cannot be - * scheduled for execution - */ - public void execute(Runnable task) { - if (task == null) - throw new NullPointerException(); - ForkJoinTask<?> job; - if (task instanceof ForkJoinTask<?>) // avoid re-wrap - job = (ForkJoinTask<?>) task; - else - job = new ForkJoinTask.RunnableExecuteAction(task); - externalPush(job); - } - - /** - * Submits a ForkJoinTask for execution. - * - * @param task the task to submit - * @param <T> the type of the task's result - * @return the task - * @throws NullPointerException if the task is null - * @throws RejectedExecutionException if the task cannot be - * scheduled for execution - */ - public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task) { - if (task == null) - throw new NullPointerException(); - externalPush(task); - return task; - } - - /** - * @throws NullPointerException if the task is null - * @throws RejectedExecutionException if the task cannot be - * scheduled for execution - */ - public <T> ForkJoinTask<T> submit(Callable<T> task) { - ForkJoinTask<T> job = new ForkJoinTask.AdaptedCallable<T>(task); - externalPush(job); - return job; - } - - /** - * @throws NullPointerException if the task is null - * @throws RejectedExecutionException if the task cannot be - * scheduled for execution - */ - public <T> ForkJoinTask<T> submit(Runnable task, T result) { - ForkJoinTask<T> job = new ForkJoinTask.AdaptedRunnable<T>(task, result); - externalPush(job); - return job; - } - - /** - * @throws NullPointerException if the task is null - * @throws RejectedExecutionException if the task cannot be - * scheduled for execution - */ - public ForkJoinTask<?> submit(Runnable task) { - if (task == null) - throw new NullPointerException(); - ForkJoinTask<?> job; - if (task instanceof ForkJoinTask<?>) // avoid re-wrap - job = (ForkJoinTask<?>) task; - else - job = new ForkJoinTask.AdaptedRunnableAction(task); - externalPush(job); - return job; - } - - /** - * @throws NullPointerException {@inheritDoc} - * @throws RejectedExecutionException {@inheritDoc} - */ - public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) { - // In previous versions of this class, this method constructed - // a task to run ForkJoinTask.invokeAll, but now external - // invocation of multiple tasks is at least as efficient. - ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size()); - - boolean done = false; - try { - for (Callable<T> t : tasks) { - ForkJoinTask<T> f = new ForkJoinTask.AdaptedCallable<T>(t); - futures.add(f); - externalPush(f); - } - for (int i = 0, size = futures.size(); i < size; i++) - ((ForkJoinTask<?>)futures.get(i)).quietlyJoin(); - done = true; - return futures; - } finally { - if (!done) - for (int i = 0, size = futures.size(); i < size; i++) - futures.get(i).cancel(false); - } - } - - /** - * Returns the factory used for constructing new workers. - * - * @return the factory used for constructing new workers - */ - public ForkJoinWorkerThreadFactory getFactory() { - return factory; - } - - /** - * Returns the handler for internal worker threads that terminate - * due to unrecoverable errors encountered while executing tasks. - * - * @return the handler, or {@code null} if none - */ - public UncaughtExceptionHandler getUncaughtExceptionHandler() { - return ueh; - } - - /** - * Returns the targeted parallelism level of this pool. - * - * @return the targeted parallelism level of this pool - */ - public int getParallelism() { - int par; - return ((par = parallelism) > 0) ? par : 1; - } - - /** - * Returns the targeted parallelism level of the common pool. - * - * @return the targeted parallelism level of the common pool - * @since 1.8 - */ - public static int getCommonPoolParallelism() { - return commonParallelism; - } - - /** - * Returns the number of worker threads that have started but not - * yet terminated. The result returned by this method may differ - * from {@link #getParallelism} when threads are created to - * maintain parallelism when others are cooperatively blocked. - * - * @return the number of worker threads - */ - public int getPoolSize() { - return parallelism + (short)(ctl >>> TC_SHIFT); - } - - /** - * Returns {@code true} if this pool uses local first-in-first-out - * scheduling mode for forked tasks that are never joined. - * - * @return {@code true} if this pool uses async mode - */ - public boolean getAsyncMode() { - return mode == FIFO_QUEUE; - } - - /** - * Returns an estimate of the number of worker threads that are - * not blocked waiting to join tasks or for other managed - * synchronization. This method may overestimate the - * number of running threads. - * - * @return the number of worker threads - */ - public int getRunningThreadCount() { - int rc = 0; - WorkQueue[] ws; WorkQueue w; - if ((ws = workQueues) != null) { - for (int i = 1; i < ws.length; i += 2) { - if ((w = ws[i]) != null && w.isApparentlyUnblocked()) - ++rc; - } - } - return rc; - } - - /** - * Returns an estimate of the number of threads that are currently - * stealing or executing tasks. This method may overestimate the - * number of active threads. - * - * @return the number of active threads - */ - public int getActiveThreadCount() { - int r = parallelism + (int)(ctl >> AC_SHIFT); - return (r <= 0) ? 0 : r; // suppress momentarily negative values - } - - /** - * Returns {@code true} if all worker threads are currently idle. - * An idle worker is one that cannot obtain a task to execute - * because none are available to steal from other threads, and - * there are no pending submissions to the pool. This method is - * conservative; it might not return {@code true} immediately upon - * idleness of all threads, but will eventually become true if - * threads remain inactive. - * - * @return {@code true} if all threads are currently idle - */ - public boolean isQuiescent() { - return parallelism + (int)(ctl >> AC_SHIFT) <= 0; - } - - /** - * Returns an estimate of the total number of tasks stolen from - * one thread's work queue by another. The reported value - * underestimates the actual total number of steals when the pool - * is not quiescent. This value may be useful for monitoring and - * tuning fork/join programs: in general, steal counts should be - * high enough to keep threads busy, but low enough to avoid - * overhead and contention across threads. - * - * @return the number of steals - */ - public long getStealCount() { - long count = stealCount; - WorkQueue[] ws; WorkQueue w; - if ((ws = workQueues) != null) { - for (int i = 1; i < ws.length; i += 2) { - if ((w = ws[i]) != null) - count += w.nsteals; - } - } - return count; - } - - /** - * Returns an estimate of the total number of tasks currently held - * in queues by worker threads (but not including tasks submitted - * to the pool that have not begun executing). This value is only - * an approximation, obtained by iterating across all threads in - * the pool. This method may be useful for tuning task - * granularities. - * - * @return the number of queued tasks - */ - public long getQueuedTaskCount() { - long count = 0; - WorkQueue[] ws; WorkQueue w; - if ((ws = workQueues) != null) { - for (int i = 1; i < ws.length; i += 2) { - if ((w = ws[i]) != null) - count += w.queueSize(); - } - } - return count; - } - - /** - * Returns an estimate of the number of tasks submitted to this - * pool that have not yet begun executing. This method may take - * time proportional to the number of submissions. - * - * @return the number of queued submissions - */ - public int getQueuedSubmissionCount() { - int count = 0; - WorkQueue[] ws; WorkQueue w; - if ((ws = workQueues) != null) { - for (int i = 0; i < ws.length; i += 2) { - if ((w = ws[i]) != null) - count += w.queueSize(); - } - } - return count; - } - - /** - * Returns {@code true} if there are any tasks submitted to this - * pool that have not yet begun executing. - * - * @return {@code true} if there are any queued submissions - */ - public boolean hasQueuedSubmissions() { - WorkQueue[] ws; WorkQueue w; - if ((ws = workQueues) != null) { - for (int i = 0; i < ws.length; i += 2) { - if ((w = ws[i]) != null && !w.isEmpty()) - return true; - } - } - return false; - } - - /** - * Removes and returns the next unexecuted submission if one is - * available. This method may be useful in extensions to this - * class that re-assign work in systems with multiple pools. - * - * @return the next submission, or {@code null} if none - */ - protected ForkJoinTask<?> pollSubmission() { - WorkQueue[] ws; WorkQueue w; ForkJoinTask<?> t; - if ((ws = workQueues) != null) { - for (int i = 0; i < ws.length; i += 2) { - if ((w = ws[i]) != null && (t = w.poll()) != null) - return t; - } - } - return null; - } - - /** - * Removes all available unexecuted submitted and forked tasks - * from scheduling queues and adds them to the given collection, - * without altering their execution status. These may include - * artificially generated or wrapped tasks. This method is - * designed to be invoked only when the pool is known to be - * quiescent. Invocations at other times may not remove all - * tasks. A failure encountered while attempting to add elements - * to collection {@code c} may result in elements being in - * neither, either or both collections when the associated - * exception is thrown. The behavior of this operation is - * undefined if the specified collection is modified while the - * operation is in progress. - * - * @param c the collection to transfer elements into - * @return the number of elements transferred - */ - protected int drainTasksTo(Collection<? super ForkJoinTask<?>> c) { - int count = 0; - WorkQueue[] ws; WorkQueue w; ForkJoinTask<?> t; - if ((ws = workQueues) != null) { - for (int i = 0; i < ws.length; ++i) { - if ((w = ws[i]) != null) { - while ((t = w.poll()) != null) { - c.add(t); - ++count; - } - } - } - } - return count; - } - - /** - * Returns a string identifying this pool, as well as its state, - * including indications of run state, parallelism level, and - * worker and task counts. - * - * @return a string identifying this pool, as well as its state - */ - public String toString() { - // Use a single pass through workQueues to collect counts - long qt = 0L, qs = 0L; int rc = 0; - long st = stealCount; - long c = ctl; - WorkQueue[] ws; WorkQueue w; - if ((ws = workQueues) != null) { - for (int i = 0; i < ws.length; ++i) { - if ((w = ws[i]) != null) { - int size = w.queueSize(); - if ((i & 1) == 0) - qs += size; - else { - qt += size; - st += w.nsteals; - if (w.isApparentlyUnblocked()) - ++rc; - } - } - } - } - int pc = parallelism; - int tc = pc + (short)(c >>> TC_SHIFT); - int ac = pc + (int)(c >> AC_SHIFT); - if (ac < 0) // ignore transient negative - ac = 0; - String level; - if ((c & STOP_BIT) != 0) - level = (tc == 0) ? "Terminated" : "Terminating"; - else - level = plock < 0 ? "Shutting down" : "Running"; - return super.toString() + - "[" + level + - ", parallelism = " + pc + - ", size = " + tc + - ", active = " + ac + - ", running = " + rc + - ", steals = " + st + - ", tasks = " + qt + - ", submissions = " + qs + - "]"; - } - - /** - * Possibly initiates an orderly shutdown in which previously - * submitted tasks are executed, but no new tasks will be - * accepted. Invocation has no effect on execution state if this - * is the {@link #commonPool()}, and no additional effect if - * already shut down. Tasks that are in the process of being - * submitted concurrently during the course of this method may or - * may not be rejected. - * - * @throws SecurityException if a security manager exists and - * the caller is not permitted to modify threads - * because it does not hold {@link - * java.lang.RuntimePermission}{@code ("modifyThread")} - */ - public void shutdown() { - checkPermission(); - tryTerminate(false, true); - } - - /** - * Possibly attempts to cancel and/or stop all tasks, and reject - * all subsequently submitted tasks. Invocation has no effect on - * execution state if this is the {@link #commonPool()}, and no - * additional effect if already shut down. Otherwise, tasks that - * are in the process of being submitted or executed concurrently - * during the course of this method may or may not be - * rejected. This method cancels both existing and unexecuted - * tasks, in order to permit termination in the presence of task - * dependencies. So the method always returns an empty list - * (unlike the case for some other Executors). - * - * @return an empty list - * @throws SecurityException if a security manager exists and - * the caller is not permitted to modify threads - * because it does not hold {@link - * java.lang.RuntimePermission}{@code ("modifyThread")} - */ - public List<Runnable> shutdownNow() { - checkPermission(); - tryTerminate(true, true); - return Collections.emptyList(); - } - - /** - * Returns {@code true} if all tasks have completed following shut down. - * - * @return {@code true} if all tasks have completed following shut down - */ - public boolean isTerminated() { - long c = ctl; - return ((c & STOP_BIT) != 0L && - (short)(c >>> TC_SHIFT) + parallelism <= 0); - } - - /** - * Returns {@code true} if the process of termination has - * commenced but not yet completed. This method may be useful for - * debugging. A return of {@code true} reported a sufficient - * period after shutdown may indicate that submitted tasks have - * ignored or suppressed interruption, or are waiting for I/O, - * causing this executor not to properly terminate. (See the - * advisory notes for class {@link ForkJoinTask} stating that - * tasks should not normally entail blocking operations. But if - * they do, they must abort them on interrupt.) - * - * @return {@code true} if terminating but not yet terminated - */ - public boolean isTerminating() { - long c = ctl; - return ((c & STOP_BIT) != 0L && - (short)(c >>> TC_SHIFT) + parallelism > 0); - } - - /** - * Returns {@code true} if this pool has been shut down. - * - * @return {@code true} if this pool has been shut down - */ - public boolean isShutdown() { - return plock < 0; - } - - /** - * Blocks until all tasks have completed execution after a - * shutdown request, or the timeout occurs, or the current thread - * is interrupted, whichever happens first. Because the {@link - * #commonPool()} never terminates until program shutdown, when - * applied to the common pool, this method is equivalent to {@link - * #awaitQuiescence(long, TimeUnit)} but always returns {@code false}. - * - * @param timeout the maximum time to wait - * @param unit the time unit of the timeout argument - * @return {@code true} if this executor terminated and - * {@code false} if the timeout elapsed before termination - * @throws InterruptedException if interrupted while waiting - */ - public boolean awaitTermination(long timeout, TimeUnit unit) - throws InterruptedException { - if (Thread.interrupted()) - throw new InterruptedException(); - if (this == common) { - awaitQuiescence(timeout, unit); - return false; - } - long nanos = unit.toNanos(timeout); - if (isTerminated()) - return true; - if (nanos <= 0L) - return false; - long deadline = System.nanoTime() + nanos; - synchronized (this) { - for (;;) { - if (isTerminated()) - return true; - if (nanos <= 0L) - return false; - long millis = TimeUnit.NANOSECONDS.toMillis(nanos); - wait(millis > 0L ? millis : 1L); - nanos = deadline - System.nanoTime(); - } - } - } - - /** - * If called by a ForkJoinTask operating in this pool, equivalent - * in effect to {@link ForkJoinTask#helpQuiesce}. Otherwise, - * waits and/or attempts to assist performing tasks until this - * pool {@link #isQuiescent} or the indicated timeout elapses. - * - * @param timeout the maximum time to wait - * @param unit the time unit of the timeout argument - * @return {@code true} if quiescent; {@code false} if the - * timeout elapsed. - */ - public boolean awaitQuiescence(long timeout, TimeUnit unit) { - long nanos = unit.toNanos(timeout); - ForkJoinWorkerThread wt; - Thread thread = Thread.currentThread(); - if ((thread instanceof ForkJoinWorkerThread) && - (wt = (ForkJoinWorkerThread)thread).pool == this) { - helpQuiescePool(wt.workQueue); - return true; - } - long startTime = System.nanoTime(); - WorkQueue[] ws; - int r = 0, m; - boolean found = true; - while (!isQuiescent() && (ws = workQueues) != null && - (m = ws.length - 1) >= 0) { - if (!found) { - if ((System.nanoTime() - startTime) > nanos) - return false; - Thread.yield(); // cannot block - } - found = false; - for (int j = (m + 1) << 2; j >= 0; --j) { - ForkJoinTask<?> t; WorkQueue q; int b; - if ((q = ws[r++ & m]) != null && (b = q.base) - q.top < 0) { - found = true; - if ((t = q.pollAt(b)) != null) - t.doExec(); - break; - } - } - } - return true; - } - - /** - * Waits and/or attempts to assist performing tasks indefinitely - * until the {@link #commonPool()} {@link #isQuiescent}. - */ - static void quiesceCommonPool() { - common.awaitQuiescence(Long.MAX_VALUE, TimeUnit.NANOSECONDS); - } - - /** - * Interface for extending managed parallelism for tasks running - * in {@link ForkJoinPool}s. - * - * <p>A {@code ManagedBlocker} provides two methods. Method - * {@code isReleasable} must return {@code true} if blocking is - * not necessary. Method {@code block} blocks the current thread - * if necessary (perhaps internally invoking {@code isReleasable} - * before actually blocking). These actions are performed by any - * thread invoking {@link ForkJoinPool#managedBlock(ManagedBlocker)}. - * The unusual methods in this API accommodate synchronizers that - * may, but don't usually, block for long periods. Similarly, they - * allow more efficient internal handling of cases in which - * additional workers may be, but usually are not, needed to - * ensure sufficient parallelism. Toward this end, - * implementations of method {@code isReleasable} must be amenable - * to repeated invocation. - * - * <p>For example, here is a ManagedBlocker based on a - * ReentrantLock: - * <pre> {@code - * class ManagedLocker implements ManagedBlocker { - * final ReentrantLock lock; - * boolean hasLock = false; - * ManagedLocker(ReentrantLock lock) { this.lock = lock; } - * public boolean block() { - * if (!hasLock) - * lock.lock(); - * return true; - * } - * public boolean isReleasable() { - * return hasLock || (hasLock = lock.tryLock()); - * } - * }}</pre> - * - * <p>Here is a class that possibly blocks waiting for an - * item on a given queue: - * <pre> {@code - * class QueueTaker<E> implements ManagedBlocker { - * final BlockingQueue<E> queue; - * volatile E item = null; - * QueueTaker(BlockingQueue<E> q) { this.queue = q; } - * public boolean block() throws InterruptedException { - * if (item == null) - * item = queue.take(); - * return true; - * } - * public boolean isReleasable() { - * return item != null || (item = queue.poll()) != null; - * } - * public E getItem() { // call after pool.managedBlock completes - * return item; - * } - * }}</pre> - */ - public static interface ManagedBlocker { - /** - * Possibly blocks the current thread, for example waiting for - * a lock or condition. - * - * @return {@code true} if no additional blocking is necessary - * (i.e., if isReleasable would return true) - * @throws InterruptedException if interrupted while waiting - * (the method is not required to do so, but is allowed to) - */ - boolean block() throws InterruptedException; - - /** - * Returns {@code true} if blocking is unnecessary. - * @return {@code true} if blocking is unnecessary - */ - boolean isReleasable(); - } - - /** - * Blocks in accord with the given blocker. If the current thread - * is a {@link ForkJoinWorkerThread}, this method possibly - * arranges for a spare thread to be activated if necessary to - * ensure sufficient parallelism while the current thread is blocked. - * - * <p>If the caller is not a {@link ForkJoinTask}, this method is - * behaviorally equivalent to - * <pre> {@code - * while (!blocker.isReleasable()) - * if (blocker.block()) - * return; - * }</pre> - * - * If the caller is a {@code ForkJoinTask}, then the pool may - * first be expanded to ensure parallelism, and later adjusted. - * - * @param blocker the blocker - * @throws InterruptedException if blocker.block did so - */ - public static void managedBlock(ManagedBlocker blocker) - throws InterruptedException { - Thread t = Thread.currentThread(); - if (t instanceof ForkJoinWorkerThread) { - ForkJoinPool p = ((ForkJoinWorkerThread)t).pool; - while (!blocker.isReleasable()) { - if (p.tryCompensate(p.ctl)) { - try { - do {} while (!blocker.isReleasable() && - !blocker.block()); - } finally { - p.incrementActiveCount(); - } - break; - } - } - } - else { - do {} while (!blocker.isReleasable() && - !blocker.block()); - } - } - - // AbstractExecutorService overrides. These rely on undocumented - // fact that ForkJoinTask.adapt returns ForkJoinTasks that also - // implement RunnableFuture. - - protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { - return new ForkJoinTask.AdaptedRunnable<T>(runnable, value); - } - - protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { - return new ForkJoinTask.AdaptedCallable<T>(callable); - } - - @ikvm.internal.InterlockedCompareAndSet("ctl") - private native boolean compareAndSwapLongCtl(long expect, long update); - - @ikvm.internal.InterlockedCompareAndSet("plock") - private native boolean compareAndSwapIntPlock(int expect, int update); - - @ikvm.internal.InterlockedCompareAndSet("indexSeed") - private native boolean compareAndSwapIntIndexSeed(int expect, int update); - - @ikvm.internal.InterlockedCompareAndSet("stealCount") - private native boolean compareAndSwapLongStealCount(long expect, long update); - - private long getAndAddLongStealCount(long delta) { - for (;;) { - long value = stealCount; - if (compareAndSwapLongStealCount(value, value + delta)) { - return value; - } - } - } - - // Unsafe mechanics - private static final sun.misc.Unsafe U; - private static final int ABASE; - private static final int ASHIFT; - - static { - // initialize field offsets for CAS etc - try { - U = sun.misc.Unsafe.getUnsafe(); - Class<?> ak = ForkJoinTask[].class; - ABASE = U.arrayBaseOffset(ak); - int scale = U.arrayIndexScale(ak); - if ((scale & (scale - 1)) != 0) - throw new Error("data type scale not a power of two"); - ASHIFT = 31 - Integer.numberOfLeadingZeros(scale); - } catch (Exception e) { - throw new Error(e); - } - - defaultForkJoinWorkerThreadFactory = - new DefaultForkJoinWorkerThreadFactory(); - modifyThreadPermission = new RuntimePermission("modifyThread"); - - common = java.security.AccessController.doPrivileged - (new java.security.PrivilegedAction<ForkJoinPool>() { - public ForkJoinPool run() { return makeCommonPool(); }}); - int par = common.parallelism; // report 1 even if threads disabled - commonParallelism = par > 0 ? par : 1; - } - - /** - * Creates and returns the common pool, respecting user settings - * specified via system properties. - */ - private static ForkJoinPool makeCommonPool() { - int parallelism = -1; - ForkJoinWorkerThreadFactory factory = null; - UncaughtExceptionHandler handler = null; - try { // ignore exceptions in accessing/parsing properties - String pp = System.getProperty - ("java.util.concurrent.ForkJoinPool.common.parallelism"); - String fp = System.getProperty - ("java.util.concurrent.ForkJoinPool.common.threadFactory"); - String hp = System.getProperty - ("java.util.concurrent.ForkJoinPool.common.exceptionHandler"); - if (pp != null) - parallelism = Integer.parseInt(pp); - if (fp != null) - factory = ((ForkJoinWorkerThreadFactory)ClassLoader. - getSystemClassLoader().loadClass(fp).newInstance()); - if (hp != null) - handler = ((UncaughtExceptionHandler)ClassLoader. - getSystemClassLoader().loadClass(hp).newInstance()); - } catch (Exception ignore) { - } - if (factory == null) { - if (System.getSecurityManager() == null) - factory = defaultForkJoinWorkerThreadFactory; - else // use security-managed default - factory = new InnocuousForkJoinWorkerThreadFactory(); - } - if (parallelism < 0 && // default 1 less than #cores - (parallelism = Runtime.getRuntime().availableProcessors() - 1) <= 0) - parallelism = 1; - if (parallelism > MAX_CAP) - parallelism = MAX_CAP; - return new ForkJoinPool(parallelism, factory, handler, LIFO_QUEUE, - "ForkJoinPool.commonPool-worker-"); - } - - /** - * Factory for innocuous worker threads - */ - static final class InnocuousForkJoinWorkerThreadFactory - implements ForkJoinWorkerThreadFactory { - - /** - * An ACC to restrict permissions for the factory itself. - * The constructed workers have no permissions set. - */ - private static final AccessControlContext innocuousAcc; - static { - Permissions innocuousPerms = new Permissions(); - innocuousPerms.add(modifyThreadPermission); - innocuousPerms.add(new RuntimePermission( - "enableContextClassLoaderOverride")); - innocuousPerms.add(new RuntimePermission( - "modifyThreadGroup")); - innocuousAcc = new AccessControlContext(new ProtectionDomain[] { - new ProtectionDomain(null, innocuousPerms) - }); - } - - public final ForkJoinWorkerThread newThread(ForkJoinPool pool) { - return (ForkJoinWorkerThread.InnocuousForkJoinWorkerThread) - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction<ForkJoinWorkerThread>() { - public ForkJoinWorkerThread run() { - return new ForkJoinWorkerThread. - InnocuousForkJoinWorkerThread(pool); - }}, innocuousAcc); - } - } - -} diff --git a/openjdk/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/openjdk/java/util/concurrent/locks/AbstractQueuedSynchronizer.java deleted file mode 100644 index 4a42dc11..00000000 --- a/openjdk/java/util/concurrent/locks/AbstractQueuedSynchronizer.java +++ /dev/null @@ -1,2299 +0,0 @@ -/* - * 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. - */ - -/* - * This file is available under and governed by the GNU General Public - * License version 2 only, as published by the Free Software Foundation. - * However, the following notice accompanied the original version of this - * file: - * - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/publicdomain/zero/1.0/ - */ - -package java.util.concurrent.locks; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.*; - -/** - * Provides a framework for implementing blocking locks and related - * synchronizers (semaphores, events, etc) that rely on - * first-in-first-out (FIFO) wait queues. This class is designed to - * be a useful basis for most kinds of synchronizers that rely on a - * single atomic <tt>int</tt> value to represent state. Subclasses - * must define the protected methods that change this state, and which - * define what that state means in terms of this object being acquired - * or released. Given these, the other methods in this class carry - * out all queuing and blocking mechanics. Subclasses can maintain - * other state fields, but only the atomically updated <tt>int</tt> - * value manipulated using methods {@link #getState}, {@link - * #setState} and {@link #compareAndSetState} is tracked with respect - * to synchronization. - * - * <p>Subclasses should be defined as non-public internal helper - * classes that are used to implement the synchronization properties - * of their enclosing class. Class - * <tt>AbstractQueuedSynchronizer</tt> does not implement any - * synchronization interface. Instead it defines methods such as - * {@link #acquireInterruptibly} that can be invoked as - * appropriate by concrete locks and related synchronizers to - * implement their public methods. - * - * <p>This class supports either or both a default <em>exclusive</em> - * mode and a <em>shared</em> mode. When acquired in exclusive mode, - * attempted acquires by other threads cannot succeed. Shared mode - * acquires by multiple threads may (but need not) succeed. This class - * does not "understand" these differences except in the - * mechanical sense that when a shared mode acquire succeeds, the next - * waiting thread (if one exists) must also determine whether it can - * acquire as well. Threads waiting in the different modes share the - * same FIFO queue. Usually, implementation subclasses support only - * one of these modes, but both can come into play for example in a - * {@link ReadWriteLock}. Subclasses that support only exclusive or - * only shared modes need not define the methods supporting the unused mode. - * - * <p>This class defines a nested {@link ConditionObject} class that - * can be used as a {@link Condition} implementation by subclasses - * supporting exclusive mode for which method {@link - * #isHeldExclusively} reports whether synchronization is exclusively - * held with respect to the current thread, method {@link #release} - * invoked with the current {@link #getState} value fully releases - * this object, and {@link #acquire}, given this saved state value, - * eventually restores this object to its previous acquired state. No - * <tt>AbstractQueuedSynchronizer</tt> method otherwise creates such a - * condition, so if this constraint cannot be met, do not use it. The - * behavior of {@link ConditionObject} depends of course on the - * semantics of its synchronizer implementation. - * - * <p>This class provides inspection, instrumentation, and monitoring - * methods for the internal queue, as well as similar methods for - * condition objects. These can be exported as desired into classes - * using an <tt>AbstractQueuedSynchronizer</tt> for their - * synchronization mechanics. - * - * <p>Serialization of this class stores only the underlying atomic - * integer maintaining state, so deserialized objects have empty - * thread queues. Typical subclasses requiring serializability will - * define a <tt>readObject</tt> method that restores this to a known - * initial state upon deserialization. - * - * <h3>Usage</h3> - * - * <p>To use this class as the basis of a synchronizer, redefine the - * following methods, as applicable, by inspecting and/or modifying - * the synchronization state using {@link #getState}, {@link - * #setState} and/or {@link #compareAndSetState}: - * - * <ul> - * <li> {@link #tryAcquire} - * <li> {@link #tryRelease} - * <li> {@link #tryAcquireShared} - * <li> {@link #tryReleaseShared} - * <li> {@link #isHeldExclusively} - *</ul> - * - * Each of these methods by default throws {@link - * UnsupportedOperationException}. Implementations of these methods - * must be internally thread-safe, and should in general be short and - * not block. Defining these methods is the <em>only</em> supported - * means of using this class. All other methods are declared - * <tt>final</tt> because they cannot be independently varied. - * - * <p>You may also find the inherited methods from {@link - * AbstractOwnableSynchronizer} useful to keep track of the thread - * owning an exclusive synchronizer. You are encouraged to use them - * -- this enables monitoring and diagnostic tools to assist users in - * determining which threads hold locks. - * - * <p>Even though this class is based on an internal FIFO queue, it - * does not automatically enforce FIFO acquisition policies. The core - * of exclusive synchronization takes the form: - * - * <pre> - * Acquire: - * while (!tryAcquire(arg)) { - * <em>enqueue thread if it is not already queued</em>; - * <em>possibly block current thread</em>; - * } - * - * Release: - * if (tryRelease(arg)) - * <em>unblock the first queued thread</em>; - * </pre> - * - * (Shared mode is similar but may involve cascading signals.) - * - * <p><a name="barging">Because checks in acquire are invoked before - * enqueuing, a newly acquiring thread may <em>barge</em> ahead of - * others that are blocked and queued. However, you can, if desired, - * define <tt>tryAcquire</tt> and/or <tt>tryAcquireShared</tt> to - * disable barging by internally invoking one or more of the inspection - * methods, thereby providing a <em>fair</em> FIFO acquisition order. - * In particular, most fair synchronizers can define <tt>tryAcquire</tt> - * to return <tt>false</tt> if {@link #hasQueuedPredecessors} (a method - * specifically designed to be used by fair synchronizers) returns - * <tt>true</tt>. Other variations are possible. - * - * <p>Throughput and scalability are generally highest for the - * default barging (also known as <em>greedy</em>, - * <em>renouncement</em>, and <em>convoy-avoidance</em>) strategy. - * While this is not guaranteed to be fair or starvation-free, earlier - * queued threads are allowed to recontend before later queued - * threads, and each recontention has an unbiased chance to succeed - * against incoming threads. Also, while acquires do not - * "spin" in the usual sense, they may perform multiple - * invocations of <tt>tryAcquire</tt> interspersed with other - * computations before blocking. This gives most of the benefits of - * spins when exclusive synchronization is only briefly held, without - * most of the liabilities when it isn't. If so desired, you can - * augment this by preceding calls to acquire methods with - * "fast-path" checks, possibly prechecking {@link #hasContended} - * and/or {@link #hasQueuedThreads} to only do so if the synchronizer - * is likely not to be contended. - * - * <p>This class provides an efficient and scalable basis for - * synchronization in part by specializing its range of use to - * synchronizers that can rely on <tt>int</tt> state, acquire, and - * release parameters, and an internal FIFO wait queue. When this does - * not suffice, you can build synchronizers from a lower level using - * {@link java.util.concurrent.atomic atomic} classes, your own custom - * {@link java.util.Queue} classes, and {@link LockSupport} blocking - * support. - * - * <h3>Usage Examples</h3> - * - * <p>Here is a non-reentrant mutual exclusion lock class that uses - * the value zero to represent the unlocked state, and one to - * represent the locked state. While a non-reentrant lock - * does not strictly require recording of the current owner - * thread, this class does so anyway to make usage easier to monitor. - * It also supports conditions and exposes - * one of the instrumentation methods: - * - * <pre> - * class Mutex implements Lock, java.io.Serializable { - * - * // Our internal helper class - * private static class Sync extends AbstractQueuedSynchronizer { - * // Report whether in locked state - * protected boolean isHeldExclusively() { - * return getState() == 1; - * } - * - * // Acquire the lock if state is zero - * public boolean tryAcquire(int acquires) { - * assert acquires == 1; // Otherwise unused - * if (compareAndSetState(0, 1)) { - * setExclusiveOwnerThread(Thread.currentThread()); - * return true; - * } - * return false; - * } - * - * // Release the lock by setting state to zero - * protected boolean tryRelease(int releases) { - * assert releases == 1; // Otherwise unused - * if (getState() == 0) throw new IllegalMonitorStateException(); - * setExclusiveOwnerThread(null); - * setState(0); - * return true; - * } - * - * // Provide a Condition - * Condition newCondition() { return new ConditionObject(); } - * - * // Deserialize properly - * private void readObject(ObjectInputStream s) - * throws IOException, ClassNotFoundException { - * s.defaultReadObject(); - * setState(0); // reset to unlocked state - * } - * } - * - * // The sync object does all the hard work. We just forward to it. - * private final Sync sync = new Sync(); - * - * public void lock() { sync.acquire(1); } - * public boolean tryLock() { return sync.tryAcquire(1); } - * public void unlock() { sync.release(1); } - * public Condition newCondition() { return sync.newCondition(); } - * public boolean isLocked() { return sync.isHeldExclusively(); } - * public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); } - * public void lockInterruptibly() throws InterruptedException { - * sync.acquireInterruptibly(1); - * } - * public boolean tryLock(long timeout, TimeUnit unit) - * throws InterruptedException { - * return sync.tryAcquireNanos(1, unit.toNanos(timeout)); - * } - * } - * </pre> - * - * <p>Here is a latch class that is like a {@link CountDownLatch} - * except that it only requires a single <tt>signal</tt> to - * fire. Because a latch is non-exclusive, it uses the <tt>shared</tt> - * acquire and release methods. - * - * <pre> - * class BooleanLatch { - * - * private static class Sync extends AbstractQueuedSynchronizer { - * boolean isSignalled() { return getState() != 0; } - * - * protected int tryAcquireShared(int ignore) { - * return isSignalled() ? 1 : -1; - * } - * - * protected boolean tryReleaseShared(int ignore) { - * setState(1); - * return true; - * } - * } - * - * private final Sync sync = new Sync(); - * public boolean isSignalled() { return sync.isSignalled(); } - * public void signal() { sync.releaseShared(1); } - * public void await() throws InterruptedException { - * sync.acquireSharedInterruptibly(1); - * } - * } - * </pre> - * - * @since 1.5 - * @author Doug Lea - */ -public abstract class AbstractQueuedSynchronizer - extends AbstractOwnableSynchronizer - implements java.io.Serializable { - - private static final long serialVersionUID = 7373984972572414691L; - - /** - * Creates a new <tt>AbstractQueuedSynchronizer</tt> instance - * with initial synchronization state of zero. - */ - protected AbstractQueuedSynchronizer() { } - - /** - * Wait queue node class. - * - * <p>The wait queue is a variant of a "CLH" (Craig, Landin, and - * Hagersten) lock queue. CLH locks are normally used for - * spinlocks. We instead use them for blocking synchronizers, but - * use the same basic tactic of holding some of the control - * information about a thread in the predecessor of its node. A - * "status" field in each node keeps track of whether a thread - * should block. A node is signalled when its predecessor - * releases. Each node of the queue otherwise serves as a - * specific-notification-style monitor holding a single waiting - * thread. The status field does NOT control whether threads are - * granted locks etc though. A thread may try to acquire if it is - * first in the queue. But being first does not guarantee success; - * it only gives the right to contend. So the currently released - * contender thread may need to rewait. - * - * <p>To enqueue into a CLH lock, you atomically splice it in as new - * tail. To dequeue, you just set the head field. - * <pre> - * +------+ prev +-----+ +-----+ - * head | | <---- | | <---- | | tail - * +------+ +-----+ +-----+ - * </pre> - * - * <p>Insertion into a CLH queue requires only a single atomic - * operation on "tail", so there is a simple atomic point of - * demarcation from unqueued to queued. Similarly, dequeing - * involves only updating the "head". However, it takes a bit - * more work for nodes to determine who their successors are, - * in part to deal with possible cancellation due to timeouts - * and interrupts. - * - * <p>The "prev" links (not used in original CLH locks), are mainly - * needed to handle cancellation. If a node is cancelled, its - * successor is (normally) relinked to a non-cancelled - * predecessor. For explanation of similar mechanics in the case - * of spin locks, see the papers by Scott and Scherer at - * http://www.cs.rochester.edu/u/scott/synchronization/ - * - * <p>We also use "next" links to implement blocking mechanics. - * The thread id for each node is kept in its own node, so a - * predecessor signals the next node to wake up by traversing - * next link to determine which thread it is. Determination of - * successor must avoid races with newly queued nodes to set - * the "next" fields of their predecessors. This is solved - * when necessary by checking backwards from the atomically - * updated "tail" when a node's successor appears to be null. - * (Or, said differently, the next-links are an optimization - * so that we don't usually need a backward scan.) - * - * <p>Cancellation introduces some conservatism to the basic - * algorithms. Since we must poll for cancellation of other - * nodes, we can miss noticing whether a cancelled node is - * ahead or behind us. This is dealt with by always unparking - * successors upon cancellation, allowing them to stabilize on - * a new predecessor, unless we can identify an uncancelled - * predecessor who will carry this responsibility. - * - * <p>CLH queues need a dummy header node to get started. But - * we don't create them on construction, because it would be wasted - * effort if there is never contention. Instead, the node - * is constructed and head and tail pointers are set upon first - * contention. - * - * <p>Threads waiting on Conditions use the same nodes, but - * use an additional link. Conditions only need to link nodes - * in simple (non-concurrent) linked queues because they are - * only accessed when exclusively held. Upon await, a node is - * inserted into a condition queue. Upon signal, the node is - * transferred to the main queue. A special value of status - * field is used to mark which queue a node is on. - * - * <p>Thanks go to Dave Dice, Mark Moir, Victor Luchangco, Bill - * Scherer and Michael Scott, along with members of JSR-166 - * expert group, for helpful ideas, discussions, and critiques - * on the design of this class. - */ - static final class Node { - static final AtomicReferenceFieldUpdater<Node, Node> nextUpdater = AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "next"); - /** Marker to indicate a node is waiting in shared mode */ - static final Node SHARED = new Node(); - /** Marker to indicate a node is waiting in exclusive mode */ - static final Node EXCLUSIVE = null; - - /** waitStatus value to indicate thread has cancelled */ - static final int CANCELLED = 1; - /** waitStatus value to indicate successor's thread needs unparking */ - static final int SIGNAL = -1; - /** waitStatus value to indicate thread is waiting on condition */ - static final int CONDITION = -2; - /** - * waitStatus value to indicate the next acquireShared should - * unconditionally propagate - */ - static final int PROPAGATE = -3; - - /** - * Status field, taking on only the values: - * SIGNAL: The successor of this node is (or will soon be) - * blocked (via park), so the current node must - * unpark its successor when it releases or - * cancels. To avoid races, acquire methods must - * first indicate they need a signal, - * then retry the atomic acquire, and then, - * on failure, block. - * CANCELLED: This node is cancelled due to timeout or interrupt. - * Nodes never leave this state. In particular, - * a thread with cancelled node never again blocks. - * CONDITION: This node is currently on a condition queue. - * It will not be used as a sync queue node - * until transferred, at which time the status - * will be set to 0. (Use of this value here has - * nothing to do with the other uses of the - * field, but simplifies mechanics.) - * PROPAGATE: A releaseShared should be propagated to other - * nodes. This is set (for head node only) in - * doReleaseShared to ensure propagation - * continues, even if other operations have - * since intervened. - * 0: None of the above - * - * The values are arranged numerically to simplify use. - * Non-negative values mean that a node doesn't need to - * signal. So, most code doesn't need to check for particular - * values, just for sign. - * - * The field is initialized to 0 for normal sync nodes, and - * CONDITION for condition nodes. It is modified using CAS - * (or when possible, unconditional volatile writes). - */ - volatile int waitStatus; - - /** - * Link to predecessor node that current node/thread relies on - * for checking waitStatus. Assigned during enqueing, and nulled - * out (for sake of GC) only upon dequeuing. Also, upon - * cancellation of a predecessor, we short-circuit while - * finding a non-cancelled one, which will always exist - * because the head node is never cancelled: A node becomes - * head only as a result of successful acquire. A - * cancelled thread never succeeds in acquiring, and a thread only - * cancels itself, not any other node. - */ - volatile Node prev; - - /** - * Link to the successor node that the current node/thread - * unparks upon release. Assigned during enqueuing, adjusted - * when bypassing cancelled predecessors, and nulled out (for - * sake of GC) when dequeued. The enq operation does not - * assign next field of a predecessor until after attachment, - * so seeing a null next field does not necessarily mean that - * node is at end of queue. However, if a next field appears - * to be null, we can scan prev's from the tail to - * double-check. The next field of cancelled nodes is set to - * point to the node itself instead of null, to make life - * easier for isOnSyncQueue. - */ - volatile Node next; - - /** - * The thread that enqueued this node. Initialized on - * construction and nulled out after use. - */ - volatile Thread thread; - - /** - * Link to next node waiting on condition, or the special - * value SHARED. Because condition queues are accessed only - * when holding in exclusive mode, we just need a simple - * linked queue to hold nodes while they are waiting on - * conditions. They are then transferred to the queue to - * re-acquire. And because conditions can only be exclusive, - * we save a field by using special value to indicate shared - * mode. - */ - Node nextWaiter; - - /** - * Returns true if node is waiting in shared mode - */ - final boolean isShared() { - return nextWaiter == SHARED; - } - - /** - * Returns previous node, or throws NullPointerException if null. - * Use when predecessor cannot be null. The null check could - * be elided, but is present to help the VM. - * - * @return the predecessor of this node - */ - final Node predecessor() throws NullPointerException { - Node p = prev; - if (p == null) - throw new NullPointerException(); - else - return p; - } - - Node() { // Used to establish initial head or SHARED marker - } - - Node(Thread thread, Node mode) { // Used by addWaiter - this.nextWaiter = mode; - this.thread = thread; - } - - Node(Thread thread, int waitStatus) { // Used by Condition - this.waitStatus = waitStatus; - this.thread = thread; - } - } - - /** - * Head of the wait queue, lazily initialized. Except for - * initialization, it is modified only via method setHead. Note: - * If head exists, its waitStatus is guaranteed not to be - * CANCELLED. - */ - private transient volatile Node head; - - /** - * Tail of the wait queue, lazily initialized. Modified only via - * method enq to add new wait node. - */ - private transient volatile Node tail; - - /** - * The synchronization state. - */ - private volatile int state; - - /** - * Returns the current value of synchronization state. - * This operation has memory semantics of a <tt>volatile</tt> read. - * @return current state value - */ - protected final int getState() { - return state; - } - - /** - * Sets the value of synchronization state. - * This operation has memory semantics of a <tt>volatile</tt> write. - * @param newState the new state value - */ - protected final void setState(int newState) { - state = newState; - } - - /** - * Atomically sets synchronization state to the given updated - * value if the current state value equals the expected value. - * This operation has memory semantics of a <tt>volatile</tt> read - * and write. - * - * @param expect the expected value - * @param update the new value - * @return true if successful. False return indicates that the actual - * value was not equal to the expected value. - */ - protected final native boolean compareAndSetState(int expect, int update); // implemented in map.xml - - // Queuing utilities - - /** - * The number of nanoseconds for which it is faster to spin - * rather than to use timed park. A rough estimate suffices - * to improve responsiveness with very short timeouts. - */ - static final long spinForTimeoutThreshold = 1000L; - - /** - * Inserts node into queue, initializing if necessary. See picture above. - * @param node the node to insert - * @return node's predecessor - */ - private Node enq(final Node node) { - for (;;) { - Node t = tail; - if (t == null) { // Must initialize - if (compareAndSetHead(new Node())) - tail = head; - } else { - node.prev = t; - if (compareAndSetTail(t, node)) { - t.next = node; - return t; - } - } - } - } - - /** - * Creates and enqueues node for current thread and given mode. - * - * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared - * @return the new node - */ - private Node addWaiter(Node mode) { - Node node = new Node(Thread.currentThread(), mode); - // Try the fast path of enq; backup to full enq on failure - Node pred = tail; - if (pred != null) { - node.prev = pred; - if (compareAndSetTail(pred, node)) { - pred.next = node; - return node; - } - } - enq(node); - return node; - } - - /** - * Sets head of queue to be node, thus dequeuing. Called only by - * acquire methods. Also nulls out unused fields for sake of GC - * and to suppress unnecessary signals and traversals. - * - * @param node the node - */ - private void setHead(Node node) { - head = node; - node.thread = null; - node.prev = null; - } - - /** - * Wakes up node's successor, if one exists. - * - * @param node the node - */ - private void unparkSuccessor(Node node) { - /* - * If status is negative (i.e., possibly needing signal) try - * to clear in anticipation of signalling. It is OK if this - * fails or if status is changed by waiting thread. - */ - int ws = node.waitStatus; - if (ws < 0) - compareAndSetWaitStatus(node, ws, 0); - - /* - * Thread to unpark is held in successor, which is normally - * just the next node. But if cancelled or apparently null, - * traverse backwards from tail to find the actual - * non-cancelled successor. - */ - Node s = node.next; - if (s == null || s.waitStatus > 0) { - s = null; - for (Node t = tail; t != null && t != node; t = t.prev) - if (t.waitStatus <= 0) - s = t; - } - if (s != null) - LockSupport.unpark(s.thread); - } - - /** - * Release action for shared mode -- signal successor and ensure - * propagation. (Note: For exclusive mode, release just amounts - * to calling unparkSuccessor of head if it needs signal.) - */ - private void doReleaseShared() { - /* - * Ensure that a release propagates, even if there are other - * in-progress acquires/releases. This proceeds in the usual - * way of trying to unparkSuccessor of head if it needs - * signal. But if it does not, status is set to PROPAGATE to - * ensure that upon release, propagation continues. - * Additionally, we must loop in case a new node is added - * while we are doing this. Also, unlike other uses of - * unparkSuccessor, we need to know if CAS to reset status - * fails, if so rechecking. - */ - for (;;) { - Node h = head; - if (h != null && h != tail) { - int ws = h.waitStatus; - if (ws == Node.SIGNAL) { - if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)) - continue; // loop to recheck cases - unparkSuccessor(h); - } - else if (ws == 0 && - !compareAndSetWaitStatus(h, 0, Node.PROPAGATE)) - continue; // loop on failed CAS - } - if (h == head) // loop if head changed - break; - } - } - - /** - * Sets head of queue, and checks if successor may be waiting - * in shared mode, if so propagating if either propagate > 0 or - * PROPAGATE status was set. - * - * @param node the node - * @param propagate the return value from a tryAcquireShared - */ - private void setHeadAndPropagate(Node node, int propagate) { - Node h = head; // Record old head for check below - setHead(node); - /* - * Try to signal next queued node if: - * Propagation was indicated by caller, - * or was recorded (as h.waitStatus) by a previous operation - * (note: this uses sign-check of waitStatus because - * PROPAGATE status may transition to SIGNAL.) - * and - * The next node is waiting in shared mode, - * or we don't know, because it appears null - * - * The conservatism in both of these checks may cause - * unnecessary wake-ups, but only when there are multiple - * racing acquires/releases, so most need signals now or soon - * anyway. - */ - if (propagate > 0 || h == null || h.waitStatus < 0) { - Node s = node.next; - if (s == null || s.isShared()) - doReleaseShared(); - } - } - - // Utilities for various versions of acquire - - /** - * Cancels an ongoing attempt to acquire. - * - * @param node the node - */ - private void cancelAcquire(Node node) { - // Ignore if node doesn't exist - if (node == null) - return; - - node.thread = null; - - // Skip cancelled predecessors - Node pred = node.prev; - while (pred.waitStatus > 0) - node.prev = pred = pred.prev; - - // predNext is the apparent node to unsplice. CASes below will - // fail if not, in which case, we lost race vs another cancel - // or signal, so no further action is necessary. - Node predNext = pred.next; - - // Can use unconditional write instead of CAS here. - // After this atomic step, other Nodes can skip past us. - // Before, we are free of interference from other threads. - node.waitStatus = Node.CANCELLED; - - // If we are the tail, remove ourselves. - if (node == tail && compareAndSetTail(node, pred)) { - compareAndSetNext(pred, predNext, null); - } else { - // If successor needs signal, try to set pred's next-link - // so it will get one. Otherwise wake it up to propagate. - int ws; - if (pred != head && - ((ws = pred.waitStatus) == Node.SIGNAL || - (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) && - pred.thread != null) { - Node next = node.next; - if (next != null && next.waitStatus <= 0) - compareAndSetNext(pred, predNext, next); - } else { - unparkSuccessor(node); - } - - node.next = node; // help GC - } - } - - /** - * Checks and updates status for a node that failed to acquire. - * Returns true if thread should block. This is the main signal - * control in all acquire loops. Requires that pred == node.prev - * - * @param pred node's predecessor holding status - * @param node the node - * @return {@code true} if thread should block - */ - private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { - int ws = pred.waitStatus; - if (ws == Node.SIGNAL) - /* - * This node has already set status asking a release - * to signal it, so it can safely park. - */ - return true; - if (ws > 0) { - /* - * Predecessor was cancelled. Skip over predecessors and - * indicate retry. - */ - do { - node.prev = pred = pred.prev; - } while (pred.waitStatus > 0); - pred.next = node; - } else { - /* - * waitStatus must be 0 or PROPAGATE. Indicate that we - * need a signal, but don't park yet. Caller will need to - * retry to make sure it cannot acquire before parking. - */ - compareAndSetWaitStatus(pred, ws, Node.SIGNAL); - } - return false; - } - - /** - * Convenience method to interrupt current thread. - */ - private static void selfInterrupt() { - Thread.currentThread().interrupt(); - } - - /** - * Convenience method to park and then check if interrupted - * - * @return {@code true} if interrupted - */ - private final boolean parkAndCheckInterrupt() { - LockSupport.park(this); - return Thread.interrupted(); - } - - /* - * Various flavors of acquire, varying in exclusive/shared and - * control modes. Each is mostly the same, but annoyingly - * different. Only a little bit of factoring is possible due to - * interactions of exception mechanics (including ensuring that we - * cancel if tryAcquire throws exception) and other control, at - * least not without hurting performance too much. - */ - - /** - * Acquires in exclusive uninterruptible mode for thread already in - * queue. Used by condition wait methods as well as acquire. - * - * @param node the node - * @param arg the acquire argument - * @return {@code true} if interrupted while waiting - */ - final boolean acquireQueued(final Node node, int arg) { - boolean failed = true; - try { - boolean interrupted = false; - for (;;) { - final Node p = node.predecessor(); - if (p == head && tryAcquire(arg)) { - setHead(node); - p.next = null; // help GC - failed = false; - return interrupted; - } - if (shouldParkAfterFailedAcquire(p, node) && - parkAndCheckInterrupt()) - interrupted = true; - } - } finally { - if (failed) - cancelAcquire(node); - } - } - - /** - * Acquires in exclusive interruptible mode. - * @param arg the acquire argument - */ - private void doAcquireInterruptibly(int arg) - throws InterruptedException { - final Node node = addWaiter(Node.EXCLUSIVE); - boolean failed = true; - try { - for (;;) { - final Node p = node.predecessor(); - if (p == head && tryAcquire(arg)) { - setHead(node); - p.next = null; // help GC - failed = false; - return; - } - if (shouldParkAfterFailedAcquire(p, node) && - parkAndCheckInterrupt()) - throw new InterruptedException(); - } - } finally { - if (failed) - cancelAcquire(node); - } - } - - /** - * Acquires in exclusive timed mode. - * - * @param arg the acquire argument - * @param nanosTimeout max wait time - * @return {@code true} if acquired - */ - private boolean doAcquireNanos(int arg, long nanosTimeout) - throws InterruptedException { - long lastTime = System.nanoTime(); - final Node node = addWaiter(Node.EXCLUSIVE); - boolean failed = true; - try { - for (;;) { - final Node p = node.predecessor(); - if (p == head && tryAcquire(arg)) { - setHead(node); - p.next = null; // help GC - failed = false; - return true; - } - if (nanosTimeout <= 0) - return false; - if (shouldParkAfterFailedAcquire(p, node) && - nanosTimeout > spinForTimeoutThreshold) - LockSupport.parkNanos(this, nanosTimeout); - long now = System.nanoTime(); - nanosTimeout -= now - lastTime; - lastTime = now; - if (Thread.interrupted()) - throw new InterruptedException(); - } - } finally { - if (failed) - cancelAcquire(node); - } - } - - /** - * Acquires in shared uninterruptible mode. - * @param arg the acquire argument - */ - private void doAcquireShared(int arg) { - final Node node = addWaiter(Node.SHARED); - boolean failed = true; - try { - boolean interrupted = false; - for (;;) { - final Node p = node.predecessor(); - if (p == head) { - int r = tryAcquireShared(arg); - if (r >= 0) { - setHeadAndPropagate(node, r); - p.next = null; // help GC - if (interrupted) - selfInterrupt(); - failed = false; - return; - } - } - if (shouldParkAfterFailedAcquire(p, node) && - parkAndCheckInterrupt()) - interrupted = true; - } - } finally { - if (failed) - cancelAcquire(node); - } - } - - /** - * Acquires in shared interruptible mode. - * @param arg the acquire argument - */ - private void doAcquireSharedInterruptibly(int arg) - throws InterruptedException { - final Node node = addWaiter(Node.SHARED); - boolean failed = true; - try { - for (;;) { - final Node p = node.predecessor(); - if (p == head) { - int r = tryAcquireShared(arg); - if (r >= 0) { - setHeadAndPropagate(node, r); - p.next = null; // help GC - failed = false; - return; - } - } - if (shouldParkAfterFailedAcquire(p, node) && - parkAndCheckInterrupt()) - throw new InterruptedException(); - } - } finally { - if (failed) - cancelAcquire(node); - } - } - - /** - * Acquires in shared timed mode. - * - * @param arg the acquire argument - * @param nanosTimeout max wait time - * @return {@code true} if acquired - */ - private boolean doAcquireSharedNanos(int arg, long nanosTimeout) - throws InterruptedException { - - long lastTime = System.nanoTime(); - final Node node = addWaiter(Node.SHARED); - boolean failed = true; - try { - for (;;) { - final Node p = node.predecessor(); - if (p == head) { - int r = tryAcquireShared(arg); - if (r >= 0) { - setHeadAndPropagate(node, r); - p.next = null; // help GC - failed = false; - return true; - } - } - if (nanosTimeout <= 0) - return false; - if (shouldParkAfterFailedAcquire(p, node) && - nanosTimeout > spinForTimeoutThreshold) - LockSupport.parkNanos(this, nanosTimeout); - long now = System.nanoTime(); - nanosTimeout -= now - lastTime; - lastTime = now; - if (Thread.interrupted()) - throw new InterruptedException(); - } - } finally { - if (failed) - cancelAcquire(node); - } - } - - // Main exported methods - - /** - * Attempts to acquire in exclusive mode. This method should query - * if the state of the object permits it to be acquired in the - * exclusive mode, and if so to acquire it. - * - * <p>This method is always invoked by the thread performing - * acquire. If this method reports failure, the acquire method - * may queue the thread, if it is not already queued, until it is - * signalled by a release from some other thread. This can be used - * to implement method {@link Lock#tryLock()}. - * - * <p>The default - * implementation throws {@link UnsupportedOperationException}. - * - * @param arg the acquire argument. This value is always the one - * passed to an acquire method, or is the value saved on entry - * to a condition wait. The value is otherwise uninterpreted - * and can represent anything you like. - * @return {@code true} if successful. Upon success, this object has - * been acquired. - * @throws IllegalMonitorStateException if acquiring would place this - * synchronizer in an illegal state. This exception must be - * thrown in a consistent fashion for synchronization to work - * correctly. - * @throws UnsupportedOperationException if exclusive mode is not supported - */ - protected boolean tryAcquire(int arg) { - throw new UnsupportedOperationException(); - } - - /** - * Attempts to set the state to reflect a release in exclusive - * mode. - * - * <p>This method is always invoked by the thread performing release. - * - * <p>The default implementation throws - * {@link UnsupportedOperationException}. - * - * @param arg the release argument. This value is always the one - * passed to a release method, or the current state value upon - * entry to a condition wait. The value is otherwise - * uninterpreted and can represent anything you like. - * @return {@code true} if this object is now in a fully released - * state, so that any waiting threads may attempt to acquire; - * and {@code false} otherwise. - * @throws IllegalMonitorStateException if releasing would place this - * synchronizer in an illegal state. This exception must be - * thrown in a consistent fashion for synchronization to work - * correctly. - * @throws UnsupportedOperationException if exclusive mode is not supported - */ - protected boolean tryRelease(int arg) { - throw new UnsupportedOperationException(); - } - - /** - * Attempts to acquire in shared mode. This method should query if - * the state of the object permits it to be acquired in the shared - * mode, and if so to acquire it. - * - * <p>This method is always invoked by the thread performing - * acquire. If this method reports failure, the acquire method - * may queue the thread, if it is not already queued, until it is - * signalled by a release from some other thread. - * - * <p>The default implementation throws {@link - * UnsupportedOperationException}. - * - * @param arg the acquire argument. This value is always the one - * passed to an acquire method, or is the value saved on entry - * to a condition wait. The value is otherwise uninterpreted - * and can represent anything you like. - * @return a negative value on failure; zero if acquisition in shared - * mode succeeded but no subsequent shared-mode acquire can - * succeed; and a positive value if acquisition in shared - * mode succeeded and subsequent shared-mode acquires might - * also succeed, in which case a subsequent waiting thread - * must check availability. (Support for three different - * return values enables this method to be used in contexts - * where acquires only sometimes act exclusively.) Upon - * success, this object has been acquired. - * @throws IllegalMonitorStateException if acquiring would place this - * synchronizer in an illegal state. This exception must be - * thrown in a consistent fashion for synchronization to work - * correctly. - * @throws UnsupportedOperationException if shared mode is not supported - */ - protected int tryAcquireShared(int arg) { - throw new UnsupportedOperationException(); - } - - /** - * Attempts to set the state to reflect a release in shared mode. - * - * <p>This method is always invoked by the thread performing release. - * - * <p>The default implementation throws - * {@link UnsupportedOperationException}. - * - * @param arg the release argument. This value is always the one - * passed to a release method, or the current state value upon - * entry to a condition wait. The value is otherwise - * uninterpreted and can represent anything you like. - * @return {@code true} if this release of shared mode may permit a - * waiting acquire (shared or exclusive) to succeed; and - * {@code false} otherwise - * @throws IllegalMonitorStateException if releasing would place this - * synchronizer in an illegal state. This exception must be - * thrown in a consistent fashion for synchronization to work - * correctly. - * @throws UnsupportedOperationException if shared mode is not supported - */ - protected boolean tryReleaseShared(int arg) { - throw new UnsupportedOperationException(); - } - - /** - * Returns {@code true} if synchronization is held exclusively with - * respect to the current (calling) thread. This method is invoked - * upon each call to a non-waiting {@link ConditionObject} method. - * (Waiting methods instead invoke {@link #release}.) - * - * <p>The default implementation throws {@link - * UnsupportedOperationException}. This method is invoked - * internally only within {@link ConditionObject} methods, so need - * not be defined if conditions are not used. - * - * @return {@code true} if synchronization is held exclusively; - * {@code false} otherwise - * @throws UnsupportedOperationException if conditions are not supported - */ - protected boolean isHeldExclusively() { - throw new UnsupportedOperationException(); - } - - /** - * Acquires in exclusive mode, ignoring interrupts. Implemented - * by invoking at least once {@link #tryAcquire}, - * returning on success. Otherwise the thread is queued, possibly - * repeatedly blocking and unblocking, invoking {@link - * #tryAcquire} until success. This method can be used - * to implement method {@link Lock#lock}. - * - * @param arg the acquire argument. This value is conveyed to - * {@link #tryAcquire} but is otherwise uninterpreted and - * can represent anything you like. - */ - public final void acquire(int arg) { - if (!tryAcquire(arg) && - acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) - selfInterrupt(); - } - - /** - * Acquires in exclusive mode, aborting if interrupted. - * Implemented by first checking interrupt status, then invoking - * at least once {@link #tryAcquire}, returning on - * success. Otherwise the thread is queued, possibly repeatedly - * blocking and unblocking, invoking {@link #tryAcquire} - * until success or the thread is interrupted. This method can be - * used to implement method {@link Lock#lockInterruptibly}. - * - * @param arg the acquire argument. This value is conveyed to - * {@link #tryAcquire} but is otherwise uninterpreted and - * can represent anything you like. - * @throws InterruptedException if the current thread is interrupted - */ - public final void acquireInterruptibly(int arg) - throws InterruptedException { - if (Thread.interrupted()) - throw new InterruptedException(); - if (!tryAcquire(arg)) - doAcquireInterruptibly(arg); - } - - /** - * Attempts to acquire in exclusive mode, aborting if interrupted, - * and failing if the given timeout elapses. Implemented by first - * checking interrupt status, then invoking at least once {@link - * #tryAcquire}, returning on success. Otherwise, the thread is - * queued, possibly repeatedly blocking and unblocking, invoking - * {@link #tryAcquire} until success or the thread is interrupted - * or the timeout elapses. This method can be used to implement - * method {@link Lock#tryLock(long, TimeUnit)}. - * - * @param arg the acquire argument. This value is conveyed to - * {@link #tryAcquire} but is otherwise uninterpreted and - * can represent anything you like. - * @param nanosTimeout the maximum number of nanoseconds to wait - * @return {@code true} if acquired; {@code false} if timed out - * @throws InterruptedException if the current thread is interrupted - */ - public final boolean tryAcquireNanos(int arg, long nanosTimeout) - throws InterruptedException { - if (Thread.interrupted()) - throw new InterruptedException(); - return tryAcquire(arg) || - doAcquireNanos(arg, nanosTimeout); - } - - /** - * Releases in exclusive mode. Implemented by unblocking one or - * more threads if {@link #tryRelease} returns true. - * This method can be used to implement method {@link Lock#unlock}. - * - * @param arg the release argument. This value is conveyed to - * {@link #tryRelease} but is otherwise uninterpreted and - * can represent anything you like. - * @return the value returned from {@link #tryRelease} - */ - public final boolean release(int arg) { - if (tryRelease(arg)) { - Node h = head; - if (h != null && h.waitStatus != 0) - unparkSuccessor(h); - return true; - } - return false; - } - - /** - * Acquires in shared mode, ignoring interrupts. Implemented by - * first invoking at least once {@link #tryAcquireShared}, - * returning on success. Otherwise the thread is queued, possibly - * repeatedly blocking and unblocking, invoking {@link - * #tryAcquireShared} until success. - * - * @param arg the acquire argument. This value is conveyed to - * {@link #tryAcquireShared} but is otherwise uninterpreted - * and can represent anything you like. - */ - public final void acquireShared(int arg) { - if (tryAcquireShared(arg) < 0) - doAcquireShared(arg); - } - - /** - * Acquires in shared mode, aborting if interrupted. Implemented - * by first checking interrupt status, then invoking at least once - * {@link #tryAcquireShared}, returning on success. Otherwise the - * thread is queued, possibly repeatedly blocking and unblocking, - * invoking {@link #tryAcquireShared} until success or the thread - * is interrupted. - * @param arg the acquire argument - * This value is conveyed to {@link #tryAcquireShared} but is - * otherwise uninterpreted and can represent anything - * you like. - * @throws InterruptedException if the current thread is interrupted - */ - public final void acquireSharedInterruptibly(int arg) - throws InterruptedException { - if (Thread.interrupted()) - throw new InterruptedException(); - if (tryAcquireShared(arg) < 0) - doAcquireSharedInterruptibly(arg); - } - - /** - * Attempts to acquire in shared mode, aborting if interrupted, and - * failing if the given timeout elapses. Implemented by first - * checking interrupt status, then invoking at least once {@link - * #tryAcquireShared}, returning on success. Otherwise, the - * thread is queued, possibly repeatedly blocking and unblocking, - * invoking {@link #tryAcquireShared} until success or the thread - * is interrupted or the timeout elapses. - * - * @param arg the acquire argument. This value is conveyed to - * {@link #tryAcquireShared} but is otherwise uninterpreted - * and can represent anything you like. - * @param nanosTimeout the maximum number of nanoseconds to wait - * @return {@code true} if acquired; {@code false} if timed out - * @throws InterruptedException if the current thread is interrupted - */ - public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) - throws InterruptedException { - if (Thread.interrupted()) - throw new InterruptedException(); - return tryAcquireShared(arg) >= 0 || - doAcquireSharedNanos(arg, nanosTimeout); - } - - /** - * Releases in shared mode. Implemented by unblocking one or more - * threads if {@link #tryReleaseShared} returns true. - * - * @param arg the release argument. This value is conveyed to - * {@link #tryReleaseShared} but is otherwise uninterpreted - * and can represent anything you like. - * @return the value returned from {@link #tryReleaseShared} - */ - public final boolean releaseShared(int arg) { - if (tryReleaseShared(arg)) { - doReleaseShared(); - return true; - } - return false; - } - - // Queue inspection methods - - /** - * Queries whether any threads are waiting to acquire. Note that - * because cancellations due to interrupts and timeouts may occur - * at any time, a {@code true} return does not guarantee that any - * other thread will ever acquire. - * - * <p>In this implementation, this operation returns in - * constant time. - * - * @return {@code true} if there may be other threads waiting to acquire - */ - public final boolean hasQueuedThreads() { - return head != tail; - } - - /** - * Queries whether any threads have ever contended to acquire this - * synchronizer; that is if an acquire method has ever blocked. - * - * <p>In this implementation, this operation returns in - * constant time. - * - * @return {@code true} if there has ever been contention - */ - public final boolean hasContended() { - return head != null; - } - - /** - * Returns the first (longest-waiting) thread in the queue, or - * {@code null} if no threads are currently queued. - * - * <p>In this implementation, this operation normally returns in - * constant time, but may iterate upon contention if other threads are - * concurrently modifying the queue. - * - * @return the first (longest-waiting) thread in the queue, or - * {@code null} if no threads are currently queued - */ - public final Thread getFirstQueuedThread() { - // handle only fast path, else relay - return (head == tail) ? null : fullGetFirstQueuedThread(); - } - - /** - * Version of getFirstQueuedThread called when fastpath fails - */ - private Thread fullGetFirstQueuedThread() { - /* - * The first node is normally head.next. Try to get its - * thread field, ensuring consistent reads: If thread - * field is nulled out or s.prev is no longer head, then - * some other thread(s) concurrently performed setHead in - * between some of our reads. We try this twice before - * resorting to traversal. - */ - Node h, s; - Thread st; - if (((h = head) != null && (s = h.next) != null && - s.prev == head && (st = s.thread) != null) || - ((h = head) != null && (s = h.next) != null && - s.prev == head && (st = s.thread) != null)) - return st; - - /* - * Head's next field might not have been set yet, or may have - * been unset after setHead. So we must check to see if tail - * is actually first node. If not, we continue on, safely - * traversing from tail back to head to find first, - * guaranteeing termination. - */ - - Node t = tail; - Thread firstThread = null; - while (t != null && t != head) { - Thread tt = t.thread; - if (tt != null) - firstThread = tt; - t = t.prev; - } - return firstThread; - } - - /** - * Returns true if the given thread is currently queued. - * - * <p>This implementation traverses the queue to determine - * presence of the given thread. - * - * @param thread the thread - * @return {@code true} if the given thread is on the queue - * @throws NullPointerException if the thread is null - */ - public final boolean isQueued(Thread thread) { - if (thread == null) - throw new NullPointerException(); - for (Node p = tail; p != null; p = p.prev) - if (p.thread == thread) - return true; - return false; - } - - /** - * Returns {@code true} if the apparent first queued thread, if one - * exists, is waiting in exclusive mode. If this method returns - * {@code true}, and the current thread is attempting to acquire in - * shared mode (that is, this method is invoked from {@link - * #tryAcquireShared}) then it is guaranteed that the current thread - * is not the first queued thread. Used only as a heuristic in - * ReentrantReadWriteLock. - */ - final boolean apparentlyFirstQueuedIsExclusive() { - Node h, s; - return (h = head) != null && - (s = h.next) != null && - !s.isShared() && - s.thread != null; - } - - /** - * Queries whether any threads have been waiting to acquire longer - * than the current thread. - * - * <p>An invocation of this method is equivalent to (but may be - * more efficient than): - * <pre> {@code - * getFirstQueuedThread() != Thread.currentThread() && - * hasQueuedThreads()}</pre> - * - * <p>Note that because cancellations due to interrupts and - * timeouts may occur at any time, a {@code true} return does not - * guarantee that some other thread will acquire before the current - * thread. Likewise, it is possible for another thread to win a - * race to enqueue after this method has returned {@code false}, - * due to the queue being empty. - * - * <p>This method is designed to be used by a fair synchronizer to - * avoid <a href="AbstractQueuedSynchronizer#barging">barging</a>. - * Such a synchronizer's {@link #tryAcquire} method should return - * {@code false}, and its {@link #tryAcquireShared} method should - * return a negative value, if this method returns {@code true} - * (unless this is a reentrant acquire). For example, the {@code - * tryAcquire} method for a fair, reentrant, exclusive mode - * synchronizer might look like this: - * - * <pre> {@code - * protected boolean tryAcquire(int arg) { - * if (isHeldExclusively()) { - * // A reentrant acquire; increment hold count - * return true; - * } else if (hasQueuedPredecessors()) { - * return false; - * } else { - * // try to acquire normally - * } - * }}</pre> - * - * @return {@code true} if there is a queued thread preceding the - * current thread, and {@code false} if the current thread - * is at the head of the queue or the queue is empty - * @since 1.7 - */ - public final boolean hasQueuedPredecessors() { - // The correctness of this depends on head being initialized - // before tail and on head.next being accurate if the current - // thread is first in queue. - Node t = tail; // Read fields in reverse initialization order - Node h = head; - Node s; - return h != t && - ((s = h.next) == null || s.thread != Thread.currentThread()); - } - - - // Instrumentation and monitoring methods - - /** - * Returns an estimate of the number of threads waiting to - * acquire. The value is only an estimate because the number of - * threads may change dynamically while this method traverses - * internal data structures. This method is designed for use in - * monitoring system state, not for synchronization - * control. - * - * @return the estimated number of threads waiting to acquire - */ - public final int getQueueLength() { - int n = 0; - for (Node p = tail; p != null; p = p.prev) { - if (p.thread != null) - ++n; - } - return n; - } - - /** - * Returns a collection containing threads that may be waiting to - * acquire. Because the actual set of threads may change - * dynamically while constructing this result, the returned - * collection is only a best-effort estimate. The elements of the - * returned collection are in no particular order. This method is - * designed to facilitate construction of subclasses that provide - * more extensive monitoring facilities. - * - * @return the collection of threads - */ - public final Collection<Thread> getQueuedThreads() { - ArrayList<Thread> list = new ArrayList<Thread>(); - for (Node p = tail; p != null; p = p.prev) { - Thread t = p.thread; - if (t != null) - list.add(t); - } - return list; - } - - /** - * Returns a collection containing threads that may be waiting to - * acquire in exclusive mode. This has the same properties - * as {@link #getQueuedThreads} except that it only returns - * those threads waiting due to an exclusive acquire. - * - * @return the collection of threads - */ - public final Collection<Thread> getExclusiveQueuedThreads() { - ArrayList<Thread> list = new ArrayList<Thread>(); - for (Node p = tail; p != null; p = p.prev) { - if (!p.isShared()) { - Thread t = p.thread; - if (t != null) - list.add(t); - } - } - return list; - } - - /** - * Returns a collection containing threads that may be waiting to - * acquire in shared mode. This has the same properties - * as {@link #getQueuedThreads} except that it only returns - * those threads waiting due to a shared acquire. - * - * @return the collection of threads - */ - public final Collection<Thread> getSharedQueuedThreads() { - ArrayList<Thread> list = new ArrayList<Thread>(); - for (Node p = tail; p != null; p = p.prev) { - if (p.isShared()) { - Thread t = p.thread; - if (t != null) - list.add(t); - } - } - return list; - } - - /** - * Returns a string identifying this synchronizer, as well as its state. - * The state, in brackets, includes the String {@code "State ="} - * followed by the current value of {@link #getState}, and either - * {@code "nonempty"} or {@code "empty"} depending on whether the - * queue is empty. - * - * @return a string identifying this synchronizer, as well as its state - */ - public String toString() { - int s = getState(); - String q = hasQueuedThreads() ? "non" : ""; - return super.toString() + - "[State = " + s + ", " + q + "empty queue]"; - } - - - // Internal support methods for Conditions - - /** - * Returns true if a node, always one that was initially placed on - * a condition queue, is now waiting to reacquire on sync queue. - * @param node the node - * @return true if is reacquiring - */ - final boolean isOnSyncQueue(Node node) { - if (node.waitStatus == Node.CONDITION || node.prev == null) - return false; - if (node.next != null) // If has successor, it must be on queue - return true; - /* - * node.prev can be non-null, but not yet on queue because - * the CAS to place it on queue can fail. So we have to - * traverse from tail to make sure it actually made it. It - * will always be near the tail in calls to this method, and - * unless the CAS failed (which is unlikely), it will be - * there, so we hardly ever traverse much. - */ - return findNodeFromTail(node); - } - - /** - * Returns true if node is on sync queue by searching backwards from tail. - * Called only when needed by isOnSyncQueue. - * @return true if present - */ - private boolean findNodeFromTail(Node node) { - Node t = tail; - for (;;) { - if (t == node) - return true; - if (t == null) - return false; - t = t.prev; - } - } - - /** - * Transfers a node from a condition queue onto sync queue. - * Returns true if successful. - * @param node the node - * @return true if successfully transferred (else the node was - * cancelled before signal). - */ - final boolean transferForSignal(Node node) { - /* - * If cannot change waitStatus, the node has been cancelled. - */ - if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) - return false; - - /* - * Splice onto queue and try to set waitStatus of predecessor to - * indicate that thread is (probably) waiting. If cancelled or - * attempt to set waitStatus fails, wake up to resync (in which - * case the waitStatus can be transiently and harmlessly wrong). - */ - Node p = enq(node); - int ws = p.waitStatus; - if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) - LockSupport.unpark(node.thread); - return true; - } - - /** - * Transfers node, if necessary, to sync queue after a cancelled - * wait. Returns true if thread was cancelled before being - * signalled. - * @param current the waiting thread - * @param node its node - * @return true if cancelled before the node was signalled - */ - final boolean transferAfterCancelledWait(Node node) { - if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) { - enq(node); - return true; - } - /* - * If we lost out to a signal(), then we can't proceed - * until it finishes its enq(). Cancelling during an - * incomplete transfer is both rare and transient, so just - * spin. - */ - while (!isOnSyncQueue(node)) - Thread.yield(); - return false; - } - - /** - * Invokes release with current state value; returns saved state. - * Cancels node and throws exception on failure. - * @param node the condition node for this wait - * @return previous sync state - */ - final int fullyRelease(Node node) { - boolean failed = true; - try { - int savedState = getState(); - if (release(savedState)) { - failed = false; - return savedState; - } else { - throw new IllegalMonitorStateException(); - } - } finally { - if (failed) - node.waitStatus = Node.CANCELLED; - } - } - - // Instrumentation methods for conditions - - /** - * Queries whether the given ConditionObject - * uses this synchronizer as its lock. - * - * @param condition the condition - * @return <tt>true</tt> if owned - * @throws NullPointerException if the condition is null - */ - public final boolean owns(ConditionObject condition) { - if (condition == null) - throw new NullPointerException(); - return condition.isOwnedBy(this); - } - - /** - * Queries whether any threads are waiting on the given condition - * associated with this synchronizer. Note that because timeouts - * and interrupts may occur at any time, a <tt>true</tt> return - * does not guarantee that a future <tt>signal</tt> will awaken - * any threads. This method is designed primarily for use in - * monitoring of the system state. - * - * @param condition the condition - * @return <tt>true</tt> if there are any waiting threads - * @throws IllegalMonitorStateException if exclusive synchronization - * is not held - * @throws IllegalArgumentException if the given condition is - * not associated with this synchronizer - * @throws NullPointerException if the condition is null - */ - public final boolean hasWaiters(ConditionObject condition) { - if (!owns(condition)) - throw new IllegalArgumentException("Not owner"); - return condition.hasWaiters(); - } - - /** - * Returns an estimate of the number of threads waiting on the - * given condition associated with this synchronizer. Note that - * because timeouts and interrupts may occur at any time, the - * estimate serves only as an upper bound on the actual number of - * waiters. This method is designed for use in monitoring of the - * system state, not for synchronization control. - * - * @param condition the condition - * @return the estimated number of waiting threads - * @throws IllegalMonitorStateException if exclusive synchronization - * is not held - * @throws IllegalArgumentException if the given condition is - * not associated with this synchronizer - * @throws NullPointerException if the condition is null - */ - public final int getWaitQueueLength(ConditionObject condition) { - if (!owns(condition)) - throw new IllegalArgumentException("Not owner"); - return condition.getWaitQueueLength(); - } - - /** - * Returns a collection containing those threads that may be - * waiting on the given condition associated with this - * synchronizer. Because the actual set of threads may change - * dynamically while constructing this result, the returned - * collection is only a best-effort estimate. The elements of the - * returned collection are in no particular order. - * - * @param condition the condition - * @return the collection of threads - * @throws IllegalMonitorStateException if exclusive synchronization - * is not held - * @throws IllegalArgumentException if the given condition is - * not associated with this synchronizer - * @throws NullPointerException if the condition is null - */ - public final Collection<Thread> getWaitingThreads(ConditionObject condition) { - if (!owns(condition)) - throw new IllegalArgumentException("Not owner"); - return condition.getWaitingThreads(); - } - - /** - * Condition implementation for a {@link - * AbstractQueuedSynchronizer} serving as the basis of a {@link - * Lock} implementation. - * - * <p>Method documentation for this class describes mechanics, - * not behavioral specifications from the point of view of Lock - * and Condition users. Exported versions of this class will in - * general need to be accompanied by documentation describing - * condition semantics that rely on those of the associated - * <tt>AbstractQueuedSynchronizer</tt>. - * - * <p>This class is Serializable, but all fields are transient, - * so deserialized conditions have no waiters. - */ - public class ConditionObject implements Condition, java.io.Serializable { - private static final long serialVersionUID = 1173984872572414699L; - /** First node of condition queue. */ - private transient Node firstWaiter; - /** Last node of condition queue. */ - private transient Node lastWaiter; - - /** - * Creates a new <tt>ConditionObject</tt> instance. - */ - public ConditionObject() { } - - // Internal methods - - /** - * Adds a new waiter to wait queue. - * @return its new wait node - */ - private Node addConditionWaiter() { - Node t = lastWaiter; - // If lastWaiter is cancelled, clean out. - if (t != null && t.waitStatus != Node.CONDITION) { - unlinkCancelledWaiters(); - t = lastWaiter; - } - Node node = new Node(Thread.currentThread(), Node.CONDITION); - if (t == null) - firstWaiter = node; - else - t.nextWaiter = node; - lastWaiter = node; - return node; - } - - /** - * Removes and transfers nodes until hit non-cancelled one or - * null. Split out from signal in part to encourage compilers - * to inline the case of no waiters. - * @param first (non-null) the first node on condition queue - */ - private void doSignal(Node first) { - do { - if ( (firstWaiter = first.nextWaiter) == null) - lastWaiter = null; - first.nextWaiter = null; - } while (!transferForSignal(first) && - (first = firstWaiter) != null); - } - - /** - * Removes and transfers all nodes. - * @param first (non-null) the first node on condition queue - */ - private void doSignalAll(Node first) { - lastWaiter = firstWaiter = null; - do { - Node next = first.nextWaiter; - first.nextWaiter = null; - transferForSignal(first); - first = next; - } while (first != null); - } - - /** - * Unlinks cancelled waiter nodes from condition queue. - * Called only while holding lock. This is called when - * cancellation occurred during condition wait, and upon - * insertion of a new waiter when lastWaiter is seen to have - * been cancelled. This method is needed to avoid garbage - * retention in the absence of signals. So even though it may - * require a full traversal, it comes into play only when - * timeouts or cancellations occur in the absence of - * signals. It traverses all nodes rather than stopping at a - * particular target to unlink all pointers to garbage nodes - * without requiring many re-traversals during cancellation - * storms. - */ - private void unlinkCancelledWaiters() { - Node t = firstWaiter; - Node trail = null; - while (t != null) { - Node next = t.nextWaiter; - if (t.waitStatus != Node.CONDITION) { - t.nextWaiter = null; - if (trail == null) - firstWaiter = next; - else - trail.nextWaiter = next; - if (next == null) - lastWaiter = trail; - } - else - trail = t; - t = next; - } - } - - // public methods - - /** - * Moves the longest-waiting thread, if one exists, from the - * wait queue for this condition to the wait queue for the - * owning lock. - * - * @throws IllegalMonitorStateException if {@link #isHeldExclusively} - * returns {@code false} - */ - public final void signal() { - if (!isHeldExclusively()) - throw new IllegalMonitorStateException(); - Node first = firstWaiter; - if (first != null) - doSignal(first); - } - - /** - * Moves all threads from the wait queue for this condition to - * the wait queue for the owning lock. - * - * @throws IllegalMonitorStateException if {@link #isHeldExclusively} - * returns {@code false} - */ - public final void signalAll() { - if (!isHeldExclusively()) - throw new IllegalMonitorStateException(); - Node first = firstWaiter; - if (first != null) - doSignalAll(first); - } - - /** - * Implements uninterruptible condition wait. - * <ol> - * <li> Save lock state returned by {@link #getState}. - * <li> Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. - * <li> Block until signalled. - * <li> Reacquire by invoking specialized version of - * {@link #acquire} with saved state as argument. - * </ol> - */ - public final void awaitUninterruptibly() { - Node node = addConditionWaiter(); - int savedState = fullyRelease(node); - boolean interrupted = false; - while (!isOnSyncQueue(node)) { - LockSupport.park(this); - if (Thread.interrupted()) - interrupted = true; - } - if (acquireQueued(node, savedState) || interrupted) - selfInterrupt(); - } - - /* - * For interruptible waits, we need to track whether to throw - * InterruptedException, if interrupted while blocked on - * condition, versus reinterrupt current thread, if - * interrupted while blocked waiting to re-acquire. - */ - - /** Mode meaning to reinterrupt on exit from wait */ - private static final int REINTERRUPT = 1; - /** Mode meaning to throw InterruptedException on exit from wait */ - private static final int THROW_IE = -1; - - /** - * Checks for interrupt, returning THROW_IE if interrupted - * before signalled, REINTERRUPT if after signalled, or - * 0 if not interrupted. - */ - private int checkInterruptWhileWaiting(Node node) { - return Thread.interrupted() ? - (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) : - 0; - } - - /** - * Throws InterruptedException, reinterrupts current thread, or - * does nothing, depending on mode. - */ - private void reportInterruptAfterWait(int interruptMode) - throws InterruptedException { - if (interruptMode == THROW_IE) - throw new InterruptedException(); - else if (interruptMode == REINTERRUPT) - selfInterrupt(); - } - - /** - * Implements interruptible condition wait. - * <ol> - * <li> If current thread is interrupted, throw InterruptedException. - * <li> Save lock state returned by {@link #getState}. - * <li> Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. - * <li> Block until signalled or interrupted. - * <li> Reacquire by invoking specialized version of - * {@link #acquire} with saved state as argument. - * <li> If interrupted while blocked in step 4, throw InterruptedException. - * </ol> - */ - public final void await() throws InterruptedException { - if (Thread.interrupted()) - throw new InterruptedException(); - Node node = addConditionWaiter(); - int savedState = fullyRelease(node); - int interruptMode = 0; - while (!isOnSyncQueue(node)) { - LockSupport.park(this); - if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) - break; - } - if (acquireQueued(node, savedState) && interruptMode != THROW_IE) - interruptMode = REINTERRUPT; - if (node.nextWaiter != null) // clean up if cancelled - unlinkCancelledWaiters(); - if (interruptMode != 0) - reportInterruptAfterWait(interruptMode); - } - - /** - * Implements timed condition wait. - * <ol> - * <li> If current thread is interrupted, throw InterruptedException. - * <li> Save lock state returned by {@link #getState}. - * <li> Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. - * <li> Block until signalled, interrupted, or timed out. - * <li> Reacquire by invoking specialized version of - * {@link #acquire} with saved state as argument. - * <li> If interrupted while blocked in step 4, throw InterruptedException. - * </ol> - */ - public final long awaitNanos(long nanosTimeout) - throws InterruptedException { - if (Thread.interrupted()) - throw new InterruptedException(); - Node node = addConditionWaiter(); - int savedState = fullyRelease(node); - long lastTime = System.nanoTime(); - int interruptMode = 0; - while (!isOnSyncQueue(node)) { - if (nanosTimeout <= 0L) { - transferAfterCancelledWait(node); - break; - } - LockSupport.parkNanos(this, nanosTimeout); - if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) - break; - - long now = System.nanoTime(); - nanosTimeout -= now - lastTime; - lastTime = now; - } - if (acquireQueued(node, savedState) && interruptMode != THROW_IE) - interruptMode = REINTERRUPT; - if (node.nextWaiter != null) - unlinkCancelledWaiters(); - if (interruptMode != 0) - reportInterruptAfterWait(interruptMode); - return nanosTimeout - (System.nanoTime() - lastTime); - } - - /** - * Implements absolute timed condition wait. - * <ol> - * <li> If current thread is interrupted, throw InterruptedException. - * <li> Save lock state returned by {@link #getState}. - * <li> Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. - * <li> Block until signalled, interrupted, or timed out. - * <li> Reacquire by invoking specialized version of - * {@link #acquire} with saved state as argument. - * <li> If interrupted while blocked in step 4, throw InterruptedException. - * <li> If timed out while blocked in step 4, return false, else true. - * </ol> - */ - public final boolean awaitUntil(Date deadline) - throws InterruptedException { - if (deadline == null) - throw new NullPointerException(); - long abstime = deadline.getTime(); - if (Thread.interrupted()) - throw new InterruptedException(); - Node node = addConditionWaiter(); - int savedState = fullyRelease(node); - boolean timedout = false; - int interruptMode = 0; - while (!isOnSyncQueue(node)) { - if (System.currentTimeMillis() > abstime) { - timedout = transferAfterCancelledWait(node); - break; - } - LockSupport.parkUntil(this, abstime); - if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) - break; - } - if (acquireQueued(node, savedState) && interruptMode != THROW_IE) - interruptMode = REINTERRUPT; - if (node.nextWaiter != null) - unlinkCancelledWaiters(); - if (interruptMode != 0) - reportInterruptAfterWait(interruptMode); - return !timedout; - } - - /** - * Implements timed condition wait. - * <ol> - * <li> If current thread is interrupted, throw InterruptedException. - * <li> Save lock state returned by {@link #getState}. - * <li> Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. - * <li> Block until signalled, interrupted, or timed out. - * <li> Reacquire by invoking specialized version of - * {@link #acquire} with saved state as argument. - * <li> If interrupted while blocked in step 4, throw InterruptedException. - * <li> If timed out while blocked in step 4, return false, else true. - * </ol> - */ - public final boolean await(long time, TimeUnit unit) - throws InterruptedException { - if (unit == null) - throw new NullPointerException(); - long nanosTimeout = unit.toNanos(time); - if (Thread.interrupted()) - throw new InterruptedException(); - Node node = addConditionWaiter(); - int savedState = fullyRelease(node); - long lastTime = System.nanoTime(); - boolean timedout = false; - int interruptMode = 0; - while (!isOnSyncQueue(node)) { - if (nanosTimeout <= 0L) { - timedout = transferAfterCancelledWait(node); - break; - } - if (nanosTimeout >= spinForTimeoutThreshold) - LockSupport.parkNanos(this, nanosTimeout); - if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) - break; - long now = System.nanoTime(); - nanosTimeout -= now - lastTime; - lastTime = now; - } - if (acquireQueued(node, savedState) && interruptMode != THROW_IE) - interruptMode = REINTERRUPT; - if (node.nextWaiter != null) - unlinkCancelledWaiters(); - if (interruptMode != 0) - reportInterruptAfterWait(interruptMode); - return !timedout; - } - - // support for instrumentation - - /** - * Returns true if this condition was created by the given - * synchronization object. - * - * @return {@code true} if owned - */ - final boolean isOwnedBy(AbstractQueuedSynchronizer sync) { - return sync == AbstractQueuedSynchronizer.this; - } - - /** - * Queries whether any threads are waiting on this condition. - * Implements {@link AbstractQueuedSynchronizer#hasWaiters}. - * - * @return {@code true} if there are any waiting threads - * @throws IllegalMonitorStateException if {@link #isHeldExclusively} - * returns {@code false} - */ - protected final boolean hasWaiters() { - if (!isHeldExclusively()) - throw new IllegalMonitorStateException(); - for (Node w = firstWaiter; w != null; w = w.nextWaiter) { - if (w.waitStatus == Node.CONDITION) - return true; - } - return false; - } - - /** - * Returns an estimate of the number of threads waiting on - * this condition. - * Implements {@link AbstractQueuedSynchronizer#getWaitQueueLength}. - * - * @return the estimated number of waiting threads - * @throws IllegalMonitorStateException if {@link #isHeldExclusively} - * returns {@code false} - */ - protected final int getWaitQueueLength() { - if (!isHeldExclusively()) - throw new IllegalMonitorStateException(); - int n = 0; - for (Node w = firstWaiter; w != null; w = w.nextWaiter) { - if (w.waitStatus == Node.CONDITION) - ++n; - } - return n; - } - - /** - * Returns a collection containing those threads that may be - * waiting on this Condition. - * Implements {@link AbstractQueuedSynchronizer#getWaitingThreads}. - * - * @return the collection of threads - * @throws IllegalMonitorStateException if {@link #isHeldExclusively} - * returns {@code false} - */ - protected final Collection<Thread> getWaitingThreads() { - if (!isHeldExclusively()) - throw new IllegalMonitorStateException(); - ArrayList<Thread> list = new ArrayList<Thread>(); - for (Node w = firstWaiter; w != null; w = w.nextWaiter) { - if (w.waitStatus == Node.CONDITION) { - Thread t = w.thread; - if (t != null) - list.add(t); - } - } - return list; - } - } - - /** - * IKVM specific. We use AtomicReferenceFieldUpdater instead of Unsafe primitives. - */ - private static final AtomicReferenceFieldUpdater<AbstractQueuedSynchronizer, Node> headUpdater = - AtomicReferenceFieldUpdater.newUpdater(AbstractQueuedSynchronizer.class, Node.class, "head"); - private static final AtomicReferenceFieldUpdater<AbstractQueuedSynchronizer, Node> tailUpdater = - AtomicReferenceFieldUpdater.newUpdater(AbstractQueuedSynchronizer.class, Node.class, "tail"); - - /** - * CAS head field. Used only by enq. - */ - private final boolean compareAndSetHead(Node update) { - return headUpdater.compareAndSet(this, null, update); - } - - /** - * CAS tail field. Used only by enq. - */ - private final boolean compareAndSetTail(Node expect, Node update) { - return tailUpdater.compareAndSet(this, expect, update); - } - - /** - * CAS waitStatus field of a node. - */ - private static final native boolean compareAndSetWaitStatus(Node node, - int expect, - int update); // implemented in map.xml - /** - * CAS next field of a node. - */ - private static final boolean compareAndSetNext(Node node, - Node expect, - Node update) { - return Node.nextUpdater.compareAndSet(node, expect, update); - } -} diff --git a/openjdk/java/util/concurrent/locks/LockSupport.java b/openjdk/java/util/concurrent/locks/LockSupport.java deleted file mode 100644 index 45a38112..00000000 --- a/openjdk/java/util/concurrent/locks/LockSupport.java +++ /dev/null @@ -1,456 +0,0 @@ -/* - * 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. - */ - -/* - * This file is available under and governed by the GNU General Public - * License version 2 only, as published by the Free Software Foundation. - * However, the following notice accompanied the original version of this - * file: - * - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/publicdomain/zero/1.0/ - */ - -package java.util.concurrent.locks; - -/** - * Basic thread blocking primitives for creating locks and other - * synchronization classes. - * - * <p>This class associates, with each thread that uses it, a permit - * (in the sense of the {@link java.util.concurrent.Semaphore - * Semaphore} class). A call to {@code park} will return immediately - * if the permit is available, consuming it in the process; otherwise - * it <em>may</em> block. A call to {@code unpark} makes the permit - * available, if it was not already available. (Unlike with Semaphores - * though, permits do not accumulate. There is at most one.) - * - * <p>Methods {@code park} and {@code unpark} provide efficient - * means of blocking and unblocking threads that do not encounter the - * problems that cause the deprecated methods {@code Thread.suspend} - * and {@code Thread.resume} to be unusable for such purposes: Races - * between one thread invoking {@code park} and another thread trying - * to {@code unpark} it will preserve liveness, due to the - * permit. Additionally, {@code park} will return if the caller's - * thread was interrupted, and timeout versions are supported. The - * {@code park} method may also return at any other time, for "no - * reason", so in general must be invoked within a loop that rechecks - * conditions upon return. In this sense {@code park} serves as an - * optimization of a "busy wait" that does not waste as much time - * spinning, but must be paired with an {@code unpark} to be - * effective. - * - * <p>The three forms of {@code park} each also support a - * {@code blocker} object parameter. This object is recorded while - * the thread is blocked to permit monitoring and diagnostic tools to - * identify the reasons that threads are blocked. (Such tools may - * access blockers using method {@link #getBlocker(Thread)}.) - * The use of these forms rather than the original forms without this - * parameter is strongly encouraged. The normal argument to supply as - * a {@code blocker} within a lock implementation is {@code this}. - * - * <p>These methods are designed to be used as tools for creating - * higher-level synchronization utilities, and are not in themselves - * useful for most concurrency control applications. The {@code park} - * method is designed for use only in constructions of the form: - * - * <pre> {@code - * while (!canProceed()) { ... LockSupport.park(this); }}</pre> - * - * where neither {@code canProceed} nor any other actions prior to the - * call to {@code park} entail locking or blocking. Because only one - * permit is associated with each thread, any intermediary uses of - * {@code park} could interfere with its intended effects. - * - * <p><b>Sample Usage.</b> Here is a sketch of a first-in-first-out - * non-reentrant lock class: - * <pre> {@code - * class FIFOMutex { - * private final AtomicBoolean locked = new AtomicBoolean(false); - * private final Queue<Thread> waiters - * = new ConcurrentLinkedQueue<Thread>(); - * - * public void lock() { - * boolean wasInterrupted = false; - * Thread current = Thread.currentThread(); - * waiters.add(current); - * - * // Block while not first in queue or cannot acquire lock - * while (waiters.peek() != current || - * !locked.compareAndSet(false, true)) { - * LockSupport.park(this); - * if (Thread.interrupted()) // ignore interrupts while waiting - * wasInterrupted = true; - * } - * - * waiters.remove(); - * if (wasInterrupted) // reassert interrupt status on exit - * current.interrupt(); - * } - * - * public void unlock() { - * locked.set(false); - * LockSupport.unpark(waiters.peek()); - * } - * }}</pre> - */ -public class LockSupport { - private LockSupport() {} // Cannot be instantiated. - - private static void setBlocker(Thread t, Object arg) { - t.parkBlocker = arg; - } - - private static final int PARK_STATE_RUNNING = 0; - private static final int PARK_STATE_PERMIT = 1; - private static final int PARK_STATE_PARKED = 2; - - // these native methods are all implemented in map.xml - private static native int cmpxchgParkState(Thread t, int newValue, int comparand); - private static native Object getParkLock(Thread t); - private static native void setParkLock(Thread t, Object obj); - - /** - * Makes available the permit for the given thread, if it - * was not already available. If the thread was blocked on - * {@code park} then it will unblock. Otherwise, its next call - * to {@code park} is guaranteed not to block. This operation - * is not guaranteed to have any effect at all if the given - * thread has not been started. - * - * @param thread the thread to unpark, or {@code null}, in which case - * this operation has no effect - */ - public static void unpark(Thread thread) { - if (thread != null) - { - if (cmpxchgParkState(thread, PARK_STATE_PERMIT, PARK_STATE_RUNNING) == PARK_STATE_PARKED) - { - if (cmpxchgParkState(thread, PARK_STATE_RUNNING, PARK_STATE_PARKED) == PARK_STATE_PARKED) - { - // thread is currently blocking, so we have to release it - Object lock = getParkLock(thread); - synchronized (lock) - { - lock.notify(); - } - } - } - } - } - - private static void parkImpl(Thread currentThread, boolean deadline, long nanos) - { - if (cmpxchgParkState(currentThread, PARK_STATE_RUNNING, PARK_STATE_PERMIT) == PARK_STATE_PERMIT) - { - // we consumed a permit - return; - } - - Object lock = getParkLock(currentThread); - if (lock == null) - { - // we lazily allocate the lock object - lock = new Object(); - setParkLock(currentThread, lock); - } - synchronized (lock) - { - if (cmpxchgParkState(currentThread, PARK_STATE_PARKED, PARK_STATE_RUNNING) == PARK_STATE_PERMIT) - { - // entering the parked state failed because we got a permit after the previous permit test - // release the permit and return - cmpxchgParkState(currentThread, PARK_STATE_RUNNING, PARK_STATE_PERMIT); - return; - } - if (deadline) - { - nanos -= System.currentTimeMillis() * 1000000; - } - if (nanos >= 0) - { - try - { - lock.wait(nanos / 1000000, (int)(nanos % 1000000)); - } - catch (InterruptedException _) - { - currentThread.interrupt(); - } - } - cmpxchgParkState(currentThread, PARK_STATE_RUNNING, PARK_STATE_PARKED); - } - } - - /** - * Disables the current thread for thread scheduling purposes unless the - * permit is available. - * - * <p>If the permit is available then it is consumed and the call returns - * immediately; otherwise - * the current thread becomes disabled for thread scheduling - * purposes and lies dormant until one of three things happens: - * - * <ul> - * <li>Some other thread invokes {@link #unpark unpark} with the - * current thread as the target; or - * - * <li>Some other thread {@linkplain Thread#interrupt interrupts} - * the current thread; or - * - * <li>The call spuriously (that is, for no reason) returns. - * </ul> - * - * <p>This method does <em>not</em> report which of these caused the - * method to return. Callers should re-check the conditions which caused - * the thread to park in the first place. Callers may also determine, - * for example, the interrupt status of the thread upon return. - * - * @param blocker the synchronization object responsible for this - * thread parking - * @since 1.6 - */ - public static void park(Object blocker) { - Thread t = Thread.currentThread(); - setBlocker(t, blocker); - parkImpl(t, false, 0L); - setBlocker(t, null); - } - - /** - * Disables the current thread for thread scheduling purposes, for up to - * the specified waiting time, unless the permit is available. - * - * <p>If the permit is available then it is consumed and the call - * returns immediately; otherwise the current thread becomes disabled - * for thread scheduling purposes and lies dormant until one of four - * things happens: - * - * <ul> - * <li>Some other thread invokes {@link #unpark unpark} with the - * current thread as the target; or - * - * <li>Some other thread {@linkplain Thread#interrupt interrupts} - * the current thread; or - * - * <li>The specified waiting time elapses; or - * - * <li>The call spuriously (that is, for no reason) returns. - * </ul> - * - * <p>This method does <em>not</em> report which of these caused the - * method to return. Callers should re-check the conditions which caused - * the thread to park in the first place. Callers may also determine, - * for example, the interrupt status of the thread, or the elapsed time - * upon return. - * - * @param blocker the synchronization object responsible for this - * thread parking - * @param nanos the maximum number of nanoseconds to wait - * @since 1.6 - */ - public static void parkNanos(Object blocker, long nanos) { - if (nanos > 0) { - Thread t = Thread.currentThread(); - setBlocker(t, blocker); - parkImpl(t, false, nanos); - setBlocker(t, null); - } - } - - /** - * Disables the current thread for thread scheduling purposes, until - * the specified deadline, unless the permit is available. - * - * <p>If the permit is available then it is consumed and the call - * returns immediately; otherwise the current thread becomes disabled - * for thread scheduling purposes and lies dormant until one of four - * things happens: - * - * <ul> - * <li>Some other thread invokes {@link #unpark unpark} with the - * current thread as the target; or - * - * <li>Some other thread {@linkplain Thread#interrupt interrupts} the - * current thread; or - * - * <li>The specified deadline passes; or - * - * <li>The call spuriously (that is, for no reason) returns. - * </ul> - * - * <p>This method does <em>not</em> report which of these caused the - * method to return. Callers should re-check the conditions which caused - * the thread to park in the first place. Callers may also determine, - * for example, the interrupt status of the thread, or the current time - * upon return. - * - * @param blocker the synchronization object responsible for this - * thread parking - * @param deadline the absolute time, in milliseconds from the Epoch, - * to wait until - * @since 1.6 - */ - public static void parkUntil(Object blocker, long deadline) { - Thread t = Thread.currentThread(); - setBlocker(t, blocker); - parkImpl(t, true, deadline * 1000000); - setBlocker(t, null); - } - - /** - * Returns the blocker object supplied to the most recent - * invocation of a park method that has not yet unblocked, or null - * if not blocked. The value returned is just a momentary - * snapshot -- the thread may have since unblocked or blocked on a - * different blocker object. - * - * @param t the thread - * @return the blocker - * @throws NullPointerException if argument is null - * @since 1.6 - */ - public static Object getBlocker(Thread t) { - if (t == null) - throw new NullPointerException(); - return t.parkBlocker; - } - - /** - * Disables the current thread for thread scheduling purposes unless the - * permit is available. - * - * <p>If the permit is available then it is consumed and the call - * returns immediately; otherwise the current thread becomes disabled - * for thread scheduling purposes and lies dormant until one of three - * things happens: - * - * <ul> - * - * <li>Some other thread invokes {@link #unpark unpark} with the - * current thread as the target; or - * - * <li>Some other thread {@linkplain Thread#interrupt interrupts} - * the current thread; or - * - * <li>The call spuriously (that is, for no reason) returns. - * </ul> - * - * <p>This method does <em>not</em> report which of these caused the - * method to return. Callers should re-check the conditions which caused - * the thread to park in the first place. Callers may also determine, - * for example, the interrupt status of the thread upon return. - */ - public static void park() { - parkImpl(Thread.currentThread(), false, 0L); - } - - /** - * Disables the current thread for thread scheduling purposes, for up to - * the specified waiting time, unless the permit is available. - * - * <p>If the permit is available then it is consumed and the call - * returns immediately; otherwise the current thread becomes disabled - * for thread scheduling purposes and lies dormant until one of four - * things happens: - * - * <ul> - * <li>Some other thread invokes {@link #unpark unpark} with the - * current thread as the target; or - * - * <li>Some other thread {@linkplain Thread#interrupt interrupts} - * the current thread; or - * - * <li>The specified waiting time elapses; or - * - * <li>The call spuriously (that is, for no reason) returns. - * </ul> - * - * <p>This method does <em>not</em> report which of these caused the - * method to return. Callers should re-check the conditions which caused - * the thread to park in the first place. Callers may also determine, - * for example, the interrupt status of the thread, or the elapsed time - * upon return. - * - * @param nanos the maximum number of nanoseconds to wait - */ - public static void parkNanos(long nanos) { - if (nanos > 0) - parkImpl(Thread.currentThread(), false, nanos); - } - - /** - * Disables the current thread for thread scheduling purposes, until - * the specified deadline, unless the permit is available. - * - * <p>If the permit is available then it is consumed and the call - * returns immediately; otherwise the current thread becomes disabled - * for thread scheduling purposes and lies dormant until one of four - * things happens: - * - * <ul> - * <li>Some other thread invokes {@link #unpark unpark} with the - * current thread as the target; or - * - * <li>Some other thread {@linkplain Thread#interrupt interrupts} - * the current thread; or - * - * <li>The specified deadline passes; or - * - * <li>The call spuriously (that is, for no reason) returns. - * </ul> - * - * <p>This method does <em>not</em> report which of these caused the - * method to return. Callers should re-check the conditions which caused - * the thread to park in the first place. Callers may also determine, - * for example, the interrupt status of the thread, or the current time - * upon return. - * - * @param deadline the absolute time, in milliseconds from the Epoch, - * to wait until - */ - public static void parkUntil(long deadline) { - parkImpl(Thread.currentThread(), true, deadline * 1000000); - } - - /** - * Returns the pseudo-randomly initialized or updated secondary seed. - * Copied from ThreadLocalRandom due to package access restrictions. - */ - static final int nextSecondarySeed() { - int r; - Thread t = Thread.currentThread(); - if ((r = t.threadLocalRandomSecondarySeed) != 0) { - r ^= r << 13; // xorshift - r ^= r >>> 17; - r ^= r << 5; - } - else if ((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) == 0) - r = 1; // avoid zero - t.threadLocalRandomSecondarySeed = r; - return r; - } - -} diff --git a/openjdk/java/util/zip/Adler32.java b/openjdk/java/util/zip/Adler32.java deleted file mode 100644 index fc1536aa..00000000 --- a/openjdk/java/util/zip/Adler32.java +++ /dev/null @@ -1,205 +0,0 @@ -/* Adler32.java - Computes Adler32 data checksum of a data stream - Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - -package java.util.zip; - -/* - * Written using on-line Java Platform 1.2 API Specification, as well - * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). - * The actual Adler32 algorithm is taken from RFC 1950. - * Status: Believed complete and correct. - */ - -/** - * Computes Adler32 checksum for a stream of data. An Adler32 - * checksum is not as reliable as a CRC32 checksum, but a lot faster to - * compute. - *<p> - * The specification for Adler32 may be found in RFC 1950. - * (ZLIB Compressed Data Format Specification version 3.3) - *<p> - *<p> - * From that document: - *<p> - * "ADLER32 (Adler-32 checksum) - * This contains a checksum value of the uncompressed data - * (excluding any dictionary data) computed according to Adler-32 - * algorithm. This algorithm is a 32-bit extension and improvement - * of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073 - * standard. - *<p> - * Adler-32 is composed of two sums accumulated per byte: s1 is - * the sum of all bytes, s2 is the sum of all s1 values. Both sums - * are done modulo 65521. s1 is initialized to 1, s2 to zero. The - * Adler-32 checksum is stored as s2*65536 + s1 in most- - * significant-byte first (network) order." - *<p> - * "8.2. The Adler-32 algorithm - *<p> - * The Adler-32 algorithm is much faster than the CRC32 algorithm yet - * still provides an extremely low probability of undetected errors. - *<p> - * The modulo on unsigned long accumulators can be delayed for 5552 - * bytes, so the modulo operation time is negligible. If the bytes - * are a, b, c, the second sum is 3a + 2b + c + 3, and so is position - * and order sensitive, unlike the first sum, which is just a - * checksum. That 65521 is prime is important to avoid a possible - * large class of two-byte errors that leave the check unchanged. - * (The Fletcher checksum uses 255, which is not prime and which also - * makes the Fletcher check insensitive to single byte changes 0 <-> - * 255.) - *<p> - * The sum s1 is initialized to 1 instead of zero to make the length - * of the sequence part of s2, so that the length does not have to be - * checked separately. (Any sequence of zeroes has a Fletcher - * checksum of zero.)" - * - * @author John Leuner, Per Bothner - * @since JDK 1.1 - * - * @see InflaterInputStream - * @see DeflaterOutputStream - */ -public class Adler32 implements Checksum -{ - - /** largest prime smaller than 65536 */ - private static final int BASE = 65521; - - private int adler; //we do all in int. - - //Note that java doesn't have unsigned integers, - //so we have to be careful with what arithmetic - //we do. We return the checksum as a long to - //avoid sign confusion. - - /** - * Creates a new instance of the <code>Adler32</code> class. - * The checksum starts off with a value of 1. - */ - public Adler32 () - { - reset(); - } - - /** - * Resets the Adler32 checksum to the initial value. - */ - public void reset () - { - adler = 1; //Initialize to 1 - } - - /** - * Updates the checksum with the byte b. - * - * @param bval the data value to add. The high byte of the int is ignored. - */ - public void update (int bval) - { - //We could make a length 1 byte array and call update again, but I - //would rather not have that overhead - int s1 = adler & 0xffff; - int s2 = adler >>> 16; - - s1 = (s1 + (bval & 0xFF)) % BASE; - s2 = (s1 + s2) % BASE; - - adler = (s2 << 16) + s1; - } - - /** - * Updates the checksum with the bytes taken from the array. - * - * @param buffer an array of bytes - */ - public void update (byte[] buffer) - { - update(buffer, 0, buffer.length); - } - - /** - * Updates the checksum with the bytes taken from the array. - * - * @param buf an array of bytes - * @param off the start of the data used for this update - * @param len the number of bytes to use for this update - */ - public void update (byte[] buf, int off, int len) - { - //(By Per Bothner) - int s1 = adler & 0xffff; - int s2 = adler >>> 16; - - while (len > 0) - { - // We can defer the modulo operation: - // s1 maximally grows from 65521 to 65521 + 255 * 3800 - // s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31 - int n = 3800; - if (n > len) - n = len; - len -= n; - while (--n >= 0) - { - s1 = s1 + (buf[off++] & 0xFF); - s2 = s2 + s1; - } - s1 %= BASE; - s2 %= BASE; - } - - /*Old implementation, borrowed from somewhere: - int n; - - while (len-- > 0) { - - s1 = (s1 + (bs[offset++] & 0xff)) % BASE; - s2 = (s2 + s1) % BASE; - }*/ - - adler = (s2 << 16) | s1; - } - - /** - * Returns the Adler32 data checksum computed so far. - */ - public long getValue() - { - return (long) adler & 0xffffffffL; - } -} diff --git a/openjdk/java/util/zip/CRC32.java b/openjdk/java/util/zip/CRC32.java deleted file mode 100644 index cea9a848..00000000 --- a/openjdk/java/util/zip/CRC32.java +++ /dev/null @@ -1,132 +0,0 @@ -/* CRC32.java - Computes CRC32 data checksum of a data stream - Copyright (C) 1999. 2000, 2001 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - -package java.util.zip; - -/* - * Written using on-line Java Platform 1.2 API Specification, as well - * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). - * The actual CRC32 algorithm is taken from RFC 1952. - * Status: Believed complete and correct. - */ - -/** - * Computes CRC32 data checksum of a data stream. - * The actual CRC32 algorithm is described in RFC 1952 - * (GZIP file format specification version 4.3). - * Can be used to get the CRC32 over a stream if used with checked input/output - * streams. - * - * @see InflaterInputStream - * @see DeflaterOutputStream - * - * @author Per Bothner - * @date April 1, 1999. - */ -public class CRC32 implements Checksum -{ - /** The crc data checksum so far. */ - private int crc = 0; - - /** The fast CRC table. Computed once when the CRC32 class is loaded. */ - private static int[] crc_table = make_crc_table(); - - /** Make the table for a fast CRC. */ - private static int[] make_crc_table () - { - int[] crc_table = new int[256]; - for (int n = 0; n < 256; n++) - { - int c = n; - for (int k = 8; --k >= 0; ) - { - if ((c & 1) != 0) - c = 0xedb88320 ^ (c >>> 1); - else - c = c >>> 1; - } - crc_table[n] = c; - } - return crc_table; - } - - /** - * Returns the CRC32 data checksum computed so far. - */ - public long getValue () - { - return (long) crc & 0xffffffffL; - } - - /** - * Resets the CRC32 data checksum as if no update was ever called. - */ - public void reset () { crc = 0; } - - /** - * Updates the checksum with the int bval. - * - * @param bval (the byte is taken as the lower 8 bits of bval) - */ - - public void update (int bval) - { - int c = ~crc; - c = crc_table[(c ^ bval) & 0xff] ^ (c >>> 8); - crc = ~c; - } - - /** - * Adds the byte array to the data checksum. - * - * @param buf the buffer which contains the data - * @param off the offset in the buffer where the data starts - * @param len the length of the data - */ - public void update (byte[] buf, int off, int len) - { - int c = ~crc; - while (--len >= 0) - c = crc_table[(c ^ buf[off++]) & 0xff] ^ (c >>> 8); - crc = ~c; - } - - /** - * Adds the complete byte array to the data checksum. - */ - public void update (byte[] buf) { update(buf, 0, buf.length); } -} diff --git a/openjdk/java/util/zip/ClassStubZipEntry.java b/openjdk/java/util/zip/ClassStubZipEntry.java deleted file mode 100644 index 6a2a6df5..00000000 --- a/openjdk/java/util/zip/ClassStubZipEntry.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - Copyright (C) 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 - -*/ -package java.util.zip; - -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.io.IOException; -import java.util.LinkedHashMap; - -final class ClassStubZipEntry extends ZipEntry -{ - private final String zipFilePath; - - ClassStubZipEntry(String zipFilePath, String name) - { - super(name); - this.zipFilePath = zipFilePath; - } - - private File getFile() - { - return new File(new File(zipFilePath).getParentFile().getParentFile(), "classes" + File.separator + name); - } - - public long getSize() - { - if (size == -1) - { - size = getFile().length(); - } - return size; - } - - public long getCompressedSize() - { - if (csize == -1) - { - csize = getSize(); - } - return csize; - } - - public long getCrc() - { - if (crc == -1) - { - crc = computeCrc(); - } - return crc; - } - - private long computeCrc() - { - try (InputStream in = getInputStream()) - { - CRC32 crc = new CRC32(); - int b; - while ((b = in.read()) != -1) - { - crc.update(b); - } - return crc.getValue(); - } - catch (IOException _) - { - return 0; - } - } - - final InputStream getInputStream() throws IOException - { - return new FileInputStream(getFile()); - } - - static native void expandIkvmClasses(ZipFile zipFile, LinkedHashMap<String, ZipEntry> entries); -} diff --git a/openjdk/java/util/zip/Deflater.java b/openjdk/java/util/zip/Deflater.java deleted file mode 100644 index 3c2a48ef..00000000 --- a/openjdk/java/util/zip/Deflater.java +++ /dev/null @@ -1,569 +0,0 @@ -/* Deflater.java - Compress a data stream - Copyright (C) 1999, 2000, 2001, 2004, 2005, 2011 - Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - -package java.util.zip; - -/** - * This is the Deflater class. The deflater class compresses input - * with the deflate algorithm described in RFC 1951. It has several - * compression levels and three different strategies described below. - * - * This class is <i>not</i> thread safe. This is inherent in the API, due - * to the split of deflate and setInput. - * - * @author Jochen Hoenicke - * @author Tom Tromey - */ -public class Deflater -{ - /** - * The best and slowest compression level. This tries to find very - * long and distant string repetitions. - */ - public static final int BEST_COMPRESSION = 9; - /** - * The worst but fastest compression level. - */ - public static final int BEST_SPEED = 1; - /** - * The default compression level. - */ - public static final int DEFAULT_COMPRESSION = -1; - /** - * This level won't compress at all but output uncompressed blocks. - */ - public static final int NO_COMPRESSION = 0; - - /** - * Flush operation. - */ - public static final int NO_FLUSH = 0; - public static final int SYNC_FLUSH = 2; - public static final int FULL_FLUSH = 3; - - /** - * The default strategy. - */ - public static final int DEFAULT_STRATEGY = 0; - /** - * This strategy will only allow longer string repetitions. It is - * useful for random data with a small character set. - */ - public static final int FILTERED = 1; - - /** - * This strategy will not look for string repetitions at all. It - * only encodes with Huffman trees (which means, that more common - * characters get a smaller encoding. - */ - public static final int HUFFMAN_ONLY = 2; - - /** - * The compression method. This is the only method supported so far. - * There is no need to use this constant at all. - */ - public static final int DEFLATED = 8; - - /* - * The Deflater can do the following state transitions: - * - * (1) -> INIT_STATE ----> INIT_FINISHING_STATE ---. - * / | (2) (5) | - * / v (5) | - * (3)| SETDICT_STATE ---> SETDICT_FINISHING_STATE |(3) - * \ | (3) | ,-------' - * | | | (3) / - * v v (5) v v - * (1) -> BUSY_STATE ----> FINISHING_STATE - * | (6) - * v - * FINISHED_STATE - * \_____________________________________/ - * | (7) - * v - * CLOSED_STATE - * - * (1) If we should produce a header we start in INIT_STATE, otherwise - * we start in BUSY_STATE. - * (2) A dictionary may be set only when we are in INIT_STATE, then - * we change the state as indicated. - * (3) Whether a dictionary is set or not, on the first call of deflate - * we change to BUSY_STATE. - * (4) -- intentionally left blank -- :) - * (5) FINISHING_STATE is entered, when flush() is called to indicate that - * there is no more INPUT. There are also states indicating, that - * the header wasn't written yet. - * (6) FINISHED_STATE is entered, when everything has been flushed to the - * internal pending output buffer. - * (7) At any time (7) - * - */ - - private static final int IS_SETDICT = 0x01; - private static final int IS_FINISHING = 0x08; - - private static final int INIT_STATE = 0x00; - private static final int SETDICT_STATE = 0x01; - private static final int INIT_FINISHING_STATE = 0x08; - private static final int SETDICT_FINISHING_STATE = 0x09; - private static final int BUSY_STATE = 0x10; - private static final int FINISHING_STATE = 0x18; - private static final int FINISHED_STATE = 0x1e; - private static final int CLOSED_STATE = 0x7f; - - /** Compression level. */ - private int level; - - /** should we include a header. */ - private boolean noHeader; - - /** The current state. */ - private int state; - - /** The flush level the previous deflate call used. */ - private int lastFlush; - - /** The total bytes of output written. */ - private long totalOut; - - /** The pending output. */ - private DeflaterPending pending; - - /** The deflater engine. */ - private DeflaterEngine engine; - - /** - * Creates a new deflater with default compression level. - */ - public Deflater() - { - this(DEFAULT_COMPRESSION, false); - } - - /** - * Creates a new deflater with given compression level. - * @param lvl the compression level, a value between NO_COMPRESSION - * and BEST_COMPRESSION, or DEFAULT_COMPRESSION. - * @exception IllegalArgumentException if lvl is out of range. - */ - public Deflater(int lvl) - { - this(lvl, false); - } - - /** - * Creates a new deflater with given compression level. - * @param lvl the compression level, a value between NO_COMPRESSION - * and BEST_COMPRESSION. - * @param nowrap true, iff we should suppress the deflate header at the - * beginning and the adler checksum at the end of the output. This is - * useful for the GZIP format. - * @exception IllegalArgumentException if lvl is out of range. - */ - public Deflater(int lvl, boolean nowrap) - { - if (lvl == DEFAULT_COMPRESSION) - lvl = 6; - else if (lvl < NO_COMPRESSION || lvl > BEST_COMPRESSION) - throw new IllegalArgumentException(); - - pending = new DeflaterPending(); - engine = new DeflaterEngine(pending); - this.noHeader = nowrap; - setStrategy(DEFAULT_STRATEGY); - setLevel(lvl); - reset(); - } - - /** - * Resets the deflater. The deflater acts afterwards as if it was - * just created with the same compression level and strategy as it - * had before. - */ - public void reset() - { - state = (noHeader ? BUSY_STATE : INIT_STATE); - totalOut = 0; - pending.reset(); - engine.reset(); - } - - /** - * Frees all objects allocated by the compressor. There's no - * reason to call this, since you can just rely on garbage - * collection. Exists only for compatibility against Sun's JDK, - * where the compressor allocates native memory. - * If you call any method (even reset) afterwards the behaviour is - * <i>undefined</i>. - */ - public void end() - { - engine = null; - pending = null; - state = CLOSED_STATE; - } - - /** - * Gets the current adler checksum of the data that was processed so - * far. - */ - public int getAdler() - { - return engine.getAdler(); - } - - /** - * Gets the number of input bytes processed so far. - */ - public int getTotalIn() - { - return (int) engine.getTotalIn(); - } - - /** - * Gets the number of input bytes processed so far. - * @since 1.5 - */ - public long getBytesRead() - { - return engine.getTotalIn(); - } - - /** - * Gets the number of output bytes so far. - */ - public int getTotalOut() - { - return (int) totalOut; - } - - /** - * Gets the number of output bytes so far. - * @since 1.5 - */ - public long getBytesWritten() - { - return totalOut; - } - - /** - * Finalizes this object. - */ - protected void finalize() - { - /* Exists solely for compatibility. We don't have any native state. */ - } - - /** - * Finishes the deflater with the current input block. It is an error - * to give more input after this method was called. This method must - * be called to force all bytes to be flushed. - */ - public void finish() { - state |= IS_FINISHING; - } - - /** - * Returns true iff the stream was finished and no more output bytes - * are available. - */ - public boolean finished() - { - return state == FINISHED_STATE && pending.isFlushed(); - } - - /** - * Returns true, if the input buffer is empty. - * You should then call setInput(). <br> - * - * <em>NOTE</em>: This method can also return true when the stream - * was finished. - */ - public boolean needsInput() - { - return engine.needsInput(); - } - - /** - * Sets the data which should be compressed next. This should be only - * called when needsInput indicates that more input is needed. - * If you call setInput when needsInput() returns false, the - * previous input that is still pending will be thrown away. - * The given byte array should not be changed, before needsInput() returns - * true again. - * This call is equivalent to <code>setInput(input, 0, input.length)</code>. - * @param input the buffer containing the input data. - * @exception IllegalStateException if the buffer was finished() or ended(). - */ - public void setInput(byte[] input) - { - setInput(input, 0, input.length); - } - - /** - * Sets the data which should be compressed next. This should be - * only called when needsInput indicates that more input is needed. - * The given byte array should not be changed, before needsInput() returns - * true again. - * @param input the buffer containing the input data. - * @param off the start of the data. - * @param len the length of the data. - * @exception IllegalStateException if the buffer was finished() or ended() - * or if previous input is still pending. - */ - public void setInput(byte[] input, int off, int len) - { - if (input == null) - throw new NullPointerException(); - if (off < 0 || len < 0 || off > input.length - len) - throw new ArrayIndexOutOfBoundsException(); - engine.setInput(input, off, len); - } - - /** - * Sets the compression level. There is no guarantee of the exact - * position of the change, but if you call this when needsInput is - * true the change of compression level will occur somewhere near - * before the end of the so far given input. - * @param lvl the new compression level. - */ - public void setLevel(int lvl) - { - if (lvl == DEFAULT_COMPRESSION) - lvl = 6; - else if (lvl < NO_COMPRESSION || lvl > BEST_COMPRESSION) - throw new IllegalArgumentException(); - - - if (level != lvl) - { - level = lvl; - engine.setLevel(lvl); - } - } - - /** - * Sets the compression strategy. Strategy is one of - * DEFAULT_STRATEGY, HUFFMAN_ONLY and FILTERED. For the exact - * position where the strategy is changed, the same as for - * setLevel() applies. - * @param stgy the new compression strategy. - */ - public void setStrategy(int stgy) - { - if (stgy != DEFAULT_STRATEGY && stgy != FILTERED - && stgy != HUFFMAN_ONLY) - throw new IllegalArgumentException(); - engine.setStrategy(stgy); - } - - /** - * Deflates the current input block to the given array. It returns - * the number of bytes compressed, or 0 if either - * needsInput() or finished() returns true or length is zero. - * @param output the buffer where to write the compressed data. - */ - public int deflate(byte[] output) - { - return deflate(output, 0, output.length, NO_FLUSH); - } - - /** - * Deflates the current input block to the given array. It returns - * the number of bytes compressed, or 0 if either - * needsInput() or finished() returns true or length is zero. - * @param output the buffer where to write the compressed data. - * @param offset the offset into the output array. - * @param length the maximum number of bytes that may be written. - * @exception IllegalStateException if end() was called. - * @exception IndexOutOfBoundsException if offset and/or length - * don't match the array length. - */ - public int deflate(byte[] output, int offset, int length) - { - return deflate(output, offset, length, NO_FLUSH); - } - - /** - * Deflates the current input block to the given array. It returns - * the number of bytes compressed, or 0 if either - * needsInput() or finished() returns true or length is zero. - * @param output the buffer where to write the compressed data. - * @param offset the offset into the output array. - * @param length the maximum number of bytes that may be written. - * @param flush the compression flush mode - * @exception IllegalStateException if end() was called. - * @exception IndexOutOfBoundsException if offset and/or length - * don't match the array length. - */ - public int deflate(byte[] output, int offset, int length, int flush) - { - if (output.length - offset < length || offset < 0 || length < 0) - throw new ArrayIndexOutOfBoundsException(); - - if (flush < NO_FLUSH || flush > FULL_FLUSH) - throw new IllegalArgumentException(); - - int origLength = length; - - if (state == CLOSED_STATE) - throw new IllegalStateException("Deflater closed"); - - if (state < BUSY_STATE) - { - /* output header */ - int header = (DEFLATED + - ((DeflaterConstants.MAX_WBITS - 8) << 4)) << 8; - int level_flags = (level - 1) >> 1; - if (level_flags < 0 || level_flags > 3) - level_flags = 3; - header |= level_flags << 6; - if ((state & IS_SETDICT) != 0) - /* Dictionary was set */ - header |= DeflaterConstants.PRESET_DICT; - header += 31 - (header % 31); - - pending.writeShortMSB(header); - if ((state & IS_SETDICT) != 0) - { - int chksum = engine.getAdler(); - engine.resetAdler(); - pending.writeShortMSB(chksum >> 16); - pending.writeShortMSB(chksum & 0xffff); - } - - state = BUSY_STATE | (state & IS_FINISHING); - } - - int oldFlush = lastFlush; - lastFlush = flush; - - if (engine.needsInput() && flush <= oldFlush && (state & IS_FINISHING) == 0) - { - int count = pending.flush(output, offset, length); - totalOut += count; - return count; - } - - boolean done = state == FINISHED_STATE; - - for (;;) - { - int count = pending.flush(output, offset, length); - offset += count; - totalOut += count; - length -= count; - if (length == 0 || done) - return origLength - length; - - if (!engine.deflate((state & IS_FINISHING) != 0 || flush != NO_FLUSH, - (state & IS_FINISHING) != 0)) - { - done = true; - if (state == FINISHING_STATE) - { - pending.alignToByte(); - /* We have completed the stream */ - if (!noHeader) - { - int adler = engine.getAdler(); - pending.writeShortMSB(adler >> 16); - pending.writeShortMSB(adler & 0xffff); - } - state = FINISHED_STATE; - } - else if (flush != NO_FLUSH) - { - if (level != NO_COMPRESSION) - { - /* We have to supply some lookahead. 8 bit lookahead - * are needed by the zlib inflater, and we must fill - * the next byte, so that all bits are flushed. - */ - int neededbits = 8 + ((-pending.getBitCount()) & 7); - while (neededbits > 0) - { - /* write a static tree block consisting solely of - * an EOF: - */ - pending.writeBits(2, 10); - neededbits -= 10; - } - } - if (flush == FULL_FLUSH) - engine.clearHash(); - } - } - } - } - - /** - * Sets the dictionary which should be used in the deflate process. - * This call is equivalent to <code>setDictionary(dict, 0, - * dict.length)</code>. - * @param dict the dictionary. - * @exception IllegalStateException if setInput () or deflate () - * were already called or another dictionary was already set. - */ - public void setDictionary(byte[] dict) - { - setDictionary(dict, 0, dict.length); - } - - /** - * Sets the dictionary which should be used in the deflate process. - * The dictionary should be a byte array containing strings that are - * likely to occur in the data which should be compressed. The - * dictionary is not stored in the compressed output, only a - * checksum. To decompress the output you need to supply the same - * dictionary again. - * @param dict the dictionary. - * @param offset an offset into the dictionary. - * @param length the length of the dictionary. - * @exception IllegalStateException if setInput () or deflate () were - * already called or another dictionary was already set. - */ - public void setDictionary(byte[] dict, int offset, int length) - { - if (state != INIT_STATE) - throw new IllegalStateException(); - - state = SETDICT_STATE; - engine.setDictionary(dict, offset, length); - } -} diff --git a/openjdk/java/util/zip/DeflaterConstants.java b/openjdk/java/util/zip/DeflaterConstants.java deleted file mode 100644 index bfef8634..00000000 --- a/openjdk/java/util/zip/DeflaterConstants.java +++ /dev/null @@ -1,78 +0,0 @@ -/* java.util.zip.DeflaterConstants - Copyright (C) 2001 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - -package java.util.zip; - -interface DeflaterConstants -{ - boolean DEBUGGING = false; - - int STORED_BLOCK = 0; - int STATIC_TREES = 1; - int DYN_TREES = 2; - int PRESET_DICT = 0x20; - - int DEFAULT_MEM_LEVEL = 8; - - int MAX_MATCH = 258; - int MIN_MATCH = 3; - - int MAX_WBITS = 15; - int WSIZE = 1 << MAX_WBITS; - int WMASK = WSIZE - 1; - - int HASH_BITS = DEFAULT_MEM_LEVEL + 7; - int HASH_SIZE = 1 << HASH_BITS; - int HASH_MASK = HASH_SIZE - 1; - int HASH_SHIFT = (HASH_BITS + MIN_MATCH - 1) / MIN_MATCH; - - int MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1; - int MAX_DIST = WSIZE - MIN_LOOKAHEAD; - - int PENDING_BUF_SIZE = 1 << (DEFAULT_MEM_LEVEL + 8); - int MAX_BLOCK_SIZE = Math.min(65535, PENDING_BUF_SIZE-5); - - int DEFLATE_STORED = 0; - int DEFLATE_FAST = 1; - int DEFLATE_SLOW = 2; - - int GOOD_LENGTH[] = { 0,4, 4, 4, 4, 8, 8, 8, 32, 32 }; - int MAX_LAZY[] = { 0,4, 5, 6, 4,16, 16, 32, 128, 258 }; - int NICE_LENGTH[] = { 0,8,16,32,16,32,128,128, 258, 258 }; - int MAX_CHAIN[] = { 0,4, 8,32,16,32,128,256,1024,4096 }; - int COMPR_FUNC[] = { 0,1, 1, 1, 1, 2, 2, 2, 2, 2 }; -} diff --git a/openjdk/java/util/zip/DeflaterEngine.java b/openjdk/java/util/zip/DeflaterEngine.java deleted file mode 100644 index 474e4913..00000000 --- a/openjdk/java/util/zip/DeflaterEngine.java +++ /dev/null @@ -1,692 +0,0 @@ -/* DeflaterEngine.java -- - Copyright (C) 2001, 2004, 2005 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - -package java.util.zip; - -final class DeflaterEngine implements DeflaterConstants -{ - private static final int TOO_FAR = 4096; - - private int ins_h; - - /** - * Hashtable, hashing three characters to an index for window, so - * that window[index]..window[index+2] have this hash code. - * Note that the array should really be unsigned short, so you need - * to and the values with 0xffff. - */ - private short[] head; - - /** - * prev[index & WMASK] points to the previous index that has the - * same hash code as the string starting at index. This way - * entries with the same hash code are in a linked list. - * Note that the array should really be unsigned short, so you need - * to and the values with 0xffff. - */ - private short[] prev; - - private int matchStart, matchLen; - private boolean prevAvailable; - private int blockStart; - - /** - * strstart points to the current character in window. - */ - private int strstart; - - /** - * lookahead is the number of characters starting at strstart in - * window that are valid. - * So window[strstart] until window[strstart+lookahead-1] are valid - * characters. - */ - private int lookahead; - - /** - * This array contains the part of the uncompressed stream that - * is of relevance. The current character is indexed by strstart. - */ - private byte[] window; - - private int strategy, max_chain, max_lazy, niceLength, goodLength; - - /** The current compression function. */ - private int comprFunc; - - /** The input data for compression. */ - private byte[] inputBuf; - - /** The total bytes of input read. */ - private long totalIn; - - /** The offset into inputBuf, where input data starts. */ - private int inputOff; - - /** The end offset of the input data. */ - private int inputEnd; - - private DeflaterPending pending; - private DeflaterHuffman huffman; - - /** The adler checksum */ - private Adler32 adler; - - /* DEFLATE ALGORITHM: - * - * The uncompressed stream is inserted into the window array. When - * the window array is full the first half is thrown away and the - * second half is copied to the beginning. - * - * The head array is a hash table. Three characters build a hash value - * and they the value points to the corresponding index in window of - * the last string with this hash. The prev array implements a - * linked list of matches with the same hash: prev[index & WMASK] points - * to the previous index with the same hash. - * - * - */ - - - DeflaterEngine(DeflaterPending pending) { - this.pending = pending; - huffman = new DeflaterHuffman(pending); - adler = new Adler32(); - - window = new byte[2*WSIZE]; - head = new short[HASH_SIZE]; - prev = new short[WSIZE]; - - /* We start at index 1, to avoid a implementation deficiency, that - * we cannot build a repeat pattern at index 0. - */ - blockStart = strstart = 1; - } - - public void reset() - { - huffman.reset(); - adler.reset(); - clearHash(); - totalIn = 0; - } - - final void clearHash() - { - blockStart = strstart = 1; - lookahead = 0; - prevAvailable = false; - matchLen = MIN_MATCH - 1; - for (int i = 0; i < HASH_SIZE; i++) - head[i] = 0; - for (int i = 0; i < WSIZE; i++) - prev[i] = 0; - } - - public final void resetAdler() - { - adler.reset(); - } - - public final int getAdler() - { - int chksum = (int) adler.getValue(); - return chksum; - } - - public final long getTotalIn() - { - return totalIn; - } - - public final void setStrategy(int strat) - { - strategy = strat; - } - - public void setLevel(int lvl) - { - goodLength = DeflaterConstants.GOOD_LENGTH[lvl]; - max_lazy = DeflaterConstants.MAX_LAZY[lvl]; - niceLength = DeflaterConstants.NICE_LENGTH[lvl]; - max_chain = DeflaterConstants.MAX_CHAIN[lvl]; - - if (DeflaterConstants.COMPR_FUNC[lvl] != comprFunc) - { - if (DeflaterConstants.DEBUGGING) - System.err.println("Change from "+comprFunc +" to " - + DeflaterConstants.COMPR_FUNC[lvl]); - switch (comprFunc) - { - case DEFLATE_STORED: - if (strstart > blockStart) - { - huffman.flushStoredBlock(window, blockStart, - strstart - blockStart, false); - blockStart = strstart; - } - updateHash(); - break; - case DEFLATE_FAST: - if (strstart > blockStart) - { - huffman.flushBlock(window, blockStart, strstart - blockStart, - false); - blockStart = strstart; - } - break; - case DEFLATE_SLOW: - if (prevAvailable) - huffman.tallyLit(window[strstart-1] & 0xff); - if (strstart > blockStart) - { - huffman.flushBlock(window, blockStart, strstart - blockStart, - false); - blockStart = strstart; - } - prevAvailable = false; - matchLen = MIN_MATCH - 1; - break; - } - comprFunc = COMPR_FUNC[lvl]; - } - } - - private void updateHash() { - if (DEBUGGING) - System.err.println("updateHash: "+strstart); - ins_h = (window[strstart] << HASH_SHIFT) ^ window[strstart + 1]; - } - - /** - * Inserts the current string in the head hash and returns the previous - * value for this hash. - */ - private int insertString() { - short match; - int hash = ((ins_h << HASH_SHIFT) ^ window[strstart + (MIN_MATCH -1)]) - & HASH_MASK; - - if (DEBUGGING) - { - if (hash != (((window[strstart] << (2*HASH_SHIFT)) - ^ (window[strstart + 1] << HASH_SHIFT) - ^ (window[strstart + 2])) & HASH_MASK)) - throw new InternalError("hash inconsistent: "+hash+"/" - +window[strstart]+"," - +window[strstart+1]+"," - +window[strstart+2]+","+HASH_SHIFT); - } - - prev[strstart & WMASK] = match = head[hash]; - head[hash] = (short) strstart; - ins_h = hash; - return match & 0xffff; - } - - private void slideWindow() - { - System.arraycopy(window, WSIZE, window, 0, WSIZE); - matchStart -= WSIZE; - strstart -= WSIZE; - blockStart -= WSIZE; - - /* Slide the hash table (could be avoided with 32 bit values - * at the expense of memory usage). - */ - for (int i = 0; i < HASH_SIZE; i++) - { - int m = head[i] & 0xffff; - head[i] = m >= WSIZE ? (short) (m - WSIZE) : 0; - } - - /* Slide the prev table. - */ - for (int i = 0; i < WSIZE; i++) - { - int m = prev[i] & 0xffff; - prev[i] = m >= WSIZE ? (short) (m - WSIZE) : 0; - } - } - - /** - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead. - * - * OUT assertions: strstart + lookahead <= 2*WSIZE - * lookahead >= MIN_LOOKAHEAD or inputOff == inputEnd - */ - private void fillWindow() - { - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - if (strstart >= WSIZE + MAX_DIST) - slideWindow(); - - /* If there is not enough lookahead, but still some input left, - * read in the input - */ - while (lookahead < DeflaterConstants.MIN_LOOKAHEAD && inputOff < inputEnd) - { - int more = 2*WSIZE - lookahead - strstart; - - if (more > inputEnd - inputOff) - more = inputEnd - inputOff; - - System.arraycopy(inputBuf, inputOff, - window, strstart + lookahead, more); - adler.update(inputBuf, inputOff, more); - inputOff += more; - totalIn += more; - lookahead += more; - } - - if (lookahead >= MIN_MATCH) - updateHash(); - } - - /** - * Find the best (longest) string in the window matching the - * string starting at strstart. - * - * Preconditions: - * strstart + MAX_MATCH <= window.length. - * - * - * @param curMatch - */ - private boolean findLongestMatch(int curMatch) { - int chainLength = this.max_chain; - int niceLength = this.niceLength; - short[] prev = this.prev; - int scan = this.strstart; - int match; - int best_end = this.strstart + matchLen; - int best_len = Math.max(matchLen, MIN_MATCH - 1); - - int limit = Math.max(strstart - MAX_DIST, 0); - - int strend = scan + MAX_MATCH - 1; - byte scan_end1 = window[best_end - 1]; - byte scan_end = window[best_end]; - - /* Do not waste too much time if we already have a good match: */ - if (best_len >= this.goodLength) - chainLength >>= 2; - - /* Do not look for matches beyond the end of the input. This is necessary - * to make deflate deterministic. - */ - if (niceLength > lookahead) - niceLength = lookahead; - - if (DeflaterConstants.DEBUGGING - && strstart > 2*WSIZE - MIN_LOOKAHEAD) - throw new InternalError("need lookahead"); - - do { - if (DeflaterConstants.DEBUGGING && curMatch >= strstart) - throw new InternalError("future match"); - if (window[curMatch + best_len] != scan_end - || window[curMatch + best_len - 1] != scan_end1 - || window[curMatch] != window[scan] - || window[curMatch+1] != window[scan + 1]) - continue; - - match = curMatch + 2; - scan += 2; - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - while (window[++scan] == window[++match] - && window[++scan] == window[++match] - && window[++scan] == window[++match] - && window[++scan] == window[++match] - && window[++scan] == window[++match] - && window[++scan] == window[++match] - && window[++scan] == window[++match] - && window[++scan] == window[++match] - && scan < strend) - ; - - if (scan > best_end) { -// if (DeflaterConstants.DEBUGGING && ins_h == 0) -// System.err.println("Found match: "+curMatch+"-"+(scan-strstart)); - matchStart = curMatch; - best_end = scan; - best_len = scan - strstart; - if (best_len >= niceLength) - break; - - scan_end1 = window[best_end-1]; - scan_end = window[best_end]; - } - scan = strstart; - } while ((curMatch = (prev[curMatch & WMASK] & 0xffff)) > limit - && --chainLength != 0); - - matchLen = Math.min(best_len, lookahead); - return matchLen >= MIN_MATCH; - } - - void setDictionary(byte[] buffer, int offset, int length) { - if (DeflaterConstants.DEBUGGING && strstart != 1) - throw new IllegalStateException("strstart not 1"); - adler.update(buffer, offset, length); - if (length < MIN_MATCH) - return; - if (length > MAX_DIST) { - offset += length - MAX_DIST; - length = MAX_DIST; - } - - System.arraycopy(buffer, offset, window, strstart, length); - - updateHash(); - length--; - while (--length > 0) - { - insertString(); - strstart++; - } - strstart += 2; - blockStart = strstart; - } - - private boolean deflateStored(boolean flush, boolean finish) - { - if (!flush && lookahead == 0) - return false; - - strstart += lookahead; - lookahead = 0; - - int storedLen = strstart - blockStart; - - if ((storedLen >= DeflaterConstants.MAX_BLOCK_SIZE) - /* Block is full */ - || (blockStart < WSIZE && storedLen >= MAX_DIST) - /* Block may move out of window */ - || flush) - { - boolean lastBlock = finish; - if (storedLen > DeflaterConstants.MAX_BLOCK_SIZE) - { - storedLen = DeflaterConstants.MAX_BLOCK_SIZE; - lastBlock = false; - } - - if (DeflaterConstants.DEBUGGING) - System.err.println("storedBlock["+storedLen+","+lastBlock+"]"); - - huffman.flushStoredBlock(window, blockStart, storedLen, lastBlock); - blockStart += storedLen; - return !lastBlock; - } - return true; - } - - private boolean deflateFast(boolean flush, boolean finish) - { - if (lookahead < MIN_LOOKAHEAD && !flush) - return false; - - while (lookahead >= MIN_LOOKAHEAD || flush) - { - if (lookahead == 0) - { - /* We are flushing everything */ - huffman.flushBlock(window, blockStart, strstart - blockStart, - finish); - blockStart = strstart; - return false; - } - - if (strstart > 2 * WSIZE - MIN_LOOKAHEAD) - { - /* slide window, as findLongestMatch need this. - * This should only happen when flushing and the window - * is almost full. - */ - slideWindow(); - } - - int hashHead; - if (lookahead >= MIN_MATCH - && (hashHead = insertString()) != 0 - && strategy != Deflater.HUFFMAN_ONLY - && strstart - hashHead <= MAX_DIST - && findLongestMatch(hashHead)) - { - /* longestMatch sets matchStart and matchLen */ - if (DeflaterConstants.DEBUGGING) - { - for (int i = 0 ; i < matchLen; i++) - { - if (window[strstart+i] != window[matchStart + i]) - throw new InternalError(); - } - } - boolean full = huffman.tallyDist(strstart - matchStart, matchLen); - - lookahead -= matchLen; - if (matchLen <= max_lazy && lookahead >= MIN_MATCH) - { - while (--matchLen > 0) - { - strstart++; - insertString(); - } - strstart++; - } - else - { - strstart += matchLen; - if (lookahead >= MIN_MATCH - 1) - updateHash(); - } - matchLen = MIN_MATCH - 1; - if (!full) - continue; - } - else - { - /* No match found */ - huffman.tallyLit(window[strstart] & 0xff); - strstart++; - lookahead--; - } - - if (huffman.isFull()) - { - boolean lastBlock = finish && lookahead == 0; - huffman.flushBlock(window, blockStart, strstart - blockStart, - lastBlock); - blockStart = strstart; - return !lastBlock; - } - } - return true; - } - - private boolean deflateSlow(boolean flush, boolean finish) - { - if (lookahead < MIN_LOOKAHEAD && !flush) - return false; - - while (lookahead >= MIN_LOOKAHEAD || flush) - { - if (lookahead == 0) - { - if (prevAvailable) - huffman.tallyLit(window[strstart-1] & 0xff); - prevAvailable = false; - - /* We are flushing everything */ - if (DeflaterConstants.DEBUGGING && !flush) - throw new InternalError("Not flushing, but no lookahead"); - huffman.flushBlock(window, blockStart, strstart - blockStart, - finish); - blockStart = strstart; - return false; - } - - if (strstart >= 2 * WSIZE - MIN_LOOKAHEAD) - { - /* slide window, as findLongestMatch need this. - * This should only happen when flushing and the window - * is almost full. - */ - slideWindow(); - } - - int prevMatch = matchStart; - int prevLen = matchLen; - if (lookahead >= MIN_MATCH) - { - int hashHead = insertString(); - if (strategy != Deflater.HUFFMAN_ONLY - && hashHead != 0 && strstart - hashHead <= MAX_DIST - && findLongestMatch(hashHead)) - { - /* longestMatch sets matchStart and matchLen */ - - /* Discard match if too small and too far away */ - if (matchLen <= 5 - && (strategy == Deflater.FILTERED - || (matchLen == MIN_MATCH - && strstart - matchStart > TOO_FAR))) { - matchLen = MIN_MATCH - 1; - } - } - } - - /* previous match was better */ - if (prevLen >= MIN_MATCH && matchLen <= prevLen) - { - if (DeflaterConstants.DEBUGGING) - { - for (int i = 0 ; i < matchLen; i++) - { - if (window[strstart-1+i] != window[prevMatch + i]) - throw new InternalError(); - } - } - huffman.tallyDist(strstart - 1 - prevMatch, prevLen); - prevLen -= 2; - do - { - strstart++; - lookahead--; - if (lookahead >= MIN_MATCH) - insertString(); - } - while (--prevLen > 0); - strstart ++; - lookahead--; - prevAvailable = false; - matchLen = MIN_MATCH - 1; - } - else - { - if (prevAvailable) - huffman.tallyLit(window[strstart-1] & 0xff); - prevAvailable = true; - strstart++; - lookahead--; - } - - if (huffman.isFull()) - { - int len = strstart - blockStart; - if (prevAvailable) - len--; - boolean lastBlock = (finish && lookahead == 0 && !prevAvailable); - huffman.flushBlock(window, blockStart, len, lastBlock); - blockStart += len; - return !lastBlock; - } - } - return true; - } - - public boolean deflate(boolean flush, boolean finish) - { - boolean progress; - do - { - fillWindow(); - boolean canFlush = flush && inputOff == inputEnd; - if (DeflaterConstants.DEBUGGING) - System.err.println("window: ["+blockStart+","+strstart+"," - +lookahead+"], "+comprFunc+","+canFlush); - switch (comprFunc) - { - case DEFLATE_STORED: - progress = deflateStored(canFlush, finish); - break; - case DEFLATE_FAST: - progress = deflateFast(canFlush, finish); - break; - case DEFLATE_SLOW: - progress = deflateSlow(canFlush, finish); - break; - default: - throw new InternalError(); - } - } - while (pending.isFlushed() /* repeat while we have no pending output */ - && progress); /* and progress was made */ - - return progress; - } - - void setInput(byte[] buf, int off, int len) - { - // caller has already checked parameters - inputBuf = buf; - inputOff = off; - inputEnd = off + len; - } - - public final boolean needsInput() - { - return inputEnd == inputOff; - } -} diff --git a/openjdk/java/util/zip/DeflaterHuffman.java b/openjdk/java/util/zip/DeflaterHuffman.java deleted file mode 100644 index 3d10cdda..00000000 --- a/openjdk/java/util/zip/DeflaterHuffman.java +++ /dev/null @@ -1,776 +0,0 @@ -/* DeflaterHuffman.java -- - Copyright (C) 2001, 2004, 2005 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - -package java.util.zip; - -/** - * This is the DeflaterHuffman class. - * - * This class is <i>not</i> thread safe. This is inherent in the API, due - * to the split of deflate and setInput. - * - * @author Jochen Hoenicke - * @date Jan 6, 2000 - */ -class DeflaterHuffman -{ - private static final int BUFSIZE = 1 << (DeflaterConstants.DEFAULT_MEM_LEVEL + 6); - private static final int LITERAL_NUM = 286; - private static final int DIST_NUM = 30; - private static final int BITLEN_NUM = 19; - private static final int REP_3_6 = 16; - private static final int REP_3_10 = 17; - private static final int REP_11_138 = 18; - private static final int EOF_SYMBOL = 256; - private static final int[] BL_ORDER = - { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; - - private static final String bit4Reverse = - "\000\010\004\014\002\012\006\016\001\011\005\015\003\013\007\017"; - - class Tree { - short[] freqs; - short[] codes; - byte[] length; - int[] bl_counts; - int minNumCodes, numCodes; - int maxLength; - - Tree(int elems, int minCodes, int maxLength) { - this.minNumCodes = minCodes; - this.maxLength = maxLength; - freqs = new short[elems]; - bl_counts = new int[maxLength]; - } - - void reset() { - for (int i = 0; i < freqs.length; i++) - freqs[i] = 0; - codes = null; - length = null; - } - - final void writeSymbol(int code) - { - if (DeflaterConstants.DEBUGGING) - { - freqs[code]--; -// System.err.print("writeSymbol("+freqs.length+","+code+"): "); - } - pending.writeBits(codes[code] & 0xffff, length[code]); - } - - final void checkEmpty() - { - boolean empty = true; - for (int i = 0; i < freqs.length; i++) - if (freqs[i] != 0) - { - System.err.println("freqs["+i+"] == "+freqs[i]); - empty = false; - } - if (!empty) - throw new InternalError(); - System.err.println("checkEmpty suceeded!"); - } - - void setStaticCodes(short[] stCodes, byte[] stLength) - { - codes = stCodes; - length = stLength; - } - - public void buildCodes() { - int[] nextCode = new int[maxLength]; - int code = 0; - codes = new short[freqs.length]; - - if (DeflaterConstants.DEBUGGING) - System.err.println("buildCodes: "+freqs.length); - for (int bits = 0; bits < maxLength; bits++) - { - nextCode[bits] = code; - code += bl_counts[bits] << (15 - bits); - if (DeflaterConstants.DEBUGGING) - System.err.println("bits: "+(bits+1)+" count: "+bl_counts[bits] - +" nextCode: "+Integer.toHexString(code)); - } - if (DeflaterConstants.DEBUGGING && code != 65536) - throw new RuntimeException("Inconsistent bl_counts!"); - - for (int i=0; i < numCodes; i++) - { - int bits = length[i]; - if (bits > 0) - { - if (DeflaterConstants.DEBUGGING) - System.err.println("codes["+i+"] = rev(" - +Integer.toHexString(nextCode[bits-1])+")," - +bits); - codes[i] = bitReverse(nextCode[bits-1]); - nextCode[bits-1] += 1 << (16 - bits); - } - } - } - - private void buildLength(int childs[]) - { - this.length = new byte [freqs.length]; - int numNodes = childs.length / 2; - int numLeafs = (numNodes + 1) / 2; - int overflow = 0; - - for (int i = 0; i < maxLength; i++) - bl_counts[i] = 0; - - /* First calculate optimal bit lengths */ - int lengths[] = new int[numNodes]; - lengths[numNodes-1] = 0; - for (int i = numNodes - 1; i >= 0; i--) - { - if (childs[2*i+1] != -1) - { - int bitLength = lengths[i] + 1; - if (bitLength > maxLength) - { - bitLength = maxLength; - overflow++; - } - lengths[childs[2*i]] = lengths[childs[2*i+1]] = bitLength; - } - else - { - /* A leaf node */ - int bitLength = lengths[i]; - bl_counts[bitLength - 1]++; - this.length[childs[2*i]] = (byte) lengths[i]; - } - } - - if (DeflaterConstants.DEBUGGING) - { - System.err.println("Tree "+freqs.length+" lengths:"); - for (int i=0; i < numLeafs; i++) - System.err.println("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]] - + " len: "+length[childs[2*i]]); - } - - if (overflow == 0) - return; - - int incrBitLen = maxLength - 1; - do - { - /* Find the first bit length which could increase: */ - while (bl_counts[--incrBitLen] == 0) - ; - - /* Move this node one down and remove a corresponding - * amount of overflow nodes. - */ - do - { - bl_counts[incrBitLen]--; - bl_counts[++incrBitLen]++; - overflow -= 1 << (maxLength - 1 - incrBitLen); - } - while (overflow > 0 && incrBitLen < maxLength - 1); - } - while (overflow > 0); - - /* We may have overshot above. Move some nodes from maxLength to - * maxLength-1 in that case. - */ - bl_counts[maxLength-1] += overflow; - bl_counts[maxLength-2] -= overflow; - - /* Now recompute all bit lengths, scanning in increasing - * frequency. It is simpler to reconstruct all lengths instead of - * fixing only the wrong ones. This idea is taken from 'ar' - * written by Haruhiko Okumura. - * - * The nodes were inserted with decreasing frequency into the childs - * array. - */ - int nodePtr = 2 * numLeafs; - for (int bits = maxLength; bits != 0; bits--) - { - int n = bl_counts[bits-1]; - while (n > 0) - { - int childPtr = 2*childs[nodePtr++]; - if (childs[childPtr + 1] == -1) - { - /* We found another leaf */ - length[childs[childPtr]] = (byte) bits; - n--; - } - } - } - if (DeflaterConstants.DEBUGGING) - { - System.err.println("*** After overflow elimination. ***"); - for (int i=0; i < numLeafs; i++) - System.err.println("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]] - + " len: "+length[childs[2*i]]); - } - } - - void buildTree() - { - int numSymbols = freqs.length; - - /* heap is a priority queue, sorted by frequency, least frequent - * nodes first. The heap is a binary tree, with the property, that - * the parent node is smaller than both child nodes. This assures - * that the smallest node is the first parent. - * - * The binary tree is encoded in an array: 0 is root node and - * the nodes 2*n+1, 2*n+2 are the child nodes of node n. - */ - int[] heap = new int[numSymbols]; - int heapLen = 0; - int maxCode = 0; - for (int n = 0; n < numSymbols; n++) - { - int freq = freqs[n]; - if (freq != 0) - { - /* Insert n into heap */ - int pos = heapLen++; - int ppos; - while (pos > 0 && - freqs[heap[ppos = (pos - 1) / 2]] > freq) { - heap[pos] = heap[ppos]; - pos = ppos; - } - heap[pos] = n; - maxCode = n; - } - } - - /* We could encode a single literal with 0 bits but then we - * don't see the literals. Therefore we force at least two - * literals to avoid this case. We don't care about order in - * this case, both literals get a 1 bit code. - */ - while (heapLen < 2) - { - int node = maxCode < 2 ? ++maxCode : 0; - heap[heapLen++] = node; - } - - numCodes = Math.max(maxCode + 1, minNumCodes); - - int numLeafs = heapLen; - int[] childs = new int[4*heapLen - 2]; - int[] values = new int[2*heapLen - 1]; - int numNodes = numLeafs; - for (int i = 0; i < heapLen; i++) - { - int node = heap[i]; - childs[2*i] = node; - childs[2*i+1] = -1; - values[i] = freqs[node] << 8; - heap[i] = i; - } - - /* Construct the Huffman tree by repeatedly combining the least two - * frequent nodes. - */ - do - { - int first = heap[0]; - int last = heap[--heapLen]; - - /* Propagate the hole to the leafs of the heap */ - int ppos = 0; - int path = 1; - while (path < heapLen) - { - if (path + 1 < heapLen - && values[heap[path]] > values[heap[path+1]]) - path++; - - heap[ppos] = heap[path]; - ppos = path; - path = path * 2 + 1; - } - - /* Now propagate the last element down along path. Normally - * it shouldn't go too deep. - */ - int lastVal = values[last]; - while ((path = ppos) > 0 - && values[heap[ppos = (path - 1)/2]] > lastVal) - heap[path] = heap[ppos]; - heap[path] = last; - - - int second = heap[0]; - - /* Create a new node father of first and second */ - last = numNodes++; - childs[2*last] = first; - childs[2*last+1] = second; - int mindepth = Math.min(values[first] & 0xff, values[second] & 0xff); - values[last] = lastVal = values[first] + values[second] - mindepth + 1; - - /* Again, propagate the hole to the leafs */ - ppos = 0; - path = 1; - while (path < heapLen) - { - if (path + 1 < heapLen - && values[heap[path]] > values[heap[path+1]]) - path++; - - heap[ppos] = heap[path]; - ppos = path; - path = ppos * 2 + 1; - } - - /* Now propagate the new element down along path */ - while ((path = ppos) > 0 - && values[heap[ppos = (path - 1)/2]] > lastVal) - heap[path] = heap[ppos]; - heap[path] = last; - } - while (heapLen > 1); - - if (heap[0] != childs.length / 2 - 1) - throw new RuntimeException("Weird!"); - - buildLength(childs); - } - - int getEncodedLength() - { - int len = 0; - for (int i = 0; i < freqs.length; i++) - len += freqs[i] * length[i]; - return len; - } - - void calcBLFreq(Tree blTree) { - int max_count; /* max repeat count */ - int min_count; /* min repeat count */ - int count; /* repeat count of the current code */ - int curlen = -1; /* length of current code */ - - int i = 0; - while (i < numCodes) - { - count = 1; - int nextlen = length[i]; - if (nextlen == 0) - { - max_count = 138; - min_count = 3; - } - else - { - max_count = 6; - min_count = 3; - if (curlen != nextlen) - { - blTree.freqs[nextlen]++; - count = 0; - } - } - curlen = nextlen; - i++; - - while (i < numCodes && curlen == length[i]) - { - i++; - if (++count >= max_count) - break; - } - - if (count < min_count) - blTree.freqs[curlen] += count; - else if (curlen != 0) - blTree.freqs[REP_3_6]++; - else if (count <= 10) - blTree.freqs[REP_3_10]++; - else - blTree.freqs[REP_11_138]++; - } - } - - void writeTree(Tree blTree) - { - int max_count; /* max repeat count */ - int min_count; /* min repeat count */ - int count; /* repeat count of the current code */ - int curlen = -1; /* length of current code */ - - int i = 0; - while (i < numCodes) - { - count = 1; - int nextlen = length[i]; - if (nextlen == 0) - { - max_count = 138; - min_count = 3; - } - else - { - max_count = 6; - min_count = 3; - if (curlen != nextlen) - { - blTree.writeSymbol(nextlen); - count = 0; - } - } - curlen = nextlen; - i++; - - while (i < numCodes && curlen == length[i]) - { - i++; - if (++count >= max_count) - break; - } - - if (count < min_count) - { - while (count-- > 0) - blTree.writeSymbol(curlen); - } - else if (curlen != 0) - { - blTree.writeSymbol(REP_3_6); - pending.writeBits(count - 3, 2); - } - else if (count <= 10) - { - blTree.writeSymbol(REP_3_10); - pending.writeBits(count - 3, 3); - } - else - { - blTree.writeSymbol(REP_11_138); - pending.writeBits(count - 11, 7); - } - } - } - } - - - - DeflaterPending pending; - private Tree literalTree, distTree, blTree; - - private short d_buf[]; - private byte l_buf[]; - private int last_lit; - private int extra_bits; - - private static short staticLCodes[]; - private static byte staticLLength[]; - private static short staticDCodes[]; - private static byte staticDLength[]; - - /** - * Reverse the bits of a 16 bit value. - */ - static short bitReverse(int value) { - return (short) (bit4Reverse.charAt(value & 0xf) << 12 - | bit4Reverse.charAt((value >> 4) & 0xf) << 8 - | bit4Reverse.charAt((value >> 8) & 0xf) << 4 - | bit4Reverse.charAt(value >> 12)); - } - - static { - /* See RFC 1951 3.2.6 */ - /* Literal codes */ - staticLCodes = new short[LITERAL_NUM]; - staticLLength = new byte[LITERAL_NUM]; - int i = 0; - while (i < 144) { - staticLCodes[i] = bitReverse((0x030 + i) << 8); - staticLLength[i++] = 8; - } - while (i < 256) { - staticLCodes[i] = bitReverse((0x190 - 144 + i) << 7); - staticLLength[i++] = 9; - } - while (i < 280) { - staticLCodes[i] = bitReverse((0x000 - 256 + i) << 9); - staticLLength[i++] = 7; - } - while (i < LITERAL_NUM) { - staticLCodes[i] = bitReverse((0x0c0 - 280 + i) << 8); - staticLLength[i++] = 8; - } - - /* Distant codes */ - staticDCodes = new short[DIST_NUM]; - staticDLength = new byte[DIST_NUM]; - for (i = 0; i < DIST_NUM; i++) { - staticDCodes[i] = bitReverse(i << 11); - staticDLength[i] = 5; - } - } - - public DeflaterHuffman(DeflaterPending pending) - { - this.pending = pending; - - literalTree = new Tree(LITERAL_NUM, 257, 15); - distTree = new Tree(DIST_NUM, 1, 15); - blTree = new Tree(BITLEN_NUM, 4, 7); - - d_buf = new short[BUFSIZE]; - l_buf = new byte [BUFSIZE]; - } - - public final void reset() { - last_lit = 0; - extra_bits = 0; - literalTree.reset(); - distTree.reset(); - blTree.reset(); - } - - private int l_code(int len) { - if (len == 255) - return 285; - - int code = 257; - while (len >= 8) - { - code += 4; - len >>= 1; - } - return code + len; - } - - private int d_code(int distance) { - int code = 0; - while (distance >= 4) - { - code += 2; - distance >>= 1; - } - return code + distance; - } - - public void sendAllTrees(int blTreeCodes) { - blTree.buildCodes(); - literalTree.buildCodes(); - distTree.buildCodes(); - pending.writeBits(literalTree.numCodes - 257, 5); - pending.writeBits(distTree.numCodes - 1, 5); - pending.writeBits(blTreeCodes - 4, 4); - for (int rank = 0; rank < blTreeCodes; rank++) - pending.writeBits(blTree.length[BL_ORDER[rank]], 3); - literalTree.writeTree(blTree); - distTree.writeTree(blTree); - if (DeflaterConstants.DEBUGGING) - blTree.checkEmpty(); - } - - public void compressBlock() { - for (int i = 0; i < last_lit; i++) - { - int litlen = l_buf[i] & 0xff; - int dist = d_buf[i]; - if (dist-- != 0) - { - if (DeflaterConstants.DEBUGGING) - System.err.print("["+(dist+1)+","+(litlen+3)+"]: "); - - int lc = l_code(litlen); - literalTree.writeSymbol(lc); - - int bits = (lc - 261) / 4; - if (bits > 0 && bits <= 5) - pending.writeBits(litlen & ((1 << bits) - 1), bits); - - int dc = d_code(dist); - distTree.writeSymbol(dc); - - bits = dc / 2 - 1; - if (bits > 0) - pending.writeBits(dist & ((1 << bits) - 1), bits); - } - else - { - if (DeflaterConstants.DEBUGGING) - { - if (litlen > 32 && litlen < 127) - System.err.print("("+(char)litlen+"): "); - else - System.err.print("{"+litlen+"}: "); - } - literalTree.writeSymbol(litlen); - } - } - if (DeflaterConstants.DEBUGGING) - System.err.print("EOF: "); - literalTree.writeSymbol(EOF_SYMBOL); - if (DeflaterConstants.DEBUGGING) - { - literalTree.checkEmpty(); - distTree.checkEmpty(); - } - } - - public void flushStoredBlock(byte[] stored, - int stored_offset, int stored_len, - boolean lastBlock) { - if (DeflaterConstants.DEBUGGING) - System.err.println("Flushing stored block "+ stored_len); - pending.writeBits((DeflaterConstants.STORED_BLOCK << 1) - + (lastBlock ? 1 : 0), 3); - pending.alignToByte(); - pending.writeShort(stored_len); - pending.writeShort(~stored_len); - pending.writeBlock(stored, stored_offset, stored_len); - reset(); - } - - public void flushBlock(byte[] stored, int stored_offset, int stored_len, - boolean lastBlock) { - literalTree.freqs[EOF_SYMBOL]++; - - /* Build trees */ - literalTree.buildTree(); - distTree.buildTree(); - - /* Calculate bitlen frequency */ - literalTree.calcBLFreq(blTree); - distTree.calcBLFreq(blTree); - - /* Build bitlen tree */ - blTree.buildTree(); - - int blTreeCodes = 4; - for (int i = 18; i > blTreeCodes; i--) - { - if (blTree.length[BL_ORDER[i]] > 0) - blTreeCodes = i+1; - } - int opt_len = 14 + blTreeCodes * 3 + blTree.getEncodedLength() - + literalTree.getEncodedLength() + distTree.getEncodedLength() - + extra_bits; - - int static_len = extra_bits; - for (int i = 0; i < LITERAL_NUM; i++) - static_len += literalTree.freqs[i] * staticLLength[i]; - for (int i = 0; i < DIST_NUM; i++) - static_len += distTree.freqs[i] * staticDLength[i]; - if (opt_len >= static_len) - { - /* Force static trees */ - opt_len = static_len; - } - - if (stored_offset >= 0 && stored_len+4 < opt_len >> 3) - { - /* Store Block */ - if (DeflaterConstants.DEBUGGING) - System.err.println("Storing, since " + stored_len + " < " + opt_len - + " <= " + static_len); - flushStoredBlock(stored, stored_offset, stored_len, lastBlock); - } - else if (opt_len == static_len) - { - /* Encode with static tree */ - pending.writeBits((DeflaterConstants.STATIC_TREES << 1) - + (lastBlock ? 1 : 0), 3); - literalTree.setStaticCodes(staticLCodes, staticLLength); - distTree.setStaticCodes(staticDCodes, staticDLength); - compressBlock(); - reset(); - } - else - { - /* Encode with dynamic tree */ - pending.writeBits((DeflaterConstants.DYN_TREES << 1) - + (lastBlock ? 1 : 0), 3); - sendAllTrees(blTreeCodes); - compressBlock(); - reset(); - } - } - - public final boolean isFull() - { - return last_lit == BUFSIZE; - } - - public final boolean tallyLit(int lit) - { - if (DeflaterConstants.DEBUGGING) - { - if (lit > 32 && lit < 127) - System.err.println("("+(char)lit+")"); - else - System.err.println("{"+lit+"}"); - } - d_buf[last_lit] = 0; - l_buf[last_lit++] = (byte) lit; - literalTree.freqs[lit]++; - return last_lit == BUFSIZE; - } - - public final boolean tallyDist(int dist, int len) - { - if (DeflaterConstants.DEBUGGING) - System.err.println("["+dist+","+len+"]"); - - d_buf[last_lit] = (short) dist; - l_buf[last_lit++] = (byte) (len - 3); - - int lc = l_code(len-3); - literalTree.freqs[lc]++; - if (lc >= 265 && lc < 285) - extra_bits += (lc - 261) / 4; - - int dc = d_code(dist-1); - distTree.freqs[dc]++; - if (dc >= 4) - extra_bits += dc / 2 - 1; - return last_lit == BUFSIZE; - } -} diff --git a/openjdk/java/util/zip/DeflaterPending.java b/openjdk/java/util/zip/DeflaterPending.java deleted file mode 100644 index f38212c3..00000000 --- a/openjdk/java/util/zip/DeflaterPending.java +++ /dev/null @@ -1,54 +0,0 @@ -/* java.util.zip.DeflaterPending - Copyright (C) 2001 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - -package java.util.zip; - -/** - * This class stores the pending output of the Deflater. - * - * @author Jochen Hoenicke - * @date Jan 5, 2000 - */ - -class DeflaterPending extends PendingBuffer -{ - public DeflaterPending() - { - super(DeflaterConstants.PENDING_BUF_SIZE); - } -} - diff --git a/openjdk/java/util/zip/Inflater.java b/openjdk/java/util/zip/Inflater.java deleted file mode 100644 index a5912bdf..00000000 --- a/openjdk/java/util/zip/Inflater.java +++ /dev/null @@ -1,727 +0,0 @@ -/* Inflater.java - Decompress a data stream - Copyright (C) 1999, 2000, 2001, 2003, 2005 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - -package java.util.zip; - -/* Written using on-line Java Platform 1.2 API Specification - * and JCL book. - * Believed complete and correct. - */ - -/** - * Inflater is used to decompress data that has been compressed according - * to the "deflate" standard described in rfc1950. - * - * The usage is as following. First you have to set some input with - * <code>setInput()</code>, then inflate() it. If inflate doesn't - * inflate any bytes there may be three reasons: - * <ul> - * <li>needsInput() returns true because the input buffer is empty. - * You have to provide more input with <code>setInput()</code>. - * NOTE: needsInput() also returns true when, the stream is finished. - * </li> - * <li>needsDictionary() returns true, you have to provide a preset - * dictionary with <code>setDictionary()</code>.</li> - * <li>finished() returns true, the inflater has finished.</li> - * </ul> - * Once the first output byte is produced, a dictionary will not be - * needed at a later stage. - * - * @author John Leuner, Jochen Hoenicke - * @author Tom Tromey - * @date May 17, 1999 - * @since JDK 1.1 - */ -public class Inflater -{ - /* Copy lengths for literal codes 257..285 */ - private static final int CPLENS[] = - { - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 - }; - - /* Extra bits for literal codes 257..285 */ - private static final int CPLEXT[] = - { - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 - }; - - /* Copy offsets for distance codes 0..29 */ - private static final int CPDIST[] = { - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577 - }; - - /* Extra bits for distance codes */ - private static final int CPDEXT[] = { - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13 - }; - - /* This are the state in which the inflater can be. */ - private static final int DECODE_HEADER = 0; - private static final int DECODE_DICT = 1; - private static final int DECODE_BLOCKS = 2; - private static final int DECODE_STORED_LEN1 = 3; - private static final int DECODE_STORED_LEN2 = 4; - private static final int DECODE_STORED = 5; - private static final int DECODE_DYN_HEADER = 6; - private static final int DECODE_HUFFMAN = 7; - private static final int DECODE_HUFFMAN_LENBITS = 8; - private static final int DECODE_HUFFMAN_DIST = 9; - private static final int DECODE_HUFFMAN_DISTBITS = 10; - private static final int DECODE_CHKSUM = 11; - private static final int FINISHED = 12; - - /** This variable contains the current state. */ - private int mode; - - /** - * The adler checksum of the dictionary or of the decompressed - * stream, as it is written in the header resp. footer of the - * compressed stream. <br> - * - * Only valid if mode is DECODE_DICT or DECODE_CHKSUM. - */ - private int readAdler; - /** - * The number of bits needed to complete the current state. This - * is valid, if mode is DECODE_DICT, DECODE_CHKSUM, - * DECODE_HUFFMAN_LENBITS or DECODE_HUFFMAN_DISTBITS. - */ - private int neededBits; - private int repLength, repDist; - private int uncomprLen; - /** - * True, if the last block flag was set in the last block of the - * inflated stream. This means that the stream ends after the - * current block. - */ - private boolean isLastBlock; - - /** - * The total number of inflated bytes. - */ - private long totalOut; - /** - * The total number of bytes set with setInput(). This is not the - * value returned by getTotalIn(), since this also includes the - * unprocessed input. - */ - private long totalIn; - /** - * This variable stores the nowrap flag that was given to the constructor. - * True means, that the inflated stream doesn't contain a header nor the - * checksum in the footer. - */ - private boolean nowrap; - - private StreamManipulator input; - private OutputWindow outputWindow; - private InflaterDynHeader dynHeader; - private InflaterHuffmanTree litlenTree, distTree; - private Adler32 adler; - - /** - * Creates a new inflater. - */ - public Inflater () - { - this (false); - } - - /** - * Creates a new inflater. - * @param nowrap true if no header and checksum field appears in the - * stream. This is used for GZIPed input. For compatibility with - * Sun JDK you should provide one byte of input more than needed in - * this case. - */ - public Inflater (boolean nowrap) - { - this.nowrap = nowrap; - this.adler = new Adler32(); - input = new StreamManipulator(); - outputWindow = new OutputWindow(); - mode = nowrap ? DECODE_BLOCKS : DECODE_HEADER; - } - - /** - * Finalizes this object. - */ - protected void finalize () - { - /* Exists only for compatibility */ - } - - /** - * Frees all objects allocated by the inflater. There's no reason - * to call this, since you can just rely on garbage collection (even - * for the Sun implementation). Exists only for compatibility - * with Sun's JDK, where the compressor allocates native memory. - * If you call any method (even reset) afterwards the behaviour is - * <i>undefined</i>. - */ - public void end () - { - outputWindow = null; - input = null; - dynHeader = null; - litlenTree = null; - distTree = null; - adler = null; - } - - /** - * Returns true, if the inflater has finished. This means, that no - * input is needed and no output can be produced. - */ - public boolean finished() - { - return mode == FINISHED - && (outputWindow == null || outputWindow.getAvailable() == 0); - } - - /** - * Gets the adler checksum. This is either the checksum of all - * uncompressed bytes returned by inflate(), or if needsDictionary() - * returns true (and thus no output was yet produced) this is the - * adler checksum of the expected dictionary. - * @returns the adler checksum. - */ - public int getAdler() - { - return needsDictionary() ? readAdler : (int) adler.getValue(); - } - - /** - * Gets the number of unprocessed input. Useful, if the end of the - * stream is reached and you want to further process the bytes after - * the deflate stream. - * @return the number of bytes of the input which were not processed. - */ - public int getRemaining() - { - return input.getAvailableBytes(); - } - - /** - * Gets the total number of processed compressed input bytes. - * @return the total number of bytes of processed input bytes. - */ - public int getTotalIn() - { - return (int) (totalIn - getRemaining()); - } - - /** - * Gets the total number of processed compressed input bytes. - * @return the total number of bytes of processed input bytes. - * @since 1.5 - */ - public long getBytesRead() - { - return totalIn - getRemaining(); - } - - /** - * Gets the total number of output bytes returned by inflate(). - * @return the total number of output bytes. - */ - public int getTotalOut() - { - return (int) totalOut; - } - - /** - * Gets the total number of output bytes returned by inflate(). - * @return the total number of output bytes. - * @since 1.5 - */ - public long getBytesWritten() - { - return totalOut; - } - - /** - * Inflates the compressed stream to the output buffer. If this - * returns 0, you should check, whether needsDictionary(), - * needsInput() or finished() returns true, to determine why no - * further output is produced. - * @param buf the output buffer. - * @return the number of bytes written to the buffer, 0 if no further - * output can be produced. - * @exception DataFormatException if deflated stream is invalid. - * @exception IllegalArgumentException if buf has length 0. - */ - public int inflate (byte[] buf) throws DataFormatException - { - return inflate (buf, 0, buf.length); - } - - /** - * Inflates the compressed stream to the output buffer. If this - * returns 0, you should check, whether needsDictionary(), - * needsInput() or finished() returns true, to determine why no - * further output is produced. - * @param buf the output buffer. - * @param off the offset into buffer where the output should start. - * @param len the maximum length of the output. - * @return the number of bytes written to the buffer, 0 if no further - * output can be produced. - * @exception DataFormatException if deflated stream is invalid. - * @exception IndexOutOfBoundsException if the off and/or len are wrong. - */ - public int inflate (byte[] buf, int off, int len) throws DataFormatException - { - /* Check for correct buff, off, len triple */ - if (0 > off || off > off + len || off + len > buf.length) - throw new ArrayIndexOutOfBoundsException(); - int count = 0; - for (;;) - { - if (outputWindow.getAvailable() == 0) - { - if (!decode()) - break; - } - else if (len > 0) - { - int more = outputWindow.copyOutput(buf, off, len); - adler.update(buf, off, more); - off += more; - count += more; - totalOut += more; - len -= more; - } - else - break; - } - return count; - } - - /** - * Returns true, if a preset dictionary is needed to inflate the input. - */ - public boolean needsDictionary () - { - return mode == DECODE_DICT && neededBits == 0; - } - - /** - * Returns true, if the input buffer is empty. - * You should then call setInput(). <br> - * - * <em>NOTE</em>: This method also returns true when the stream is finished. - */ - public boolean needsInput () - { - return input == null || input.needsInput (); - } - - /** - * Resets the inflater so that a new stream can be decompressed. All - * pending input and output will be discarded. - */ - public void reset () - { - mode = nowrap ? DECODE_BLOCKS : DECODE_HEADER; - totalIn = totalOut = 0; - input.reset(); - outputWindow.reset(); - dynHeader = null; - litlenTree = null; - distTree = null; - isLastBlock = false; - adler.reset(); - } - - /** - * Sets the preset dictionary. This should only be called, if - * needsDictionary() returns true and it should set the same - * dictionary, that was used for deflating. The getAdler() - * function returns the checksum of the dictionary needed. - * @param buffer the dictionary. - * @exception IllegalStateException if no dictionary is needed. - * @exception IllegalArgumentException if the dictionary checksum is - * wrong. - */ - public void setDictionary (byte[] buffer) - { - setDictionary(buffer, 0, buffer.length); - } - - /** - * Sets the preset dictionary. This should only be called, if - * needsDictionary() returns true and it should set the same - * dictionary, that was used for deflating. The getAdler() - * function returns the checksum of the dictionary needed. - * @param buffer the dictionary. - * @param off the offset into buffer where the dictionary starts. - * @param len the length of the dictionary. - * @exception IllegalStateException if no dictionary is needed. - * @exception IllegalArgumentException if the dictionary checksum is - * wrong. - * @exception IndexOutOfBoundsException if the off and/or len are wrong. - */ - public void setDictionary (byte[] buffer, int off, int len) - { - if (!needsDictionary()) - throw new IllegalStateException(); - - adler.update(buffer, off, len); - if ((int) adler.getValue() != readAdler) - throw new IllegalArgumentException("Wrong adler checksum"); - adler.reset(); - outputWindow.copyDict(buffer, off, len); - mode = DECODE_BLOCKS; - } - - /** - * Sets the input. This should only be called, if needsInput() - * returns true. - * @param buf the input. - * @exception IllegalStateException if no input is needed. - */ - public void setInput (byte[] buf) - { - setInput (buf, 0, buf.length); - } - - /** - * Sets the input. This should only be called, if needsInput() - * returns true. - * @param buf the input. - * @param off the offset into buffer where the input starts. - * @param len the length of the input. - * @exception IllegalStateException if no input is needed. - * @exception IndexOutOfBoundsException if the off and/or len are wrong. - */ - public void setInput (byte[] buf, int off, int len) - { - input.setInput (buf, off, len); - totalIn += len; - } - - /** - * Decodes the deflate header. - * @return false if more input is needed. - * @exception DataFormatException if header is invalid. - */ - private boolean decodeHeader () throws DataFormatException - { - int header = input.peekBits(16); - if (header < 0) - return false; - input.dropBits(16); - - /* The header is written in "wrong" byte order */ - header = ((header << 8) | (header >> 8)) & 0xffff; - if (header % 31 != 0) - throw new DataFormatException("Header checksum illegal"); - - if ((header & 0x0f00) != (Deflater.DEFLATED << 8)) - throw new DataFormatException("Compression Method unknown"); - - /* Maximum size of the backwards window in bits. - * We currently ignore this, but we could use it to make the - * inflater window more space efficient. On the other hand the - * full window (15 bits) is needed most times, anyway. - int max_wbits = ((header & 0x7000) >> 12) + 8; - */ - - if ((header & 0x0020) == 0) // Dictionary flag? - { - mode = DECODE_BLOCKS; - } - else - { - mode = DECODE_DICT; - neededBits = 32; - } - return true; - } - - /** - * Decodes the dictionary checksum after the deflate header. - * @return false if more input is needed. - */ - private boolean decodeDict () - { - while (neededBits > 0) - { - int dictByte = input.peekBits(8); - if (dictByte < 0) - return false; - input.dropBits(8); - readAdler = (readAdler << 8) | dictByte; - neededBits -= 8; - } - return false; - } - - /** - * Decodes the huffman encoded symbols in the input stream. - * @return false if more input is needed, true if output window is - * full or the current block ends. - * @exception DataFormatException if deflated stream is invalid. - */ - private boolean decodeHuffman () throws DataFormatException - { - int free = outputWindow.getFreeSpace(); - while (free >= 258) - { - int symbol; - switch (mode) - { - case DECODE_HUFFMAN: - /* This is the inner loop so it is optimized a bit */ - while (((symbol = litlenTree.getSymbol(input)) & ~0xff) == 0) - { - outputWindow.write(symbol); - if (--free < 258) - return true; - } - if (symbol < 257) - { - if (symbol < 0) - return false; - else - { - /* symbol == 256: end of block */ - distTree = null; - litlenTree = null; - mode = DECODE_BLOCKS; - return true; - } - } - - try - { - repLength = CPLENS[symbol - 257]; - neededBits = CPLEXT[symbol - 257]; - } - catch (ArrayIndexOutOfBoundsException ex) - { - throw new DataFormatException("Illegal rep length code"); - } - /* fall through */ - case DECODE_HUFFMAN_LENBITS: - if (neededBits > 0) - { - mode = DECODE_HUFFMAN_LENBITS; - int i = input.peekBits(neededBits); - if (i < 0) - return false; - input.dropBits(neededBits); - repLength += i; - } - mode = DECODE_HUFFMAN_DIST; - /* fall through */ - case DECODE_HUFFMAN_DIST: - symbol = distTree.getSymbol(input); - if (symbol < 0) - return false; - try - { - repDist = CPDIST[symbol]; - neededBits = CPDEXT[symbol]; - } - catch (ArrayIndexOutOfBoundsException ex) - { - throw new DataFormatException("Illegal rep dist code"); - } - /* fall through */ - case DECODE_HUFFMAN_DISTBITS: - if (neededBits > 0) - { - mode = DECODE_HUFFMAN_DISTBITS; - int i = input.peekBits(neededBits); - if (i < 0) - return false; - input.dropBits(neededBits); - repDist += i; - } - outputWindow.repeat(repLength, repDist); - free -= repLength; - mode = DECODE_HUFFMAN; - break; - default: - throw new IllegalStateException(); - } - } - return true; - } - - /** - * Decodes the adler checksum after the deflate stream. - * @return false if more input is needed. - * @exception DataFormatException if checksum doesn't match. - */ - private boolean decodeChksum () throws DataFormatException - { - while (neededBits > 0) - { - int chkByte = input.peekBits(8); - if (chkByte < 0) - return false; - input.dropBits(8); - readAdler = (readAdler << 8) | chkByte; - neededBits -= 8; - } - if ((int) adler.getValue() != readAdler) - throw new DataFormatException("Adler chksum doesn't match: " - +Integer.toHexString((int)adler.getValue()) - +" vs. "+Integer.toHexString(readAdler)); - mode = FINISHED; - return false; - } - - /** - * Decodes the deflated stream. - * @return false if more input is needed, or if finished. - * @exception DataFormatException if deflated stream is invalid. - */ - private boolean decode () throws DataFormatException - { - switch (mode) - { - case DECODE_HEADER: - return decodeHeader(); - case DECODE_DICT: - return decodeDict(); - case DECODE_CHKSUM: - return decodeChksum(); - - case DECODE_BLOCKS: - if (isLastBlock) - { - if (nowrap) - { - mode = FINISHED; - return false; - } - else - { - input.skipToByteBoundary(); - neededBits = 32; - mode = DECODE_CHKSUM; - return true; - } - } - - int type = input.peekBits(3); - if (type < 0) - return false; - input.dropBits(3); - - if ((type & 1) != 0) - isLastBlock = true; - switch (type >> 1) - { - case DeflaterConstants.STORED_BLOCK: - input.skipToByteBoundary(); - mode = DECODE_STORED_LEN1; - break; - case DeflaterConstants.STATIC_TREES: - litlenTree = InflaterHuffmanTree.defLitLenTree; - distTree = InflaterHuffmanTree.defDistTree; - mode = DECODE_HUFFMAN; - break; - case DeflaterConstants.DYN_TREES: - dynHeader = new InflaterDynHeader(); - mode = DECODE_DYN_HEADER; - break; - default: - throw new DataFormatException("Unknown block type "+type); - } - return true; - - case DECODE_STORED_LEN1: - { - if ((uncomprLen = input.peekBits(16)) < 0) - return false; - input.dropBits(16); - mode = DECODE_STORED_LEN2; - } - /* fall through */ - case DECODE_STORED_LEN2: - { - int nlen = input.peekBits(16); - if (nlen < 0) - return false; - input.dropBits(16); - if (nlen != (uncomprLen ^ 0xffff)) - throw new DataFormatException("broken uncompressed block"); - mode = DECODE_STORED; - } - /* fall through */ - case DECODE_STORED: - { - int more = outputWindow.copyStored(input, uncomprLen); - uncomprLen -= more; - if (uncomprLen == 0) - { - mode = DECODE_BLOCKS; - return true; - } - return !input.needsInput(); - } - - case DECODE_DYN_HEADER: - if (!dynHeader.decode(input)) - return false; - litlenTree = dynHeader.buildLitLenTree(); - distTree = dynHeader.buildDistTree(); - mode = DECODE_HUFFMAN; - /* fall through */ - case DECODE_HUFFMAN: - case DECODE_HUFFMAN_LENBITS: - case DECODE_HUFFMAN_DIST: - case DECODE_HUFFMAN_DISTBITS: - return decodeHuffman(); - case FINISHED: - return false; - default: - throw new IllegalStateException(); - } - } -} diff --git a/openjdk/java/util/zip/InflaterDynHeader.java b/openjdk/java/util/zip/InflaterDynHeader.java deleted file mode 100644 index ad931e49..00000000 --- a/openjdk/java/util/zip/InflaterDynHeader.java +++ /dev/null @@ -1,203 +0,0 @@ -/* java.util.zip.InflaterDynHeader - Copyright (C) 2001 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - -package java.util.zip; - -class InflaterDynHeader -{ - private static final int LNUM = 0; - private static final int DNUM = 1; - private static final int BLNUM = 2; - private static final int BLLENS = 3; - private static final int LENS = 4; - private static final int REPS = 5; - - private static final int repMin[] = { 3, 3, 11 }; - private static final int repBits[] = { 2, 3, 7 }; - - - private byte[] blLens; - private byte[] litdistLens; - - private InflaterHuffmanTree blTree; - - private int mode; - private int lnum, dnum, blnum, num; - private int repSymbol; - private byte lastLen; - private int ptr; - - private static final int[] BL_ORDER = - { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; - - public InflaterDynHeader() - { - } - - public boolean decode(StreamManipulator input) throws DataFormatException - { - decode_loop: - for (;;) - { - switch (mode) - { - case LNUM: - lnum = input.peekBits(5); - if (lnum < 0) - return false; - lnum += 257; - input.dropBits(5); -// System.err.println("LNUM: "+lnum); - mode = DNUM; - /* fall through */ - case DNUM: - dnum = input.peekBits(5); - if (dnum < 0) - return false; - dnum++; - input.dropBits(5); -// System.err.println("DNUM: "+dnum); - num = lnum+dnum; - litdistLens = new byte[num]; - mode = BLNUM; - /* fall through */ - case BLNUM: - blnum = input.peekBits(4); - if (blnum < 0) - return false; - blnum += 4; - input.dropBits(4); - blLens = new byte[19]; - ptr = 0; -// System.err.println("BLNUM: "+blnum); - mode = BLLENS; - /* fall through */ - case BLLENS: - while (ptr < blnum) - { - int len = input.peekBits(3); - if (len < 0) - return false; - input.dropBits(3); -// System.err.println("blLens["+BL_ORDER[ptr]+"]: "+len); - blLens[BL_ORDER[ptr]] = (byte) len; - ptr++; - } - blTree = new InflaterHuffmanTree(blLens); - blLens = null; - ptr = 0; - mode = LENS; - /* fall through */ - case LENS: - { - int symbol; - while (((symbol = blTree.getSymbol(input)) & ~15) == 0) - { - /* Normal case: symbol in [0..15] */ - -// System.err.println("litdistLens["+ptr+"]: "+symbol); - litdistLens[ptr++] = lastLen = (byte) symbol; - - if (ptr == num) - { - /* Finished */ - return true; - } - } - - /* need more input ? */ - if (symbol < 0) - return false; - - /* otherwise repeat code */ - if (symbol >= 17) - { - /* repeat zero */ -// System.err.println("repeating zero"); - lastLen = 0; - } - else - { - if (ptr == 0) - throw new DataFormatException(); - } - repSymbol = symbol-16; - mode = REPS; - } - /* fall through */ - - case REPS: - { - int bits = repBits[repSymbol]; - int count = input.peekBits(bits); - if (count < 0) - return false; - input.dropBits(bits); - count += repMin[repSymbol]; -// System.err.println("litdistLens repeated: "+count); - - if (ptr + count > num) - throw new DataFormatException(); - while (count-- > 0) - litdistLens[ptr++] = lastLen; - - if (ptr == num) - { - /* Finished */ - return true; - } - } - mode = LENS; - continue decode_loop; - } - } - } - - public InflaterHuffmanTree buildLitLenTree() throws DataFormatException - { - byte[] litlenLens = new byte[lnum]; - System.arraycopy(litdistLens, 0, litlenLens, 0, lnum); - return new InflaterHuffmanTree(litlenLens); - } - - public InflaterHuffmanTree buildDistTree() throws DataFormatException - { - byte[] distLens = new byte[dnum]; - System.arraycopy(litdistLens, lnum, distLens, 0, dnum); - return new InflaterHuffmanTree(distLens); - } -} diff --git a/openjdk/java/util/zip/InflaterHuffmanTree.java b/openjdk/java/util/zip/InflaterHuffmanTree.java deleted file mode 100644 index 1a152d2b..00000000 --- a/openjdk/java/util/zip/InflaterHuffmanTree.java +++ /dev/null @@ -1,220 +0,0 @@ -/* InflaterHuffmanTree.java -- - Copyright (C) 2001, 2004 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - -package java.util.zip; - -class InflaterHuffmanTree -{ - private static final int MAX_BITLEN = 15; - - private short[] tree; - - static InflaterHuffmanTree defLitLenTree, defDistTree; - - static - { - try - { - byte[] codeLengths = new byte[288]; - int i = 0; - while (i < 144) - codeLengths[i++] = 8; - while (i < 256) - codeLengths[i++] = 9; - while (i < 280) - codeLengths[i++] = 7; - while (i < 288) - codeLengths[i++] = 8; - defLitLenTree = new InflaterHuffmanTree(codeLengths); - - codeLengths = new byte[32]; - i = 0; - while (i < 32) - codeLengths[i++] = 5; - defDistTree = new InflaterHuffmanTree(codeLengths); - } - catch (DataFormatException ex) - { - throw new InternalError - ("InflaterHuffmanTree: static tree length illegal"); - } - } - - /** - * Constructs a Huffman tree from the array of code lengths. - * - * @param codeLengths the array of code lengths - */ - InflaterHuffmanTree(byte[] codeLengths) throws DataFormatException - { - buildTree(codeLengths); - } - - private void buildTree(byte[] codeLengths) throws DataFormatException - { - int[] blCount = new int[MAX_BITLEN+1]; - int[] nextCode = new int[MAX_BITLEN+1]; - for (int i = 0; i < codeLengths.length; i++) - { - int bits = codeLengths[i]; - if (bits > 0) - blCount[bits]++; - } - - int max = 0; - int code = 0; - int treeSize = 512; - for (int bits = 1; bits <= MAX_BITLEN; bits++) - { - nextCode[bits] = code; - if (blCount[bits] > 0) - max = bits; - code += blCount[bits] << (16 - bits); - if (bits >= 10) - { - /* We need an extra table for bit lengths >= 10. */ - int start = nextCode[bits] & 0x1ff80; - int end = code & 0x1ff80; - treeSize += (end - start) >> (16 - bits); - } - } - if (code != 65536 && max > 1) - throw new DataFormatException("incomplete dynamic bit lengths tree"); - - /* Now create and fill the extra tables from longest to shortest - * bit len. This way the sub trees will be aligned. - */ - tree = new short[treeSize]; - int treePtr = 512; - for (int bits = MAX_BITLEN; bits >= 10; bits--) - { - int end = code & 0x1ff80; - code -= blCount[bits] << (16 - bits); - int start = code & 0x1ff80; - for (int i = start; i < end; i += 1 << 7) - { - tree[DeflaterHuffman.bitReverse(i)] - = (short) ((-treePtr << 4) | bits); - treePtr += 1 << (bits-9); - } - } - - for (int i = 0; i < codeLengths.length; i++) - { - int bits = codeLengths[i]; - if (bits == 0) - continue; - code = nextCode[bits]; - int revcode = DeflaterHuffman.bitReverse(code); - if (bits <= 9) - { - do - { - tree[revcode] = (short) ((i << 4) | bits); - revcode += 1 << bits; - } - while (revcode < 512); - } - else - { - int subTree = tree[revcode & 511]; - int treeLen = 1 << (subTree & 15); - subTree = -(subTree >> 4); - do - { - tree[subTree | (revcode >> 9)] = (short) ((i << 4) | bits); - revcode += 1 << bits; - } - while (revcode < treeLen); - } - nextCode[bits] = code + (1 << (16 - bits)); - } - } - - /** - * Reads the next symbol from input. The symbol is encoded using the - * huffman tree. - * @param input the input source. - * @return the next symbol, or -1 if not enough input is available. - */ - int getSymbol(StreamManipulator input) throws DataFormatException - { - int lookahead, symbol; - if ((lookahead = input.peekBits(9)) >= 0) - { - if ((symbol = tree[lookahead]) >= 0) - { - input.dropBits(symbol & 15); - return symbol >> 4; - } - int subtree = -(symbol >> 4); - int bitlen = symbol & 15; - if ((lookahead = input.peekBits(bitlen)) >= 0) - { - symbol = tree[subtree | (lookahead >> 9)]; - input.dropBits(symbol & 15); - return symbol >> 4; - } - else - { - int bits = input.getAvailableBits(); - lookahead = input.peekBits(bits); - symbol = tree[subtree | (lookahead >> 9)]; - if ((symbol & 15) <= bits) - { - input.dropBits(symbol & 15); - return symbol >> 4; - } - else - return -1; - } - } - else - { - int bits = input.getAvailableBits(); - lookahead = input.peekBits(bits); - symbol = tree[lookahead]; - if (symbol >= 0 && (symbol & 15) <= bits) - { - input.dropBits(symbol & 15); - return symbol >> 4; - } - else - return -1; - } - } -} diff --git a/openjdk/java/util/zip/OutputWindow.java b/openjdk/java/util/zip/OutputWindow.java deleted file mode 100644 index f4326053..00000000 --- a/openjdk/java/util/zip/OutputWindow.java +++ /dev/null @@ -1,178 +0,0 @@ -/* OutputWindow.java -- - Copyright (C) 2001, 2004 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - -package java.util.zip; - -/** - * Contains the output from the Inflation process. - * - * We need to have a window so that we can refer backwards into the output stream - * to repeat stuff. - * - * @author John Leuner - * @since 1.1 - */ -class OutputWindow -{ - private static final int WINDOW_SIZE = 1 << 15; - private static final int WINDOW_MASK = WINDOW_SIZE - 1; - - private byte[] window = new byte[WINDOW_SIZE]; //The window is 2^15 bytes - private int window_end = 0; - private int window_filled = 0; - - public void write(int abyte) - { - if (window_filled++ == WINDOW_SIZE) - throw new IllegalStateException("Window full"); - window[window_end++] = (byte) abyte; - window_end &= WINDOW_MASK; - } - - private void slowRepeat(int rep_start, int len, int dist) - { - while (len-- > 0) - { - window[window_end++] = window[rep_start++]; - window_end &= WINDOW_MASK; - rep_start &= WINDOW_MASK; - } - } - - public void repeat(int len, int dist) - { - if ((window_filled += len) > WINDOW_SIZE) - throw new IllegalStateException("Window full"); - - int rep_start = (window_end - dist) & WINDOW_MASK; - int border = WINDOW_SIZE - len; - if (rep_start <= border && window_end < border) - { - if (len <= dist) - { - System.arraycopy(window, rep_start, window, window_end, len); - window_end += len; - } - else - { - /* We have to copy manually, since the repeat pattern overlaps. - */ - while (len-- > 0) - window[window_end++] = window[rep_start++]; - } - } - else - slowRepeat(rep_start, len, dist); - } - - public int copyStored(StreamManipulator input, int len) - { - len = Math.min(Math.min(len, WINDOW_SIZE - window_filled), - input.getAvailableBytes()); - int copied; - - int tailLen = WINDOW_SIZE - window_end; - if (len > tailLen) - { - copied = input.copyBytes(window, window_end, tailLen); - if (copied == tailLen) - copied += input.copyBytes(window, 0, len - tailLen); - } - else - copied = input.copyBytes(window, window_end, len); - - window_end = (window_end + copied) & WINDOW_MASK; - window_filled += copied; - return copied; - } - - public void copyDict(byte[] dict, int offset, int len) - { - if (window_filled > 0) - throw new IllegalStateException(); - - if (len > WINDOW_SIZE) - { - offset += len - WINDOW_SIZE; - len = WINDOW_SIZE; - } - System.arraycopy(dict, offset, window, 0, len); - window_end = len & WINDOW_MASK; - } - - public int getFreeSpace() - { - return WINDOW_SIZE - window_filled; - } - - public int getAvailable() - { - return window_filled; - } - - public int copyOutput(byte[] output, int offset, int len) - { - int copy_end = window_end; - if (len > window_filled) - len = window_filled; - else - copy_end = (window_end - window_filled + len) & WINDOW_MASK; - - int copied = len; - int tailLen = len - copy_end; - - if (tailLen > 0) - { - System.arraycopy(window, WINDOW_SIZE - tailLen, - output, offset, tailLen); - offset += tailLen; - len = copy_end; - } - System.arraycopy(window, copy_end - len, output, offset, len); - window_filled -= copied; - if (window_filled < 0) - throw new IllegalStateException(); - return copied; - } - - public void reset() { - window_filled = window_end = 0; - } -} - - - diff --git a/openjdk/java/util/zip/PendingBuffer.java b/openjdk/java/util/zip/PendingBuffer.java deleted file mode 100644 index 4c7e2165..00000000 --- a/openjdk/java/util/zip/PendingBuffer.java +++ /dev/null @@ -1,200 +0,0 @@ -/* java.util.zip.PendingBuffer - Copyright (C) 2001 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - -package java.util.zip; - -/** - * This class is general purpose class for writing data to a buffer. - * - * It allows you to write bits as well as bytes - * - * Based on DeflaterPending.java - * - * @author Jochen Hoenicke - * @date Jan 5, 2000 - */ - -class PendingBuffer -{ - protected byte[] buf; - int start; - int end; - - int bits; - int bitCount; - - public PendingBuffer() - { - this( 4096 ); - } - - public PendingBuffer(int bufsize) - { - buf = new byte[bufsize]; - } - - public final void reset() { - start = end = bitCount = 0; - } - - public final void writeByte(int b) - { - if (DeflaterConstants.DEBUGGING && start != 0) - throw new IllegalStateException(); - buf[end++] = (byte) b; - } - - public final void writeShort(int s) - { - if (DeflaterConstants.DEBUGGING && start != 0) - throw new IllegalStateException(); - buf[end++] = (byte) s; - buf[end++] = (byte) (s >> 8); - } - - public final void writeInt(int s) - { - if (DeflaterConstants.DEBUGGING && start != 0) - throw new IllegalStateException(); - buf[end++] = (byte) s; - buf[end++] = (byte) (s >> 8); - buf[end++] = (byte) (s >> 16); - buf[end++] = (byte) (s >> 24); - } - - public final void writeBlock(byte[] block, int offset, int len) - { - if (DeflaterConstants.DEBUGGING && start != 0) - throw new IllegalStateException(); - System.arraycopy(block, offset, buf, end, len); - end += len; - } - - public final int getBitCount() { - return bitCount; - } - - public final void alignToByte() { - if (DeflaterConstants.DEBUGGING && start != 0) - throw new IllegalStateException(); - if (bitCount > 0) - { - buf[end++] = (byte) bits; - if (bitCount > 8) - buf[end++] = (byte) (bits >>> 8); - } - bits = 0; - bitCount = 0; - } - - public final void writeBits(int b, int count) - { - if (DeflaterConstants.DEBUGGING && start != 0) - throw new IllegalStateException(); - if (DeflaterConstants.DEBUGGING) - System.err.println("writeBits("+Integer.toHexString(b)+","+count+")"); - bits |= b << bitCount; - bitCount += count; - if (bitCount >= 16) { - buf[end++] = (byte) bits; - buf[end++] = (byte) (bits >>> 8); - bits >>>= 16; - bitCount -= 16; - } - } - - public final void writeShortMSB(int s) { - if (DeflaterConstants.DEBUGGING && start != 0) - throw new IllegalStateException(); - buf[end++] = (byte) (s >> 8); - buf[end++] = (byte) s; - } - - public final boolean isFlushed() { - return end == 0; - } - - /** - * Flushes the pending buffer into the given output array. If the - * output array is to small, only a partial flush is done. - * - * @param output the output array; - * @param offset the offset into output array; - * @param length the maximum number of bytes to store; - * @exception IndexOutOfBoundsException if offset or length are - * invalid. - */ - public final int flush(byte[] output, int offset, int length) { - if (bitCount >= 8) - { - buf[end++] = (byte) bits; - bits >>>= 8; - bitCount -= 8; - } - if (length > end - start) - { - length = end - start; - System.arraycopy(buf, start, output, offset, length); - start = 0; - end = 0; - } - else - { - System.arraycopy(buf, start, output, offset, length); - start += length; - } - return length; - } - - /** - * Flushes the pending buffer and returns that data in a new array - * - * @return the output stream - */ - - public final byte[] toByteArray() - { - byte[] ret = new byte[ end - start ]; - System.arraycopy(buf, start, ret, 0, ret.length); - start = 0; - end = 0; - return ret; - } - - -} - diff --git a/openjdk/java/util/zip/StreamManipulator.java b/openjdk/java/util/zip/StreamManipulator.java deleted file mode 100644 index 16585def..00000000 --- a/openjdk/java/util/zip/StreamManipulator.java +++ /dev/null @@ -1,216 +0,0 @@ -/* java.util.zip.StreamManipulator - Copyright (C) 2001 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - -package java.util.zip; - -/** - * This class allows us to retrieve a specified amount of bits from - * the input buffer, as well as copy big byte blocks. - * - * It uses an int buffer to store up to 31 bits for direct - * manipulation. This guarantees that we can get at least 16 bits, - * but we only need at most 15, so this is all safe. - * - * There are some optimizations in this class, for example, you must - * never peek more then 8 bits more than needed, and you must first - * peek bits before you may drop them. This is not a general purpose - * class but optimized for the behaviour of the Inflater. - * - * @author John Leuner, Jochen Hoenicke - */ - -class StreamManipulator -{ - private byte[] window; - private int window_start = 0; - private int window_end = 0; - - private int buffer = 0; - private int bits_in_buffer = 0; - - /** - * Get the next n bits but don't increase input pointer. n must be - * less or equal 16 and if you if this call succeeds, you must drop - * at least n-8 bits in the next call. - * - * @return the value of the bits, or -1 if not enough bits available. */ - public final int peekBits(int n) - { - if (bits_in_buffer < n) - { - if (window_start == window_end) - return -1; - buffer |= (window[window_start++] & 0xff - | (window[window_start++] & 0xff) << 8) << bits_in_buffer; - bits_in_buffer += 16; - } - return buffer & ((1 << n) - 1); - } - - /* Drops the next n bits from the input. You should have called peekBits - * with a bigger or equal n before, to make sure that enough bits are in - * the bit buffer. - */ - public final void dropBits(int n) - { - buffer >>>= n; - bits_in_buffer -= n; - } - - /** - * Gets the next n bits and increases input pointer. This is equivalent - * to peekBits followed by dropBits, except for correct error handling. - * @return the value of the bits, or -1 if not enough bits available. - */ - public final int getBits(int n) - { - int bits = peekBits(n); - if (bits >= 0) - dropBits(n); - return bits; - } - /** - * Gets the number of bits available in the bit buffer. This must be - * only called when a previous peekBits() returned -1. - * @return the number of bits available. - */ - public final int getAvailableBits() - { - return bits_in_buffer; - } - - /** - * Gets the number of bytes available. - * @return the number of bytes available. - */ - public final int getAvailableBytes() - { - return window_end - window_start + (bits_in_buffer >> 3); - } - - /** - * Skips to the next byte boundary. - */ - public void skipToByteBoundary() - { - buffer >>= (bits_in_buffer & 7); - bits_in_buffer &= ~7; - } - - public final boolean needsInput() { - return window_start == window_end; - } - - - /* Copies length bytes from input buffer to output buffer starting - * at output[offset]. You have to make sure, that the buffer is - * byte aligned. If not enough bytes are available, copies fewer - * bytes. - * @param length the length to copy, 0 is allowed. - * @return the number of bytes copied, 0 if no byte is available. - */ - public int copyBytes(byte[] output, int offset, int length) - { - if (length < 0) - throw new IllegalArgumentException("length negative"); - if ((bits_in_buffer & 7) != 0) - /* bits_in_buffer may only be 0 or 8 */ - throw new IllegalStateException("Bit buffer is not aligned!"); - - int count = 0; - while (bits_in_buffer > 0 && length > 0) - { - output[offset++] = (byte) buffer; - buffer >>>= 8; - bits_in_buffer -= 8; - length--; - count++; - } - if (length == 0) - return count; - - int avail = window_end - window_start; - if (length > avail) - length = avail; - System.arraycopy(window, window_start, output, offset, length); - window_start += length; - - if (((window_start - window_end) & 1) != 0) - { - /* We always want an even number of bytes in input, see peekBits */ - buffer = (window[window_start++] & 0xff); - bits_in_buffer = 8; - } - return count + length; - } - - public StreamManipulator() - { - } - - public void reset() - { - window_start = window_end = buffer = bits_in_buffer = 0; - } - - public void setInput(byte[] buf, int off, int len) - { - if (window_start < window_end) - throw new IllegalStateException - ("Old input was not completely processed"); - - int end = off + len; - - /* We want to throw an ArrayIndexOutOfBoundsException early. The - * check is very tricky: it also handles integer wrap around. - */ - if (0 > off || off > end || end > buf.length) - throw new ArrayIndexOutOfBoundsException(); - - if ((len & 1) != 0) - { - /* We always want an even number of bytes in input, see peekBits */ - buffer |= (buf[off++] & 0xff) << bits_in_buffer; - bits_in_buffer += 8; - } - - window = buf; - window_start = off; - window_end = end; - } -} - diff --git a/openjdk/java/util/zip/ZipEntry.java b/openjdk/java/util/zip/ZipEntry.java deleted file mode 100644 index 4d7e3f24..00000000 --- a/openjdk/java/util/zip/ZipEntry.java +++ /dev/null @@ -1,330 +0,0 @@ -/* ZipEntry.java -- - Copyright (C) 2001, 2002, 2004, 2005, 2011 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - - -package java.util.zip; - -import java.util.Date; - -/** - * This class represents a member of a zip archive. ZipFile and - * ZipInputStream will give you instances of this class as information - * about the members in an archive. On the other hand ZipOutputStream - * needs an instance of this class to create a new member. - * - * @author Jochen Hoenicke - */ -public class ZipEntry implements ZipConstants, Cloneable -{ - String name; - long time = -1; - long crc = -1; - long size = -1; - long csize = -1; - int method = -1; - int flag; - byte[] extra; - String comment; - - long offset; /* used by ZipFile */ - - /** - * Compression method. This method doesn't compress at all. - */ - public static final int STORED = 0; - /** - * Compression method. This method uses the Deflater. - */ - public static final int DEFLATED = 8; - - /** - * Creates a zip entry with the given name. - * @param name the name. May include directory components separated - * by '/'. - * - * @exception NullPointerException when name is null. - * @exception IllegalArgumentException when name is bigger then 65535 chars. - */ - public ZipEntry(String name) - { - int length = name.length(); - if (length > 65535) - throw new IllegalArgumentException("name length is " + length); - this.name = name; - } - - /** - * Creates a copy of the given zip entry. - * @param e the entry to copy. - */ - public ZipEntry(ZipEntry e) - { - name = e.name; - time = e.time; - crc = e.crc; - size = e.size; - csize = e.csize; - method = e.method; - flag = e.flag; - extra = e.extra; - comment = e.comment; - } - - ZipEntry() - { - } - - /** - * Creates a copy of this zip entry. - */ - /** - * Clones the entry. - */ - public Object clone() - { - try - { - // The JCL says that the `extra' field is also copied. - ZipEntry clone = (ZipEntry)super.clone(); - if (extra != null) - clone.extra = (byte[])extra.clone(); - return clone; - } - catch (CloneNotSupportedException ex) - { - throw new InternalError(); - } - } - - /** - * Returns the entry name. The path components in the entry are - * always separated by slashes ('/'). - */ - public String getName() - { - return name; - } - - /** - * Sets the time of last modification of the entry. - * @time the time of last modification of the entry. - */ - public void setTime(long time) - { - Date d = new Date(time); - if (d.getYear() < 80) - { - d = new Date(80, 0, 1); - } - this.time = ((d.getYear() - 80) << 25) - | ((d.getMonth() + 1) << 21) - | (d.getDate() << 16) - | (d.getHours() << 11) - | (d.getMinutes() << 5) - | (d.getSeconds() >> 1); - } - - /** - * Gets the time of last modification of the entry. - * @return the time of last modification of the entry, or -1 if unknown. - */ - public long getTime() - { - if (time == -1) - { - return -1; - } - Date d = new Date((int)(((time >> 25) & 0x7f) + 80), - (int)(((time >> 21) & 0x0f) - 1), - (int)((time >> 16) & 0x1f), - (int)((time >> 11) & 0x1f), - (int)((time >> 5) & 0x3f), - (int)((time << 1) & 0x3e)); - return d.getTime(); - } - - /** - * Sets the size of the uncompressed data. - * @exception IllegalArgumentException if size is negative. - */ - public void setSize(long size) - { - if (size < 0) - throw new IllegalArgumentException(); - this.size = size; - } - - /** - * Gets the size of the uncompressed data. - * @return the size or -1 if unknown. - */ - public long getSize() - { - return size; - } - - /** - * Sets the size of the compressed data. - */ - public void setCompressedSize(long csize) - { - this.csize = csize; - } - - /** - * Gets the size of the compressed data. - * @return the size or -1 if unknown. - */ - public long getCompressedSize() - { - return csize; - } - - /** - * Sets the crc of the uncompressed data. - * @exception IllegalArgumentException if crc is not in 0..0xffffffffL - */ - public void setCrc(long crc) - { - if ((crc & 0xffffffff00000000L) != 0) - throw new IllegalArgumentException(); - this.crc = crc; - } - - /** - * Gets the crc of the uncompressed data. - * @return the crc or -1 if unknown. - */ - public long getCrc() - { - return crc; - } - - /** - * Sets the compression method. Only DEFLATED and STORED are - * supported. - * @exception IllegalArgumentException if method is not supported. - * @see ZipOutputStream#DEFLATED - * @see ZipOutputStream#STORED - */ - public void setMethod(int method) - { - if (method != ZipOutputStream.STORED - && method != ZipOutputStream.DEFLATED) - throw new IllegalArgumentException(); - this.method = method; - } - - /** - * Gets the compression method. - * @return the compression method or -1 if unknown. - */ - public int getMethod() - { - return method; - } - - /** - * Sets the extra data. - * @exception IllegalArgumentException if extra is longer than 0xffff bytes. - */ - public void setExtra(byte[] extra) - { - if (extra == null) - { - this.extra = null; - return; - } - if (extra.length > 0xffff) - throw new IllegalArgumentException(); - this.extra = extra; - } - - /** - * Gets the extra data. - * @return the extra data or null if not set. - */ - public byte[] getExtra() - { - return extra; - } - - /** - * Sets the entry comment. - */ - public void setComment(String comment) - { - this.comment = comment; - } - - /** - * Gets the comment. - * @return the comment or null if not set. - */ - public String getComment() - { - return comment; - } - - /** - * Gets true, if the entry is a directory. This is solely - * determined by the name, a trailing slash '/' marks a directory. - */ - public boolean isDirectory() - { - int nlen = name.length(); - return nlen > 0 && name.charAt(nlen - 1) == '/'; - } - - /** - * Gets the string representation of this ZipEntry. This is just - * the name as returned by getName(). - */ - public String toString() - { - return getName(); - } - - /** - * Gets the hashCode of this ZipEntry. This is just the hashCode - * of the name. Note that the equals method isn't changed, though. - */ - public int hashCode() - { - return name.hashCode(); - } -} diff --git a/openjdk/java/util/zip/ZipFile.java b/openjdk/java/util/zip/ZipFile.java deleted file mode 100644 index 35fbc665..00000000 --- a/openjdk/java/util/zip/ZipFile.java +++ /dev/null @@ -1,889 +0,0 @@ -/* ZipFile.java -- - Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2011 - Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - - -package java.util.zip; - -import java.io.Closeable; -import java.io.EOFException; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.RandomAccessFile; -import java.io.UnsupportedEncodingException; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.LinkedHashMap; -import static java.util.zip.ZipConstants64.*; - -/** - * This class represents a Zip archive. You can ask for the contained - * entries, or get an input stream for a file entry. The entry is - * automatically decompressed. - * - * This class is thread safe: You can open input streams for arbitrary - * entries in different threads. - * - * @author Jochen Hoenicke - * @author Artur Biesiadowski - */ -public class ZipFile implements ZipConstants, Closeable -{ - - /** - * Mode flag to open a zip file for reading. - */ - public static final int OPEN_READ = 0x1; - - /** - * Mode flag to delete a zip file after reading. - */ - public static final int OPEN_DELETE = 0x4; - - /** - * This field isn't defined in the JDK's ZipConstants, but should be. - */ - static final int ENDNRD = 4; - - // Name of this zip file. - private final String name; - - // Encoding to use for name and comment strings - private final Charset charset; - - // File from which zip entries are read. - private final RandomAccessFile raf; - - // The entries of this zip file when initialized and not yet closed. - private LinkedHashMap<String, ZipEntry> entries; - - private boolean closed = false; - - /** - * Opens a Zip file with the given name for reading. - * @exception IOException if a i/o error occured. - * @exception ZipException if the file doesn't contain a valid zip - * archive. - */ - public ZipFile(String name) throws ZipException, IOException - { - this(new File(name), OPEN_READ); - } - - /** - * Opens a Zip file reading the given File. - * @exception IOException if a i/o error occured. - * @exception ZipException if the file doesn't contain a valid zip - * archive. - */ - public ZipFile(File file) throws ZipException, IOException - { - this(file, OPEN_READ); - } - - /** - * Opens a Zip file reading the given File. - * @exception IOException if a i/o error occured. - * @exception ZipException if the file doesn't contain a valid zip - * archive. - */ - public ZipFile(File file, Charset charset) throws IOException - { - this(file, OPEN_READ, charset); - } - - /** - * Opens a Zip file reading the given File. - * @exception IOException if a i/o error occured. - * @exception ZipException if the file doesn't contain a valid zip - * archive. - */ - public ZipFile(String name, Charset charset) throws IOException - { - this(new File(name), OPEN_READ, charset); - } - - /** - * Opens a Zip file reading the given File in the given mode. - * - * If the OPEN_DELETE mode is specified, the zip file will be deleted at - * some time moment after it is opened. It will be deleted before the zip - * file is closed or the Virtual Machine exits. - * - * The contents of the zip file will be accessible until it is closed. - * - * @since JDK1.3 - * @param mode Must be one of OPEN_READ or OPEN_READ | OPEN_DELETE - * - * @exception IOException if a i/o error occured. - * @exception ZipException if the file doesn't contain a valid zip - * archive. - */ - public ZipFile(File file, int mode) throws IOException - { - this(file, mode, StandardCharsets.UTF_8); - } - - /** - * Opens a Zip file reading the given File in the given mode. - * - * If the OPEN_DELETE mode is specified, the zip file will be deleted at - * some time moment after it is opened. It will be deleted before the zip - * file is closed or the Virtual Machine exits. - * - * The contents of the zip file will be accessible until it is closed. - * - * @since JDK1.7 - * @param mode Must be one of OPEN_READ or OPEN_READ | OPEN_DELETE - * @param charset Character encoding to use for names and comments - * - * @exception IOException if a i/o error occured. - * @exception ZipException if the file doesn't contain a valid zip - * archive. - */ - public ZipFile(File file, int mode, Charset charset) throws IOException - { - if (mode != OPEN_READ && mode != (OPEN_READ | OPEN_DELETE)) - throw new IllegalArgumentException("Illegal mode: 0x" + Integer.toHexString(mode)); - if (charset == null) - throw new NullPointerException("charset is null"); - if ((mode & OPEN_DELETE) != 0) - file.deleteOnExit(); - this.raf = new RandomAccessFile(file, "r"); - this.name = file.getPath(); - this.charset = charset; - - boolean valid = false; - - try - { - readEntries(); - ClassStubZipEntry.expandIkvmClasses(this, entries); - valid = true; - } - catch (EOFException _) - { - throw new ZipException("invalid CEN header (bad header size)"); - } - finally - { - if (!valid) - { - try - { - raf.close(); - } - catch (IOException _) - { - } - } - } - } - - /** - * Checks if file is closed and throws an exception. - */ - private void checkClosed() - { - if (closed) - throw new IllegalStateException("zip file closed"); - } - - /** - * Read the central directory of a zip file and fill the entries - * array. This is called exactly once when first needed. It is called - * while holding the lock on <code>raf</code>. - * - * @exception IOException if a i/o error occured. - * @exception ZipException if the central directory is malformed - */ - private void readEntries() throws IOException - { - PartialInputStream inp = new PartialInputStream(4096); - long pos = inp.seekEndOfCentralDirectory(); - inp.skip(6); - int count = inp.readLeUnsignedShort(); - long centralSize = inp.readLeUnsignedInt(); - long centralOffset = inp.readLeUnsignedInt(); - - if (centralSize == ZIP64_MAGICVAL - || centralOffset == ZIP64_MAGICVAL - || count == ZIP64_MAGICCOUNT) - { - inp.seek(pos - ZIP64_LOCHDR); - if (inp.readLeInt() == ZIP64_LOCSIG) - { - inp.skip(4); - long zip64end = inp.readLeLong(); - inp.seek(zip64end); - if (inp.readLeInt() == ZIP64_ENDSIG) - { - inp.skip(ZIP64_ENDSIZ - 4); - centralSize = inp.readLeLong(); - centralOffset = inp.readLeLong(); - pos = zip64end; - } - } - } - - if (centralSize > pos) - throw new ZipException("invalid END header (bad central directory size)"); - - if (centralOffset > pos - centralSize) - throw new ZipException("invalid END header (bad central directory offset)"); - - entries = new LinkedHashMap<String, ZipEntry> (count+count/2); - inp.seek(pos - centralSize); - - while (inp.position() <= pos - CENHDR) - { - if (inp.readLeInt() != CENSIG) - throw new ZipException("invalid CEN header (bad signature)"); - - inp.skip(4); - int flags = inp.readLeUnsignedShort(); - if ((flags & 1) != 0) - throw new ZipException("invalid CEN header (encrypted entry)"); - int method = inp.readLeUnsignedShort(); - if (method != ZipEntry.STORED && method != ZipEntry.DEFLATED) - throw new ZipException("invalid CEN header (bad compression method)"); - ZipEntry entry = new ZipEntry(); - entry.flag = flags; - entry.method = method; - entry.time = inp.readLeUnsignedInt(); - entry.crc = inp.readLeUnsignedInt(); - entry.csize = inp.readLeUnsignedInt(); - entry.size = inp.readLeUnsignedInt(); - int nameLen = inp.readLeUnsignedShort(); - int extraLen = inp.readLeUnsignedShort(); - int commentLen = inp.readLeUnsignedShort(); - inp.skip(8); - entry.offset = inp.readLeUnsignedInt(); - entry.name = inp.readString(nameLen, (flags & EFS) != 0); - - if (extraLen > 0) - { - byte[] extra = new byte[extraLen]; - inp.readFully(extra); - entry.extra = extra; - readZip64ExtraField(entry, extra); - } - if (commentLen > 0) - { - entry.comment = inp.readString(commentLen, (flags & EFS) != 0); - } - entries.put(entry.name, entry); - } - - if (inp.position() != pos) - throw new ZipException("invalid CEN header (bad header size)"); - } - - private static void readZip64ExtraField(ZipEntry entry, byte[] extra) - { - if (entry.csize == ZIP64_MAGICVAL || entry.size == ZIP64_MAGICVAL - || entry.offset == ZIP64_MAGICVAL) - { - for (int pos = 0; pos < extra.length - 4; ) - { - int headerID = decodeLeUnsignedShort(extra, pos); - int dataSize = decodeLeUnsignedShort(extra, pos + 2); - pos += 4; - if (headerID == ZIP64_EXTID) - { - if (entry.size == ZIP64_MAGICVAL) - { - entry.size = decodeLeLong(extra, pos); - pos += 8; - } - if (entry.csize == ZIP64_MAGICVAL) - { - entry.csize = decodeLeLong(extra, pos); - pos += 8; - } - if (entry.offset == ZIP64_MAGICVAL) - { - entry.offset = decodeLeLong(extra, pos); - pos += 8; - } - break; - } - pos += dataSize; - } - } - } - - private static int decodeLeUnsignedShort(byte[] b, int off) - { - return (b[off] & 0xFF) | ((b[off + 1] & 0xFF) << 8); - } - - private static long decodeLeLong(byte[] b, int off) - { - return 0 - | ((b[off + 0] & 0xFFL) << 0) - | ((b[off + 1] & 0xFFL) << 8) - | ((b[off + 2] & 0xFFL) << 16) - | ((b[off + 3] & 0xFFL) << 24) - | ((b[off + 4] & 0xFFL) << 32) - | ((b[off + 5] & 0xFFL) << 40) - | ((b[off + 6] & 0xFFL) << 48) - | ((b[off + 7] & 0xFFL) << 56); - } - - /** - * Closes the ZipFile. This also closes all input streams given by - * this class. After this is called, no further method should be - * called. - * - * @exception IOException if a i/o error occured. - */ - public void close() throws IOException - { - RandomAccessFile raf = this.raf; - if (raf == null) - return; - - synchronized (raf) - { - closed = true; - entries = null; - raf.close(); - } - } - - /** - * Calls the <code>close()</code> method when this ZipFile has not yet - * been explicitly closed. - */ - protected void finalize() throws IOException - { - if (!closed && raf != null) close(); - } - - /** - * Returns an enumeration of all Zip entries in this Zip file. - * - * @exception IllegalStateException when the ZipFile has already been closed - */ - public Enumeration<? extends ZipEntry> entries() - { - checkClosed(); - return new ZipEntryEnumeration(entries.values().iterator()); - } - - /** - * Searches for a zip entry in this archive with the given name. - * - * @param name the name. May contain directory components separated by - * slashes ('/'). - * @return the zip entry, or null if no entry with that name exists. - * - * @exception IllegalStateException when the ZipFile has already been closed - */ - public ZipEntry getEntry(String name) - { - checkClosed(); - ZipEntry entry = entries.get(name); - // If we didn't find it, maybe it's a directory. - if (entry == null && !name.endsWith("/")) - entry = entries.get(name + '/'); - return entry != null ? (ZipEntry)entry.clone() : null; - } - - /** - * Creates an input stream reading the given zip entry as - * uncompressed data. Normally zip entry should be an entry - * returned by getEntry() or entries(). - * - * This implementation returns null if the requested entry does not - * exist. This decision is not obviously correct, however, it does - * appear to mirror Sun's implementation, and it is consistant with - * their javadoc. On the other hand, the old JCL book, 2nd Edition, - * claims that this should return a "non-null ZIP entry". We have - * chosen for now ignore the old book, as modern versions of Ant (an - * important application) depend on this behaviour. See discussion - * in this thread: - * http://gcc.gnu.org/ml/java-patches/2004-q2/msg00602.html - * - * @param entry the entry to create an InputStream for. - * @return the input stream, or null if the requested entry does not exist. - * - * @exception IllegalStateException when the ZipFile has already been closed - * @exception IOException if a i/o error occured. - * @exception ZipException if the Zip archive is malformed. - */ - public InputStream getInputStream(ZipEntry entry) throws IOException - { - checkClosed(); - - final ZipEntry zipEntry = entries.get(entry.getName()); - if (zipEntry == null) - return null; - - if (zipEntry instanceof ClassStubZipEntry) - return ((ClassStubZipEntry)zipEntry).getInputStream(); - - PartialInputStream inp = new PartialInputStream(1024) { - void lazyInitialSeek() throws IOException { - seek(zipEntry.offset); - - if (readLeInt() != LOCSIG) - throw new ZipException("invalid LOC header (bad signature)"); - - skip(22); - - int nameLen = readLeUnsignedShort(); - int extraLen = readLeUnsignedShort(); - skip(nameLen + extraLen); - - setLength(zipEntry.getCompressedSize()); - } - }; - - switch (zipEntry.getMethod()) - { - case ZipOutputStream.STORED: - return inp; - case ZipOutputStream.DEFLATED: - inp.addDummyByte(); - final Inflater inf = new Inflater(true); - final int sz = (int) zipEntry.getSize(); - return new InflaterInputStream(inp, inf) - { - private boolean closed; - public void close() throws IOException - { - closed = true; - super.close(); - } - public int available() throws IOException - { - if (closed) - return 0; - if (sz == -1) - return super.available(); - if (super.available() != 0) - return sz - inf.getTotalOut(); - return 0; - } - }; - default: - throw new ZipException("invalid compression method"); - } - } - - /** - * Returns the (path) name of this zip file. - */ - public String getName() - { - return name; - } - - /** - * Returns the number of entries in this zip file. - * - * @exception IllegalStateException when the ZipFile has already been closed - */ - public int size() - { - checkClosed(); - return entries.size(); - } - - /** - * Returns the zip file comment. - * - * @exception IllegalStateException when the ZipFile has already been closed - */ - public synchronized String getComment() - { - checkClosed(); - try - { - PartialInputStream inp = new PartialInputStream(4096); - long pos = inp.seekEndOfCentralDirectory(); - inp.skip(16); - int commentLength = inp.readLeUnsignedShort(); - if (commentLength == 0) - return null; - return inp.readString(commentLength, false); - } - catch (IOException _) - { - return null; - } - } - - private static class ZipEntryEnumeration implements Enumeration<ZipEntry> - { - private final Iterator<ZipEntry> elements; - - public ZipEntryEnumeration(Iterator<ZipEntry> elements) - { - this.elements = elements; - } - - public boolean hasMoreElements() - { - return elements.hasNext(); - } - - public ZipEntry nextElement() - { - /* We return a clone, just to be safe that the user doesn't - * change the entry. - */ - return (ZipEntry) (elements.next().clone()); - } - } - - private class PartialInputStream extends InputStream - { - private final byte[] buffer; - private long bufferOffset; - private int pos; - private long end; - private boolean lazy; - // We may need to supply an extra dummy byte to our reader. - // See Inflater. We use a count here to simplify the logic - // elsewhere in this class. Note that we ignore the dummy - // byte in methods where we know it is not needed. - private int dummyByteCount; - - public PartialInputStream(int bufferSize) - throws IOException - { - buffer = new byte[bufferSize]; - bufferOffset = -buffer.length; - pos = buffer.length; - end = raf.length(); - lazy = true; - } - - // Seek to the "end of central directory record" and position - // the stream after the ENDSIG and return the file offset - // where the record starts. - long seekEndOfCentralDirectory() throws IOException - { - /* Search for the End Of Central Directory. When a zip comment is - * present the directory may start earlier. - * Note that a comment has a maximum length of 64K, so that is the - * maximum we search backwards. - */ - long length = raf.length(); - if (length == 0) - throw new ZipException("zip file is empty"); - long pos = length - ENDHDR; - long top = Math.max(0, pos - 65536); - do - { - if (pos < top) - throw new ZipException("error in opening zip file"); - seek(pos--); - } - while (readLeInt() != ENDSIG); - return pos + 1; - } - - void lazyInitialSeek() throws IOException - { - } - - void setLength(long length) - { - end = bufferOffset + pos + length; - } - - private void fillBuffer() throws IOException - { - if (closed) - throw new ZipException("ZipFile closed"); - - synchronized (raf) - { - long len = end - bufferOffset; - if (len == 0 && dummyByteCount > 0) - { - buffer[0] = 0; - dummyByteCount = 0; - } - else - { - raf.seek(bufferOffset); - raf.readFully(buffer, 0, (int) Math.min(buffer.length, len)); - } - } - } - - public int available() throws IOException - { - if (lazy) - { - lazy = false; - lazyInitialSeek(); - } - long amount = end - (bufferOffset + pos); - if (amount > Integer.MAX_VALUE) - return Integer.MAX_VALUE; - return (int) amount; - } - - public int read() throws IOException - { - if (bufferOffset + pos >= end + dummyByteCount) - return -1; - if (pos == buffer.length) - { - if (lazy) - { - lazy = false; - lazyInitialSeek(); - return read(); - } - bufferOffset += buffer.length; - pos = 0; - fillBuffer(); - } - - return buffer[pos++] & 0xFF; - } - - public int read(byte[] b, int off, int len) throws IOException - { - if (lazy) - { - lazy = false; - lazyInitialSeek(); - } - - if (len > end + dummyByteCount - (bufferOffset + pos)) - { - len = (int) (end + dummyByteCount - (bufferOffset + pos)); - if (len == 0) - return -1; - } - - int totalBytesRead = Math.min(buffer.length - pos, len); - System.arraycopy(buffer, pos, b, off, totalBytesRead); - pos += totalBytesRead; - off += totalBytesRead; - len -= totalBytesRead; - - while (len > 0) - { - bufferOffset += buffer.length; - pos = 0; - fillBuffer(); - int remain = Math.min(buffer.length, len); - System.arraycopy(buffer, pos, b, off, remain); - pos += remain; - off += remain; - len -= remain; - totalBytesRead += remain; - } - - return totalBytesRead; - } - - public long skip(long amount) throws IOException - { - if (lazy) - { - lazy = false; - lazyInitialSeek(); - } - if (amount < 0) - return 0; - if (amount > end - (bufferOffset + pos)) - amount = end - (bufferOffset + pos); - seek(bufferOffset + pos + amount); - return amount; - } - - void seek(long newpos) throws IOException - { - long offset = newpos - bufferOffset; - if (offset >= 0 && offset <= buffer.length) - { - pos = (int) offset; - } - else - { - bufferOffset = newpos; - pos = 0; - fillBuffer(); - } - } - - long position() - { - return bufferOffset + pos; - } - - void readFully(byte[] buf) throws IOException - { - if (read(buf, 0, buf.length) != buf.length) - throw new EOFException(); - } - - void readFully(byte[] buf, int off, int len) throws IOException - { - if (read(buf, off, len) != len) - throw new EOFException(); - } - - int readLeUnsignedShort() throws IOException - { - int result; - if(pos + 1 < buffer.length) - { - result = ((buffer[pos + 0] & 0xff) | (buffer[pos + 1] & 0xff) << 8); - pos += 2; - } - else - { - int b0 = read(); - int b1 = read(); - if (b1 == -1) - throw new EOFException(); - result = (b0 & 0xff) | (b1 & 0xff) << 8; - } - return result; - } - - int readLeInt() throws IOException - { - int result; - if(pos + 3 < buffer.length) - { - result = (((buffer[pos + 0] & 0xff) | (buffer[pos + 1] & 0xff) << 8) - | ((buffer[pos + 2] & 0xff) - | (buffer[pos + 3] & 0xff) << 8) << 16); - pos += 4; - } - else - { - int b0 = read(); - int b1 = read(); - int b2 = read(); - int b3 = read(); - if (b3 == -1) - throw new EOFException(); - result = (((b0 & 0xff) | (b1 & 0xff) << 8) | ((b2 & 0xff) - | (b3 & 0xff) << 8) << 16); - } - return result; - } - - final long readLeUnsignedInt() throws IOException - { - return readLeInt() & 0xffffffffL; - } - - final long readLeLong() throws IOException - { - return readLeUnsignedInt() | (readLeUnsignedInt() << 32); - } - - /** - * Decode chars from byte buffer using charset encoding. This - * operation is performance-critical since a jar file contains a - * large number of strings for the name of each file in the - * archive. This routine therefore avoids using the expensive - * utf8Decoder when decoding is straightforward. - * - * @param buffer the buffer that contains the encoded character - * data - * @param pos the index in buffer of the first byte of the encoded - * data - * @param length the length of the encoded data in number of - * bytes. - * - * @return a String that contains the decoded characters. - */ - private String decodeChars(byte[] buffer, int pos, int length, boolean utf8) - throws IOException - { - if (!utf8 && charset != StandardCharsets.UTF_8) - return new String(buffer, pos, length, charset); - - for (int i = pos; i < pos + length; i++) - { - if (buffer[i] <= 0) - return new String(buffer, pos, length, "UTF-8"); - } - return new String(buffer, 0, pos, length); - } - - String readString(int length, boolean utf8) throws IOException - { - if (length > end - (bufferOffset + pos)) - throw new EOFException(); - - String result = null; - try - { - if (buffer.length - pos >= length) - { - result = decodeChars(buffer, pos, length, utf8); - pos += length; - } - else - { - byte[] b = new byte[length]; - readFully(b); - result = decodeChars(b, 0, length, utf8); - } - } - catch (UnsupportedEncodingException uee) - { - throw new AssertionError(uee); - } - return result; - } - - public void addDummyByte() - { - dummyByteCount = 1; - } - } -} |