mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
Merge
This commit is contained in:
commit
b3eb4c3ce8
3478 changed files with 69866 additions and 22997 deletions
|
@ -1366,7 +1366,7 @@ class ConstantPool {
|
|||
}
|
||||
if (tag == CONSTANT_Utf8) {
|
||||
// Special case: First Utf8 must always be empty string.
|
||||
assert(cpMap.length == 0 || cpMap[0].stringValue().equals(""));
|
||||
assert(cpMap.length == 0 || cpMap[0].stringValue().isEmpty());
|
||||
}
|
||||
indexByTag[tag] = ix;
|
||||
// decache indexes derived from this one:
|
||||
|
|
|
@ -208,7 +208,7 @@ class Driver {
|
|||
}
|
||||
}
|
||||
|
||||
if (logFile != null && !logFile.equals("")) {
|
||||
if (logFile != null && !logFile.isEmpty()) {
|
||||
if (logFile.equals("-")) {
|
||||
System.setErr(System.out);
|
||||
} else {
|
||||
|
@ -246,7 +246,7 @@ class Driver {
|
|||
}
|
||||
newfile = packfile;
|
||||
// The optional second argument is the source JAR file.
|
||||
if (jarfile.equals("")) {
|
||||
if (jarfile.isEmpty()) {
|
||||
// If only one file is given, it is the only JAR.
|
||||
// It serves as both input and output.
|
||||
jarfile = newfile;
|
||||
|
@ -352,7 +352,7 @@ class Driver {
|
|||
if (Utils.isGZIPMagic(Utils.readMagic(inBuf))) {
|
||||
in = new GZIPInputStream(in);
|
||||
}
|
||||
String outfile = newfile.equals("")? jarfile: newfile;
|
||||
String outfile = newfile.isEmpty()? jarfile: newfile;
|
||||
OutputStream fileOut;
|
||||
if (outfile.equals("-"))
|
||||
fileOut = System.out;
|
||||
|
@ -366,7 +366,7 @@ class Driver {
|
|||
// At this point, we have a good jarfile (or newfile, if -r)
|
||||
}
|
||||
|
||||
if (!bakfile.equals("")) {
|
||||
if (!bakfile.isEmpty()) {
|
||||
// On success, abort jarfile recovery bracket.
|
||||
new File(bakfile).delete();
|
||||
bakfile = "";
|
||||
|
@ -374,13 +374,13 @@ class Driver {
|
|||
|
||||
} finally {
|
||||
// Close jarfile recovery bracket.
|
||||
if (!bakfile.equals("")) {
|
||||
if (!bakfile.isEmpty()) {
|
||||
File jarFile = new File(jarfile);
|
||||
jarFile.delete(); // Win32 requires this, see above
|
||||
new File(bakfile).renameTo(jarFile);
|
||||
}
|
||||
// In all cases, delete temporary *.pack.
|
||||
if (!tmpfile.equals(""))
|
||||
if (!tmpfile.isEmpty())
|
||||
new File(tmpfile).delete();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -685,7 +685,7 @@ class Package {
|
|||
return; // do not choose yet
|
||||
}
|
||||
String canonName = canonicalFileName();
|
||||
if (file.nameString.equals("")) {
|
||||
if (file.nameString.isEmpty()) {
|
||||
file.nameString = canonName;
|
||||
}
|
||||
if (file.nameString.equals(canonName)) {
|
||||
|
@ -706,7 +706,7 @@ class Package {
|
|||
|
||||
public java.io.File getFileName(java.io.File parent) {
|
||||
String name = file.name.stringValue();
|
||||
if (name.equals(""))
|
||||
if (name.isEmpty())
|
||||
name = canonicalFileName();
|
||||
String fname = name.replace('/', java.io.File.separatorChar);
|
||||
return new java.io.File(parent, fname);
|
||||
|
@ -779,7 +779,7 @@ class Package {
|
|||
}
|
||||
public boolean isTrivialClassStub() {
|
||||
return isClassStub()
|
||||
&& name.stringValue().equals("")
|
||||
&& name.stringValue().isEmpty()
|
||||
&& (modtime == NO_MODTIME || modtime == default_modtime)
|
||||
&& (options &~ FO_IS_CLASS_STUB) == 0;
|
||||
}
|
||||
|
|
|
@ -646,7 +646,7 @@ class PackageWriter extends BandStructure {
|
|||
return; // nothing to write
|
||||
|
||||
// The first element must always be the empty string.
|
||||
assert(cpMap[0].stringValue().equals(""));
|
||||
assert(cpMap[0].stringValue().isEmpty());
|
||||
final int SUFFIX_SKIP_1 = 1;
|
||||
final int PREFIX_SKIP_2 = 2;
|
||||
|
||||
|
|
|
@ -237,7 +237,7 @@ public class PackerImpl extends TLGlobals implements Pack200.Packer {
|
|||
final long segmentLimit;
|
||||
{
|
||||
long limit;
|
||||
if (props.getProperty(Pack200.Packer.SEGMENT_LIMIT, "").equals(""))
|
||||
if (props.getProperty(Pack200.Packer.SEGMENT_LIMIT, "").isEmpty())
|
||||
limit = -1;
|
||||
else
|
||||
limit = props.getLong(Pack200.Packer.SEGMENT_LIMIT);
|
||||
|
|
|
@ -257,7 +257,7 @@ public class File
|
|||
*/
|
||||
private File(String child, File parent) {
|
||||
assert parent.path != null;
|
||||
assert (!parent.path.equals(""));
|
||||
assert (!parent.path.isEmpty());
|
||||
this.path = fs.resolve(parent.path, child);
|
||||
this.prefixLength = parent.prefixLength;
|
||||
}
|
||||
|
@ -316,7 +316,7 @@ public class File
|
|||
throw new NullPointerException();
|
||||
}
|
||||
if (parent != null) {
|
||||
if (parent.equals("")) {
|
||||
if (parent.isEmpty()) {
|
||||
this.path = fs.resolve(fs.getDefaultParent(),
|
||||
fs.normalize(child));
|
||||
} else {
|
||||
|
@ -359,7 +359,7 @@ public class File
|
|||
throw new NullPointerException();
|
||||
}
|
||||
if (parent != null) {
|
||||
if (parent.path.equals("")) {
|
||||
if (parent.path.isEmpty()) {
|
||||
this.path = fs.resolve(fs.getDefaultParent(),
|
||||
fs.normalize(child));
|
||||
} else {
|
||||
|
@ -426,7 +426,7 @@ public class File
|
|||
if (uri.getRawQuery() != null)
|
||||
throw new IllegalArgumentException("URI has a query component");
|
||||
String p = uri.getPath();
|
||||
if (p.equals(""))
|
||||
if (p.isEmpty())
|
||||
throw new IllegalArgumentException("URI path component is empty");
|
||||
|
||||
// Okay, now initialize
|
||||
|
|
|
@ -64,8 +64,8 @@ public abstract class InputStream implements Closeable {
|
|||
* <p> While the stream is open, the {@code available()}, {@code read()},
|
||||
* {@code read(byte[])}, {@code read(byte[], int, int)},
|
||||
* {@code readAllBytes()}, {@code readNBytes(byte[], int, int)},
|
||||
* {@code readNBytes(int)}, {@code skip(long)}, and
|
||||
* {@code transferTo()} methods all behave as if end of stream has been
|
||||
* {@code readNBytes(int)}, {@code skip(long)}, {@code skipNBytes(long)},
|
||||
* and {@code transferTo()} methods all behave as if end of stream has been
|
||||
* reached. After the stream has been closed, these methods all throw
|
||||
* {@code IOException}.
|
||||
*
|
||||
|
@ -138,6 +138,14 @@ public abstract class InputStream implements Closeable {
|
|||
return 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void skipNBytes(long n) throws IOException {
|
||||
ensureOpen();
|
||||
if (n > 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long transferTo(OutputStream out) throws IOException {
|
||||
Objects.requireNonNull(out);
|
||||
|
@ -513,11 +521,11 @@ public abstract class InputStream implements Closeable {
|
|||
* For instance, the implementation may depend on the ability to seek.
|
||||
*
|
||||
* @param n the number of bytes to be skipped.
|
||||
* @return the actual number of bytes skipped.
|
||||
* @return the actual number of bytes skipped which might be zero.
|
||||
* @throws IOException if an I/O error occurs.
|
||||
* @see java.io.InputStream#skipNBytes(long)
|
||||
*/
|
||||
public long skip(long n) throws IOException {
|
||||
|
||||
long remaining = n;
|
||||
int nr;
|
||||
|
||||
|
@ -538,6 +546,65 @@ public abstract class InputStream implements Closeable {
|
|||
return n - remaining;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips over and discards exactly {@code n} bytes of data from this input
|
||||
* stream. If {@code n} is zero, then no bytes are skipped.
|
||||
* If {@code n} is negative, then no bytes are skipped.
|
||||
* Subclasses may handle the negative value differently.
|
||||
*
|
||||
* <p> This method blocks until the requested number of bytes have been
|
||||
* skipped, end of file is reached, or an exception is thrown.
|
||||
*
|
||||
* <p> If end of stream is reached before the stream is at the desired
|
||||
* position, then an {@code EOFException} is thrown.
|
||||
*
|
||||
* <p> If an I/O error occurs, then the input stream may be
|
||||
* in an inconsistent state. It is strongly recommended that the
|
||||
* stream be promptly closed if an I/O error occurs.
|
||||
*
|
||||
* @implNote
|
||||
* Subclasses are encouraged to provide a more efficient implementation
|
||||
* of this method.
|
||||
*
|
||||
* @implSpec
|
||||
* If {@code n} is zero or negative, then no bytes are skipped.
|
||||
* If {@code n} is positive, the default implementation of this method
|
||||
* invokes {@link #skip(long) skip()} with parameter {@code n}. If the
|
||||
* return value of {@code skip(n)} is non-negative and less than {@code n},
|
||||
* then {@link #read()} is invoked repeatedly until the stream is {@code n}
|
||||
* bytes beyond its position when this method was invoked or end of stream
|
||||
* is reached. If the return value of {@code skip(n)} is negative or
|
||||
* greater than {@code n}, then an {@code IOException} is thrown. Any
|
||||
* exception thrown by {@code skip()} or {@code read()} will be propagated.
|
||||
*
|
||||
* @param n the number of bytes to be skipped.
|
||||
* @throws EOFException if end of stream is encountered before the
|
||||
* stream can be positioned {@code n} bytes beyond its position
|
||||
* when this method was invoked.
|
||||
* @throws IOException if the stream cannot be positioned properly or
|
||||
* if an I/O error occurs.
|
||||
* @see java.io.InputStream#skip(long)
|
||||
*/
|
||||
public void skipNBytes(long n) throws IOException {
|
||||
if (n > 0) {
|
||||
long ns = skip(n);
|
||||
if (ns >= 0 && ns < n) { // skipped too few bytes
|
||||
// adjust number to skip
|
||||
n -= ns;
|
||||
// read until requested number skipped or EOS reached
|
||||
while (n > 0 && read() != -1) {
|
||||
n--;
|
||||
}
|
||||
// if not enough skipped, then EOFE
|
||||
if (n != 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
} else if (ns != n) { // skipped negative or too many bytes
|
||||
throw new IOException("Unable to skip exactly");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an estimate of the number of bytes that can be read (or skipped
|
||||
* over) from this input stream without blocking, which may be 0, or 0 when
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
package java.lang;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.invoke.TypeDescriptor;
|
||||
import java.lang.module.ModuleReader;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.io.IOException;
|
||||
|
@ -46,6 +48,7 @@ import java.lang.reflect.Modifier;
|
|||
import java.lang.reflect.Proxy;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.lang.constant.Constable;
|
||||
import java.net.URL;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
@ -58,6 +61,7 @@ import java.util.LinkedHashSet;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -72,6 +76,7 @@ import jdk.internal.reflect.ConstantPool;
|
|||
import jdk.internal.reflect.Reflection;
|
||||
import jdk.internal.reflect.ReflectionFactory;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
import sun.invoke.util.Wrapper;
|
||||
import sun.reflect.generics.factory.CoreReflectionFactory;
|
||||
import sun.reflect.generics.factory.GenericsFactory;
|
||||
import sun.reflect.generics.repository.ClassRepository;
|
||||
|
@ -154,7 +159,9 @@ import sun.reflect.misc.ReflectUtil;
|
|||
public final class Class<T> implements java.io.Serializable,
|
||||
GenericDeclaration,
|
||||
Type,
|
||||
AnnotatedElement {
|
||||
AnnotatedElement,
|
||||
TypeDescriptor.OfField<Class<?>>,
|
||||
Constable {
|
||||
private static final int ANNOTATION= 0x00002000;
|
||||
private static final int ENUM = 0x00004000;
|
||||
private static final int SYNTHETIC = 0x00001000;
|
||||
|
@ -4027,4 +4034,68 @@ public final class Class<T> implements java.io.Serializable,
|
|||
}
|
||||
return members;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type descriptor string for this class.
|
||||
* <p>
|
||||
* Note that this is not a strict inverse of {@link #forName};
|
||||
* distinct classes which share a common name but have different class loaders
|
||||
* will have identical descriptor strings.
|
||||
*
|
||||
* @return the type descriptor representation
|
||||
* @jvms 4.3.2 Field Descriptors
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public String descriptorString() {
|
||||
if (isPrimitive())
|
||||
return Wrapper.forPrimitiveType(this).basicTypeString();
|
||||
else if (isArray()) {
|
||||
return "[" + componentType.descriptorString();
|
||||
}
|
||||
else {
|
||||
return "L" + getName().replace('.', '/') + ";";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the component type of this {@code Class}, if it describes
|
||||
* an array type, or {@code null} otherwise.
|
||||
*
|
||||
* @implSpec
|
||||
* Equivalent to {@link Class#getComponentType()}.
|
||||
*
|
||||
* @return a {@code Class} describing the component type, or {@code null}
|
||||
* if this {@code Class} does not describe an array type
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public Class<?> componentType() {
|
||||
return isArray() ? componentType : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Class} for an array type whose component type
|
||||
* is described by this {@linkplain Class}.
|
||||
*
|
||||
* @return a {@code Class} describing the array type
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public Class<?> arrayType() {
|
||||
return Array.newInstance(this, 0).getClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a nominal descriptor for this instance, if one can be
|
||||
* constructed, or an empty {@link Optional} if one cannot be.
|
||||
*
|
||||
* @return An {@link Optional} containing the resulting nominal descriptor,
|
||||
* or an empty {@link Optional} if one cannot be constructed.
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public Optional<ClassDesc> describeConstable() {
|
||||
return Optional.of(ClassDesc.ofDescriptor(descriptorString()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2430,7 +2430,7 @@ public abstract class ClassLoader {
|
|||
if (!load0(name, isBuiltin)) return false;
|
||||
|
||||
// register the class loader for cleanup when unloaded
|
||||
// built class loaders are never unloaded
|
||||
// builtin class loaders are never unloaded
|
||||
ClassLoader loader = fromClass.getClassLoader();
|
||||
if (loader != null &&
|
||||
loader != getBuiltinPlatformClassLoader() &&
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1994, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -25,6 +25,11 @@
|
|||
|
||||
package java.lang;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.constant.Constable;
|
||||
import java.lang.constant.ConstantDesc;
|
||||
import java.util.Optional;
|
||||
|
||||
import jdk.internal.math.FloatingDecimal;
|
||||
import jdk.internal.math.DoubleConsts;
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
|
@ -46,7 +51,8 @@ import jdk.internal.HotSpotIntrinsicCandidate;
|
|||
* @author Joseph D. Darcy
|
||||
* @since 1.0
|
||||
*/
|
||||
public final class Double extends Number implements Comparable<Double> {
|
||||
public final class Double extends Number
|
||||
implements Comparable<Double>, Constable, ConstantDesc {
|
||||
/**
|
||||
* A constant holding the positive infinity of type
|
||||
* {@code double}. It is equal to the value returned by
|
||||
|
@ -1070,6 +1076,31 @@ public final class Double extends Number implements Comparable<Double> {
|
|||
return Math.min(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a nominal descriptor for this instance, which is the instance
|
||||
* itself.
|
||||
*
|
||||
* @return an {@link Optional} describing the {@linkplain Double} instance
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public Optional<Double> describeConstable() {
|
||||
return Optional.of(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this instance as a {@link ConstantDesc}, the result of which is
|
||||
* the instance itself.
|
||||
*
|
||||
* @param lookup ignored
|
||||
* @return the {@linkplain Double} instance
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public Double resolveConstantDesc(MethodHandles.Lookup lookup) {
|
||||
return this;
|
||||
}
|
||||
|
||||
/** use serialVersionUID from JDK 1.0.2 for interoperability */
|
||||
private static final long serialVersionUID = -9172774392245257468L;
|
||||
}
|
||||
|
|
|
@ -25,11 +25,19 @@
|
|||
|
||||
package java.lang;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.Constable;
|
||||
import java.lang.constant.ConstantDescs;
|
||||
import java.lang.constant.DynamicConstantDesc;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Optional;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
/**
|
||||
* This is the common base class of all Java language enumeration types.
|
||||
|
@ -56,7 +64,7 @@ import java.io.ObjectStreamException;
|
|||
@SuppressWarnings("serial") // No serialVersionUID needed due to
|
||||
// special-casing of enum types.
|
||||
public abstract class Enum<E extends Enum<E>>
|
||||
implements Comparable<E>, Serializable {
|
||||
implements Constable, 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
|
||||
|
@ -203,6 +211,21 @@ public abstract class Enum<E extends Enum<E>>
|
|||
return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an enum descriptor {@code EnumDesc} for this instance, if one can be
|
||||
* constructed, or an empty {@link Optional} if one cannot be.
|
||||
*
|
||||
* @return An {@link Optional} containing the resulting nominal descriptor,
|
||||
* or an empty {@link Optional} if one cannot be constructed.
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public final Optional<EnumDesc<E>> describeConstable() {
|
||||
return getDeclaringClass()
|
||||
.describeConstable()
|
||||
.map(c -> EnumDesc.of(c, name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the enum constant of the specified enum type with the
|
||||
* specified name. The name must match exactly an identifier used
|
||||
|
@ -258,4 +281,56 @@ public abstract class Enum<E extends Enum<E>>
|
|||
private void readObjectNoData() throws ObjectStreamException {
|
||||
throw new InvalidObjectException("can't deserialize enum");
|
||||
}
|
||||
|
||||
/**
|
||||
* A <a href="package-summary.html#nominal">nominal descriptor</a> for an
|
||||
* {@code enum} constant.
|
||||
*
|
||||
* @param <E> the type of the enum constant
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public static final class EnumDesc<E extends Enum<E>>
|
||||
extends DynamicConstantDesc<E> {
|
||||
|
||||
/**
|
||||
* Constructs a nominal descriptor for the specified {@code enum} class and name.
|
||||
*
|
||||
* @param constantType a {@link ClassDesc} describing the {@code enum} class
|
||||
* @param constantName the unqualified name of the enum constant
|
||||
* @throws NullPointerException if any argument is null
|
||||
* @jvms 4.2.2 Unqualified Names
|
||||
*/
|
||||
private EnumDesc(ClassDesc constantType, String constantName) {
|
||||
super(ConstantDescs.BSM_ENUM_CONSTANT, requireNonNull(constantName), requireNonNull(constantType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a nominal descriptor for the specified {@code enum} class and name
|
||||
*
|
||||
* @param <E> the type of the enum constant
|
||||
* @param enumClass a {@link ClassDesc} describing the {@code enum} class
|
||||
* @param constantName the unqualified name of the enum constant
|
||||
* @return the nominal descriptor
|
||||
* @throws NullPointerException if any argument is null
|
||||
* @jvms 4.2.2 Unqualified Names
|
||||
* @since 12
|
||||
*/
|
||||
public static<E extends Enum<E>> EnumDesc<E> of(ClassDesc enumClass,
|
||||
String constantName) {
|
||||
return new EnumDesc<>(enumClass, constantName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public E resolveConstantDesc(MethodHandles.Lookup lookup)
|
||||
throws ReflectiveOperationException {
|
||||
return Enum.valueOf((Class<E>) constantType().resolveConstantDesc(lookup), constantName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("EnumDesc[%s.%s]", constantType().displayName(), constantName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1994, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -25,6 +25,11 @@
|
|||
|
||||
package java.lang;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.constant.Constable;
|
||||
import java.lang.constant.ConstantDesc;
|
||||
import java.util.Optional;
|
||||
|
||||
import jdk.internal.math.FloatingDecimal;
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
|
||||
|
@ -45,7 +50,8 @@ import jdk.internal.HotSpotIntrinsicCandidate;
|
|||
* @author Joseph D. Darcy
|
||||
* @since 1.0
|
||||
*/
|
||||
public final class Float extends Number implements Comparable<Float> {
|
||||
public final class Float extends Number
|
||||
implements Comparable<Float>, Constable, ConstantDesc {
|
||||
/**
|
||||
* A constant holding the positive infinity of type
|
||||
* {@code float}. It is equal to the value returned by
|
||||
|
@ -982,6 +988,31 @@ public final class Float extends Number implements Comparable<Float> {
|
|||
return Math.min(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a nominal descriptor for this instance, which is the instance
|
||||
* itself.
|
||||
*
|
||||
* @return an {@link Optional} describing the {@linkplain Float} instance
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public Optional<Float> describeConstable() {
|
||||
return Optional.of(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this instance as a {@link ConstantDesc}, the result of which is
|
||||
* the instance itself.
|
||||
*
|
||||
* @param lookup ignored
|
||||
* @return the {@linkplain Float} instance
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public Float resolveConstantDesc(MethodHandles.Lookup lookup) {
|
||||
return this;
|
||||
}
|
||||
|
||||
/** use serialVersionUID from JDK 1.0.2 for interoperability */
|
||||
private static final long serialVersionUID = -2671257302660747028L;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,12 @@
|
|||
package java.lang;
|
||||
|
||||
import java.lang.annotation.Native;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.constant.Constable;
|
||||
import java.lang.constant.ConstantDesc;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
import jdk.internal.misc.VM;
|
||||
|
||||
|
@ -56,7 +61,8 @@ import static java.lang.String.UTF16;
|
|||
* @author Joseph D. Darcy
|
||||
* @since 1.0
|
||||
*/
|
||||
public final class Integer extends Number implements Comparable<Integer> {
|
||||
public final class Integer extends Number
|
||||
implements Comparable<Integer>, Constable, ConstantDesc {
|
||||
/**
|
||||
* A constant holding the minimum value an {@code int} can
|
||||
* have, -2<sup>31</sup>.
|
||||
|
@ -1831,6 +1837,31 @@ public final class Integer extends Number implements Comparable<Integer> {
|
|||
return Math.min(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a nominal descriptor for this instance, which is the instance
|
||||
* itself.
|
||||
*
|
||||
* @return an {@link Optional} describing the {@linkplain Integer} instance
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public Optional<Integer> describeConstable() {
|
||||
return Optional.of(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this instance as a {@link ConstantDesc}, the result of which is
|
||||
* the instance itself.
|
||||
*
|
||||
* @param lookup ignored
|
||||
* @return the {@linkplain Integer} instance
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public Integer resolveConstantDesc(MethodHandles.Lookup lookup) {
|
||||
return this;
|
||||
}
|
||||
|
||||
/** use serialVersionUID from JDK 1.0.2 for interoperability */
|
||||
@Native private static final long serialVersionUID = 1360826667806852920L;
|
||||
}
|
||||
|
|
|
@ -26,8 +26,13 @@
|
|||
package java.lang;
|
||||
|
||||
import java.lang.annotation.Native;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.constant.Constable;
|
||||
import java.lang.constant.ConstantDesc;
|
||||
import java.math.*;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
import jdk.internal.misc.VM;
|
||||
|
||||
|
@ -57,7 +62,8 @@ import static java.lang.String.UTF16;
|
|||
* @author Joseph D. Darcy
|
||||
* @since 1.0
|
||||
*/
|
||||
public final class Long extends Number implements Comparable<Long> {
|
||||
public final class Long extends Number
|
||||
implements Comparable<Long>, Constable, ConstantDesc {
|
||||
/**
|
||||
* A constant holding the minimum value a {@code long} can
|
||||
* have, -2<sup>63</sup>.
|
||||
|
@ -1960,6 +1966,31 @@ public final class Long extends Number implements Comparable<Long> {
|
|||
return Math.min(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a nominal descriptor for this instance, which is the instance
|
||||
* itself.
|
||||
*
|
||||
* @return an {@link Optional} describing the {@linkplain Long} instance
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public Optional<Long> describeConstable() {
|
||||
return Optional.of(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this instance as a {@link ConstantDesc}, the result of which is
|
||||
* the instance itself.
|
||||
*
|
||||
* @param lookup ignored
|
||||
* @return the {@linkplain Long} instance
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public Long resolveConstantDesc(MethodHandles.Lookup lookup) {
|
||||
return this;
|
||||
}
|
||||
|
||||
/** use serialVersionUID from JDK 1.0.2 for interoperability */
|
||||
@Native private static final long serialVersionUID = 4290774380558885855L;
|
||||
}
|
||||
|
|
|
@ -1201,7 +1201,7 @@ public class SecurityManager {
|
|||
|
||||
private static String[] getPackages(String p) {
|
||||
String packages[] = null;
|
||||
if (p != null && !p.equals("")) {
|
||||
if (p != null && !p.isEmpty()) {
|
||||
java.util.StringTokenizer tok =
|
||||
new java.util.StringTokenizer(p, ",");
|
||||
int n = tok.countTokens();
|
||||
|
|
|
@ -28,6 +28,9 @@ package java.lang;
|
|||
import java.io.ObjectStreamField;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.annotation.Native;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.constant.Constable;
|
||||
import java.lang.constant.ConstantDesc;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -35,6 +38,7 @@ import java.util.Comparator;
|
|||
import java.util.Formatter;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Spliterator;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.function.Function;
|
||||
|
@ -127,7 +131,8 @@ import static java.util.function.Predicate.not;
|
|||
*/
|
||||
|
||||
public final class String
|
||||
implements java.io.Serializable, Comparable<String>, CharSequence {
|
||||
implements java.io.Serializable, Comparable<String>, CharSequence,
|
||||
Constable, ConstantDesc {
|
||||
|
||||
/**
|
||||
* The value is used for character storage.
|
||||
|
@ -3538,4 +3543,30 @@ public final class String
|
|||
throw new IllegalArgumentException(
|
||||
format("Not a valid Unicode code point: 0x%X", codePoint));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a nominal descriptor for this instance, which is the instance
|
||||
* itself.
|
||||
*
|
||||
* @return an {@link Optional} describing the {@linkplain String} instance
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public Optional<String> describeConstable() {
|
||||
return Optional.of(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this instance as a {@link ConstantDesc}, the result of which is
|
||||
* the instance itself.
|
||||
*
|
||||
* @param lookup ignored
|
||||
* @return the {@linkplain String} instance
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public String resolveConstantDesc(MethodHandles.Lookup lookup) {
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -970,7 +970,7 @@ public final class System {
|
|||
if (key == null) {
|
||||
throw new NullPointerException("key can't be null");
|
||||
}
|
||||
if (key.equals("")) {
|
||||
if (key.isEmpty()) {
|
||||
throw new IllegalArgumentException("key can't be empty");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 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.constant;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
||||
import static java.lang.constant.ConstantDescs.BSM_INVOKE;
|
||||
import static java.lang.constant.ConstantDescs.CD_MethodHandle;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
/**
|
||||
* A <a href="package-summary.html#nominal">nominal descriptor</a> for a
|
||||
* {@link MethodHandle} constant that performs a {@link MethodHandle#asType(MethodType)}
|
||||
* adaptation on another {@link MethodHandle}.
|
||||
*/
|
||||
final class AsTypeMethodHandleDesc extends DynamicConstantDesc<MethodHandle>
|
||||
implements MethodHandleDesc {
|
||||
|
||||
private final MethodHandleDesc underlying;
|
||||
private final MethodTypeDesc type;
|
||||
|
||||
AsTypeMethodHandleDesc(MethodHandleDesc underlying, MethodTypeDesc type) {
|
||||
super(BSM_INVOKE, ConstantDescs.DEFAULT_NAME, CD_MethodHandle,
|
||||
ConstantDescs.MHD_METHODHANDLE_ASTYPE, underlying, type);
|
||||
this.underlying = requireNonNull(underlying);
|
||||
this.type = requireNonNull(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodTypeDesc invocationType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodHandle resolveConstantDesc(MethodHandles.Lookup lookup)
|
||||
throws ReflectiveOperationException {
|
||||
MethodHandle handle = (MethodHandle) underlying.resolveConstantDesc(lookup);
|
||||
MethodType methodType = (MethodType) type.resolveConstantDesc(lookup);
|
||||
return handle.asType(methodType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s.asType%s", underlying.toString(), type.displayDescriptor());
|
||||
}
|
||||
}
|
299
src/java.base/share/classes/java/lang/constant/ClassDesc.java
Normal file
299
src/java.base/share/classes/java/lang/constant/ClassDesc.java
Normal file
|
@ -0,0 +1,299 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 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.constant;
|
||||
|
||||
import java.lang.invoke.TypeDescriptor;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import sun.invoke.util.Wrapper;
|
||||
|
||||
import static java.lang.constant.ConstantUtils.binaryToInternal;
|
||||
import static java.lang.constant.ConstantUtils.dropLastChar;
|
||||
import static java.lang.constant.ConstantUtils.internalToBinary;
|
||||
import static java.lang.constant.ConstantUtils.validateMemberName;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
/**
|
||||
* A <a href="package-summary.html#nominal">nominal descriptor</a> for a
|
||||
* {@link Class} constant.
|
||||
*
|
||||
* <p>For common system types, including all the primitive types, there are
|
||||
* predefined {@linkplain ClassDesc} constants in {@link ConstantDescs}.
|
||||
* (The {@code java.lang.constant} APIs consider {@code void} to be a primitive type.)
|
||||
* To create a {@linkplain ClassDesc} for a class or interface type, use {@link #of} or
|
||||
* {@link #ofDescriptor(String)}; to create a {@linkplain ClassDesc} for an array
|
||||
* type, use {@link #ofDescriptor(String)}, or first obtain a
|
||||
* {@linkplain ClassDesc} for the component type and then call the {@link #arrayType()}
|
||||
* or {@link #arrayType(int)} methods.
|
||||
*
|
||||
* @apiNote In the future, if the Java language permits, {@linkplain ClassDesc}
|
||||
* may become a {@code sealed} interface, which would prohibit subclassing except
|
||||
* by explicitly permitted types. Non-platform classes should not implement
|
||||
* {@linkplain ClassDesc} directly.
|
||||
*
|
||||
* @see ConstantDescs
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public interface ClassDesc
|
||||
extends ConstantDesc,
|
||||
TypeDescriptor.OfField<ClassDesc> {
|
||||
|
||||
/**
|
||||
* Returns a {@linkplain ClassDesc} for a class or interface type,
|
||||
* given the name of the class or interface, such as {@code "java.lang.String"}.
|
||||
* (To create a descriptor for an array type, either use {@link #ofDescriptor(String)}
|
||||
* or {@link #arrayType()}; to create a descriptor for a primitive type, use
|
||||
* {@link #ofDescriptor(String)} or use the predefined constants in
|
||||
* {@link ConstantDescs}).
|
||||
*
|
||||
* @param name the fully qualified (dot-separated) binary class name
|
||||
* @return a {@linkplain ClassDesc} describing the desired class
|
||||
* @throws NullPointerException if any argument is {@code null}
|
||||
* @throws IllegalArgumentException if the name string is not in the
|
||||
* correct format
|
||||
*/
|
||||
static ClassDesc of(String name) {
|
||||
ConstantUtils.validateBinaryClassName(requireNonNull(name));
|
||||
return ClassDesc.ofDescriptor("L" + binaryToInternal(name) + ";");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@linkplain ClassDesc} for a class or interface type,
|
||||
* given a package name and the unqualified (simple) name for the
|
||||
* class or interface.
|
||||
*
|
||||
* @param packageName the package name (dot-separated); if the package
|
||||
* name is the empty string, the class is considered to
|
||||
* be in the unnamed package
|
||||
* @param className the unqualified (simple) class name
|
||||
* @return a {@linkplain ClassDesc} describing the desired class
|
||||
* @throws NullPointerException if any argument is {@code null}
|
||||
* @throws IllegalArgumentException if the package name or class name are
|
||||
* not in the correct format
|
||||
*/
|
||||
static ClassDesc of(String packageName, String className) {
|
||||
ConstantUtils.validateBinaryClassName(requireNonNull(packageName));
|
||||
validateMemberName(requireNonNull(className));
|
||||
return ofDescriptor(String.format("L%s%s%s;",
|
||||
binaryToInternal(packageName),
|
||||
(packageName.length() > 0 ? "/" : ""),
|
||||
className));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@linkplain ClassDesc} given a descriptor string for a class,
|
||||
* interface, array, or primitive type.
|
||||
*
|
||||
* @apiNote
|
||||
*
|
||||
* A field type descriptor string for a non-array type is either
|
||||
* a one-letter code corresponding to a primitive type
|
||||
* ({@code J,I,C,S,B,D,F,Z,V}), or the letter {@code L}, followed
|
||||
* by the fully qualified binary name of a class, followed by {@code ;}.
|
||||
* A field type descriptor for an array type is the character {@code [}
|
||||
* followed by the field descriptor for the component type. Examples of
|
||||
* valid type descriptor strings include {@code Ljava/lang/String;}, {@code I},
|
||||
* {@code [I}, {@code V}, {@code [Ljava/lang/String;}, etc.
|
||||
* for more detail.
|
||||
*
|
||||
* @param descriptor a field descriptor string
|
||||
* @return a {@linkplain ClassDesc} describing the desired class
|
||||
* @throws NullPointerException if any argument is {@code null}
|
||||
* @throws IllegalArgumentException if the name string is not in the
|
||||
* correct format
|
||||
* @jvms 4.3.2 Field Descriptors
|
||||
*/
|
||||
static ClassDesc ofDescriptor(String descriptor) {
|
||||
requireNonNull(descriptor);
|
||||
return (descriptor.length() == 1)
|
||||
? new PrimitiveClassDescImpl(descriptor)
|
||||
: new ReferenceClassDescImpl(descriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@linkplain ClassDesc} for an array type whose component type
|
||||
* is described by this {@linkplain ClassDesc}.
|
||||
*
|
||||
* @return a {@linkplain ClassDesc} describing the array type
|
||||
*/
|
||||
default ClassDesc arrayType() {
|
||||
return arrayType(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@linkplain ClassDesc} for an array type of the specified rank,
|
||||
* whose component type is described by this {@linkplain ClassDesc}.
|
||||
*
|
||||
* @param rank the rank of the array
|
||||
* @return a {@linkplain ClassDesc} describing the array type
|
||||
* @throws IllegalArgumentException if the rank is zero or negative
|
||||
*/
|
||||
default ClassDesc arrayType(int rank) {
|
||||
if (rank <= 0)
|
||||
throw new IllegalArgumentException("rank: " + rank);
|
||||
return ClassDesc.ofDescriptor("[".repeat(rank) + descriptorString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@linkplain ClassDesc} for a nested class of the class or
|
||||
* interface type described by this {@linkplain ClassDesc}.
|
||||
*
|
||||
* @param nestedName the unqualified name of the nested class
|
||||
* @return a {@linkplain ClassDesc} describing the nested class
|
||||
* @throws NullPointerException if any argument is {@code null}
|
||||
* @throws IllegalStateException if this {@linkplain ClassDesc} does not
|
||||
* describe a class or interface type
|
||||
* @throws IllegalArgumentException if the nested class name is invalid
|
||||
*/
|
||||
default ClassDesc nested(String nestedName) {
|
||||
validateMemberName(nestedName);
|
||||
if (!isClassOrInterface())
|
||||
throw new IllegalStateException("Outer class is not a class or interface type");
|
||||
return ClassDesc.ofDescriptor(String.format("%s$%s;", dropLastChar(descriptorString()), nestedName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@linkplain ClassDesc} for a nested class of the class or
|
||||
* interface type described by this {@linkplain ClassDesc}.
|
||||
*
|
||||
* @param firstNestedName the unqualified name of the first level of nested class
|
||||
* @param moreNestedNames the unqualified name(s) of the remaining levels of
|
||||
* nested class
|
||||
* @return a {@linkplain ClassDesc} describing the nested class
|
||||
* @throws NullPointerException if any argument is {@code null}
|
||||
* @throws IllegalStateException if this {@linkplain ClassDesc} does not
|
||||
* describe a class or interface type
|
||||
* @throws IllegalArgumentException if the nested class name is invalid
|
||||
*/
|
||||
default ClassDesc nested(String firstNestedName, String... moreNestedNames) {
|
||||
if (!isClassOrInterface())
|
||||
throw new IllegalStateException("Outer class is not a class or interface type");
|
||||
return moreNestedNames.length == 0
|
||||
? nested(firstNestedName)
|
||||
: nested(firstNestedName + Stream.of(moreNestedNames).collect(joining("$", "$", "")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this {@linkplain ClassDesc} describes an array type.
|
||||
*
|
||||
* @return whether this {@linkplain ClassDesc} describes an array type
|
||||
*/
|
||||
default boolean isArray() {
|
||||
return descriptorString().startsWith("[");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this {@linkplain ClassDesc} describes a primitive type.
|
||||
*
|
||||
* @return whether this {@linkplain ClassDesc} describes a primitive type
|
||||
*/
|
||||
default boolean isPrimitive() {
|
||||
return descriptorString().length() == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this {@linkplain ClassDesc} describes a class or interface type.
|
||||
*
|
||||
* @return whether this {@linkplain ClassDesc} describes a class or interface type
|
||||
*/
|
||||
default boolean isClassOrInterface() {
|
||||
return descriptorString().startsWith("L");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the component type of this {@linkplain ClassDesc}, if it describes
|
||||
* an array type, or {@code null} otherwise.
|
||||
*
|
||||
* @return a {@linkplain ClassDesc} describing the component type, or {@code null}
|
||||
* if this descriptor does not describe an array type
|
||||
*/
|
||||
default ClassDesc componentType() {
|
||||
return isArray() ? ClassDesc.ofDescriptor(descriptorString().substring(1)) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the package name of this {@linkplain ClassDesc}, if it describes
|
||||
* a class or interface type.
|
||||
*
|
||||
* @return the package name, or the empty string if the class is in the
|
||||
* default package, or this {@linkplain ClassDesc} does not describe a class or interface type
|
||||
*/
|
||||
default String packageName() {
|
||||
if (!isClassOrInterface())
|
||||
return "";
|
||||
String className = internalToBinary(ConstantUtils.dropFirstAndLastChar(descriptorString()));
|
||||
int index = className.lastIndexOf('.');
|
||||
return (index == -1) ? "" : className.substring(0, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a human-readable name for the type described by this descriptor.
|
||||
*
|
||||
* @implSpec
|
||||
* <p>The default implementation returns the simple name
|
||||
* (e.g., {@code int}) for primitive types, the unqualified class name
|
||||
* for class or interface types, or the display name of the component type
|
||||
* suffixed with the appropriate number of {@code []} pairs for array types.
|
||||
*
|
||||
* @return the human-readable name
|
||||
*/
|
||||
default String displayName() {
|
||||
if (isPrimitive())
|
||||
return Wrapper.forBasicType(descriptorString().charAt(0)).primitiveSimpleName();
|
||||
else if (isClassOrInterface()) {
|
||||
return descriptorString().substring(Math.max(1, descriptorString().lastIndexOf('/') + 1),
|
||||
descriptorString().length() - 1);
|
||||
}
|
||||
else if (isArray()) {
|
||||
int depth = ConstantUtils.arrayDepth(descriptorString());
|
||||
ClassDesc c = this;
|
||||
for (int i=0; i<depth; i++)
|
||||
c = c.componentType();
|
||||
return c.displayName() + "[]".repeat(depth);
|
||||
}
|
||||
else
|
||||
throw new IllegalStateException(descriptorString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a field type descriptor string for this type
|
||||
*
|
||||
* @return the descriptor string
|
||||
* @jvms 4.3.2 Field Descriptors
|
||||
*/
|
||||
String descriptorString();
|
||||
|
||||
/**
|
||||
* Compare the specified object with this descriptor for equality. Returns
|
||||
* {@code true} if and only if the specified object is also a
|
||||
* {@linkplain ClassDesc} and both describe the same type.
|
||||
*
|
||||
* @param o the other object
|
||||
* @return whether this descriptor is equal to the other object
|
||||
*/
|
||||
boolean equals(Object o);
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 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.constant;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Represents a type which is <em>constable</em>. A constable type is one whose
|
||||
* values are constants that can be represented in the constant pool of a Java
|
||||
* classfile as described in JVMS 4.4, and whose instances can describe themselves
|
||||
* nominally as a {@link ConstantDesc}.
|
||||
*
|
||||
* <p>Some constable types have a native representation in the constant pool:
|
||||
* {@link String}, {@link Integer}, {@link Long}, {@link Float},
|
||||
* {@link Double}, {@link Class}, {@link MethodType}, and {@link MethodHandle}.
|
||||
* The types {@link String}, {@link Integer}, {@link Long}, {@link Float},
|
||||
* and {@link Double} serve as their own nominal descriptors; {@link Class},
|
||||
* {@link MethodType}, and {@link MethodHandle} have corresponding nominal
|
||||
* descriptors {@link ClassDesc}, {@link MethodTypeDesc}, and {@link MethodHandleDesc}.
|
||||
*
|
||||
* <p>Other reference types can be constable if their instances can describe
|
||||
* themselves in nominal form as a {@link ConstantDesc}. Examples in the Java SE
|
||||
* Platform API are types that support Java language features such as {@link Enum},
|
||||
* and runtime support classes such as {@link VarHandle}. These are typically
|
||||
* described with a {@link DynamicConstantDesc}, which describes dynamically
|
||||
* generated constants (JVMS 4.4.10).
|
||||
*
|
||||
* <p>The nominal form of an instance of a constable type is obtained via
|
||||
* {@link #describeConstable()}. A {@linkplain Constable} need
|
||||
* not be able to (or may choose not to) describe all its instances in the form of
|
||||
* a {@link ConstantDesc}; this method returns an {@link Optional} that can be
|
||||
* empty to indicate that a nominal descriptor could not be created for an instance.
|
||||
* (For example, {@link MethodHandle} will produce nominal descriptors for direct
|
||||
* method handles, but not necessarily those produced by method handle
|
||||
* combinators.)
|
||||
* @jvms 4.4 The Constant Pool
|
||||
* @jvms 4.4.10 The CONSTANT_InvokeDynamic_info Structure
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public interface Constable {
|
||||
/**
|
||||
* Returns a nominal descriptor for this instance, if one can be
|
||||
* constructed, or an empty {@link Optional} if one cannot be constructed.
|
||||
*
|
||||
* @return An {@link Optional} containing the resulting nominal descriptor,
|
||||
* or an empty {@link Optional} if one cannot be constructed.
|
||||
*/
|
||||
Optional<? extends ConstantDesc> describeConstable();
|
||||
}
|
104
src/java.base/share/classes/java/lang/constant/ConstantDesc.java
Normal file
104
src/java.base/share/classes/java/lang/constant/ConstantDesc.java
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 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.constant;
|
||||
|
||||
import java.lang.Enum.EnumDesc;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.VarHandle.VarHandleDesc;
|
||||
|
||||
/**
|
||||
* A <a href="package-summary.html#nominal">nominal descriptor</a> for a loadable
|
||||
* constant value, as defined in JVMS 4.4. Such a descriptor can be resolved via
|
||||
* {@link ConstantDesc#resolveConstantDesc(MethodHandles.Lookup)} to yield the
|
||||
* constant value itself.
|
||||
*
|
||||
* <p>Class names in a nominal descriptor, like class names in the constant pool
|
||||
* of a classfile, must be interpreted with respect to a particular class
|
||||
* loader, which is not part of the nominal descriptor.
|
||||
*
|
||||
* <p>Static constants that are expressible natively in the constant pool ({@link String},
|
||||
* {@link Integer}, {@link Long}, {@link Float}, and {@link Double}) implement
|
||||
* {@link ConstantDesc}, and serve as nominal descriptors for themselves.
|
||||
* Native linkable constants ({@link Class}, {@link MethodType}, and
|
||||
* {@link MethodHandle}) have counterpart {@linkplain ConstantDesc} types:
|
||||
* {@link ClassDesc}, {@link MethodTypeDesc}, and {@link MethodHandleDesc}.
|
||||
* Other constants are represented by subtypes of {@link DynamicConstantDesc}.
|
||||
*
|
||||
* <p>APIs that perform generation or parsing of bytecode are encouraged to use
|
||||
* {@linkplain ConstantDesc} to describe the operand of an {@code ldc} instruction
|
||||
* (including dynamic constants), the static bootstrap arguments of
|
||||
* dynamic constants and {@code invokedynamic} instructions, and other
|
||||
* bytecodes or classfile structures that make use of the constant pool.
|
||||
*
|
||||
* <p>Constants describing various common constants (such as {@link ClassDesc}
|
||||
* instances for platform types) can be found in {@link ConstantDescs}.
|
||||
*
|
||||
* <p>Implementations of {@linkplain ConstantDesc} must be
|
||||
* <a href="../doc-files/ValueBased.html">value-based</a> classes.
|
||||
*
|
||||
* <p>Non-platform classes should not implement {@linkplain ConstantDesc} directly.
|
||||
* Instead, they should extend {@link DynamicConstantDesc} (as {@link EnumDesc}
|
||||
* and {@link VarHandleDesc} do.)
|
||||
*
|
||||
* <p>Nominal descriptors should be compared using the
|
||||
* {@link Object#equals(Object)} method. There is no guarantee that any
|
||||
* particular entity will always be represented by the same descriptor instance.
|
||||
*
|
||||
* @apiNote In the future, if the Java language permits, {@linkplain ConstantDesc}
|
||||
* may become a {@code sealed} interface, which would prohibit subclassing except by
|
||||
* explicitly permitted types. Clients can assume that the following
|
||||
* set of subtypes is exhaustive: {@link String}, {@link Integer},
|
||||
* {@link Long}, {@link Float}, {@link Double}, {@link ClassDesc},
|
||||
* {@link MethodTypeDesc}, {@link MethodHandleDesc}, and
|
||||
* {@link DynamicConstantDesc}; this list may be extended to reflect future
|
||||
* changes to the constant pool format as defined in JVMS 4.4.
|
||||
*
|
||||
* @see Constable
|
||||
* @see ConstantDescs
|
||||
*
|
||||
* @jvms 4.4 The Constant Pool
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public interface ConstantDesc {
|
||||
/**
|
||||
* Resolves this descriptor reflectively, emulating the resolution behavior
|
||||
* of JVMS 5.4.3 and the access control behavior of JVMS 5.4.4. The resolution
|
||||
* and access control context is provided by the {@link MethodHandles.Lookup}
|
||||
* parameter. No caching of the resulting value is performed.
|
||||
*
|
||||
* @param lookup The {@link MethodHandles.Lookup} to provide name resolution
|
||||
* and access control context
|
||||
* @return the resolved constant value
|
||||
* @throws ReflectiveOperationException if a class, method, or field
|
||||
* could not be reflectively resolved in the course of resolution
|
||||
* @throws LinkageError if a linkage error occurs
|
||||
* @jvms 5.4.3 Resolution
|
||||
* @jvms 5.4.4 Access Control
|
||||
*/
|
||||
Object resolveConstantDesc(MethodHandles.Lookup lookup) throws ReflectiveOperationException;
|
||||
}
|
|
@ -0,0 +1,298 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 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.constant;
|
||||
|
||||
import java.lang.Enum.EnumDesc;
|
||||
import java.lang.invoke.CallSite;
|
||||
import java.lang.invoke.ConstantBootstraps;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodHandles.Lookup;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.lang.invoke.VarHandle.VarHandleDesc;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.lang.constant.DirectMethodHandleDesc.*;
|
||||
import static java.lang.constant.DirectMethodHandleDesc.Kind.STATIC;
|
||||
|
||||
/**
|
||||
* Predefined values of <a href="package-summary.html#nominal">nominal descriptor</a>
|
||||
* for common constants, including descriptors for primitive class types and
|
||||
* other common platform types, and descriptors for method handles for standard
|
||||
* bootstrap methods.
|
||||
*
|
||||
* @see ConstantDesc
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public final class ConstantDescs {
|
||||
// No instances
|
||||
private ConstantDescs() { }
|
||||
|
||||
/** Invocation name to use when no name is needed, such as the name of a
|
||||
* constructor, or the invocation name of a dynamic constant or dynamic
|
||||
* callsite when the bootstrap is known to ignore the invocation name.
|
||||
*/
|
||||
public static final String DEFAULT_NAME = "_";
|
||||
|
||||
// Don't change the order of these declarations!
|
||||
|
||||
/** {@link ClassDesc} representing {@link Object} */
|
||||
public static final ClassDesc CD_Object = ClassDesc.of("java.lang.Object");
|
||||
|
||||
/** {@link ClassDesc} representing {@link String} */
|
||||
public static final ClassDesc CD_String = ClassDesc.of("java.lang.String");
|
||||
|
||||
/** {@link ClassDesc} representing {@link Class} */
|
||||
public static final ClassDesc CD_Class = ClassDesc.of("java.lang.Class");
|
||||
|
||||
/** {@link ClassDesc} representing {@link Number} */
|
||||
public static final ClassDesc CD_Number = ClassDesc.of("java.lang.Number");
|
||||
|
||||
/** {@link ClassDesc} representing {@link Integer} */
|
||||
public static final ClassDesc CD_Integer = ClassDesc.of("java.lang.Integer");
|
||||
|
||||
/** {@link ClassDesc} representing {@link Long} */
|
||||
public static final ClassDesc CD_Long = ClassDesc.of("java.lang.Long");
|
||||
|
||||
/** {@link ClassDesc} representing {@link Float} */
|
||||
public static final ClassDesc CD_Float = ClassDesc.of("java.lang.Float");
|
||||
|
||||
/** {@link ClassDesc} representing {@link Double} */
|
||||
public static final ClassDesc CD_Double = ClassDesc.of("java.lang.Double");
|
||||
|
||||
/** {@link ClassDesc} representing {@link Short} */
|
||||
public static final ClassDesc CD_Short = ClassDesc.of("java.lang.Short");
|
||||
|
||||
/** {@link ClassDesc} representing {@link Byte} */
|
||||
public static final ClassDesc CD_Byte = ClassDesc.of("java.lang.Byte");
|
||||
|
||||
/** {@link ClassDesc} representing {@link Character} */
|
||||
public static final ClassDesc CD_Character = ClassDesc.of("java.lang.Character");
|
||||
|
||||
/** {@link ClassDesc} representing {@link Boolean} */
|
||||
public static final ClassDesc CD_Boolean = ClassDesc.of("java.lang.Boolean");
|
||||
|
||||
/** {@link ClassDesc} representing {@link Void} */
|
||||
public static final ClassDesc CD_Void = ClassDesc.of("java.lang.Void");
|
||||
|
||||
/** {@link ClassDesc} representing {@link Throwable} */
|
||||
public static final ClassDesc CD_Throwable = ClassDesc.of("java.lang.Throwable");
|
||||
|
||||
/** {@link ClassDesc} representing {@link Exception} */
|
||||
public static final ClassDesc CD_Exception = ClassDesc.of("java.lang.Exception");
|
||||
|
||||
/** {@link ClassDesc} representing {@link Enum} */
|
||||
public static final ClassDesc CD_Enum = ClassDesc.of("java.lang.Enum");
|
||||
|
||||
/** {@link ClassDesc} representing {@link VarHandle} */
|
||||
public static final ClassDesc CD_VarHandle = ClassDesc.of("java.lang.invoke.VarHandle");
|
||||
|
||||
/** {@link ClassDesc} representing {@link MethodHandles} */
|
||||
public static final ClassDesc CD_MethodHandles = ClassDesc.of("java.lang.invoke.MethodHandles");
|
||||
|
||||
/** {@link ClassDesc} representing {@link MethodHandles.Lookup} */
|
||||
public static final ClassDesc CD_MethodHandles_Lookup = CD_MethodHandles.nested("Lookup");
|
||||
|
||||
/** {@link ClassDesc} representing {@link MethodHandle} */
|
||||
public static final ClassDesc CD_MethodHandle = ClassDesc.of("java.lang.invoke.MethodHandle");
|
||||
|
||||
/** {@link ClassDesc} representing {@link MethodType} */
|
||||
public static final ClassDesc CD_MethodType = ClassDesc.of("java.lang.invoke.MethodType");
|
||||
|
||||
/** {@link ClassDesc} representing {@link CallSite} */
|
||||
public static final ClassDesc CD_CallSite = ClassDesc.of("java.lang.invoke.CallSite");
|
||||
|
||||
/** {@link ClassDesc} representing {@link Collection} */
|
||||
public static final ClassDesc CD_Collection = ClassDesc.of("java.util.Collection");
|
||||
|
||||
/** {@link ClassDesc} representing {@link List} */
|
||||
public static final ClassDesc CD_List = ClassDesc.of("java.util.List");
|
||||
|
||||
/** {@link ClassDesc} representing {@link Set} */
|
||||
public static final ClassDesc CD_Set = ClassDesc.of("java.util.Set");
|
||||
|
||||
/** {@link ClassDesc} representing {@link Map} */
|
||||
public static final ClassDesc CD_Map = ClassDesc.of("java.util.Map");
|
||||
|
||||
/** {@link ClassDesc} representing {@link ConstantDesc} */
|
||||
public static final ClassDesc CD_ConstantDesc = ClassDesc.of("java.lang.constant.ConstantDesc");
|
||||
|
||||
/** {@link ClassDesc} representing {@link ClassDesc} */
|
||||
public static final ClassDesc CD_ClassDesc = ClassDesc.of("java.lang.constant.ClassDesc");
|
||||
|
||||
/** {@link ClassDesc} representing {@link EnumDesc} */
|
||||
public static final ClassDesc CD_EnumDesc = CD_Enum.nested("EnumDesc");
|
||||
|
||||
/** {@link ClassDesc} representing {@link MethodTypeDesc} */
|
||||
public static final ClassDesc CD_MethodTypeDesc = ClassDesc.of("java.lang.constant.MethodTypeDesc");
|
||||
|
||||
/** {@link ClassDesc} representing {@link MethodHandleDesc} */
|
||||
public static final ClassDesc CD_MethodHandleDesc = ClassDesc.of("java.lang.constant.MethodHandleDesc");
|
||||
|
||||
/** {@link ClassDesc} representing {@link DirectMethodHandleDesc} */
|
||||
public static final ClassDesc CD_DirectMethodHandleDesc = ClassDesc.of("java.lang.constant.DirectMethodHandleDesc");
|
||||
|
||||
/** {@link ClassDesc} representing {@link VarHandleDesc} */
|
||||
public static final ClassDesc CD_VarHandleDesc = CD_VarHandle.nested("VarHandleDesc");
|
||||
|
||||
/** {@link ClassDesc} representing {@link DirectMethodHandleDesc.Kind} */
|
||||
public static final ClassDesc CD_MethodHandleDesc_Kind = CD_DirectMethodHandleDesc.nested("Kind");
|
||||
|
||||
/** {@link ClassDesc} representing {@link DynamicConstantDesc} */
|
||||
public static final ClassDesc CD_DynamicConstantDesc = ClassDesc.of("java.lang.constant.DynamicConstantDesc");
|
||||
|
||||
/** {@link ClassDesc} representing {@link DynamicCallSiteDesc} */
|
||||
public static final ClassDesc CD_DynamicCallSiteDesc = ClassDesc.of("java.lang.constant.DynamicCallSiteDesc");
|
||||
|
||||
/** {@link ClassDesc} representing {@link ConstantBootstraps} */
|
||||
public static final ClassDesc CD_ConstantBootstraps = ClassDesc.of("java.lang.invoke.ConstantBootstraps");
|
||||
|
||||
private static final ClassDesc[] INDY_BOOTSTRAP_ARGS = {
|
||||
ConstantDescs.CD_MethodHandles_Lookup,
|
||||
ConstantDescs.CD_String,
|
||||
ConstantDescs.CD_MethodType};
|
||||
|
||||
private static final ClassDesc[] CONDY_BOOTSTRAP_ARGS = {
|
||||
ConstantDescs.CD_MethodHandles_Lookup,
|
||||
ConstantDescs.CD_String,
|
||||
ConstantDescs.CD_Class};
|
||||
|
||||
/** {@link MethodHandleDesc} representing {@link ConstantBootstraps#primitiveClass(Lookup, String, Class) ConstantBootstraps.primitiveClass} */
|
||||
public static final DirectMethodHandleDesc BSM_PRIMITIVE_CLASS
|
||||
= ofConstantBootstrap(CD_ConstantBootstraps, "primitiveClass",
|
||||
CD_Class);
|
||||
|
||||
/** {@link MethodHandleDesc} representing {@link ConstantBootstraps#enumConstant(Lookup, String, Class) ConstantBootstraps.enumConstant} */
|
||||
public static final DirectMethodHandleDesc BSM_ENUM_CONSTANT
|
||||
= ofConstantBootstrap(CD_ConstantBootstraps, "enumConstant",
|
||||
CD_Enum);
|
||||
|
||||
/** {@link MethodHandleDesc} representing {@link ConstantBootstraps#nullConstant(Lookup, String, Class) ConstantBootstraps.nullConstant} */
|
||||
public static final DirectMethodHandleDesc BSM_NULL_CONSTANT
|
||||
= ofConstantBootstrap(CD_ConstantBootstraps, "nullConstant",
|
||||
ConstantDescs.CD_Object);
|
||||
|
||||
/** {@link MethodHandleDesc} representing {@link ConstantBootstraps#fieldVarHandle(Lookup, String, Class, Class, Class) ConstantBootstraps.fieldVarHandle} */
|
||||
public static final DirectMethodHandleDesc BSM_VARHANDLE_FIELD
|
||||
= ofConstantBootstrap(CD_ConstantBootstraps, "fieldVarHandle",
|
||||
CD_VarHandle, CD_Class, CD_Class);
|
||||
|
||||
/** {@link MethodHandleDesc} representing {@link ConstantBootstraps#staticFieldVarHandle(Lookup, String, Class, Class, Class) ConstantBootstraps.staticVarHandle} */
|
||||
public static final DirectMethodHandleDesc BSM_VARHANDLE_STATIC_FIELD
|
||||
= ofConstantBootstrap(CD_ConstantBootstraps, "staticFieldVarHandle",
|
||||
CD_VarHandle, CD_Class, CD_Class);
|
||||
|
||||
/** {@link MethodHandleDesc} representing {@link ConstantBootstraps#arrayVarHandle(Lookup, String, Class, Class) ConstantBootstraps.arrayVarHandle} */
|
||||
public static final DirectMethodHandleDesc BSM_VARHANDLE_ARRAY
|
||||
= ofConstantBootstrap(CD_ConstantBootstraps, "arrayVarHandle",
|
||||
CD_VarHandle, CD_Class);
|
||||
|
||||
/** {@link MethodHandleDesc} representing {@link ConstantBootstraps#invoke(Lookup, String, Class, MethodHandle, Object...) ConstantBootstraps.invoke} */
|
||||
public static final DirectMethodHandleDesc BSM_INVOKE
|
||||
= ofConstantBootstrap(CD_ConstantBootstraps, "invoke",
|
||||
CD_Object, CD_MethodHandle, CD_Object.arrayType());
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code int} */
|
||||
public static final ClassDesc CD_int = ClassDesc.ofDescriptor("I");
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code long} */
|
||||
public static final ClassDesc CD_long = ClassDesc.ofDescriptor("J");
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code float} */
|
||||
public static final ClassDesc CD_float = ClassDesc.ofDescriptor("F");
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code double} */
|
||||
public static final ClassDesc CD_double = ClassDesc.ofDescriptor("D");
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code short} */
|
||||
public static final ClassDesc CD_short = ClassDesc.ofDescriptor("S");
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code byte} */
|
||||
public static final ClassDesc CD_byte = ClassDesc.ofDescriptor("B");
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code char} */
|
||||
public static final ClassDesc CD_char = ClassDesc.ofDescriptor("C");
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code boolean} */
|
||||
public static final ClassDesc CD_boolean = ClassDesc.ofDescriptor("Z");
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code void} */
|
||||
public static final ClassDesc CD_void = ClassDesc.ofDescriptor("V");
|
||||
|
||||
/** Nominal descriptor representing the constant {@code null} */
|
||||
public static final ConstantDesc NULL
|
||||
= DynamicConstantDesc.ofNamed(ConstantDescs.BSM_NULL_CONSTANT,
|
||||
DEFAULT_NAME, ConstantDescs.CD_Object);
|
||||
|
||||
static final DirectMethodHandleDesc MHD_METHODHANDLE_ASTYPE
|
||||
= MethodHandleDesc.ofMethod(Kind.VIRTUAL, CD_MethodHandle, "asType",
|
||||
MethodTypeDesc.of(CD_MethodHandle, CD_MethodType));
|
||||
/**
|
||||
* Returns a {@link MethodHandleDesc} corresponding to a bootstrap method for
|
||||
* an {@code invokedynamic} callsite, which is a static method whose leading
|
||||
* parameter types are {@code Lookup}, {@code String}, and {@code MethodType}.
|
||||
*
|
||||
* @param owner the class declaring the method
|
||||
* @param name the unqualified name of the method
|
||||
* @param returnType the return type of the method
|
||||
* @param paramTypes the types of the static bootstrap arguments, if any
|
||||
* @return the {@link MethodHandleDesc}
|
||||
* @throws NullPointerException if any of the arguments are null
|
||||
* @jvms 4.2.2 Unqualified Names
|
||||
*/
|
||||
public static DirectMethodHandleDesc ofCallsiteBootstrap(ClassDesc owner,
|
||||
String name,
|
||||
ClassDesc returnType,
|
||||
ClassDesc... paramTypes) {
|
||||
return MethodHandleDesc.ofMethod(STATIC, owner, name, MethodTypeDesc.of(returnType, paramTypes)
|
||||
.insertParameterTypes(0, INDY_BOOTSTRAP_ARGS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link MethodHandleDesc} corresponding to a bootstrap method for a
|
||||
* dynamic constant, which is a static method whose leading arguments are
|
||||
* {@code Lookup}, {@code String}, and {@code Class}.
|
||||
*
|
||||
* @param owner the class declaring the method
|
||||
* @param name the unqualified name of the method
|
||||
* @param returnType the return type of the method
|
||||
* @param paramTypes the types of the static bootstrap arguments, if any
|
||||
* @return the {@link MethodHandleDesc}
|
||||
* @throws NullPointerException if any of the arguments are null
|
||||
* @jvms 4.2.2 Unqualified Names
|
||||
*/
|
||||
public static DirectMethodHandleDesc ofConstantBootstrap(ClassDesc owner,
|
||||
String name,
|
||||
ClassDesc returnType,
|
||||
ClassDesc... paramTypes) {
|
||||
return MethodHandleDesc.ofMethod(STATIC, owner, name, MethodTypeDesc.of(returnType, paramTypes)
|
||||
.insertParameterTypes(0, CONDY_BOOTSTRAP_ARGS));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 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.constant;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
/**
|
||||
* Helper methods for the implementation of {@code java.lang.constant}.
|
||||
*/
|
||||
class ConstantUtils {
|
||||
/** an empty constant descriptor */
|
||||
public static final ConstantDesc[] EMPTY_CONSTANTDESC = new ConstantDesc[0];
|
||||
static final Constable[] EMPTY_CONSTABLE = new Constable[0];
|
||||
|
||||
private static final Set<String> pointyNames = Set.of("<init>", "<clinit>");
|
||||
|
||||
/**
|
||||
* Validates the correctness of a binary class name. In particular checks for the presence of
|
||||
* invalid characters in the name.
|
||||
*
|
||||
* @param name the class name
|
||||
* @return the class name passed if valid
|
||||
* @throws IllegalArgumentException if the class name is invalid
|
||||
*/
|
||||
static String validateBinaryClassName(String name) {
|
||||
for (int i=0; i<name.length(); i++) {
|
||||
char ch = name.charAt(i);
|
||||
if (ch == ';' || ch == '[' || ch == '/')
|
||||
throw new IllegalArgumentException("Invalid class name: " + name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a member name
|
||||
*
|
||||
* @param name the name of the member
|
||||
* @return the name passed if valid
|
||||
* @throws IllegalArgumentException if the member name is invalid
|
||||
*/
|
||||
public static String validateMemberName(String name) {
|
||||
requireNonNull(name);
|
||||
if (name.length() == 0)
|
||||
throw new IllegalArgumentException("zero-length member name");
|
||||
for (int i=0; i<name.length(); i++) {
|
||||
char ch = name.charAt(i);
|
||||
if (ch == '.' || ch == ';' || ch == '[' || ch == '/')
|
||||
throw new IllegalArgumentException("Invalid member name: " + name);
|
||||
if (ch == '<' || ch == '>') {
|
||||
if (!pointyNames.contains(name))
|
||||
throw new IllegalArgumentException("Invalid member name: " + name);
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
static void validateClassOrInterface(ClassDesc classDesc) {
|
||||
if (!classDesc.isClassOrInterface())
|
||||
throw new IllegalArgumentException("not a class or interface type: " + classDesc);
|
||||
}
|
||||
|
||||
static int arrayDepth(String descriptorString) {
|
||||
int depth = 0;
|
||||
while (descriptorString.charAt(depth) == '[')
|
||||
depth++;
|
||||
return depth;
|
||||
}
|
||||
|
||||
static String binaryToInternal(String name) {
|
||||
return name.replace('.', '/');
|
||||
}
|
||||
|
||||
static String internalToBinary(String name) {
|
||||
return name.replace('/', '.');
|
||||
}
|
||||
|
||||
static String dropLastChar(String s) {
|
||||
return s.substring(0, s.length() - 1);
|
||||
}
|
||||
|
||||
static String dropFirstAndLastChar(String s) {
|
||||
return s.substring(1, s.length() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a method descriptor string, and return a list of field descriptor
|
||||
* strings, return type first, then parameter types
|
||||
*
|
||||
* @param descriptor the descriptor string
|
||||
* @return the list of types
|
||||
* @throws IllegalArgumentException if the descriptor string is not valid
|
||||
*/
|
||||
static List<String> parseMethodDescriptor(String descriptor) {
|
||||
int cur = 0, end = descriptor.length();
|
||||
ArrayList<String> ptypes = new ArrayList<>();
|
||||
|
||||
if (cur >= end || descriptor.charAt(cur) != '(')
|
||||
throw new IllegalArgumentException("Bad method descriptor: " + descriptor);
|
||||
|
||||
++cur; // skip '('
|
||||
while (cur < end && descriptor.charAt(cur) != ')') {
|
||||
int len = matchSig(descriptor, cur, end);
|
||||
if (len == 0 || descriptor.charAt(cur) == 'V')
|
||||
throw new IllegalArgumentException("Bad method descriptor: " + descriptor);
|
||||
ptypes.add(descriptor.substring(cur, cur + len));
|
||||
cur += len;
|
||||
}
|
||||
if (cur >= end)
|
||||
throw new IllegalArgumentException("Bad method descriptor: " + descriptor);
|
||||
++cur; // skip ')'
|
||||
|
||||
int rLen = matchSig(descriptor, cur, end);
|
||||
if (rLen == 0 || cur + rLen != end)
|
||||
throw new IllegalArgumentException("Bad method descriptor: " + descriptor);
|
||||
ptypes.add(0, descriptor.substring(cur, cur + rLen));
|
||||
return ptypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that the characters at [start, end) within the provided string
|
||||
* describe a valid field type descriptor.
|
||||
*
|
||||
* @param str the descriptor string
|
||||
* @param start the starting index into the string
|
||||
* @param end the ending index within the string
|
||||
* @return the length of the descriptor, or 0 if it is not a descriptor
|
||||
* @throws IllegalArgumentException if the descriptor string is not valid
|
||||
*/
|
||||
static int matchSig(String str, int start, int end) {
|
||||
if (start >= end || start >= str.length() || end > str.length())
|
||||
return 0;
|
||||
char c = str.charAt(start);
|
||||
if (c == 'L') {
|
||||
int endc = str.indexOf(';', start);
|
||||
int badc = str.indexOf('.', start);
|
||||
if (badc >= 0 && badc < endc)
|
||||
return 0;
|
||||
badc = str.indexOf('[', start);
|
||||
if (badc >= 0 && badc < endc)
|
||||
return 0;
|
||||
return (endc < 0) ? 0 : endc - start + 1;
|
||||
} else if (c == '[') {
|
||||
int t = matchSig(str, start+1, end);
|
||||
return (t > 0) ? t + 1 : 0;
|
||||
} else {
|
||||
return ("IJCSBFDZV".indexOf(c) >= 0) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 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.constant;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandleInfo;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
import static java.lang.invoke.MethodHandleInfo.REF_getField;
|
||||
import static java.lang.invoke.MethodHandleInfo.REF_getStatic;
|
||||
import static java.lang.invoke.MethodHandleInfo.REF_invokeInterface;
|
||||
import static java.lang.invoke.MethodHandleInfo.REF_invokeSpecial;
|
||||
import static java.lang.invoke.MethodHandleInfo.REF_invokeStatic;
|
||||
import static java.lang.invoke.MethodHandleInfo.REF_invokeVirtual;
|
||||
import static java.lang.invoke.MethodHandleInfo.REF_newInvokeSpecial;
|
||||
import static java.lang.invoke.MethodHandleInfo.REF_putField;
|
||||
import static java.lang.invoke.MethodHandleInfo.REF_putStatic;
|
||||
|
||||
/**
|
||||
* A <a href="package-summary.html#nominal">nominal descriptor</a> for a direct
|
||||
* {@link MethodHandle}. A {@linkplain DirectMethodHandleDesc} corresponds to
|
||||
* a {@code Constant_MethodHandle_info} entry in the constant pool of a classfile.
|
||||
*
|
||||
* @apiNote In the future, if the Java language permits, {@linkplain DirectMethodHandleDesc}
|
||||
* may become a {@code sealed} interface, which would prohibit subclassing except
|
||||
* by explicitly permitted types. Non-platform classes should not implement
|
||||
* {@linkplain DirectMethodHandleDesc} directly.
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public interface DirectMethodHandleDesc extends MethodHandleDesc {
|
||||
/**
|
||||
* Kinds of method handles that can be described with {@linkplain DirectMethodHandleDesc}.
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
enum Kind {
|
||||
/** A method handle for a method invoked as with {@code invokestatic} */
|
||||
STATIC(REF_invokeStatic),
|
||||
/** A method handle for a method invoked as with {@code invokestatic} */
|
||||
INTERFACE_STATIC(REF_invokeStatic, true),
|
||||
/** A method handle for a method invoked as with {@code invokevirtual} */
|
||||
VIRTUAL(REF_invokeVirtual),
|
||||
/** A method handle for a method invoked as with {@code invokeinterface} */
|
||||
INTERFACE_VIRTUAL(REF_invokeInterface, true),
|
||||
/** A method handle for a method invoked as with {@code invokespecial} */
|
||||
SPECIAL(REF_invokeSpecial),
|
||||
/** A method handle for an interface method invoked as with {@code invokespecial} */
|
||||
INTERFACE_SPECIAL(REF_invokeSpecial, true),
|
||||
/** A method handle for a constructor */
|
||||
CONSTRUCTOR(REF_newInvokeSpecial),
|
||||
/** A method handle for a read accessor for an instance field */
|
||||
GETTER(REF_getField),
|
||||
/** A method handle for a write accessor for an instance field */
|
||||
SETTER(REF_putField),
|
||||
/** A method handle for a read accessor for a static field */
|
||||
STATIC_GETTER(REF_getStatic),
|
||||
/** A method handle for a write accessor for a static field */
|
||||
STATIC_SETTER(REF_putStatic);
|
||||
|
||||
/** The corresponding {@code refKind} value for this kind of method handle,
|
||||
* as defined by {@link MethodHandleInfo}
|
||||
*/
|
||||
public final int refKind;
|
||||
|
||||
/** Is this an interface
|
||||
*/
|
||||
public final boolean isInterface;
|
||||
Kind(int refKind) {
|
||||
this(refKind, false);
|
||||
}
|
||||
|
||||
Kind(int refKind, boolean isInterface) { this.refKind = refKind; this.isInterface = isInterface; }
|
||||
|
||||
/**
|
||||
* Returns the enumeration member with the given {@code refKind} field.
|
||||
* Behaves as if {@code valueOf(refKind, false)}. As a special case,
|
||||
* if {@code refKind} is {@code REF_invokeInterface} (9) then the
|
||||
* {@code isInterface} field will be true.
|
||||
*
|
||||
* @param refKind refKind of desired member
|
||||
* @return the matching enumeration member
|
||||
* @throws IllegalArgumentException if there is no such member
|
||||
*/
|
||||
public static Kind valueOf(int refKind) {
|
||||
return valueOf(refKind, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the enumeration member with the given the {@code refKind} and
|
||||
* {@code isInterface} arguments.
|
||||
* For most values of {@code refKind} there is an exact match regardless of the value of {@code isInterface}.
|
||||
* These are:
|
||||
* <UL>
|
||||
* <LI>{@code REF_invokeVirtual} which matches to {@code VIRTUAL}
|
||||
* <LI>{@code REF_invokeInterface} which matches to {@code INTERFACE_VIRTUAL}
|
||||
* <LI>{@code REF_newInvokeSpecial} which matches to {@code CONSTRUCTOR}
|
||||
* <LI>{@code REF_getField} which matches to {@code GETTER}
|
||||
* <LI>{@code REF_putField} which matches to {@code SETTER}
|
||||
* <LI>{@code REF_getStatic} which matches to {@code STATIC_GETTER}
|
||||
* <LI>{@code REF_putStatic} which matches to {@code STATIC_SETTER}
|
||||
* </UL>
|
||||
* As for the rest, the returned kind will depend on the value (false or true accordingly) of {@code isInterface}:
|
||||
* <UL>
|
||||
* <LI>{@code REF_invokeStatic} which matches to {@code STATIC} or {@code INTERFACE_STATIC}
|
||||
* <LI>{@code REF_invokeSpecial} which matches to {@code SPECIAL} or {@code INTERFACE_SPECIAL}
|
||||
* </UL>
|
||||
* @param refKind refKind of desired member
|
||||
* @param isInterface whether desired member is for interface methods
|
||||
* @return the matching enumeration member
|
||||
* @throws IllegalArgumentException if there is no such member
|
||||
*/
|
||||
public static Kind valueOf(int refKind, boolean isInterface) {
|
||||
int i = tableIndex(refKind, isInterface);
|
||||
if (i >= 0 && i < TABLE.length) {
|
||||
Kind kind = TABLE[i];
|
||||
if (kind == null) {
|
||||
throw new IllegalArgumentException(String.format("refKind=%d", refKind));
|
||||
}
|
||||
if (kind.refKind == refKind && kind.isInterface == isInterface) {
|
||||
return kind;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException(String.format("refKind=%d", refKind));
|
||||
}
|
||||
|
||||
private static int tableIndex(int refKind, boolean isInterface) {
|
||||
if (refKind < 0) return refKind;
|
||||
return (refKind * 2) + (isInterface ? 1 : 0);
|
||||
}
|
||||
|
||||
private static final @Stable Kind[] TABLE;
|
||||
|
||||
static {
|
||||
// Pack the static table.
|
||||
int max = 0;
|
||||
for (Kind k : values())
|
||||
max = Math.max(max, tableIndex(k.refKind, true));
|
||||
|
||||
TABLE = new Kind[max+1];
|
||||
for (Kind kind : values()) {
|
||||
int i = tableIndex(kind.refKind, kind.isInterface);
|
||||
if (i >= TABLE.length || TABLE[i] != null)
|
||||
throw new AssertionError("TABLE entry for " + kind);
|
||||
TABLE[i] = kind;
|
||||
}
|
||||
|
||||
// Pack in some aliases also.
|
||||
int ii = tableIndex(REF_invokeInterface, false);
|
||||
if (TABLE[ii] != null)
|
||||
throw new AssertionError("TABLE entry for (invokeInterface, false) used by " + TABLE[ii]);
|
||||
TABLE[ii] = INTERFACE_VIRTUAL;
|
||||
|
||||
for (Kind kind : values()) {
|
||||
if (!kind.isInterface) {
|
||||
// Add extra cache entry to alias the isInterface case.
|
||||
// For example, (REF_getStatic, X) will produce STATIC_GETTER
|
||||
// for either truth value of X.
|
||||
int i = tableIndex(kind.refKind, true);
|
||||
if (TABLE[i] == null) {
|
||||
// There is not a specific Kind for interfaces
|
||||
if (kind == VIRTUAL) kind = INTERFACE_VIRTUAL;
|
||||
if (TABLE[i] == null) TABLE[i] = kind;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this {@code Kind} correspond to a virtual method invocation?
|
||||
*
|
||||
* @return if this {@code Kind} corresponds to a virtual method invocation
|
||||
*/
|
||||
boolean isVirtualMethod() {
|
||||
switch (this) {
|
||||
case VIRTUAL:
|
||||
case SPECIAL:
|
||||
case INTERFACE_VIRTUAL:
|
||||
case INTERFACE_SPECIAL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code kind} of the method handle described by this nominal
|
||||
* descriptor.
|
||||
*
|
||||
* @return the {@link Kind}
|
||||
*/
|
||||
Kind kind();
|
||||
|
||||
/**
|
||||
* Returns the {@code refKind} of the method handle described by this nominal
|
||||
* reference, as defined by {@link MethodHandleInfo}.
|
||||
*
|
||||
* @return the reference kind
|
||||
*/
|
||||
int refKind();
|
||||
|
||||
/**
|
||||
* Indicates if the method is declared by an interface
|
||||
*
|
||||
* @return true if the method is declared by an interface
|
||||
*/
|
||||
boolean isOwnerInterface();
|
||||
|
||||
/**
|
||||
* Returns a {@link ClassDesc} describing the class declaring the
|
||||
* method or field described by this nominal descriptor.
|
||||
*
|
||||
* @return the class declaring the method or field
|
||||
*/
|
||||
ClassDesc owner();
|
||||
|
||||
/**
|
||||
* Returns the name of the method or field described by this nominal descriptor.
|
||||
* For constructors, returns the reserved name {@code "<init>"}.
|
||||
*
|
||||
* @return the name of the method or field
|
||||
*/
|
||||
String methodName();
|
||||
|
||||
/**
|
||||
* Returns the lookup descriptor of the method handle described by this descriptor,
|
||||
* after adjusting for the invocation mode. This will correspond to either
|
||||
* a method type descriptor string (for methods and constructors), or a field
|
||||
* descriptor string (for field access method handles). The lookup descriptor
|
||||
* string is in the same format as accepted by {@link MethodHandleDesc#of(Kind, ClassDesc, String, String)}.
|
||||
*
|
||||
* @return the lookup descriptor string
|
||||
*/
|
||||
String lookupDescriptor();
|
||||
}
|
|
@ -0,0 +1,220 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 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.constant;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.Objects;
|
||||
|
||||
import static java.lang.constant.ConstantDescs.CD_void;
|
||||
import static java.lang.constant.ConstantUtils.validateClassOrInterface;
|
||||
import static java.lang.constant.ConstantUtils.validateMemberName;
|
||||
import static java.lang.constant.DirectMethodHandleDesc.Kind.CONSTRUCTOR;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
/**
|
||||
* A <a href="package-summary.html#nominal">nominal descriptor</a> for a direct
|
||||
* {@link MethodHandle}. A {@linkplain DirectMethodHandleDescImpl} corresponds to
|
||||
* a {@code Constant_MethodHandle_info} entry in the constant pool of a classfile.
|
||||
*/
|
||||
final class DirectMethodHandleDescImpl implements DirectMethodHandleDesc {
|
||||
|
||||
private final Kind kind;
|
||||
private final ClassDesc owner;
|
||||
private final String name;
|
||||
private final MethodTypeDesc invocationType;
|
||||
|
||||
/**
|
||||
* Constructs a {@linkplain DirectMethodHandleDescImpl} for a method or field
|
||||
* from a kind, owner, name, and type
|
||||
*
|
||||
* @param kind the kind of the method handle
|
||||
* @param owner the declaring class or interface for the method
|
||||
* @param name the unqualified name of the method (ignored if {@code kind} is {@code CONSTRUCTOR})
|
||||
* @param type the lookup type of the method
|
||||
* @throws NullPointerException if any non-ignored argument is null
|
||||
* @throws IllegalArgumentException if {@code kind} describes a field accessor,
|
||||
* and {@code type} is not consistent with that kind of field accessor, or if
|
||||
* {@code kind} describes a constructor, and the return type of {@code type}
|
||||
* is not {@code void}
|
||||
* @jvms 4.2.2 Unqualified Names
|
||||
*/
|
||||
DirectMethodHandleDescImpl(Kind kind, ClassDesc owner, String name, MethodTypeDesc type) {
|
||||
if (kind == CONSTRUCTOR)
|
||||
name = "<init>";
|
||||
|
||||
requireNonNull(kind);
|
||||
validateClassOrInterface(requireNonNull(owner));
|
||||
validateMemberName(requireNonNull(name));
|
||||
requireNonNull(type);
|
||||
|
||||
switch (kind) {
|
||||
case CONSTRUCTOR: validateConstructor(type); break;
|
||||
case GETTER: validateFieldType(type, false, true); break;
|
||||
case SETTER: validateFieldType(type, true, true); break;
|
||||
case STATIC_GETTER: validateFieldType(type, false, false); break;
|
||||
case STATIC_SETTER: validateFieldType(type, true, false); break;
|
||||
}
|
||||
|
||||
this.kind = kind;
|
||||
this.owner = owner;
|
||||
this.name = name;
|
||||
if (kind.isVirtualMethod())
|
||||
this.invocationType = type.insertParameterTypes(0, owner);
|
||||
else if (kind == CONSTRUCTOR)
|
||||
this.invocationType = type.changeReturnType(owner);
|
||||
else
|
||||
this.invocationType = type;
|
||||
}
|
||||
|
||||
private static void validateFieldType(MethodTypeDesc type, boolean isSetter, boolean isVirtual) {
|
||||
boolean isVoid = type.returnType().descriptorString().equals("V");
|
||||
int expectedParams = (isSetter ? 1 : 0) + (isVirtual ? 1 : 0);
|
||||
if (isVoid != isSetter
|
||||
|| type.parameterCount() != expectedParams
|
||||
|| (isVirtual && type.parameterType(0).isPrimitive())) {
|
||||
String expectedType = String.format("(%s%s)%s", (isVirtual ? "R" : ""),
|
||||
(isSetter ? "T" : ""), (isSetter ? "V" : "T"));
|
||||
throw new IllegalArgumentException(String.format("Expected type of %s for getter, found %s", expectedType, type));
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateConstructor(MethodTypeDesc type) {
|
||||
if (!type.returnType().descriptorString().equals("V")) {
|
||||
throw new IllegalArgumentException(String.format("Expected type of (T*)V for constructor, found %s", type));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Kind kind() { return kind; }
|
||||
|
||||
@Override
|
||||
public int refKind() { return kind.refKind; }
|
||||
|
||||
@Override
|
||||
public boolean isOwnerInterface() { return kind.isInterface; }
|
||||
|
||||
@Override
|
||||
public ClassDesc owner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String methodName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodTypeDesc invocationType() {
|
||||
return invocationType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String lookupDescriptor() {
|
||||
switch (kind) {
|
||||
case VIRTUAL:
|
||||
case SPECIAL:
|
||||
case INTERFACE_VIRTUAL:
|
||||
case INTERFACE_SPECIAL:
|
||||
return invocationType.dropParameterTypes(0, 1).descriptorString();
|
||||
case STATIC:
|
||||
case INTERFACE_STATIC:
|
||||
return invocationType.descriptorString();
|
||||
case CONSTRUCTOR:
|
||||
return invocationType.changeReturnType(CD_void).descriptorString();
|
||||
case GETTER:
|
||||
case STATIC_GETTER:
|
||||
return invocationType.returnType().descriptorString();
|
||||
case SETTER:
|
||||
return invocationType.parameterType(1).descriptorString();
|
||||
case STATIC_SETTER:
|
||||
return invocationType.parameterType(0).descriptorString();
|
||||
default:
|
||||
throw new IllegalStateException(kind.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public MethodHandle resolveConstantDesc(MethodHandles.Lookup lookup)
|
||||
throws ReflectiveOperationException {
|
||||
Class<?> resolvedOwner = (Class<?>) owner.resolveConstantDesc(lookup);
|
||||
MethodType invocationType = (MethodType) this.invocationType().resolveConstantDesc(lookup);
|
||||
switch (kind) {
|
||||
case STATIC:
|
||||
case INTERFACE_STATIC:
|
||||
return lookup.findStatic(resolvedOwner, name, invocationType);
|
||||
case INTERFACE_VIRTUAL:
|
||||
case VIRTUAL:
|
||||
return lookup.findVirtual(resolvedOwner, name, invocationType.dropParameterTypes(0, 1));
|
||||
case SPECIAL:
|
||||
case INTERFACE_SPECIAL:
|
||||
return lookup.findSpecial(resolvedOwner, name, invocationType.dropParameterTypes(0, 1),
|
||||
lookup.lookupClass());
|
||||
case CONSTRUCTOR:
|
||||
return lookup.findConstructor(resolvedOwner, invocationType.changeReturnType(void.class));
|
||||
case GETTER:
|
||||
return lookup.findGetter(resolvedOwner, name, invocationType.returnType());
|
||||
case STATIC_GETTER:
|
||||
return lookup.findStaticGetter(resolvedOwner, name, invocationType.returnType());
|
||||
case SETTER:
|
||||
return lookup.findSetter(resolvedOwner, name, invocationType.parameterType(1));
|
||||
case STATIC_SETTER:
|
||||
return lookup.findStaticSetter(resolvedOwner, name, invocationType.parameterType(0));
|
||||
default:
|
||||
throw new IllegalStateException(kind.name());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this {@linkplain DirectMethodHandleDescImpl} is
|
||||
* equal to another {@linkplain DirectMethodHandleDescImpl}. Equality is
|
||||
* determined by the two descriptors having equal kind, owner, name, and type
|
||||
* descriptor.
|
||||
* @param o a {@code DirectMethodHandleDescImpl} to compare to this
|
||||
* {@code DirectMethodHandleDescImpl}
|
||||
* @return {@code true} if the specified {@code DirectMethodHandleDescImpl} is
|
||||
* equals to this {@code DirectMethodHandleDescImpl}.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
DirectMethodHandleDescImpl desc = (DirectMethodHandleDescImpl) o;
|
||||
return kind == desc.kind &&
|
||||
Objects.equals(owner, desc.owner) &&
|
||||
Objects.equals(name, desc.name) &&
|
||||
Objects.equals(invocationType, desc.invocationType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(kind, owner, name, invocationType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("MethodHandleDesc[%s/%s::%s%s]", kind, owner.displayName(), name, invocationType.displayDescriptor());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,289 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 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.constant;
|
||||
|
||||
import java.lang.invoke.CallSite;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.lang.constant.ConstantDescs.CD_String;
|
||||
import static java.lang.constant.ConstantUtils.EMPTY_CONSTANTDESC;
|
||||
import static java.lang.constant.ConstantUtils.validateMemberName;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
/**
|
||||
* A <a href="package-summary.html#nominal">nominal descriptor</a> for an
|
||||
* {@code invokedynamic} call site.
|
||||
*
|
||||
* <p>Concrete subtypes of {@linkplain DynamicCallSiteDesc} must be
|
||||
* <a href="../doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public class DynamicCallSiteDesc {
|
||||
|
||||
private final DirectMethodHandleDesc bootstrapMethod;
|
||||
private final ConstantDesc[] bootstrapArgs;
|
||||
private final String invocationName;
|
||||
private final MethodTypeDesc invocationType;
|
||||
|
||||
/**
|
||||
* Creates a nominal descriptor for an {@code invokedynamic} call site.
|
||||
*
|
||||
* @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
|
||||
* bootstrap method for the {@code invokedynamic}
|
||||
* @param invocationName The unqualified name that would appear in the {@code NameAndType}
|
||||
* operand of the {@code invokedynamic}
|
||||
* @param invocationType a {@link MethodTypeDesc} describing the invocation
|
||||
* type that would appear in the {@code NameAndType}
|
||||
* operand of the {@code invokedynamic}
|
||||
* @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
|
||||
* to the bootstrap, that would appear in the
|
||||
* {@code BootstrapMethods} attribute
|
||||
* @throws NullPointerException if any parameter is null
|
||||
* @throws IllegalArgumentException if the invocation name has the incorrect
|
||||
* format
|
||||
* @jvms 4.2.2 Unqualified Names
|
||||
*/
|
||||
private DynamicCallSiteDesc(DirectMethodHandleDesc bootstrapMethod,
|
||||
String invocationName,
|
||||
MethodTypeDesc invocationType,
|
||||
ConstantDesc[] bootstrapArgs) {
|
||||
this.invocationName = validateMemberName(requireNonNull(invocationName));
|
||||
this.invocationType = requireNonNull(invocationType);
|
||||
this.bootstrapMethod = requireNonNull(bootstrapMethod);
|
||||
this.bootstrapArgs = requireNonNull(bootstrapArgs.clone());
|
||||
if (invocationName.length() == 0)
|
||||
throw new IllegalArgumentException("Illegal invocation name: " + invocationName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a nominal descriptor for an {@code invokedynamic} call site.
|
||||
*
|
||||
* @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
|
||||
* bootstrap method for the {@code invokedynamic}
|
||||
* @param invocationName The unqualified name that would appear in the {@code NameAndType}
|
||||
* operand of the {@code invokedynamic}
|
||||
* @param invocationType a {@link MethodTypeDesc} describing the invocation
|
||||
* type that would appear in the {@code NameAndType}
|
||||
* operand of the {@code invokedynamic}
|
||||
* @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
|
||||
* to the bootstrap, that would appear in the
|
||||
* {@code BootstrapMethods} attribute
|
||||
* @return the nominal descriptor
|
||||
* @throws NullPointerException if any parameter is null
|
||||
* @throws IllegalArgumentException if the invocation name has the incorrect
|
||||
* format
|
||||
* @jvms 4.2.2 Unqualified Names
|
||||
*/
|
||||
public static DynamicCallSiteDesc of(DirectMethodHandleDesc bootstrapMethod,
|
||||
String invocationName,
|
||||
MethodTypeDesc invocationType,
|
||||
ConstantDesc... bootstrapArgs) {
|
||||
return new DynamicCallSiteDesc(bootstrapMethod, invocationName, invocationType, bootstrapArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a nominal descriptor for an {@code invokedynamic} call site whose
|
||||
* bootstrap method has no static arguments.
|
||||
*
|
||||
* @param bootstrapMethod The bootstrap method for the {@code invokedynamic}
|
||||
* @param invocationName The invocationName that would appear in the
|
||||
* {@code NameAndType} operand of the {@code invokedynamic}
|
||||
* @param invocationType The invocation invocationType that would appear
|
||||
* in the {@code NameAndType} operand of the {@code invokedynamic}
|
||||
* @return the nominal descriptor
|
||||
* @throws NullPointerException if any parameter is null
|
||||
* @throws IllegalArgumentException if the invocation name has the incorrect
|
||||
* format
|
||||
*/
|
||||
public static DynamicCallSiteDesc of(DirectMethodHandleDesc bootstrapMethod,
|
||||
String invocationName,
|
||||
MethodTypeDesc invocationType) {
|
||||
return new DynamicCallSiteDesc(bootstrapMethod, invocationName, invocationType, EMPTY_CONSTANTDESC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a nominal descriptor for an {@code invokedynamic} call site whose
|
||||
* bootstrap method has no static arguments and for which the name parameter
|
||||
* is {@link ConstantDescs#DEFAULT_NAME}.
|
||||
*
|
||||
* @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
|
||||
* bootstrap method for the {@code invokedynamic}
|
||||
* @param invocationType a {@link MethodTypeDesc} describing the invocation
|
||||
* type that would appear in the {@code NameAndType}
|
||||
* operand of the {@code invokedynamic}
|
||||
* @return the nominal descriptor
|
||||
* @throws NullPointerException if any parameter is null
|
||||
*/
|
||||
public static DynamicCallSiteDesc of(DirectMethodHandleDesc bootstrapMethod,
|
||||
MethodTypeDesc invocationType) {
|
||||
return of(bootstrapMethod, ConstantDescs.DEFAULT_NAME, invocationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a nominal descriptor for an {@code invokedynamic} call site whose
|
||||
* bootstrap method, name, and invocation type are the same as this one, but
|
||||
* with the specified bootstrap arguments.
|
||||
*
|
||||
* @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
|
||||
* to the bootstrap, that would appear in the
|
||||
* {@code BootstrapMethods} attribute
|
||||
* @return the nominal descriptor
|
||||
* @throws NullPointerException if any parameter is null
|
||||
*/
|
||||
public DynamicCallSiteDesc withArgs(ConstantDesc... bootstrapArgs) {
|
||||
return new DynamicCallSiteDesc(bootstrapMethod, invocationName, invocationType, bootstrapArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a nominal descriptor for an {@code invokedynamic} call site whose
|
||||
* bootstrap and bootstrap arguments are the same as this one, but with the
|
||||
* specified invocationName and invocation invocationType
|
||||
*
|
||||
* @param invocationName The unqualified name that would appear in the {@code NameAndType}
|
||||
* operand of the {@code invokedynamic}
|
||||
* @param invocationType a {@link MethodTypeDesc} describing the invocation
|
||||
* type that would appear in the {@code NameAndType}
|
||||
* operand of the {@code invokedynamic}
|
||||
* @return the nominal descriptor
|
||||
* @throws NullPointerException if any parameter is null
|
||||
* @throws IllegalArgumentException if the invocation name has the incorrect
|
||||
* format
|
||||
* @jvms 4.2.2 Unqualified Names
|
||||
*/
|
||||
public DynamicCallSiteDesc withNameAndType(String invocationName,
|
||||
MethodTypeDesc invocationType) {
|
||||
return new DynamicCallSiteDesc(bootstrapMethod, invocationName, invocationType, bootstrapArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the invocation name that would appear in the {@code NameAndType}
|
||||
* operand of the {@code invokedynamic}.
|
||||
*
|
||||
* @return the invocation name
|
||||
*/
|
||||
public String invocationName() {
|
||||
return invocationName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link MethodTypeDesc} describing the invocation type that
|
||||
* would appear in the {@code NameAndType} operand of the {@code invokedynamic}.
|
||||
*
|
||||
* @return the invocation type
|
||||
*/
|
||||
public MethodTypeDesc invocationType() {
|
||||
return invocationType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link MethodHandleDesc} describing the bootstrap method for
|
||||
* the {@code invokedynamic}.
|
||||
*
|
||||
* @return the bootstrap method for the {@code invokedynamic}
|
||||
*/
|
||||
public MethodHandleDesc bootstrapMethod() { return bootstrapMethod; }
|
||||
|
||||
/**
|
||||
* Returns {@link ConstantDesc}s describing the bootstrap arguments for the
|
||||
* {@code invokedynamic}. The returned array is always non-null. A zero
|
||||
* length array is returned if this {@linkplain DynamicCallSiteDesc} has no
|
||||
* bootstrap arguments.
|
||||
*
|
||||
* @return the bootstrap arguments for the {@code invokedynamic}
|
||||
*/
|
||||
public ConstantDesc[] bootstrapArgs() { return bootstrapArgs.clone(); }
|
||||
|
||||
/**
|
||||
* Reflectively invokes the bootstrap method with the specified arguments,
|
||||
* and return the resulting {@link CallSite}
|
||||
*
|
||||
* @param lookup The {@link MethodHandles.Lookup} used to resolve class names
|
||||
* @return the {@link CallSite}
|
||||
* @throws Throwable if any exception is thrown by the bootstrap method
|
||||
*/
|
||||
public CallSite resolveCallSiteDesc(MethodHandles.Lookup lookup) throws Throwable {
|
||||
assert bootstrapMethod.invocationType().parameterType(1).equals(CD_String);
|
||||
MethodHandle bsm = (MethodHandle) bootstrapMethod.resolveConstantDesc(lookup);
|
||||
Object[] args = new Object[bootstrapArgs.length + 3];
|
||||
args[0] = lookup;
|
||||
args[1] = invocationName;
|
||||
args[2] = invocationType.resolveConstantDesc(lookup);
|
||||
System.arraycopy(bootstrapArgs, 0, args, 3, bootstrapArgs.length);
|
||||
return (CallSite) bsm.invokeWithArguments(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the specified object with this descriptor for equality. Returns
|
||||
* {@code true} if and only if the specified object is also a
|
||||
* {@linkplain DynamicCallSiteDesc}, and both descriptors have equal
|
||||
* bootstrap methods, bootstrap argument lists, invocation name, and
|
||||
* invocation type.
|
||||
*
|
||||
* @param o the {@code DynamicCallSiteDesc} to compare to this
|
||||
* {@code DynamicCallSiteDesc}
|
||||
* @return {@code true} if the specified {@code DynamicCallSiteDesc} is
|
||||
* equals to this {@code DynamicCallSiteDesc}.
|
||||
*/
|
||||
@Override
|
||||
public final boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
DynamicCallSiteDesc specifier = (DynamicCallSiteDesc) o;
|
||||
return Objects.equals(bootstrapMethod, specifier.bootstrapMethod) &&
|
||||
Arrays.equals(bootstrapArgs, specifier.bootstrapArgs) &&
|
||||
Objects.equals(invocationName, specifier.invocationName) &&
|
||||
Objects.equals(invocationType, specifier.invocationType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
int result = Objects.hash(bootstrapMethod, invocationName, invocationType);
|
||||
result = 31 * result + Arrays.hashCode(bootstrapArgs);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a compact textual description of this call site description,
|
||||
* including the bootstrap method, the invocation name and type, and
|
||||
* the static bootstrap arguments.
|
||||
*
|
||||
* @return A compact textual description of this call site descriptor
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("DynamicCallSiteDesc[%s::%s(%s%s):%s]",
|
||||
bootstrapMethod.owner().displayName(),
|
||||
bootstrapMethod.methodName(),
|
||||
invocationName.equals(ConstantDescs.DEFAULT_NAME) ? "" : invocationName + "/",
|
||||
Stream.of(bootstrapArgs).map(Object::toString).collect(joining(",")),
|
||||
invocationType.displayDescriptor());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,397 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 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.constant;
|
||||
|
||||
import java.lang.Enum.EnumDesc;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.lang.invoke.VarHandle.VarHandleDesc;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.lang.constant.ConstantDescs.CD_Class;
|
||||
import static java.lang.constant.ConstantDescs.CD_VarHandle;
|
||||
import static java.lang.constant.ConstantDescs.DEFAULT_NAME;
|
||||
import static java.lang.constant.ConstantUtils.EMPTY_CONSTANTDESC;
|
||||
import static java.lang.constant.ConstantUtils.validateMemberName;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
/**
|
||||
* A <a href="package-summary.html#nominal">nominal descriptor</a> for a
|
||||
* dynamic constant (one described in the constant pool with
|
||||
* {@code Constant_Dynamic_info}.)
|
||||
*
|
||||
* <p>Concrete subtypes of {@linkplain DynamicConstantDesc} must be
|
||||
* <a href="../doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @param <T> the type of the dynamic constant
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public abstract class DynamicConstantDesc<T>
|
||||
implements ConstantDesc {
|
||||
|
||||
private final DirectMethodHandleDesc bootstrapMethod;
|
||||
private final ConstantDesc[] bootstrapArgs;
|
||||
private final String constantName;
|
||||
private final ClassDesc constantType;
|
||||
|
||||
private static final Map<MethodHandleDesc, Function<DynamicConstantDesc<?>, ConstantDesc>> canonicalMap
|
||||
= Map.ofEntries(Map.entry(ConstantDescs.BSM_PRIMITIVE_CLASS, DynamicConstantDesc::canonicalizePrimitiveClass),
|
||||
Map.entry(ConstantDescs.BSM_ENUM_CONSTANT, DynamicConstantDesc::canonicalizeEnum),
|
||||
Map.entry(ConstantDescs.BSM_NULL_CONSTANT, DynamicConstantDesc::canonicalizeNull),
|
||||
Map.entry(ConstantDescs.BSM_VARHANDLE_STATIC_FIELD, DynamicConstantDesc::canonicalizeStaticFieldVarHandle),
|
||||
Map.entry(ConstantDescs.BSM_VARHANDLE_FIELD, DynamicConstantDesc::canonicalizeFieldVarHandle),
|
||||
Map.entry(ConstantDescs.BSM_VARHANDLE_ARRAY, DynamicConstantDesc::canonicalizeArrayVarHandle)
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates a nominal descriptor for a dynamic constant.
|
||||
*
|
||||
* @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
|
||||
* bootstrap method for the constant
|
||||
* @param constantName The unqualified name that would appear in the {@code NameAndType}
|
||||
* operand of the {@code LDC} for this constant
|
||||
* @param constantType a {@link ClassDesc} describing the type
|
||||
* that would appear in the {@code NameAndType} operand
|
||||
* of the {@code LDC} for this constant
|
||||
* @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
|
||||
* to the bootstrap, that would appear in the
|
||||
* {@code BootstrapMethods} attribute
|
||||
* @throws NullPointerException if any argument is null
|
||||
* @throws IllegalArgumentException if the {@code name} has the incorrect
|
||||
* format
|
||||
* @jvms 4.2.2 Unqualified Names
|
||||
*/
|
||||
protected DynamicConstantDesc(DirectMethodHandleDesc bootstrapMethod,
|
||||
String constantName,
|
||||
ClassDesc constantType,
|
||||
ConstantDesc... bootstrapArgs) {
|
||||
this.bootstrapMethod = requireNonNull(bootstrapMethod);
|
||||
this.constantName = validateMemberName(requireNonNull(constantName));
|
||||
this.constantType = requireNonNull(constantType);
|
||||
this.bootstrapArgs = requireNonNull(bootstrapArgs).clone();
|
||||
|
||||
if (constantName.length() == 0)
|
||||
throw new IllegalArgumentException("Illegal invocation name: " + constantName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a nominal descriptor for a dynamic constant, transforming it into
|
||||
* a more specific type if the constant bootstrap is a well-known one and a
|
||||
* more specific nominal descriptor type (e.g., ClassDesc) is available.
|
||||
*
|
||||
* <p>Classes whose {@link Constable#describeConstable()} method produce
|
||||
* a {@linkplain DynamicConstantDesc} with a well-known bootstrap including
|
||||
* {@link Class} (for instances describing primitive types), {@link Enum},
|
||||
* and {@link VarHandle}.
|
||||
*
|
||||
* <p>Bytecode-reading APIs that process the constant pool and wish to expose
|
||||
* entries as {@link ConstantDesc} to their callers should generally use this
|
||||
* method in preference to {@link #ofNamed(DirectMethodHandleDesc, String, ClassDesc, ConstantDesc...)}
|
||||
* because this may result in a more specific type that can be provided to
|
||||
* callers.
|
||||
*
|
||||
* @param <T> the type of the dynamic constant
|
||||
* @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
|
||||
* bootstrap method for the constant
|
||||
* @param constantName The unqualified name that would appear in the {@code NameAndType}
|
||||
* operand of the {@code LDC} for this constant
|
||||
* @param constantType a {@link ClassDesc} describing the type
|
||||
* that would appear in the {@code NameAndType} operand
|
||||
* of the {@code LDC} for this constant
|
||||
* @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
|
||||
* to the bootstrap, that would appear in the
|
||||
* {@code BootstrapMethods} attribute
|
||||
* @return the nominal descriptor
|
||||
* @throws NullPointerException if any argument is null
|
||||
* @throws IllegalArgumentException if the {@code name} has the incorrect
|
||||
* format
|
||||
* @jvms 4.2.2 Unqualified Names
|
||||
*/
|
||||
public static<T> ConstantDesc ofCanonical(DirectMethodHandleDesc bootstrapMethod,
|
||||
String constantName,
|
||||
ClassDesc constantType,
|
||||
ConstantDesc[] bootstrapArgs) {
|
||||
return DynamicConstantDesc.<T>ofNamed(bootstrapMethod, constantName, constantType, bootstrapArgs)
|
||||
.tryCanonicalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a nominal descriptor for a dynamic constant.
|
||||
*
|
||||
* @param <T> the type of the dynamic constant
|
||||
* @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
|
||||
* bootstrap method for the constant
|
||||
* @param constantName The unqualified name that would appear in the {@code NameAndType}
|
||||
* operand of the {@code LDC} for this constant
|
||||
* @param constantType a {@link ClassDesc} describing the type
|
||||
* that would appear in the {@code NameAndType} operand
|
||||
* of the {@code LDC} for this constant
|
||||
* @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
|
||||
* to the bootstrap, that would appear in the
|
||||
* {@code BootstrapMethods} attribute
|
||||
* @return the nominal descriptor
|
||||
* @throws NullPointerException if any argument is null
|
||||
* @throws IllegalArgumentException if the {@code name} has the incorrect
|
||||
* format
|
||||
* @jvms 4.2.2 Unqualified Names
|
||||
*/
|
||||
|
||||
public static<T> DynamicConstantDesc<T> ofNamed(DirectMethodHandleDesc bootstrapMethod,
|
||||
String constantName,
|
||||
ClassDesc constantType,
|
||||
ConstantDesc... bootstrapArgs) {
|
||||
return new AnonymousDynamicConstantDesc<>(bootstrapMethod, constantName, constantType, bootstrapArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a nominal descriptor for a dynamic constant whose name parameter
|
||||
* is {@link ConstantDescs#DEFAULT_NAME}, and whose type parameter is always
|
||||
* the same as the bootstrap method return type.
|
||||
*
|
||||
* @param <T> the type of the dynamic constant
|
||||
* @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
|
||||
* bootstrap method for the constant
|
||||
* @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
|
||||
* to the bootstrap, that would appear in the
|
||||
* {@code BootstrapMethods} attribute
|
||||
* @return the nominal descriptor
|
||||
* @throws NullPointerException if any argument is null
|
||||
* @jvms 4.2.2 Unqualified Names
|
||||
*/
|
||||
public static<T> DynamicConstantDesc<T> of(DirectMethodHandleDesc bootstrapMethod,
|
||||
ConstantDesc... bootstrapArgs) {
|
||||
return ofNamed(bootstrapMethod, DEFAULT_NAME, bootstrapMethod.invocationType().returnType(), bootstrapArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a nominal descriptor for a dynamic constant whose bootstrap has
|
||||
* no static arguments, whose name parameter is {@link ConstantDescs#DEFAULT_NAME},
|
||||
* and whose type parameter is always the same as the bootstrap method return type.
|
||||
*
|
||||
* @param <T> the type of the dynamic constant
|
||||
* @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
|
||||
* bootstrap method for the constant
|
||||
* @return the nominal descriptor
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
public static<T> DynamicConstantDesc<T> of(DirectMethodHandleDesc bootstrapMethod) {
|
||||
return of(bootstrapMethod, EMPTY_CONSTANTDESC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name that would appear in the {@code NameAndType} operand
|
||||
* of the {@code LDC} for this constant.
|
||||
*
|
||||
* @return the constant name
|
||||
*/
|
||||
public String constantName() {
|
||||
return constantName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link ClassDesc} describing the type that would appear in the
|
||||
* {@code NameAndType} operand of the {@code LDC} for this constant.
|
||||
*
|
||||
* @return the constant type
|
||||
*/
|
||||
public ClassDesc constantType() {
|
||||
return constantType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link MethodHandleDesc} describing the bootstrap method for
|
||||
* this constant.
|
||||
*
|
||||
* @return the bootstrap method
|
||||
*/
|
||||
public DirectMethodHandleDesc bootstrapMethod() {
|
||||
return bootstrapMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bootstrap arguments for this constant.
|
||||
*
|
||||
* @return the bootstrap arguments
|
||||
*/
|
||||
public ConstantDesc[] bootstrapArgs() {
|
||||
return bootstrapArgs.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bootstrap arguments for this constant as an immutable {@link List}.
|
||||
*
|
||||
* @return a {@link List} of the bootstrap arguments
|
||||
*/
|
||||
public List<ConstantDesc> bootstrapArgsList() {
|
||||
return List.of(bootstrapArgs);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public T resolveConstantDesc(MethodHandles.Lookup lookup) throws ReflectiveOperationException {
|
||||
try {
|
||||
MethodHandle bsm = (MethodHandle) bootstrapMethod.resolveConstantDesc(lookup);
|
||||
if (bsm.type().parameterCount() < 2 ||
|
||||
!MethodHandles.Lookup.class.isAssignableFrom(bsm.type().parameterType(0))) {
|
||||
throw new BootstrapMethodError(
|
||||
"Invalid bootstrap method declared for resolving a dynamic constant: " + bootstrapMethod);
|
||||
}
|
||||
Object[] bsmArgs = new Object[3 + bootstrapArgs.length];
|
||||
bsmArgs[0] = lookup;
|
||||
bsmArgs[1] = constantName;
|
||||
bsmArgs[2] = constantType.resolveConstantDesc(lookup);
|
||||
for (int i = 0; i < bootstrapArgs.length; i++)
|
||||
bsmArgs[3 + i] = bootstrapArgs[i].resolveConstantDesc(lookup);
|
||||
|
||||
return (T) bsm.invokeWithArguments(bsmArgs);
|
||||
} catch (Error e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
throw new BootstrapMethodError(t);
|
||||
}
|
||||
}
|
||||
|
||||
private ConstantDesc tryCanonicalize() {
|
||||
Function<DynamicConstantDesc<?>, ConstantDesc> f = canonicalMap.get(bootstrapMethod);
|
||||
if (f != null) {
|
||||
try {
|
||||
return f.apply(this);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private static ConstantDesc canonicalizeNull(DynamicConstantDesc<?> desc) {
|
||||
if (desc.bootstrapArgs.length != 0)
|
||||
return desc;
|
||||
return ConstantDescs.NULL;
|
||||
}
|
||||
|
||||
private static ConstantDesc canonicalizeEnum(DynamicConstantDesc<?> desc) {
|
||||
if (desc.bootstrapArgs.length != 0
|
||||
|| desc.constantName == null)
|
||||
return desc;
|
||||
return EnumDesc.of(desc.constantType, desc.constantName);
|
||||
}
|
||||
|
||||
private static ConstantDesc canonicalizePrimitiveClass(DynamicConstantDesc<?> desc) {
|
||||
if (desc.bootstrapArgs.length != 0
|
||||
|| !desc.constantType().equals(CD_Class)
|
||||
|| desc.constantName == null)
|
||||
return desc;
|
||||
return ClassDesc.ofDescriptor(desc.constantName);
|
||||
}
|
||||
|
||||
private static ConstantDesc canonicalizeStaticFieldVarHandle(DynamicConstantDesc<?> desc) {
|
||||
if (desc.bootstrapArgs.length != 2
|
||||
|| !desc.constantType().equals(CD_VarHandle))
|
||||
return desc;
|
||||
return VarHandleDesc.ofStaticField((ClassDesc) desc.bootstrapArgs[0],
|
||||
desc.constantName,
|
||||
(ClassDesc) desc.bootstrapArgs[1]);
|
||||
}
|
||||
|
||||
private static ConstantDesc canonicalizeFieldVarHandle(DynamicConstantDesc<?> desc) {
|
||||
if (desc.bootstrapArgs.length != 2
|
||||
|| !desc.constantType().equals(CD_VarHandle))
|
||||
return desc;
|
||||
return VarHandleDesc.ofField((ClassDesc) desc.bootstrapArgs[0],
|
||||
desc.constantName,
|
||||
(ClassDesc) desc.bootstrapArgs[1]);
|
||||
}
|
||||
|
||||
private static ConstantDesc canonicalizeArrayVarHandle(DynamicConstantDesc<?> desc) {
|
||||
if (desc.bootstrapArgs.length != 1
|
||||
|| !desc.constantType().equals(CD_VarHandle))
|
||||
return desc;
|
||||
return VarHandleDesc.ofArray((ClassDesc) desc.bootstrapArgs[0]);
|
||||
}
|
||||
|
||||
// @@@ To eventually support in canonicalization: DCR with BSM=MHR_METHODHANDLEDESC_ASTYPE becomes AsTypeMHDesc
|
||||
|
||||
/**
|
||||
* Compares the specified object with this descriptor for equality. Returns
|
||||
* {@code true} if and only if the specified object is also a
|
||||
* {@linkplain DynamicConstantDesc}, and both descriptors have equal
|
||||
* bootstrap methods, bootstrap argument lists, constant name, and
|
||||
* constant type.
|
||||
*
|
||||
* @param o the {@code DynamicConstantDesc} to compare to this
|
||||
* {@code DynamicConstantDesc}
|
||||
* @return {@code true} if the specified {@code DynamicConstantDesc} is
|
||||
* equals to this {@code DynamicConstantDesc}.
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public final boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof DynamicConstantDesc)) return false;
|
||||
DynamicConstantDesc<?> desc = (DynamicConstantDesc<?>) o;
|
||||
return Objects.equals(bootstrapMethod, desc.bootstrapMethod) &&
|
||||
Arrays.equals(bootstrapArgs, desc.bootstrapArgs) &&
|
||||
Objects.equals(constantName, desc.constantName) &&
|
||||
Objects.equals(constantType, desc.constantType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
int result = Objects.hash(bootstrapMethod, constantName, constantType);
|
||||
result = 31 * result + Arrays.hashCode(bootstrapArgs);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a compact textual description of this constant description,
|
||||
* including the bootstrap method, the constant name and type, and
|
||||
* the static bootstrap arguments.
|
||||
*
|
||||
* @return A compact textual description of this call site descriptor
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("DynamicConstantDesc[%s::%s(%s%s)%s]",
|
||||
bootstrapMethod.owner().displayName(),
|
||||
bootstrapMethod.methodName(),
|
||||
constantName.equals(ConstantDescs.DEFAULT_NAME) ? "" : constantName + "/",
|
||||
Stream.of(bootstrapArgs).map(Object::toString).collect(joining(",")),
|
||||
constantType.displayName());
|
||||
}
|
||||
|
||||
private static class AnonymousDynamicConstantDesc<T> extends DynamicConstantDesc<T> {
|
||||
AnonymousDynamicConstantDesc(DirectMethodHandleDesc bootstrapMethod, String constantName, ClassDesc constantType, ConstantDesc... bootstrapArgs) {
|
||||
super(bootstrapMethod, constantName, constantType, bootstrapArgs);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 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.constant;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
||||
import static java.lang.constant.ConstantDescs.CD_void;
|
||||
import static java.lang.constant.DirectMethodHandleDesc.Kind.CONSTRUCTOR;
|
||||
|
||||
/**
|
||||
* A <a href="package-summary.html#nominal">nominal descriptor</a> for a
|
||||
* {@link MethodHandle} constant.
|
||||
*
|
||||
* @apiNote In the future, if the Java language permits, {@linkplain MethodHandleDesc}
|
||||
* may become a {@code sealed} interface, which would prohibit subclassing except
|
||||
* by explicitly permitted types. Non-platform classes should not implement
|
||||
* {@linkplain MethodHandleDesc} directly.
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public interface MethodHandleDesc
|
||||
extends ConstantDesc {
|
||||
|
||||
/**
|
||||
* Creates a {@linkplain MethodHandleDesc} corresponding to an invocation of a
|
||||
* declared method, invocation of a constructor, or access to a field.
|
||||
*
|
||||
* <p>The lookup descriptor string has the same format as for the various
|
||||
* variants of {@code CONSTANT_MethodHandle_info} and for the lookup
|
||||
* methods on {@link MethodHandles.Lookup}. For a method or constructor
|
||||
* invocation, it is interpreted as a method type descriptor; for field
|
||||
* access, it is interpreted as a field descriptor. If {@code kind} is
|
||||
* {@code CONSTRUCTOR}, the {@code name} parameter is ignored and the return
|
||||
* type of the lookup descriptor must be {@code void}. If {@code kind}
|
||||
* corresponds to a virtual method invocation, the lookup type includes the
|
||||
* method parameters but not the receiver type.
|
||||
*
|
||||
* @param kind The kind of method handle to be described
|
||||
* @param owner a {@link ClassDesc} describing the class containing the
|
||||
* method, constructor, or field
|
||||
* @param name the unqualified name of the method or field (ignored if
|
||||
* {@code kind} is {@code CONSTRUCTOR})
|
||||
* @param lookupDescriptor a method descriptor string the lookup type,
|
||||
* if the request is for a method invocation, or
|
||||
* describing the invocation type, if the request is
|
||||
* for a field or constructor
|
||||
* @return the {@linkplain MethodHandleDesc}
|
||||
* @throws NullPointerException if any of the non-ignored arguments are null
|
||||
* @jvms 4.4.8 The CONSTANT_MethodHandle_info Structure
|
||||
* @jvms 4.2.2 Unqualified Names
|
||||
* @jvms 4.3.2 Field Descriptors
|
||||
* @jvms 4.3.3 Method Descriptors
|
||||
*/
|
||||
static DirectMethodHandleDesc of(DirectMethodHandleDesc.Kind kind,
|
||||
ClassDesc owner,
|
||||
String name,
|
||||
String lookupDescriptor) {
|
||||
switch (kind) {
|
||||
case GETTER:
|
||||
case SETTER:
|
||||
case STATIC_GETTER:
|
||||
case STATIC_SETTER:
|
||||
return ofField(kind, owner, name, ClassDesc.ofDescriptor(lookupDescriptor));
|
||||
default:
|
||||
return new DirectMethodHandleDescImpl(kind, owner, name, MethodTypeDesc.ofDescriptor(lookupDescriptor));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@linkplain MethodHandleDesc} corresponding to an invocation of a
|
||||
* declared method or constructor.
|
||||
*
|
||||
* <p>The lookup descriptor string has the same format as for the lookup
|
||||
* methods on {@link MethodHandles.Lookup}. If {@code kind} is
|
||||
* {@code CONSTRUCTOR}, the name is ignored and the return type of the lookup
|
||||
* type must be {@code void}. If {@code kind} corresponds to a virtual method
|
||||
* invocation, the lookup type includes the method parameters but not the
|
||||
* receiver type.
|
||||
*
|
||||
* @param kind The kind of method handle to be described; must be one of
|
||||
* {@code SPECIAL, VIRTUAL, STATIC, INTERFACE_SPECIAL,
|
||||
* INTERFACE_VIRTUAL, INTERFACE_STATIC, CONSTRUCTOR}
|
||||
* @param owner a {@link ClassDesc} describing the class containing the
|
||||
* method or constructor
|
||||
* @param name the unqualified name of the method (ignored if {@code kind}
|
||||
* is {@code CONSTRUCTOR})
|
||||
* @param lookupMethodType a {@link MethodTypeDesc} describing the lookup type
|
||||
* @return the {@linkplain MethodHandleDesc}
|
||||
* @throws NullPointerException if any non-ignored arguments are null
|
||||
* @throws IllegalArgumentException if the {@code name} has the incorrect
|
||||
* format, or the kind is invalid
|
||||
* @jvms 4.2.2 Unqualified Names
|
||||
*/
|
||||
static DirectMethodHandleDesc ofMethod(DirectMethodHandleDesc.Kind kind,
|
||||
ClassDesc owner,
|
||||
String name,
|
||||
MethodTypeDesc lookupMethodType) {
|
||||
switch (kind) {
|
||||
case GETTER:
|
||||
case SETTER:
|
||||
case STATIC_GETTER:
|
||||
case STATIC_SETTER:
|
||||
throw new IllegalArgumentException(kind.toString());
|
||||
case VIRTUAL:
|
||||
case SPECIAL:
|
||||
case INTERFACE_VIRTUAL:
|
||||
case INTERFACE_SPECIAL:
|
||||
case INTERFACE_STATIC:
|
||||
case STATIC:
|
||||
case CONSTRUCTOR:
|
||||
return new DirectMethodHandleDescImpl(kind, owner, name, lookupMethodType);
|
||||
default:
|
||||
throw new IllegalArgumentException(kind.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@linkplain MethodHandleDesc} corresponding to a method handle
|
||||
* that accesses a field.
|
||||
*
|
||||
* @param kind the kind of the method handle to be described; must be one of {@code GETTER},
|
||||
* {@code SETTER}, {@code STATIC_GETTER}, or {@code STATIC_SETTER}
|
||||
* @param owner a {@link ClassDesc} describing the class containing the field
|
||||
* @param fieldName the unqualified name of the field
|
||||
* @param fieldType a {@link ClassDesc} describing the type of the field
|
||||
* @return the {@linkplain MethodHandleDesc}
|
||||
* @throws NullPointerException if any of the arguments are null
|
||||
* @throws IllegalArgumentException if the {@code kind} is not one of the
|
||||
* valid values or if the field name is not valid
|
||||
* @jvms 4.2.2 Unqualified Names
|
||||
*/
|
||||
static DirectMethodHandleDesc ofField(DirectMethodHandleDesc.Kind kind,
|
||||
ClassDesc owner,
|
||||
String fieldName,
|
||||
ClassDesc fieldType) {
|
||||
MethodTypeDesc mtr;
|
||||
switch (kind) {
|
||||
case GETTER: mtr = MethodTypeDesc.of(fieldType, owner); break;
|
||||
case SETTER: mtr = MethodTypeDesc.of(CD_void, owner, fieldType); break;
|
||||
case STATIC_GETTER: mtr = MethodTypeDesc.of(fieldType); break;
|
||||
case STATIC_SETTER: mtr = MethodTypeDesc.of(CD_void, fieldType); break;
|
||||
default:
|
||||
throw new IllegalArgumentException(kind.toString());
|
||||
}
|
||||
return new DirectMethodHandleDescImpl(kind, owner, fieldName, mtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@linkplain MethodHandleDesc} corresponding to invocation of a constructor
|
||||
*
|
||||
* @param owner a {@link ClassDesc} describing the class containing the
|
||||
* constructor
|
||||
* @param paramTypes {@link ClassDesc}s describing the parameter types of
|
||||
* the constructor
|
||||
* @return the {@linkplain MethodHandleDesc}
|
||||
* @throws NullPointerException if any of the arguments are null
|
||||
*/
|
||||
static DirectMethodHandleDesc ofConstructor(ClassDesc owner,
|
||||
ClassDesc... paramTypes) {
|
||||
return MethodHandleDesc.ofMethod(CONSTRUCTOR, owner, ConstantDescs.DEFAULT_NAME,
|
||||
MethodTypeDesc.of(CD_void, paramTypes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@linkplain MethodHandleDesc} that describes this method handle
|
||||
* adapted to a different type, as if by {@link MethodHandle#asType(MethodType)}.
|
||||
*
|
||||
* @param type a {@link MethodHandleDesc} describing the new method type
|
||||
* @return a {@linkplain MethodHandleDesc} for the adapted method handle
|
||||
*/
|
||||
default MethodHandleDesc asType(MethodTypeDesc type) {
|
||||
return (invocationType().equals(type)) ? this : new AsTypeMethodHandleDesc(this, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link MethodTypeDesc} describing the invocation type of the
|
||||
* method handle described by this nominal descriptor. The invocation type
|
||||
* describes the full set of stack values that are consumed by the invocation
|
||||
* (including the receiver, if any).
|
||||
*
|
||||
* @return a {@linkplain MethodHandleDesc} describing the method handle type
|
||||
*/
|
||||
MethodTypeDesc invocationType();
|
||||
|
||||
/**
|
||||
* Compares the specified object with this descriptor for equality. Returns
|
||||
* {@code true} if and only if the specified object is also a
|
||||
* {@linkplain MethodHandleDesc}, and both encode the same nominal description
|
||||
* of a method handle.
|
||||
*
|
||||
* @param o the other object
|
||||
* @return whether this descriptor is equal to the other object
|
||||
*/
|
||||
boolean equals(Object o);
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 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.constant;
|
||||
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.TypeDescriptor;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* A <a href="package-summary.html#nominal">nominal descriptor</a> for a
|
||||
* {@linkplain MethodType} constant.
|
||||
*
|
||||
* @apiNote In the future, if the Java language permits, {@linkplain MethodTypeDesc}
|
||||
* may become a {@code sealed} interface, which would prohibit subclassing except
|
||||
* by explicitly permitted types. Non-platform classes should not implement
|
||||
* {@linkplain MethodTypeDesc} directly.
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public interface MethodTypeDesc
|
||||
extends ConstantDesc,
|
||||
TypeDescriptor.OfMethod<ClassDesc, MethodTypeDesc> {
|
||||
/**
|
||||
* Creates a {@linkplain MethodTypeDesc} given a method descriptor string.
|
||||
*
|
||||
* @param descriptor a method descriptor string
|
||||
* @return a {@linkplain MethodTypeDesc} describing the desired method type
|
||||
* @throws NullPointerException if any argument is {@code null}
|
||||
* @throws IllegalArgumentException if the descriptor string is not a valid
|
||||
* method descriptor
|
||||
* @jvms 4.3.3 Method Descriptors
|
||||
*/
|
||||
static MethodTypeDesc ofDescriptor(String descriptor) {
|
||||
return MethodTypeDescImpl.ofDescriptor(descriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@linkplain MethodTypeDesc} given the return type and parameter
|
||||
* types.
|
||||
*
|
||||
* @param returnDesc a {@linkplain ClassDesc} describing the return type
|
||||
* @param paramDescs {@linkplain ClassDesc}s describing the argument types
|
||||
* @return a {@linkplain MethodTypeDesc} describing the desired method type
|
||||
* @throws NullPointerException if any argument is {@code null}
|
||||
*/
|
||||
static MethodTypeDesc of(ClassDesc returnDesc, ClassDesc... paramDescs) {
|
||||
return new MethodTypeDescImpl(returnDesc, paramDescs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the return type of the method type described by this {@linkplain MethodTypeDesc}.
|
||||
*
|
||||
* @return a {@link ClassDesc} describing the return type of the method type
|
||||
*/
|
||||
ClassDesc returnType();
|
||||
|
||||
/**
|
||||
* Returns the number of parameters of the method type described by
|
||||
* this {@linkplain MethodTypeDesc}.
|
||||
* @return the number of parameters
|
||||
*/
|
||||
int parameterCount();
|
||||
|
||||
/**
|
||||
* Returns the parameter type of the {@code index}'th parameter of the method type
|
||||
* described by this {@linkplain MethodTypeDesc}.
|
||||
*
|
||||
* @param index the index of the parameter to retrieve
|
||||
* @return a {@link ClassDesc} describing the desired parameter type
|
||||
* @throws IndexOutOfBoundsException if the index is outside the half-open
|
||||
* range {[0, parameterCount())}
|
||||
*/
|
||||
ClassDesc parameterType(int index);
|
||||
|
||||
/**
|
||||
* Returns the parameter types as an immutable {@link List}.
|
||||
*
|
||||
* @return a {@link List} of {@link ClassDesc} describing the parameter types
|
||||
*/
|
||||
List<ClassDesc> parameterList();
|
||||
|
||||
/**
|
||||
* Returns the parameter types as an array.
|
||||
*
|
||||
* @return an array of {@link ClassDesc} describing the parameter types
|
||||
*/
|
||||
ClassDesc[] parameterArray();
|
||||
|
||||
/**
|
||||
* Returns a {@linkplain MethodTypeDesc} that is identical to
|
||||
* this one, except with the specified return type.
|
||||
*
|
||||
* @param returnType a {@link ClassDesc} describing the new return type
|
||||
* @return a {@linkplain MethodTypeDesc} describing the desired method type
|
||||
* @throws NullPointerException if any argument is {@code null}
|
||||
*/
|
||||
MethodTypeDesc changeReturnType(ClassDesc returnType);
|
||||
|
||||
/**
|
||||
* Returns a {@linkplain MethodTypeDesc} that is identical to this one,
|
||||
* except that a single parameter type has been changed to the specified type.
|
||||
*
|
||||
* @param index the index of the parameter to change
|
||||
* @param paramType a {@link ClassDesc} describing the new parameter type
|
||||
* @return a {@linkplain MethodTypeDesc} describing the desired method type
|
||||
* @throws NullPointerException if any argument is {@code null}
|
||||
* @throws IndexOutOfBoundsException if the index is outside the half-open
|
||||
* range {[0, parameterCount)}
|
||||
*/
|
||||
MethodTypeDesc changeParameterType(int index, ClassDesc paramType);
|
||||
|
||||
/**
|
||||
* Returns a {@linkplain MethodTypeDesc} that is identical to this one,
|
||||
* except that a range of parameter types have been removed.
|
||||
*
|
||||
* @param start the index of the first parameter to remove
|
||||
* @param end the index after the last parameter to remove
|
||||
* @return a {@linkplain MethodTypeDesc} describing the desired method type
|
||||
* @throws IndexOutOfBoundsException if {@code start} is outside the half-open
|
||||
* range {[0, parameterCount)}, or {@code end} is outside the closed range
|
||||
* {@code [0, parameterCount]}
|
||||
*/
|
||||
MethodTypeDesc dropParameterTypes(int start, int end);
|
||||
|
||||
/**
|
||||
* Returns a {@linkplain MethodTypeDesc} that is identical to this one,
|
||||
* except that a range of additional parameter types have been inserted.
|
||||
*
|
||||
* @param pos the index at which to insert the first inserted parameter
|
||||
* @param paramTypes {@link ClassDesc}s describing the new parameter types
|
||||
* to insert
|
||||
* @return a {@linkplain MethodTypeDesc} describing the desired method type
|
||||
* @throws NullPointerException if any argument is {@code null}
|
||||
* @throws IndexOutOfBoundsException if {@code pos} is outside the closed
|
||||
* range {[0, parameterCount]}
|
||||
*/
|
||||
MethodTypeDesc insertParameterTypes(int pos, ClassDesc... paramTypes);
|
||||
|
||||
/**
|
||||
* Returns the method type descriptor string.
|
||||
*
|
||||
* @return the method type descriptor string
|
||||
* @jvms 4.3.3 Method Descriptors
|
||||
*/
|
||||
default String descriptorString() {
|
||||
return String.format("(%s)%s",
|
||||
Stream.of(parameterArray())
|
||||
.map(ClassDesc::descriptorString)
|
||||
.collect(Collectors.joining()),
|
||||
returnType().descriptorString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a human-readable descriptor for this method type, using the
|
||||
* canonical names for parameter and return types.
|
||||
*
|
||||
* @return the human-readable descriptor for this method type
|
||||
*/
|
||||
default String displayDescriptor() {
|
||||
return String.format("(%s)%s",
|
||||
Stream.of(parameterArray())
|
||||
.map(ClassDesc::displayName)
|
||||
.collect(Collectors.joining(",")),
|
||||
returnType().displayName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the specified object with this descriptor for equality. Returns
|
||||
* {@code true} if and only if the specified object is also a
|
||||
* {@linkplain MethodTypeDesc} both have the same arity, their return types
|
||||
* are equal, and each pair of corresponding parameter types are equal.
|
||||
*
|
||||
* @param o the other object
|
||||
* @return whether this descriptor is equal to the other object
|
||||
*/
|
||||
boolean equals(Object o);
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 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.constant;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
/**
|
||||
* A <a href="package-summary.html#nominal">nominal descriptor</a> for a
|
||||
* {@link MethodType}. A {@linkplain MethodTypeDescImpl} corresponds to a
|
||||
* {@code Constant_MethodType_info} entry in the constant pool of a classfile.
|
||||
*/
|
||||
final class MethodTypeDescImpl implements MethodTypeDesc {
|
||||
private final ClassDesc returnType;
|
||||
private final ClassDesc[] argTypes;
|
||||
|
||||
/**
|
||||
* Constructs a {@linkplain MethodTypeDesc} with the specified return type
|
||||
* and parameter types
|
||||
*
|
||||
* @param returnType a {@link ClassDesc} describing the return type
|
||||
* @param argTypes {@link ClassDesc}s describing the parameter types
|
||||
*/
|
||||
MethodTypeDescImpl(ClassDesc returnType, ClassDesc[] argTypes) {
|
||||
this.returnType = requireNonNull(returnType);
|
||||
this.argTypes = requireNonNull(argTypes);
|
||||
|
||||
for (ClassDesc cr : argTypes)
|
||||
if (cr.isPrimitive() && cr.descriptorString().equals("V"))
|
||||
throw new IllegalArgumentException("Void parameters not permitted");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@linkplain MethodTypeDescImpl} given a method descriptor string.
|
||||
*
|
||||
* @param descriptor the method descriptor string
|
||||
* @return a {@linkplain MethodTypeDescImpl} describing the desired method type
|
||||
* @throws IllegalArgumentException if the descriptor string is not a valid
|
||||
* method descriptor
|
||||
* @jvms 4.3.3 Method Descriptors
|
||||
*/
|
||||
static MethodTypeDescImpl ofDescriptor(String descriptor) {
|
||||
requireNonNull(descriptor);
|
||||
List<String> types = ConstantUtils.parseMethodDescriptor(descriptor);
|
||||
ClassDesc[] paramTypes = types.stream().skip(1).map(ClassDesc::ofDescriptor).toArray(ClassDesc[]::new);
|
||||
return new MethodTypeDescImpl(ClassDesc.ofDescriptor(types.get(0)), paramTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassDesc returnType() {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int parameterCount() {
|
||||
return argTypes.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassDesc parameterType(int index) {
|
||||
return argTypes[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ClassDesc> parameterList() {
|
||||
return List.of(argTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassDesc[] parameterArray() {
|
||||
return argTypes.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodTypeDesc changeReturnType(ClassDesc returnType) {
|
||||
return MethodTypeDesc.of(returnType, argTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodTypeDesc changeParameterType(int index, ClassDesc paramType) {
|
||||
ClassDesc[] newArgs = argTypes.clone();
|
||||
newArgs[index] = paramType;
|
||||
return MethodTypeDesc.of(returnType, newArgs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodTypeDesc dropParameterTypes(int start, int end) {
|
||||
if (start < 0 || start >= argTypes.length || end < 0 || end > argTypes.length)
|
||||
throw new IndexOutOfBoundsException();
|
||||
else if (start > end)
|
||||
throw new IllegalArgumentException(String.format("Range (%d, %d) not valid for size %d", start, end, argTypes.length));
|
||||
ClassDesc[] newArgs = new ClassDesc[argTypes.length - (end - start)];
|
||||
System.arraycopy(argTypes, 0, newArgs, 0, start);
|
||||
System.arraycopy(argTypes, end, newArgs, start, argTypes.length - end);
|
||||
return MethodTypeDesc.of(returnType, newArgs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodTypeDesc insertParameterTypes(int pos, ClassDesc... paramTypes) {
|
||||
if (pos < 0 || pos > argTypes.length)
|
||||
throw new IndexOutOfBoundsException(pos);
|
||||
ClassDesc[] newArgs = new ClassDesc[argTypes.length + paramTypes.length];
|
||||
System.arraycopy(argTypes, 0, newArgs, 0, pos);
|
||||
System.arraycopy(paramTypes, 0, newArgs, pos, paramTypes.length);
|
||||
System.arraycopy(argTypes, pos, newArgs, pos+paramTypes.length, argTypes.length - pos);
|
||||
return MethodTypeDesc.of(returnType, newArgs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodType resolveConstantDesc(MethodHandles.Lookup lookup) {
|
||||
return MethodType.fromMethodDescriptorString(descriptorString(), lookup.lookupClass().getClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this {@linkplain MethodTypeDescImpl} is
|
||||
* equal to another {@linkplain MethodTypeDescImpl}. Equality is
|
||||
* determined by the two descriptors having equal return types and argument
|
||||
* types.
|
||||
*
|
||||
* @param o the {@code MethodTypeDescImpl} to compare to this
|
||||
* {@code MethodTypeDescImpl}
|
||||
* @return {@code true} if the specified {@code MethodTypeDescImpl} is
|
||||
* equals to this {@code MethodTypeDescImpl}.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
MethodTypeDescImpl constant = (MethodTypeDescImpl) o;
|
||||
|
||||
return returnType.equals(constant.returnType)
|
||||
&& Arrays.equals(argTypes, constant.argTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = returnType.hashCode();
|
||||
result = 31 * result + Arrays.hashCode(argTypes);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("MethodTypeDesc[%s]", displayDescriptor());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 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.constant;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
|
||||
import sun.invoke.util.Wrapper;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
/**
|
||||
* A <a href="package-summary.html#nominal">nominal descriptor</a> for the class
|
||||
* constant corresponding to a primitive type (e.g., {@code int.class}).
|
||||
*/
|
||||
final class PrimitiveClassDescImpl
|
||||
extends DynamicConstantDesc<Class<?>> implements ClassDesc {
|
||||
|
||||
private final String descriptor;
|
||||
|
||||
/**
|
||||
* Creates a {@linkplain ClassDesc} given a descriptor string for a primitive
|
||||
* type.
|
||||
*
|
||||
* @param descriptor the descriptor string, which must be a one-character
|
||||
* string corresponding to one of the nine base types
|
||||
* @throws IllegalArgumentException if the descriptor string does not
|
||||
* describe a valid primitive type
|
||||
* @jvms 4.3 Descriptors
|
||||
*/
|
||||
PrimitiveClassDescImpl(String descriptor) {
|
||||
super(ConstantDescs.BSM_PRIMITIVE_CLASS, requireNonNull(descriptor), ConstantDescs.CD_Class);
|
||||
if (descriptor.length() != 1
|
||||
|| "VIJCSBFDZ".indexOf(descriptor.charAt(0)) < 0)
|
||||
throw new IllegalArgumentException(String.format("not a valid primitive type descriptor: %s", descriptor));
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String descriptorString() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> resolveConstantDesc(MethodHandles.Lookup lookup) {
|
||||
return Wrapper.forBasicType(descriptorString().charAt(0)).primitiveType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("PrimitiveClassDesc[%s]", displayName());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 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.constant;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
|
||||
import static java.lang.constant.ConstantUtils.dropFirstAndLastChar;
|
||||
import static java.lang.constant.ConstantUtils.internalToBinary;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
/**
|
||||
* A <a href="package-summary.html#nominal">nominal descriptor</a> for a class,
|
||||
* interface, or array type. A {@linkplain ReferenceClassDescImpl} corresponds to a
|
||||
* {@code Constant_Class_info} entry in the constant pool of a classfile.
|
||||
*/
|
||||
final class ReferenceClassDescImpl implements ClassDesc {
|
||||
private final String descriptor;
|
||||
|
||||
/**
|
||||
* Creates a {@linkplain ClassDesc} from a descriptor string for a class or
|
||||
* interface type
|
||||
*
|
||||
* @param descriptor a field descriptor string for a class or interface type
|
||||
* @throws IllegalArgumentException if the descriptor string is not a valid
|
||||
* field descriptor string, or does not describe a class or interface type
|
||||
* @jvms 4.3.2 Field Descriptors
|
||||
*/
|
||||
ReferenceClassDescImpl(String descriptor) {
|
||||
requireNonNull(descriptor);
|
||||
int len = ConstantUtils.matchSig(descriptor, 0, descriptor.length());
|
||||
if (len == 0 || len == 1
|
||||
|| len != descriptor.length())
|
||||
throw new IllegalArgumentException(String.format("not a valid reference type descriptor: %s", descriptor));
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String descriptorString() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> resolveConstantDesc(MethodHandles.Lookup lookup)
|
||||
throws ReflectiveOperationException {
|
||||
ClassDesc c = this;
|
||||
int depth = ConstantUtils.arrayDepth(descriptorString());
|
||||
for (int i=0; i<depth; i++)
|
||||
c = c.componentType();
|
||||
|
||||
if (c.isPrimitive())
|
||||
return lookup.findClass(descriptorString());
|
||||
else {
|
||||
Class<?> clazz = lookup.findClass(internalToBinary(dropFirstAndLastChar(c.descriptorString())));
|
||||
for (int i = 0; i < depth; i++)
|
||||
clazz = clazz.arrayType();
|
||||
return clazz;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this {@linkplain ReferenceClassDescImpl} is
|
||||
* equal to another {@linkplain ReferenceClassDescImpl}. Equality is
|
||||
* determined by the two class descriptors having equal class descriptor
|
||||
* strings.
|
||||
*
|
||||
* @param o the {@code ClassDesc} to compare to this
|
||||
* {@code ClassDesc}
|
||||
* @return {@code true} if the specified {@code ClassDesc} is
|
||||
* equals to this {@code ClassDesc}.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
ClassDesc constant = (ClassDesc) o;
|
||||
return descriptor.equals(constant.descriptorString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return descriptor.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("ClassDesc[%s]", displayName());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Classes and interfaces to represent <em>nominal descriptors</em> for run-time
|
||||
* entities such as classes or method handles, and classfile entities such as
|
||||
* constant pool entries or {@code invokedynamic} call sites. These classes
|
||||
* are suitable for use in bytecode reading and writing APIs, {@code invokedynamic}
|
||||
* bootstraps, bytecode intrinsic APIs, and compile-time or link-time program
|
||||
* analysis tools.
|
||||
*
|
||||
* <p>Every API that reads and writes bytecode instructions needs to model the
|
||||
* operands to these instructions and other classfile structures (such as entries
|
||||
* in the bootstrap methods table or stack maps, which frequently reference
|
||||
* entries in the classfile constant pool.) Such entries can denote values of
|
||||
* fundamental types, such as strings or integers; parts of a program, such as
|
||||
* classes or method handles; or values of arbitrary user-defined types. The
|
||||
* {@link java.lang.constant.ConstantDesc} hierarchy provides a representation of
|
||||
* constant pool entries in nominal form that is convenient for APIs to model
|
||||
* operands of bytecode instructions.
|
||||
*
|
||||
* <h2><a id="nominal"></a>Nominal Descriptors</h2>
|
||||
*
|
||||
* <p>A {@link java.lang.constant.ConstantDesc} is a description of a constant
|
||||
* value. Such a description is the <em>nominal form</em> of the constant value;
|
||||
* it is not the value itself, but rather a "recipe" for describing the value,
|
||||
* storing the value in a constant pool entry, or reconstituting the value given
|
||||
* a class loading context. Every {@link java.lang.constant.ConstantDesc}
|
||||
* knows how to <em>resolve</em> itself -- compute the value that it describes --
|
||||
* via {@link java.lang.constant.ConstantDesc#resolveConstantDesc(java.lang.invoke.MethodHandles.Lookup)}.
|
||||
* This allows an API which accepts {@link java.lang.constant.ConstantDesc}
|
||||
* objects to evaluate them reflectively, provided that the classes and methods
|
||||
* referenced in their nominal description are present and accessible.
|
||||
*
|
||||
* <p>The subtypes of {@link java.lang.constant.ConstantDesc} describe various kinds
|
||||
* of constant values. For each type of loadable constant pool entry defined in JVMS 4.4,
|
||||
* there is a corresponding subtype of {@link java.lang.constant.ConstantDesc}:
|
||||
* {@link java.lang.constant.ClassDesc}, {@link java.lang.constant.MethodTypeDesc},
|
||||
* {@link java.lang.constant.DirectMethodHandleDesc}, {@link java.lang.String},
|
||||
* {@link java.lang.Integer}, {@link java.lang.Long}, {@link java.lang.Float},
|
||||
* {@link java.lang.Double}, and {@link java.lang.constant.DynamicConstantDesc}. These classes
|
||||
* provide type-specific accessor methods to extract the nominal information for
|
||||
* that kind of constant. When a bytecode-writing API encounters a {@link java.lang.constant.ConstantDesc},
|
||||
* it should examine it to see which of these types it is, cast it, extract
|
||||
* its nominal information, and generate the corresponding entry to the constant pool.
|
||||
* When a bytecode-reading API encounters a constant pool entry, it can
|
||||
* convert it to the appropriate type of nominal descriptor. For dynamic
|
||||
* constants, bytecode-reading APIs may wish to use the factory
|
||||
* {@link java.lang.constant.DynamicConstantDesc#ofCanonical(DirectMethodHandleDesc, java.lang.String, ClassDesc, ConstantDesc[])},
|
||||
* which will inspect the bootstrap and, for well-known bootstraps, return
|
||||
* a more specific subtype of {@link java.lang.constant.DynamicConstantDesc}, such as
|
||||
* {@link java.lang.Enum.EnumDesc}.
|
||||
*
|
||||
* <p>Another way to obtain the nominal description of a value is to ask the value
|
||||
* itself. A {@link java.lang.constant.Constable} is a type whose values
|
||||
* can describe themselves in nominal form as a {@link java.lang.constant.ConstantDesc}.
|
||||
* Fundamental types such as {@link java.lang.String} and {@link java.lang.Class}
|
||||
* implement {@link java.lang.constant.Constable}, as can user-defined
|
||||
* classes. Entities that generate classfiles (such as compilers) can introspect
|
||||
* over constable objects to obtain a more efficient way to represent their values
|
||||
* in classfiles.
|
||||
*
|
||||
* <p>This package also includes {@link java.lang.constant.DynamicCallSiteDesc},
|
||||
* which represents a (non-loadable) {@code Constant_InvokeDynamic_info} constant
|
||||
* pool entry. It describes the bootstrap method, invocation name and type,
|
||||
* and bootstrap arguments associated with an {@code invokedynamic} instruction.
|
||||
* It is also suitable for describing {@code invokedynamic} call sites in bytecode
|
||||
* reading and writing APIs.
|
||||
*
|
||||
* @jvms 4.4 The Constant Pool
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
package java.lang.constant;
|
|
@ -28,10 +28,19 @@ package java.lang.invoke;
|
|||
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.Constable;
|
||||
import java.lang.constant.ConstantDesc;
|
||||
import java.lang.constant.DirectMethodHandleDesc;
|
||||
import java.lang.constant.MethodHandleDesc;
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import static java.lang.invoke.MethodHandleInfo.*;
|
||||
import static java.lang.invoke.MethodHandleStatics.*;
|
||||
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
|
||||
/**
|
||||
* A method handle is a typed, directly executable reference to an underlying method,
|
||||
|
@ -428,7 +437,7 @@ mh.invokeExact(System.out, "Hello, world.");
|
|||
* @author John Rose, JSR 292 EG
|
||||
* @since 1.7
|
||||
*/
|
||||
public abstract class MethodHandle {
|
||||
public abstract class MethodHandle implements Constable {
|
||||
|
||||
/**
|
||||
* Internal marker interface which distinguishes (to the Java compiler)
|
||||
|
@ -1511,6 +1520,60 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
|
|||
return bindArgumentL(0, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a nominal descriptor for this instance, if one can be
|
||||
* constructed, or an empty {@link Optional} if one cannot be.
|
||||
*
|
||||
* @return An {@link Optional} containing the resulting nominal descriptor,
|
||||
* or an empty {@link Optional} if one cannot be constructed.
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public Optional<MethodHandleDesc> describeConstable() {
|
||||
MethodHandleInfo info;
|
||||
ClassDesc owner;
|
||||
String name;
|
||||
MethodTypeDesc type;
|
||||
boolean isInterface;
|
||||
try {
|
||||
info = IMPL_LOOKUP.revealDirect(this);
|
||||
isInterface = info.getDeclaringClass().isInterface();
|
||||
owner = info.getDeclaringClass().describeConstable().orElseThrow();
|
||||
type = info.getMethodType().describeConstable().orElseThrow();
|
||||
name = info.getName();
|
||||
}
|
||||
catch (Exception e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
switch (info.getReferenceKind()) {
|
||||
case REF_getField:
|
||||
return Optional.of(MethodHandleDesc.ofField(DirectMethodHandleDesc.Kind.GETTER, owner, name, type.returnType()));
|
||||
case REF_putField:
|
||||
return Optional.of(MethodHandleDesc.ofField(DirectMethodHandleDesc.Kind.SETTER, owner, name, type.parameterType(0)));
|
||||
case REF_getStatic:
|
||||
return Optional.of(MethodHandleDesc.ofField(DirectMethodHandleDesc.Kind.STATIC_GETTER, owner, name, type.returnType()));
|
||||
case REF_putStatic:
|
||||
return Optional.of(MethodHandleDesc.ofField(DirectMethodHandleDesc.Kind.STATIC_SETTER, owner, name, type.parameterType(0)));
|
||||
case REF_invokeVirtual:
|
||||
return Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.VIRTUAL, owner, name, type));
|
||||
case REF_invokeStatic:
|
||||
return isInterface ?
|
||||
Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, owner, name, type)) :
|
||||
Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.STATIC, owner, name, type));
|
||||
case REF_invokeSpecial:
|
||||
return isInterface ?
|
||||
Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_SPECIAL, owner, name, type)) :
|
||||
Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.SPECIAL, owner, name, type));
|
||||
case REF_invokeInterface:
|
||||
return Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_VIRTUAL, owner, name, type));
|
||||
case REF_newInvokeSpecial:
|
||||
return Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.CONSTRUCTOR, owner, name, type));
|
||||
default:
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the method handle,
|
||||
* starting with the string {@code "MethodHandle"} and
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -25,21 +25,30 @@
|
|||
|
||||
package java.lang.invoke;
|
||||
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
import sun.invoke.util.Wrapper;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.Constable;
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
import sun.invoke.util.BytecodeDescriptor;
|
||||
import static java.lang.invoke.MethodHandleStatics.*;
|
||||
import sun.invoke.util.VerifyType;
|
||||
import sun.invoke.util.Wrapper;
|
||||
|
||||
import static java.lang.invoke.MethodHandleStatics.UNSAFE;
|
||||
import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* A method type represents the arguments and return type accepted and
|
||||
|
@ -91,7 +100,10 @@ import sun.invoke.util.VerifyType;
|
|||
* @since 1.7
|
||||
*/
|
||||
public final
|
||||
class MethodType implements java.io.Serializable {
|
||||
class MethodType
|
||||
implements Constable,
|
||||
TypeDescriptor.OfMethod<Class<?>, MethodType>,
|
||||
java.io.Serializable {
|
||||
private static final long serialVersionUID = 292L; // {rtype, {ptype...}}
|
||||
|
||||
// The rtype and ptypes fields define the structural identity of the method type:
|
||||
|
@ -1175,10 +1187,43 @@ class MethodType implements java.io.Serializable {
|
|||
return desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a field type descriptor string for this type
|
||||
*
|
||||
* @return the descriptor string
|
||||
* @jvms 4.3.2 Field Descriptors
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public String descriptorString() {
|
||||
return toMethodDescriptorString();
|
||||
}
|
||||
|
||||
/*non-public*/ static String toFieldDescriptorString(Class<?> cls) {
|
||||
return BytecodeDescriptor.unparse(cls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a nominal descriptor for this instance, if one can be
|
||||
* constructed, or an empty {@link Optional} if one cannot be.
|
||||
*
|
||||
* @return An {@link Optional} containing the resulting nominal descriptor,
|
||||
* or an empty {@link Optional} if one cannot be constructed.
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public Optional<MethodTypeDesc> describeConstable() {
|
||||
try {
|
||||
return Optional.of(MethodTypeDesc.of(returnType().describeConstable().orElseThrow(),
|
||||
Stream.of(parameterArray())
|
||||
.map(p -> p.describeConstable().orElseThrow())
|
||||
.toArray(ClassDesc[]::new)));
|
||||
}
|
||||
catch (NoSuchElementException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialization.
|
||||
|
||||
/**
|
||||
|
|
187
src/java.base/share/classes/java/lang/invoke/TypeDescriptor.java
Normal file
187
src/java.base/share/classes/java/lang/invoke/TypeDescriptor.java
Normal file
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 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.List;
|
||||
|
||||
/**
|
||||
* An entity that has a field or method type descriptor
|
||||
*
|
||||
* @jvms 4.3.2 Field Descriptors
|
||||
* @jvms 4.3.3 Method Descriptors
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public interface TypeDescriptor {
|
||||
/**
|
||||
* Return the type descriptor string for this instance, which must be either
|
||||
* a field type descriptor (JVMS 4.3.2) or method type descriptor (JVMS 4.3.3).
|
||||
*
|
||||
* @return the type descriptor
|
||||
* @jvms 4.3.2 Field Descriptors
|
||||
* @jvms 4.3.3 Method Descriptors
|
||||
*/
|
||||
String descriptorString();
|
||||
|
||||
|
||||
/**
|
||||
* An entity that has a field type descriptor
|
||||
*
|
||||
* @param <F> the class implementing {@linkplain TypeDescriptor.OfField}
|
||||
* @jvms 4.3.2 Field Descriptors
|
||||
* @since 12
|
||||
*/
|
||||
interface OfField<F extends TypeDescriptor.OfField<F>> extends TypeDescriptor {
|
||||
/**
|
||||
* Does this field descriptor describe an array type?
|
||||
* @return whether this field descriptor describes an array type
|
||||
*/
|
||||
boolean isArray();
|
||||
|
||||
/**
|
||||
* Does this field descriptor describe a primitive type?
|
||||
* @return whether this field descriptor describes a primitive type
|
||||
*/
|
||||
boolean isPrimitive();
|
||||
|
||||
/**
|
||||
* If this field descriptor describes an array type, return
|
||||
* a descriptor for its component type, otherwise return {@code null}.
|
||||
* @return the component type, or {@code null} if this field descriptor does
|
||||
* not describe an array type
|
||||
*/
|
||||
F componentType();
|
||||
|
||||
/**
|
||||
* Return a descriptor for the array type whose component type is described by this
|
||||
* descriptor
|
||||
* @return the descriptor for the array type
|
||||
*/
|
||||
F arrayType();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An entity that has a method type descriptor
|
||||
*
|
||||
* @param <F> the type representing field type descriptors
|
||||
* @param <M> the class implementing {@linkplain TypeDescriptor.OfMethod}
|
||||
* @jvms 4.3.2 Field Descriptors
|
||||
* @jvms 4.3.3 Method Descriptors
|
||||
* @since 12
|
||||
*/
|
||||
interface OfMethod<F extends TypeDescriptor.OfField<F>, M extends TypeDescriptor.OfMethod<F, M>>
|
||||
extends TypeDescriptor {
|
||||
|
||||
/**
|
||||
* Return the number of parameters in the method type
|
||||
* @return the number of parameters
|
||||
*/
|
||||
int parameterCount();
|
||||
|
||||
/**
|
||||
* Return a field descriptor describing the requested parameter of the method type
|
||||
* described by this descriptor
|
||||
* @param i the index of the parameter
|
||||
* @return a field descriptor for the requested parameter type
|
||||
* @throws IndexOutOfBoundsException if the index is outside the half-open
|
||||
* range {[0, parameterCount)}
|
||||
*/
|
||||
F parameterType(int i);
|
||||
|
||||
/**
|
||||
* Return a field descriptor describing the return type of the method type described
|
||||
* by this descriptor
|
||||
* @return a field descriptor for the return type
|
||||
*/
|
||||
F returnType();
|
||||
|
||||
/**
|
||||
* Return an array of field descriptors for the parameter types of the method type
|
||||
* described by this descriptor
|
||||
* @return field descriptors for the parameter types
|
||||
*/
|
||||
F[] parameterArray();
|
||||
|
||||
/**
|
||||
* Return an immutable list of field descriptors for the parameter types of the method type
|
||||
* described by this descriptor
|
||||
* @return field descriptors for the parameter types
|
||||
*/
|
||||
List<F> parameterList();
|
||||
|
||||
/**
|
||||
* Return a method descriptor that is identical to this one, except that the return
|
||||
* type has been changed to the specified type
|
||||
*
|
||||
* @param newReturn a field descriptor for the new return type
|
||||
* @throws NullPointerException if any argument is {@code null}
|
||||
* @return the new method descriptor
|
||||
*/
|
||||
M changeReturnType(F newReturn);
|
||||
|
||||
/**
|
||||
* Return a method descriptor that is identical to this one,
|
||||
* except that a single parameter type has been changed to the specified type.
|
||||
*
|
||||
* @param index the index of the parameter to change
|
||||
* @param paramType a field descriptor describing the new parameter type
|
||||
* @return the new method descriptor
|
||||
* @throws NullPointerException if any argument is {@code null}
|
||||
* @throws IndexOutOfBoundsException if the index is outside the half-open
|
||||
* range {[0, parameterCount)}
|
||||
*/
|
||||
M changeParameterType(int index, F paramType);
|
||||
|
||||
/**
|
||||
* Return a method descriptor that is identical to this one,
|
||||
* except that a range of parameter types have been removed.
|
||||
*
|
||||
* @param start the index of the first parameter to remove
|
||||
* @param end the index after the last parameter to remove
|
||||
* @return the new method descriptor
|
||||
*
|
||||
* @throws IndexOutOfBoundsException if {@code start} is outside the half-open
|
||||
* range {@code [0, parameterCount)}, or {@code end} is outside the closed range
|
||||
* {@code [0, parameterCount]}, or if {@code start > end}
|
||||
*/
|
||||
M dropParameterTypes(int start, int end);
|
||||
|
||||
/**
|
||||
* Return a method descriptor that is identical to this one,
|
||||
* except that a range of additional parameter types have been inserted.
|
||||
*
|
||||
* @param pos the index at which to insert the first inserted parameter
|
||||
* @param paramTypes field descriptors describing the new parameter types
|
||||
* to insert
|
||||
* @return the new method descriptor
|
||||
* @throws NullPointerException if any argument is {@code null}
|
||||
* @throws IndexOutOfBoundsException if {@code pos} is outside the closed
|
||||
* range {[0, parameterCount]}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
M insertParameterTypes(int pos, F... paramTypes);
|
||||
}
|
||||
}
|
|
@ -25,19 +25,26 @@
|
|||
|
||||
package java.lang.invoke;
|
||||
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.Constable;
|
||||
import java.lang.constant.ConstantDesc;
|
||||
import java.lang.constant.ConstantDescs;
|
||||
import java.lang.constant.DirectMethodHandleDesc;
|
||||
import java.lang.constant.DynamicConstantDesc;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
import jdk.internal.util.Preconditions;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static java.lang.invoke.MethodHandleStatics.UNSAFE;
|
||||
import static java.lang.invoke.MethodHandleStatics.newInternalError;
|
||||
|
||||
/**
|
||||
* A VarHandle is a dynamically strongly typed reference to a variable, or to a
|
||||
|
@ -437,7 +444,7 @@ import static java.lang.invoke.MethodHandleStatics.newInternalError;
|
|||
* @see MethodType
|
||||
* @since 9
|
||||
*/
|
||||
public abstract class VarHandle {
|
||||
public abstract class VarHandle implements Constable {
|
||||
final VarForm vform;
|
||||
|
||||
VarHandle(VarForm vform) {
|
||||
|
@ -1857,6 +1864,32 @@ public abstract class VarHandle {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
VarHandle that = (VarHandle) o;
|
||||
return accessModeType(AccessMode.GET).equals(that.accessModeType(AccessMode.GET)) &&
|
||||
internalEquals(that);
|
||||
}
|
||||
|
||||
abstract boolean internalEquals(VarHandle vh);
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return 31 * accessModeType(AccessMode.GET).hashCode() + internalHashCode();
|
||||
}
|
||||
|
||||
abstract int internalHashCode();
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
return String.format("VarHandle[varType=%s, coord=%s]",
|
||||
varType().getName(),
|
||||
coordinateTypes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the variable type of variables referenced by this VarHandle.
|
||||
*
|
||||
|
@ -1951,6 +1984,20 @@ public abstract class VarHandle {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a nominal descriptor for this instance, if one can be
|
||||
* constructed, or an empty {@link Optional} if one cannot be.
|
||||
*
|
||||
* @return An {@link Optional} containing the resulting nominal descriptor,
|
||||
* or an empty {@link Optional} if one cannot be constructed.
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public Optional<VarHandleDesc> describeConstable() {
|
||||
// partial function for field and array only
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Stable
|
||||
TypesAndInvokers typesAndInvokers;
|
||||
|
||||
|
@ -2082,4 +2129,163 @@ public abstract class VarHandle {
|
|||
public static void storeStoreFence() {
|
||||
UNSAFE.storeStoreFence();
|
||||
}
|
||||
|
||||
/**
|
||||
* A <a href="package-summary.html#nominal">nominal descriptor</a> for a
|
||||
* {@link VarHandle} constant.
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public static final class VarHandleDesc extends DynamicConstantDesc<VarHandle> {
|
||||
|
||||
/**
|
||||
* Kinds of variable handle descs
|
||||
*/
|
||||
private enum Kind {
|
||||
FIELD(ConstantDescs.BSM_VARHANDLE_FIELD),
|
||||
STATIC_FIELD(ConstantDescs.BSM_VARHANDLE_STATIC_FIELD),
|
||||
ARRAY(ConstantDescs.BSM_VARHANDLE_ARRAY);
|
||||
|
||||
final DirectMethodHandleDesc bootstrapMethod;
|
||||
|
||||
Kind(DirectMethodHandleDesc bootstrapMethod) {
|
||||
this.bootstrapMethod = bootstrapMethod;
|
||||
}
|
||||
|
||||
ConstantDesc[] toBSMArgs(ClassDesc declaringClass, ClassDesc varType) {
|
||||
switch (this) {
|
||||
case FIELD:
|
||||
case STATIC_FIELD:
|
||||
return new ConstantDesc[] {declaringClass, varType };
|
||||
case ARRAY:
|
||||
return new ConstantDesc[] {declaringClass };
|
||||
default:
|
||||
throw new InternalError("Cannot reach here");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final Kind kind;
|
||||
private final ClassDesc declaringClass;
|
||||
private final ClassDesc varType;
|
||||
|
||||
/**
|
||||
* Construct a {@linkplain VarHandleDesc} given a kind, name, and declaring
|
||||
* class.
|
||||
*
|
||||
* @param kind the kind of of the var handle
|
||||
* @param name the unqualified name of the field, for field var handles; otherwise ignored
|
||||
* @param declaringClass a {@link ClassDesc} describing the declaring class,
|
||||
* for field var handles
|
||||
* @param varType a {@link ClassDesc} describing the type of the variable
|
||||
* @throws NullPointerException if any required argument is null
|
||||
* @jvms 4.2.2 Unqualified Names
|
||||
*/
|
||||
private VarHandleDesc(Kind kind, String name, ClassDesc declaringClass, ClassDesc varType) {
|
||||
super(kind.bootstrapMethod, name,
|
||||
ConstantDescs.CD_VarHandle,
|
||||
kind.toBSMArgs(declaringClass, varType));
|
||||
this.kind = kind;
|
||||
this.declaringClass = declaringClass;
|
||||
this.varType = varType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@linkplain VarHandleDesc} corresponding to a {@link VarHandle}
|
||||
* for an instance field.
|
||||
*
|
||||
* @param name the unqualifed name of the field
|
||||
* @param declaringClass a {@link ClassDesc} describing the declaring class,
|
||||
* for field var handles
|
||||
* @param fieldType a {@link ClassDesc} describing the type of the field
|
||||
* @return the {@linkplain VarHandleDesc}
|
||||
* @throws NullPointerException if any of the arguments are null
|
||||
* @jvms 4.2.2 Unqualified Names
|
||||
*/
|
||||
public static VarHandleDesc ofField(ClassDesc declaringClass, String name, ClassDesc fieldType) {
|
||||
Objects.requireNonNull(declaringClass);
|
||||
Objects.requireNonNull(name);
|
||||
Objects.requireNonNull(fieldType);
|
||||
return new VarHandleDesc(Kind.FIELD, name, declaringClass, fieldType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@linkplain VarHandleDesc} corresponding to a {@link VarHandle}
|
||||
* for a static field.
|
||||
*
|
||||
* @param name the unqualified name of the field
|
||||
* @param declaringClass a {@link ClassDesc} describing the declaring class,
|
||||
* for field var handles
|
||||
* @param fieldType a {@link ClassDesc} describing the type of the field
|
||||
* @return the {@linkplain VarHandleDesc}
|
||||
* @throws NullPointerException if any of the arguments are null
|
||||
* @jvms 4.2.2 Unqualified Names
|
||||
*/
|
||||
public static VarHandleDesc ofStaticField(ClassDesc declaringClass, String name, ClassDesc fieldType) {
|
||||
Objects.requireNonNull(declaringClass);
|
||||
Objects.requireNonNull(name);
|
||||
Objects.requireNonNull(fieldType);
|
||||
return new VarHandleDesc(Kind.STATIC_FIELD, name, declaringClass, fieldType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@linkplain VarHandleDesc} corresponding to a {@link VarHandle}
|
||||
* for for an array type.
|
||||
*
|
||||
* @param arrayClass a {@link ClassDesc} describing the type of the array
|
||||
* @return the {@linkplain VarHandleDesc}
|
||||
* @throws NullPointerException if any of the arguments are null
|
||||
*/
|
||||
public static VarHandleDesc ofArray(ClassDesc arrayClass) {
|
||||
Objects.requireNonNull(arrayClass);
|
||||
if (!arrayClass.isArray())
|
||||
throw new IllegalArgumentException("Array class argument not an array: " + arrayClass);
|
||||
return new VarHandleDesc(Kind.ARRAY, ConstantDescs.DEFAULT_NAME, arrayClass, arrayClass.componentType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link ClassDesc} describing the type of the variable described
|
||||
* by this descriptor.
|
||||
*
|
||||
* @return the variable type
|
||||
*/
|
||||
public ClassDesc varType() {
|
||||
return varType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VarHandle resolveConstantDesc(MethodHandles.Lookup lookup)
|
||||
throws ReflectiveOperationException {
|
||||
switch (kind) {
|
||||
case FIELD:
|
||||
return lookup.findVarHandle((Class<?>) declaringClass.resolveConstantDesc(lookup),
|
||||
constantName(),
|
||||
(Class<?>) varType.resolveConstantDesc(lookup));
|
||||
case STATIC_FIELD:
|
||||
return lookup.findStaticVarHandle((Class<?>) declaringClass.resolveConstantDesc(lookup),
|
||||
constantName(),
|
||||
(Class<?>) varType.resolveConstantDesc(lookup));
|
||||
case ARRAY:
|
||||
return MethodHandles.arrayElementVarHandle((Class<?>) declaringClass.resolveConstantDesc(lookup));
|
||||
default:
|
||||
throw new InternalError("Cannot reach here");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
switch (kind) {
|
||||
case FIELD:
|
||||
case STATIC_FIELD:
|
||||
return String.format("VarHandleDesc[%s%s.%s:%s]",
|
||||
(kind == Kind.STATIC_FIELD) ? "static " : "",
|
||||
declaringClass.displayName(), constantName(), varType.displayName());
|
||||
case ARRAY:
|
||||
return String.format("VarHandleDesc[%s[]]", declaringClass.displayName());
|
||||
default:
|
||||
throw new InternalError("Cannot reach here");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -25,6 +25,9 @@
|
|||
|
||||
package java.lang.invoke;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import static java.lang.invoke.MethodHandleStatics.UNSAFE;
|
||||
|
||||
final class VarHandles {
|
||||
|
@ -144,6 +147,38 @@ final class VarHandles {
|
|||
}
|
||||
}
|
||||
|
||||
// Required by instance field handles
|
||||
static Field getFieldFromReceiverAndOffset(Class<?> receiverType,
|
||||
long offset,
|
||||
Class<?> fieldType) {
|
||||
for (Field f : receiverType.getDeclaredFields()) {
|
||||
if (Modifier.isStatic(f.getModifiers())) continue;
|
||||
|
||||
if (offset == UNSAFE.objectFieldOffset(f)) {
|
||||
assert f.getType() == fieldType;
|
||||
return f;
|
||||
}
|
||||
}
|
||||
throw new InternalError("Field not found at offset");
|
||||
}
|
||||
|
||||
// Required by instance static field handles
|
||||
static Field getStaticFieldFromBaseAndOffset(Object base,
|
||||
long offset,
|
||||
Class<?> fieldType) {
|
||||
// @@@ This is a little fragile assuming the base is the class
|
||||
Class<?> receiverType = (Class<?>) base;
|
||||
for (Field f : receiverType.getDeclaredFields()) {
|
||||
if (!Modifier.isStatic(f.getModifiers())) continue;
|
||||
|
||||
if (offset == UNSAFE.staticFieldOffset(f)) {
|
||||
assert f.getType() == fieldType;
|
||||
return f;
|
||||
}
|
||||
}
|
||||
throw new InternalError("Static field not found at offset");
|
||||
}
|
||||
|
||||
static VarHandle makeArrayElementHandle(Class<?> arrayClass) {
|
||||
if (!arrayClass.isArray())
|
||||
throw new IllegalArgumentException("not an array: " + arrayClass);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -27,7 +27,9 @@ package java.lang.invoke;
|
|||
import jdk.internal.util.Preconditions;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
|
||||
import java.lang.invoke.VarHandle.VarHandleDesc;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import static java.lang.invoke.MethodHandleStatics.UNSAFE;
|
||||
|
||||
|
@ -61,6 +63,30 @@ final class VarHandle$Type$s {
|
|||
return accessMode.at.accessModeType(receiverType, {#if[Object]?fieldType:$type$.class});
|
||||
}
|
||||
|
||||
@Override
|
||||
final boolean internalEquals(VarHandle vh) {
|
||||
FieldInstanceReadOnly that = (FieldInstanceReadOnly) vh;
|
||||
return fieldOffset == that.fieldOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
final int internalHashCode() {
|
||||
return Long.hashCode(fieldOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<VarHandleDesc> describeConstable() {
|
||||
var receiverTypeRef = receiverType.describeConstable();
|
||||
var fieldTypeRef = {#if[Object]?fieldType:$type$.class}.describeConstable();
|
||||
if (!receiverTypeRef.isPresent() || !fieldTypeRef.isPresent())
|
||||
return Optional.empty();
|
||||
|
||||
// Reflect on this VarHandle to extract the field name
|
||||
String name = VarHandles.getFieldFromReceiverAndOffset(
|
||||
receiverType, fieldOffset, {#if[Object]?fieldType:$type$.class}).getName();
|
||||
return Optional.of(VarHandleDesc.ofField(receiverTypeRef.get(), name, fieldTypeRef.get()));
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
static $type$ get(FieldInstanceReadOnly handle, Object holder) {
|
||||
return UNSAFE.get$Type$(Objects.requireNonNull(handle.receiverType.cast(holder)),
|
||||
|
@ -323,6 +349,32 @@ final class VarHandle$Type$s {
|
|||
#end[Object]
|
||||
}
|
||||
|
||||
@Override
|
||||
final boolean internalEquals(VarHandle vh) {
|
||||
FieldStaticReadOnly that = (FieldStaticReadOnly) vh;
|
||||
return base == that.base && fieldOffset == that.fieldOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
final int internalHashCode() {
|
||||
return 31 * Long.hashCode(fieldOffset) + base.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<VarHandleDesc> describeConstable() {
|
||||
var fieldTypeRef = {#if[Object]?fieldType:$type$.class}.describeConstable();
|
||||
if (!fieldTypeRef.isPresent())
|
||||
return Optional.empty();
|
||||
|
||||
// Reflect on this VarHandle to extract the field name
|
||||
var staticField = VarHandles.getStaticFieldFromBaseAndOffset(
|
||||
base, fieldOffset, {#if[Object]?fieldType:$type$.class});
|
||||
var receiverTypeRef = staticField.getDeclaringClass().describeConstable();
|
||||
if (!receiverTypeRef.isPresent())
|
||||
return Optional.empty();
|
||||
return Optional.of(VarHandleDesc.ofStaticField(receiverTypeRef.get(), staticField.getName(), fieldTypeRef.get()));
|
||||
}
|
||||
|
||||
@Override
|
||||
final MethodType accessModeTypeUncached(AccessMode accessMode) {
|
||||
return accessMode.at.accessModeType(null, {#if[Object]?fieldType:$type$.class});
|
||||
|
@ -587,6 +639,29 @@ final class VarHandle$Type$s {
|
|||
#end[Object]
|
||||
}
|
||||
|
||||
@Override
|
||||
final boolean internalEquals(VarHandle vh) {
|
||||
// Equality of access mode types of AccessMode.GET is sufficient for
|
||||
// equality checks
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
final int internalHashCode() {
|
||||
// The hash code of the access mode types of AccessMode.GET is
|
||||
// sufficient for hash code generation
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<VarHandleDesc> describeConstable() {
|
||||
var arrayTypeRef = {#if[Object]?arrayType:$type$[].class}.describeConstable();
|
||||
if (!arrayTypeRef.isPresent())
|
||||
return Optional.empty();
|
||||
|
||||
return Optional.of(VarHandleDesc.ofArray(arrayTypeRef.get()));
|
||||
}
|
||||
|
||||
@Override
|
||||
final MethodType accessModeTypeUncached(AccessMode accessMode) {
|
||||
return accessMode.at.accessModeType({#if[Object]?arrayType:$type$[].class}, {#if[Object]?arrayType.getComponentType():$type$.class}, int.class);
|
||||
|
|
|
@ -67,6 +67,17 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
|
|||
super(form);
|
||||
this.be = be;
|
||||
}
|
||||
|
||||
@Override
|
||||
final boolean internalEquals(VarHandle vh) {
|
||||
ByteArrayViewVarHandle that = (ByteArrayViewVarHandle) vh;
|
||||
return be == that.be;
|
||||
}
|
||||
|
||||
@Override
|
||||
final int internalHashCode() {
|
||||
return Boolean.hashCode(be);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ArrayHandle extends ByteArrayViewVarHandle {
|
||||
|
|
|
@ -174,9 +174,9 @@ public final class Parameter implements AnnotatedElement {
|
|||
*/
|
||||
public String getName() {
|
||||
// Note: empty strings as parameter names are now outlawed.
|
||||
// The .equals("") is for compatibility with current JVM
|
||||
// The .isEmpty() is for compatibility with current JVM
|
||||
// behavior. It may be removed at some point.
|
||||
if(name == null || name.equals(""))
|
||||
if(name == null || name.isEmpty())
|
||||
return "arg" + index;
|
||||
else
|
||||
return name;
|
||||
|
|
|
@ -241,7 +241,7 @@ class HostPortrange {
|
|||
int[] parsePort(String port)
|
||||
{
|
||||
|
||||
if (port == null || port.equals("")) {
|
||||
if (port == null || port.isEmpty()) {
|
||||
return defaultPort();
|
||||
}
|
||||
|
||||
|
@ -260,13 +260,13 @@ class HostPortrange {
|
|||
String high = port.substring(dash+1);
|
||||
int l,h;
|
||||
|
||||
if (low.equals("")) {
|
||||
if (low.isEmpty()) {
|
||||
l = PORT_MIN;
|
||||
} else {
|
||||
l = Integer.parseInt(low);
|
||||
}
|
||||
|
||||
if (high.equals("")) {
|
||||
if (high.isEmpty()) {
|
||||
h = PORT_MAX;
|
||||
} else {
|
||||
h = Integer.parseInt(high);
|
||||
|
|
|
@ -1009,7 +1009,7 @@ class InetAddress implements java.io.Serializable {
|
|||
+ " not found ");
|
||||
}
|
||||
|
||||
if ((host == null) || (host.equals("")) || (host.equals(" "))) {
|
||||
if ((host == null) || (host.isEmpty()) || (host.equals(" "))) {
|
||||
throw new UnknownHostException("Requested address "
|
||||
+ addrString
|
||||
+ " resolves to an invalid entry in hosts file "
|
||||
|
@ -1046,7 +1046,7 @@ class InetAddress implements java.io.Serializable {
|
|||
hostEntry = removeComments(hostEntry);
|
||||
if (hostEntry.contains(host)) {
|
||||
addrStr = extractHostAddr(hostEntry, host);
|
||||
if ((addrStr != null) && (!addrStr.equals(""))) {
|
||||
if ((addrStr != null) && (!addrStr.isEmpty())) {
|
||||
addr = createAddressByteArray(addrStr);
|
||||
if (inetAddresses == null) {
|
||||
inetAddresses = new ArrayList<>(1);
|
||||
|
|
|
@ -305,7 +305,7 @@ public final class SocketPermission extends Permission
|
|||
}
|
||||
|
||||
private static String getHost(String host) {
|
||||
if (host.equals("")) {
|
||||
if (host.isEmpty()) {
|
||||
return "localhost";
|
||||
} else {
|
||||
/* IPv6 literal address used in this context should follow
|
||||
|
@ -344,7 +344,7 @@ public final class SocketPermission extends Permission
|
|||
throws Exception
|
||||
{
|
||||
|
||||
if (port == null || port.equals("") || port.equals("*")) {
|
||||
if (port == null || port.isEmpty() || port.equals("*")) {
|
||||
return new int[] {PORT_MIN, PORT_MAX};
|
||||
}
|
||||
|
||||
|
@ -358,13 +358,13 @@ public final class SocketPermission extends Permission
|
|||
String high = port.substring(dash+1);
|
||||
int l,h;
|
||||
|
||||
if (low.equals("")) {
|
||||
if (low.isEmpty()) {
|
||||
l = PORT_MIN;
|
||||
} else {
|
||||
l = Integer.parseInt(low);
|
||||
}
|
||||
|
||||
if (high.equals("")) {
|
||||
if (high.isEmpty()) {
|
||||
h = PORT_MAX;
|
||||
} else {
|
||||
h = Integer.parseInt(high);
|
||||
|
@ -496,7 +496,7 @@ public final class SocketPermission extends Permission
|
|||
throw new NullPointerException("action can't be null");
|
||||
}
|
||||
|
||||
if (action.equals("")) {
|
||||
if (action.isEmpty()) {
|
||||
throw new IllegalArgumentException("action can't be empty");
|
||||
}
|
||||
|
||||
|
|
|
@ -533,11 +533,11 @@ public final class URLPermission extends Permission {
|
|||
String thishost = this.p.hostname();
|
||||
String thathost = that.p.hostname();
|
||||
|
||||
if (p.wildcard() && thishost.equals("")) {
|
||||
if (p.wildcard() && thishost.isEmpty()) {
|
||||
// this "*" implies all others
|
||||
return true;
|
||||
}
|
||||
if (that.p.wildcard() && thathost.equals("")) {
|
||||
if (that.p.wildcard() && thathost.isEmpty()) {
|
||||
// that "*" can only be implied by this "*"
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -437,7 +437,7 @@ public abstract class URLStreamHandler {
|
|||
return u.hostAddress;
|
||||
|
||||
String host = u.getHost();
|
||||
if (host == null || host.equals("")) {
|
||||
if (host == null || host.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
try {
|
||||
|
|
2130
src/java.base/share/classes/java/text/CompactNumberFormat.java
Normal file
2130
src/java.base/share/classes/java/text/CompactNumberFormat.java
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -48,9 +48,6 @@ import java.text.spi.NumberFormatProvider;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Currency;
|
||||
import java.util.Locale;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import sun.util.locale.provider.LocaleProviderAdapter;
|
||||
|
@ -157,7 +154,7 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter;
|
|||
* used. So <code>"#,##,###,####"</code> == <code>"######,####"</code> ==
|
||||
* <code>"##,####,####"</code>.
|
||||
*
|
||||
* <h4>Special Pattern Characters</h4>
|
||||
* <h4><a id="special_pattern_character">Special Pattern Characters</a></h4>
|
||||
*
|
||||
* <p>Many characters in a pattern are taken literally; they are matched during
|
||||
* parsing and output unchanged during formatting. Special characters, on the
|
||||
|
@ -572,14 +569,11 @@ public class DecimalFormat extends NumberFormat {
|
|||
* mode being set to RoundingMode.UNNECESSARY
|
||||
* @return The formatted number string
|
||||
*/
|
||||
private StringBuffer format(double number, StringBuffer result,
|
||||
StringBuffer format(double number, StringBuffer result,
|
||||
FieldDelegate delegate) {
|
||||
if (Double.isNaN(number) ||
|
||||
(Double.isInfinite(number) && multiplier == 0)) {
|
||||
int iFieldStart = result.length();
|
||||
result.append(symbols.getNaN());
|
||||
delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
|
||||
iFieldStart, result.length(), result);
|
||||
|
||||
boolean nanOrInfinity = handleNaN(number, result, delegate);
|
||||
if (nanOrInfinity) {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -599,6 +593,56 @@ public class DecimalFormat extends NumberFormat {
|
|||
number *= multiplier;
|
||||
}
|
||||
|
||||
nanOrInfinity = handleInfinity(number, result, delegate, isNegative);
|
||||
if (nanOrInfinity) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (isNegative) {
|
||||
number = -number;
|
||||
}
|
||||
|
||||
// at this point we are guaranteed a nonnegative finite number.
|
||||
assert (number >= 0 && !Double.isInfinite(number));
|
||||
return doubleSubformat(number, result, delegate, isNegative);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given {@code number} is {@code Double.NaN}. if yes;
|
||||
* appends the NaN symbol to the result string. The NaN string is
|
||||
* determined by the DecimalFormatSymbols object.
|
||||
* @param number the double number to format
|
||||
* @param result where the text is to be appended
|
||||
* @param delegate notified of locations of sub fields
|
||||
* @return true, if number is a NaN; false otherwise
|
||||
*/
|
||||
boolean handleNaN(double number, StringBuffer result,
|
||||
FieldDelegate delegate) {
|
||||
if (Double.isNaN(number)
|
||||
|| (Double.isInfinite(number) && multiplier == 0)) {
|
||||
int iFieldStart = result.length();
|
||||
result.append(symbols.getNaN());
|
||||
delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
|
||||
iFieldStart, result.length(), result);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given {@code number} is {@code Double.NEGATIVE_INFINITY}
|
||||
* or {@code Double.POSITIVE_INFINITY}. if yes;
|
||||
* appends the infinity string to the result string. The infinity string is
|
||||
* determined by the DecimalFormatSymbols object.
|
||||
* @param number the double number to format
|
||||
* @param result where the text is to be appended
|
||||
* @param delegate notified of locations of sub fields
|
||||
* @param isNegative whether the given {@code number} is negative
|
||||
* @return true, if number is a {@code Double.NEGATIVE_INFINITY} or
|
||||
* {@code Double.POSITIVE_INFINITY}; false otherwise
|
||||
*/
|
||||
boolean handleInfinity(double number, StringBuffer result,
|
||||
FieldDelegate delegate, boolean isNegative) {
|
||||
if (Double.isInfinite(number)) {
|
||||
if (isNegative) {
|
||||
append(result, negativePrefix, delegate,
|
||||
|
@ -621,27 +665,24 @@ public class DecimalFormat extends NumberFormat {
|
|||
getPositiveSuffixFieldPositions(), Field.SIGN);
|
||||
}
|
||||
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isNegative) {
|
||||
number = -number;
|
||||
}
|
||||
|
||||
// at this point we are guaranteed a nonnegative finite number.
|
||||
assert(number >= 0 && !Double.isInfinite(number));
|
||||
|
||||
synchronized(digitList) {
|
||||
StringBuffer doubleSubformat(double number, StringBuffer result,
|
||||
FieldDelegate delegate, boolean isNegative) {
|
||||
synchronized (digitList) {
|
||||
int maxIntDigits = super.getMaximumIntegerDigits();
|
||||
int minIntDigits = super.getMinimumIntegerDigits();
|
||||
int maxFraDigits = super.getMaximumFractionDigits();
|
||||
int minFraDigits = super.getMinimumFractionDigits();
|
||||
|
||||
digitList.set(isNegative, number, useExponentialNotation ?
|
||||
maxIntDigits + maxFraDigits : maxFraDigits,
|
||||
!useExponentialNotation);
|
||||
digitList.set(isNegative, number, useExponentialNotation
|
||||
? maxIntDigits + maxFraDigits : maxFraDigits,
|
||||
!useExponentialNotation);
|
||||
return subformat(result, delegate, isNegative, false,
|
||||
maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
|
||||
maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -683,7 +724,7 @@ public class DecimalFormat extends NumberFormat {
|
|||
* mode being set to RoundingMode.UNNECESSARY
|
||||
* @see java.text.FieldPosition
|
||||
*/
|
||||
private StringBuffer format(long number, StringBuffer result,
|
||||
StringBuffer format(long number, StringBuffer result,
|
||||
FieldDelegate delegate) {
|
||||
boolean isNegative = (number < 0);
|
||||
if (isNegative) {
|
||||
|
@ -774,7 +815,7 @@ public class DecimalFormat extends NumberFormat {
|
|||
* mode being set to RoundingMode.UNNECESSARY
|
||||
* @return The formatted number string
|
||||
*/
|
||||
private StringBuffer format(BigDecimal number, StringBuffer result,
|
||||
StringBuffer format(BigDecimal number, StringBuffer result,
|
||||
FieldDelegate delegate) {
|
||||
if (multiplier != 1) {
|
||||
number = number.multiply(getBigDecimalMultiplier());
|
||||
|
@ -835,7 +876,7 @@ public class DecimalFormat extends NumberFormat {
|
|||
* mode being set to RoundingMode.UNNECESSARY
|
||||
* @see java.text.FieldPosition
|
||||
*/
|
||||
private StringBuffer format(BigInteger number, StringBuffer result,
|
||||
StringBuffer format(BigInteger number, StringBuffer result,
|
||||
FieldDelegate delegate, boolean formatLong) {
|
||||
if (multiplier != 1) {
|
||||
number = number.multiply(getBigIntegerMultiplier());
|
||||
|
@ -917,7 +958,7 @@ public class DecimalFormat extends NumberFormat {
|
|||
return delegate.getIterator(sb.toString());
|
||||
}
|
||||
|
||||
// ==== Begin fast-path formating logic for double =========================
|
||||
// ==== Begin fast-path formatting logic for double =========================
|
||||
|
||||
/* Fast-path formatting will be used for format(double ...) methods iff a
|
||||
* number of conditions are met (see checkAndSetFastPathStatus()):
|
||||
|
@ -1662,6 +1703,26 @@ public class DecimalFormat extends NumberFormat {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@code DigitList} used by this {@code DecimalFormat}
|
||||
* instance.
|
||||
* @param number the number to format
|
||||
* @param isNegative true, if the number is negative; false otherwise
|
||||
* @param maxDigits the max digits
|
||||
*/
|
||||
void setDigitList(Number number, boolean isNegative, int maxDigits) {
|
||||
|
||||
if (number instanceof Double) {
|
||||
digitList.set(isNegative, (Double) number, maxDigits, true);
|
||||
} else if (number instanceof BigDecimal) {
|
||||
digitList.set(isNegative, (BigDecimal) number, maxDigits, true);
|
||||
} else if (number instanceof Long) {
|
||||
digitList.set(isNegative, (Long) number, maxDigits);
|
||||
} else if (number instanceof BigInteger) {
|
||||
digitList.set(isNegative, (BigInteger) number, maxDigits);
|
||||
}
|
||||
}
|
||||
|
||||
// ======== End fast-path formating logic for double =========================
|
||||
|
||||
/**
|
||||
|
@ -1669,29 +1730,59 @@ public class DecimalFormat extends NumberFormat {
|
|||
* be filled in with the correct digits.
|
||||
*/
|
||||
private StringBuffer subformat(StringBuffer result, FieldDelegate delegate,
|
||||
boolean isNegative, boolean isInteger,
|
||||
int maxIntDigits, int minIntDigits,
|
||||
int maxFraDigits, int minFraDigits) {
|
||||
// NOTE: This isn't required anymore because DigitList takes care of this.
|
||||
//
|
||||
// // The negative of the exponent represents the number of leading
|
||||
// // zeros between the decimal and the first non-zero digit, for
|
||||
// // a value < 0.1 (e.g., for 0.00123, -fExponent == 2). If this
|
||||
// // is more than the maximum fraction digits, then we have an underflow
|
||||
// // for the printed representation. We recognize this here and set
|
||||
// // the DigitList representation to zero in this situation.
|
||||
//
|
||||
// if (-digitList.decimalAt >= getMaximumFractionDigits())
|
||||
// {
|
||||
// digitList.count = 0;
|
||||
// }
|
||||
boolean isNegative, boolean isInteger,
|
||||
int maxIntDigits, int minIntDigits,
|
||||
int maxFraDigits, int minFraDigits) {
|
||||
|
||||
// Process prefix
|
||||
if (isNegative) {
|
||||
append(result, negativePrefix, delegate,
|
||||
getNegativePrefixFieldPositions(), Field.SIGN);
|
||||
} else {
|
||||
append(result, positivePrefix, delegate,
|
||||
getPositivePrefixFieldPositions(), Field.SIGN);
|
||||
}
|
||||
|
||||
// Process number
|
||||
subformatNumber(result, delegate, isNegative, isInteger,
|
||||
maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
|
||||
|
||||
// Process suffix
|
||||
if (isNegative) {
|
||||
append(result, negativeSuffix, delegate,
|
||||
getNegativeSuffixFieldPositions(), Field.SIGN);
|
||||
} else {
|
||||
append(result, positiveSuffix, delegate,
|
||||
getPositiveSuffixFieldPositions(), Field.SIGN);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subformats number part using the {@code DigitList} of this
|
||||
* {@code DecimalFormat} instance.
|
||||
* @param result where the text is to be appended
|
||||
* @param delegate notified of the location of sub fields
|
||||
* @param isNegative true, if the number is negative; false otherwise
|
||||
* @param isInteger true, if the number is an integer; false otherwise
|
||||
* @param maxIntDigits maximum integer digits
|
||||
* @param minIntDigits minimum integer digits
|
||||
* @param maxFraDigits maximum fraction digits
|
||||
* @param minFraDigits minimum fraction digits
|
||||
*/
|
||||
void subformatNumber(StringBuffer result, FieldDelegate delegate,
|
||||
boolean isNegative, boolean isInteger,
|
||||
int maxIntDigits, int minIntDigits,
|
||||
int maxFraDigits, int minFraDigits) {
|
||||
|
||||
char grouping = symbols.getGroupingSeparator();
|
||||
char zero = symbols.getZeroDigit();
|
||||
int zeroDelta = zero - '0'; // '0' is the DigitList representation of zero
|
||||
char grouping = symbols.getGroupingSeparator();
|
||||
|
||||
char decimal = isCurrencyFormat ?
|
||||
symbols.getMonetaryDecimalSeparator() :
|
||||
symbols.getDecimalSeparator();
|
||||
symbols.getMonetaryDecimalSeparator() :
|
||||
symbols.getDecimalSeparator();
|
||||
|
||||
/* Per bug 4147706, DecimalFormat must respect the sign of numbers which
|
||||
* format as zero. This allows sensible computations and preserves
|
||||
|
@ -1703,14 +1794,6 @@ public class DecimalFormat extends NumberFormat {
|
|||
digitList.decimalAt = 0; // Normalize
|
||||
}
|
||||
|
||||
if (isNegative) {
|
||||
append(result, negativePrefix, delegate,
|
||||
getNegativePrefixFieldPositions(), Field.SIGN);
|
||||
} else {
|
||||
append(result, positivePrefix, delegate,
|
||||
getPositivePrefixFieldPositions(), Field.SIGN);
|
||||
}
|
||||
|
||||
if (useExponentialNotation) {
|
||||
int iFieldStart = result.length();
|
||||
int iFieldEnd = -1;
|
||||
|
@ -1719,7 +1802,6 @@ public class DecimalFormat extends NumberFormat {
|
|||
// Minimum integer digits are handled in exponential format by
|
||||
// adjusting the exponent. For example, 0.01234 with 3 minimum
|
||||
// integer digits is "123.4E-4".
|
||||
|
||||
// Maximum integer digits are interpreted as indicating the
|
||||
// repeating range. This is useful for engineering notation, in
|
||||
// which the exponent is restricted to a multiple of 3. For
|
||||
|
@ -1782,8 +1864,8 @@ public class DecimalFormat extends NumberFormat {
|
|||
fFieldStart = result.length();
|
||||
}
|
||||
result.append((i < digitList.count) ?
|
||||
(char)(digitList.digits[i] + zeroDelta) :
|
||||
zero);
|
||||
(char)(digitList.digits[i] + zeroDelta) :
|
||||
zero);
|
||||
}
|
||||
|
||||
if (decimalSeparatorAlwaysShown && totalDigits == integerDigits) {
|
||||
|
@ -1802,17 +1884,17 @@ public class DecimalFormat extends NumberFormat {
|
|||
iFieldEnd = result.length();
|
||||
}
|
||||
delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
|
||||
iFieldStart, iFieldEnd, result);
|
||||
iFieldStart, iFieldEnd, result);
|
||||
if (addedDecimalSeparator) {
|
||||
delegate.formatted(Field.DECIMAL_SEPARATOR,
|
||||
Field.DECIMAL_SEPARATOR,
|
||||
iFieldEnd, fFieldStart, result);
|
||||
Field.DECIMAL_SEPARATOR,
|
||||
iFieldEnd, fFieldStart, result);
|
||||
}
|
||||
if (fFieldStart == -1) {
|
||||
fFieldStart = result.length();
|
||||
}
|
||||
delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
|
||||
fFieldStart, result.length(), result);
|
||||
fFieldStart, result.length(), result);
|
||||
|
||||
// The exponent is output using the pattern-specified minimum
|
||||
// exponent digits. There is no maximum limit to the exponent
|
||||
|
@ -1823,7 +1905,7 @@ public class DecimalFormat extends NumberFormat {
|
|||
result.append(symbols.getExponentSeparator());
|
||||
|
||||
delegate.formatted(Field.EXPONENT_SYMBOL, Field.EXPONENT_SYMBOL,
|
||||
fieldStart, result.length(), result);
|
||||
fieldStart, result.length(), result);
|
||||
|
||||
// For zero values, we force the exponent to zero. We
|
||||
// must do this here, and not earlier, because the value
|
||||
|
@ -1838,7 +1920,7 @@ public class DecimalFormat extends NumberFormat {
|
|||
fieldStart = result.length();
|
||||
result.append(symbols.getMinusSign());
|
||||
delegate.formatted(Field.EXPONENT_SIGN, Field.EXPONENT_SIGN,
|
||||
fieldStart, result.length(), result);
|
||||
fieldStart, result.length(), result);
|
||||
}
|
||||
digitList.set(negativeExponent, exponent);
|
||||
|
||||
|
@ -1849,10 +1931,10 @@ public class DecimalFormat extends NumberFormat {
|
|||
}
|
||||
for (int i=0; i<digitList.decimalAt; ++i) {
|
||||
result.append((i < digitList.count) ?
|
||||
(char)(digitList.digits[i] + zeroDelta) : zero);
|
||||
(char)(digitList.digits[i] + zeroDelta) : zero);
|
||||
}
|
||||
delegate.formatted(Field.EXPONENT, Field.EXPONENT, eFieldStart,
|
||||
result.length(), result);
|
||||
result.length(), result);
|
||||
} else {
|
||||
int iFieldStart = result.length();
|
||||
|
||||
|
@ -1889,19 +1971,19 @@ public class DecimalFormat extends NumberFormat {
|
|||
// grouping separator if i==0 though; that's at the end of
|
||||
// the integer part.
|
||||
if (isGroupingUsed() && i>0 && (groupingSize != 0) &&
|
||||
(i % groupingSize == 0)) {
|
||||
(i % groupingSize == 0)) {
|
||||
int gStart = result.length();
|
||||
result.append(grouping);
|
||||
delegate.formatted(Field.GROUPING_SEPARATOR,
|
||||
Field.GROUPING_SEPARATOR, gStart,
|
||||
result.length(), result);
|
||||
Field.GROUPING_SEPARATOR, gStart,
|
||||
result.length(), result);
|
||||
}
|
||||
}
|
||||
|
||||
// Determine whether or not there are any printable fractional
|
||||
// digits. If we've used up the digits we know there aren't.
|
||||
boolean fractionPresent = (minFraDigits > 0) ||
|
||||
(!isInteger && digitIndex < digitList.count);
|
||||
(!isInteger && digitIndex < digitList.count);
|
||||
|
||||
// If there is no fraction present, and we haven't printed any
|
||||
// integer digits, then print a zero. Otherwise we won't print
|
||||
|
@ -1911,7 +1993,7 @@ public class DecimalFormat extends NumberFormat {
|
|||
}
|
||||
|
||||
delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
|
||||
iFieldStart, result.length(), result);
|
||||
iFieldStart, result.length(), result);
|
||||
|
||||
// Output the decimal separator if we always do so.
|
||||
int sStart = result.length();
|
||||
|
@ -1921,8 +2003,8 @@ public class DecimalFormat extends NumberFormat {
|
|||
|
||||
if (sStart != result.length()) {
|
||||
delegate.formatted(Field.DECIMAL_SEPARATOR,
|
||||
Field.DECIMAL_SEPARATOR,
|
||||
sStart, result.length(), result);
|
||||
Field.DECIMAL_SEPARATOR,
|
||||
sStart, result.length(), result);
|
||||
}
|
||||
int fFieldStart = result.length();
|
||||
|
||||
|
@ -1934,7 +2016,7 @@ public class DecimalFormat extends NumberFormat {
|
|||
// we have an integer, so there is no fractional stuff to
|
||||
// display, or we're out of significant digits.
|
||||
if (i >= minFraDigits &&
|
||||
(isInteger || digitIndex >= digitList.count)) {
|
||||
(isInteger || digitIndex >= digitList.count)) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1957,18 +2039,8 @@ public class DecimalFormat extends NumberFormat {
|
|||
|
||||
// Record field information for caller.
|
||||
delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
|
||||
fFieldStart, result.length(), result);
|
||||
fFieldStart, result.length(), result);
|
||||
}
|
||||
|
||||
if (isNegative) {
|
||||
append(result, negativeSuffix, delegate,
|
||||
getNegativeSuffixFieldPositions(), Field.SIGN);
|
||||
} else {
|
||||
append(result, positiveSuffix, delegate,
|
||||
getPositiveSuffixFieldPositions(), Field.SIGN);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2209,19 +2281,18 @@ public class DecimalFormat extends NumberFormat {
|
|||
* whether the value was infinite and whether it was positive.
|
||||
*/
|
||||
private final boolean subparse(String text, ParsePosition parsePosition,
|
||||
String positivePrefix, String negativePrefix,
|
||||
DigitList digits, boolean isExponent,
|
||||
boolean status[]) {
|
||||
String positivePrefix, String negativePrefix,
|
||||
DigitList digits, boolean isExponent,
|
||||
boolean status[]) {
|
||||
int position = parsePosition.index;
|
||||
int oldStart = parsePosition.index;
|
||||
int backup;
|
||||
boolean gotPositive, gotNegative;
|
||||
|
||||
// check for positivePrefix; take longest
|
||||
gotPositive = text.regionMatches(position, positivePrefix, 0,
|
||||
positivePrefix.length());
|
||||
positivePrefix.length());
|
||||
gotNegative = text.regionMatches(position, negativePrefix, 0,
|
||||
negativePrefix.length());
|
||||
negativePrefix.length());
|
||||
|
||||
if (gotPositive && gotNegative) {
|
||||
if (positivePrefix.length() > negativePrefix.length()) {
|
||||
|
@ -2240,10 +2311,75 @@ public class DecimalFormat extends NumberFormat {
|
|||
return false;
|
||||
}
|
||||
|
||||
position = subparseNumber(text, position, digits, true, isExponent, status);
|
||||
if (position == -1) {
|
||||
parsePosition.index = oldStart;
|
||||
parsePosition.errorIndex = oldStart;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for suffix
|
||||
if (!isExponent) {
|
||||
if (gotPositive) {
|
||||
gotPositive = text.regionMatches(position,positiveSuffix,0,
|
||||
positiveSuffix.length());
|
||||
}
|
||||
if (gotNegative) {
|
||||
gotNegative = text.regionMatches(position,negativeSuffix,0,
|
||||
negativeSuffix.length());
|
||||
}
|
||||
|
||||
// If both match, take longest
|
||||
if (gotPositive && gotNegative) {
|
||||
if (positiveSuffix.length() > negativeSuffix.length()) {
|
||||
gotNegative = false;
|
||||
} else if (positiveSuffix.length() < negativeSuffix.length()) {
|
||||
gotPositive = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Fail if neither or both
|
||||
if (gotPositive == gotNegative) {
|
||||
parsePosition.errorIndex = position;
|
||||
return false;
|
||||
}
|
||||
|
||||
parsePosition.index = position +
|
||||
(gotPositive ? positiveSuffix.length() : negativeSuffix.length()); // mark success!
|
||||
} else {
|
||||
parsePosition.index = position;
|
||||
}
|
||||
|
||||
status[STATUS_POSITIVE] = gotPositive;
|
||||
if (parsePosition.index == oldStart) {
|
||||
parsePosition.errorIndex = position;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a number from the given {@code text}. The text is parsed
|
||||
* beginning at position, until an unparseable character is seen.
|
||||
*
|
||||
* @param text the string to parse
|
||||
* @param position the position at which parsing begins
|
||||
* @param digits the DigitList to set to the parsed value
|
||||
* @param checkExponent whether to check for exponential number
|
||||
* @param isExponent if the exponential part is encountered
|
||||
* @param status upon return contains boolean status flags indicating
|
||||
* whether the value is infinite and whether it is
|
||||
* positive
|
||||
* @return returns the position of the first unparseable character or
|
||||
* -1 in case of no valid number parsed
|
||||
*/
|
||||
int subparseNumber(String text, int position,
|
||||
DigitList digits, boolean checkExponent,
|
||||
boolean isExponent, boolean status[]) {
|
||||
// process digits or Inf, find decimal position
|
||||
status[STATUS_INFINITE] = false;
|
||||
if (!isExponent && text.regionMatches(position,symbols.getInfinity(),0,
|
||||
symbols.getInfinity().length())) {
|
||||
symbols.getInfinity().length())) {
|
||||
position += symbols.getInfinity().length();
|
||||
status[STATUS_INFINITE] = true;
|
||||
} else {
|
||||
|
@ -2257,8 +2393,8 @@ public class DecimalFormat extends NumberFormat {
|
|||
digits.decimalAt = digits.count = 0;
|
||||
char zero = symbols.getZeroDigit();
|
||||
char decimal = isCurrencyFormat ?
|
||||
symbols.getMonetaryDecimalSeparator() :
|
||||
symbols.getDecimalSeparator();
|
||||
symbols.getMonetaryDecimalSeparator() :
|
||||
symbols.getDecimalSeparator();
|
||||
char grouping = symbols.getGroupingSeparator();
|
||||
String exponentString = symbols.getExponentSeparator();
|
||||
boolean sawDecimal = false;
|
||||
|
@ -2270,7 +2406,7 @@ public class DecimalFormat extends NumberFormat {
|
|||
// pin when the maximum allowable digits is reached.
|
||||
int digitCount = 0;
|
||||
|
||||
backup = -1;
|
||||
int backup = -1;
|
||||
for (; position < text.length(); ++position) {
|
||||
char ch = text.charAt(position);
|
||||
|
||||
|
@ -2334,15 +2470,15 @@ public class DecimalFormat extends NumberFormat {
|
|||
// require that they be followed by a digit. Otherwise
|
||||
// we backup and reprocess them.
|
||||
backup = position;
|
||||
} else if (!isExponent && text.regionMatches(position, exponentString, 0, exponentString.length())
|
||||
&& !sawExponent) {
|
||||
} else if (checkExponent && !isExponent && text.regionMatches(position, exponentString, 0, exponentString.length())
|
||||
&& !sawExponent) {
|
||||
// Process the exponent by recursively calling this method.
|
||||
ParsePosition pos = new ParsePosition(position + exponentString.length());
|
||||
ParsePosition pos = new ParsePosition(position + exponentString.length());
|
||||
boolean[] stat = new boolean[STATUS_LENGTH];
|
||||
DigitList exponentDigits = new DigitList();
|
||||
|
||||
if (subparse(text, pos, "", Character.toString(symbols.getMinusSign()), exponentDigits, true, stat) &&
|
||||
exponentDigits.fitsIntoLong(stat[STATUS_POSITIVE], true)) {
|
||||
exponentDigits.fitsIntoLong(stat[STATUS_POSITIVE], true)) {
|
||||
position = pos.index; // Advance past the exponent
|
||||
exponent = (int)exponentDigits.getLong();
|
||||
if (!stat[STATUS_POSITIVE]) {
|
||||
|
@ -2373,50 +2509,11 @@ public class DecimalFormat extends NumberFormat {
|
|||
// parse "$" with pattern "$#0.00". (return index 0 and error
|
||||
// index 1).
|
||||
if (!sawDigit && digitCount == 0) {
|
||||
parsePosition.index = oldStart;
|
||||
parsePosition.errorIndex = oldStart;
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return position;
|
||||
|
||||
// check for suffix
|
||||
if (!isExponent) {
|
||||
if (gotPositive) {
|
||||
gotPositive = text.regionMatches(position,positiveSuffix,0,
|
||||
positiveSuffix.length());
|
||||
}
|
||||
if (gotNegative) {
|
||||
gotNegative = text.regionMatches(position,negativeSuffix,0,
|
||||
negativeSuffix.length());
|
||||
}
|
||||
|
||||
// if both match, take longest
|
||||
if (gotPositive && gotNegative) {
|
||||
if (positiveSuffix.length() > negativeSuffix.length()) {
|
||||
gotNegative = false;
|
||||
} else if (positiveSuffix.length() < negativeSuffix.length()) {
|
||||
gotPositive = false;
|
||||
}
|
||||
}
|
||||
|
||||
// fail if neither or both
|
||||
if (gotPositive == gotNegative) {
|
||||
parsePosition.errorIndex = position;
|
||||
return false;
|
||||
}
|
||||
|
||||
parsePosition.index = position +
|
||||
(gotPositive ? positiveSuffix.length() : negativeSuffix.length()); // mark success!
|
||||
} else {
|
||||
parsePosition.index = position;
|
||||
}
|
||||
|
||||
status[STATUS_POSITIVE] = gotPositive;
|
||||
if (parsePosition.index == oldStart) {
|
||||
parsePosition.errorIndex = position;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2018, 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
|
||||
|
@ -47,13 +47,11 @@ import java.math.RoundingMode;
|
|||
import java.text.spi.NumberFormatProvider;
|
||||
import java.util.Currency;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.spi.LocaleServiceProvider;
|
||||
import sun.util.locale.provider.LocaleProviderAdapter;
|
||||
import sun.util.locale.provider.LocaleServiceProviderPool;
|
||||
|
||||
|
@ -112,9 +110,12 @@ import sun.util.locale.provider.LocaleServiceProviderPool;
|
|||
* Use <code>getInstance</code> or <code>getNumberInstance</code> to get the
|
||||
* normal number format. Use <code>getIntegerInstance</code> to get an
|
||||
* integer number format. Use <code>getCurrencyInstance</code> to get the
|
||||
* currency number format. And use <code>getPercentInstance</code> to get a
|
||||
* format for displaying percentages. With this format, a fraction like
|
||||
* 0.53 is displayed as 53%.
|
||||
* currency number format. Use {@code getCompactNumberInstance} to get the
|
||||
* compact number format to format a number in shorter form. For example,
|
||||
* {@code 2000} can be formatted as {@code "2K"} in
|
||||
* {@link java.util.Locale#US US locale}. Use <code>getPercentInstance</code>
|
||||
* to get a format for displaying percentages. With this format, a fraction
|
||||
* like 0.53 is displayed as 53%.
|
||||
*
|
||||
* <p>
|
||||
* You can also control the display of numbers with such methods as
|
||||
|
@ -122,9 +123,10 @@ import sun.util.locale.provider.LocaleServiceProviderPool;
|
|||
* If you want even more control over the format or parsing,
|
||||
* or want to give your users more control,
|
||||
* you can try casting the <code>NumberFormat</code> you get from the factory methods
|
||||
* to a <code>DecimalFormat</code>. This will work for the vast majority
|
||||
* of locales; just remember to put it in a <code>try</code> block in case you
|
||||
* encounter an unusual one.
|
||||
* to a {@code DecimalFormat} or {@code CompactNumberFormat} depending on
|
||||
* the factory method used. This will work for the vast majority of locales;
|
||||
* just remember to put it in a <code>try</code> block in case you encounter
|
||||
* an unusual one.
|
||||
*
|
||||
* <p>
|
||||
* NumberFormat and DecimalFormat are designed such that some controls
|
||||
|
@ -201,6 +203,7 @@ import sun.util.locale.provider.LocaleServiceProviderPool;
|
|||
*
|
||||
* @see DecimalFormat
|
||||
* @see ChoiceFormat
|
||||
* @see CompactNumberFormat
|
||||
* @author Mark Davis
|
||||
* @author Helena Shih
|
||||
* @since 1.1
|
||||
|
@ -472,7 +475,7 @@ public abstract class NumberFormat extends Format {
|
|||
* formatting
|
||||
*/
|
||||
public static final NumberFormat getInstance() {
|
||||
return getInstance(Locale.getDefault(Locale.Category.FORMAT), NUMBERSTYLE);
|
||||
return getInstance(Locale.getDefault(Locale.Category.FORMAT), null, NUMBERSTYLE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -485,7 +488,7 @@ public abstract class NumberFormat extends Format {
|
|||
* formatting
|
||||
*/
|
||||
public static NumberFormat getInstance(Locale inLocale) {
|
||||
return getInstance(inLocale, NUMBERSTYLE);
|
||||
return getInstance(inLocale, null, NUMBERSTYLE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -501,7 +504,7 @@ public abstract class NumberFormat extends Format {
|
|||
* @see java.util.Locale.Category#FORMAT
|
||||
*/
|
||||
public static final NumberFormat getNumberInstance() {
|
||||
return getInstance(Locale.getDefault(Locale.Category.FORMAT), NUMBERSTYLE);
|
||||
return getInstance(Locale.getDefault(Locale.Category.FORMAT), null, NUMBERSTYLE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -512,7 +515,7 @@ public abstract class NumberFormat extends Format {
|
|||
* formatting
|
||||
*/
|
||||
public static NumberFormat getNumberInstance(Locale inLocale) {
|
||||
return getInstance(inLocale, NUMBERSTYLE);
|
||||
return getInstance(inLocale, null, NUMBERSTYLE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -534,7 +537,7 @@ public abstract class NumberFormat extends Format {
|
|||
* @since 1.4
|
||||
*/
|
||||
public static final NumberFormat getIntegerInstance() {
|
||||
return getInstance(Locale.getDefault(Locale.Category.FORMAT), INTEGERSTYLE);
|
||||
return getInstance(Locale.getDefault(Locale.Category.FORMAT), null, INTEGERSTYLE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -551,7 +554,7 @@ public abstract class NumberFormat extends Format {
|
|||
* @since 1.4
|
||||
*/
|
||||
public static NumberFormat getIntegerInstance(Locale inLocale) {
|
||||
return getInstance(inLocale, INTEGERSTYLE);
|
||||
return getInstance(inLocale, null, INTEGERSTYLE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -566,7 +569,7 @@ public abstract class NumberFormat extends Format {
|
|||
* @see java.util.Locale.Category#FORMAT
|
||||
*/
|
||||
public static final NumberFormat getCurrencyInstance() {
|
||||
return getInstance(Locale.getDefault(Locale.Category.FORMAT), CURRENCYSTYLE);
|
||||
return getInstance(Locale.getDefault(Locale.Category.FORMAT), null, CURRENCYSTYLE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -576,7 +579,7 @@ public abstract class NumberFormat extends Format {
|
|||
* @return the {@code NumberFormat} instance for currency formatting
|
||||
*/
|
||||
public static NumberFormat getCurrencyInstance(Locale inLocale) {
|
||||
return getInstance(inLocale, CURRENCYSTYLE);
|
||||
return getInstance(inLocale, null, CURRENCYSTYLE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -591,7 +594,7 @@ public abstract class NumberFormat extends Format {
|
|||
* @see java.util.Locale.Category#FORMAT
|
||||
*/
|
||||
public static final NumberFormat getPercentInstance() {
|
||||
return getInstance(Locale.getDefault(Locale.Category.FORMAT), PERCENTSTYLE);
|
||||
return getInstance(Locale.getDefault(Locale.Category.FORMAT), null, PERCENTSTYLE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -601,14 +604,14 @@ public abstract class NumberFormat extends Format {
|
|||
* @return the {@code NumberFormat} instance for percentage formatting
|
||||
*/
|
||||
public static NumberFormat getPercentInstance(Locale inLocale) {
|
||||
return getInstance(inLocale, PERCENTSTYLE);
|
||||
return getInstance(inLocale, null, PERCENTSTYLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a scientific format for the current default locale.
|
||||
*/
|
||||
/*public*/ final static NumberFormat getScientificInstance() {
|
||||
return getInstance(Locale.getDefault(Locale.Category.FORMAT), SCIENTIFICSTYLE);
|
||||
return getInstance(Locale.getDefault(Locale.Category.FORMAT), null, SCIENTIFICSTYLE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -617,7 +620,50 @@ public abstract class NumberFormat extends Format {
|
|||
* @param inLocale the desired locale
|
||||
*/
|
||||
/*public*/ static NumberFormat getScientificInstance(Locale inLocale) {
|
||||
return getInstance(inLocale, SCIENTIFICSTYLE);
|
||||
return getInstance(inLocale, null, SCIENTIFICSTYLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a compact number format for the default
|
||||
* {@link java.util.Locale.Category#FORMAT FORMAT} locale with
|
||||
* {@link NumberFormat.Style#SHORT "SHORT"} format style.
|
||||
*
|
||||
* @return A {@code NumberFormat} instance for compact number
|
||||
* formatting
|
||||
*
|
||||
* @see CompactNumberFormat
|
||||
* @see NumberFormat.Style
|
||||
* @see java.util.Locale#getDefault(java.util.Locale.Category)
|
||||
* @see java.util.Locale.Category#FORMAT
|
||||
* @since 12
|
||||
*/
|
||||
public static NumberFormat getCompactNumberInstance() {
|
||||
return getInstance(Locale.getDefault(
|
||||
Locale.Category.FORMAT), NumberFormat.Style.SHORT, COMPACTSTYLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a compact number format for the specified {@link java.util.Locale locale}
|
||||
* and {@link NumberFormat.Style formatStyle}.
|
||||
*
|
||||
* @param locale the desired locale
|
||||
* @param formatStyle the style for formatting a number
|
||||
* @return A {@code NumberFormat} instance for compact number
|
||||
* formatting
|
||||
* @throws NullPointerException if {@code locale} or {@code formatStyle}
|
||||
* is {@code null}
|
||||
*
|
||||
* @see CompactNumberFormat
|
||||
* @see NumberFormat.Style
|
||||
* @see java.util.Locale
|
||||
* @since 12
|
||||
*/
|
||||
public static NumberFormat getCompactNumberInstance(Locale locale,
|
||||
NumberFormat.Style formatStyle) {
|
||||
|
||||
Objects.requireNonNull(locale);
|
||||
Objects.requireNonNull(formatStyle);
|
||||
return getInstance(locale, formatStyle, COMPACTSTYLE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -900,20 +946,22 @@ public abstract class NumberFormat extends Format {
|
|||
// =======================privates===============================
|
||||
|
||||
private static NumberFormat getInstance(Locale desiredLocale,
|
||||
int choice) {
|
||||
Style formatStyle, int choice) {
|
||||
LocaleProviderAdapter adapter;
|
||||
adapter = LocaleProviderAdapter.getAdapter(NumberFormatProvider.class,
|
||||
desiredLocale);
|
||||
NumberFormat numberFormat = getInstance(adapter, desiredLocale, choice);
|
||||
desiredLocale);
|
||||
NumberFormat numberFormat = getInstance(adapter, desiredLocale,
|
||||
formatStyle, choice);
|
||||
if (numberFormat == null) {
|
||||
numberFormat = getInstance(LocaleProviderAdapter.forJRE(),
|
||||
desiredLocale, choice);
|
||||
desiredLocale, formatStyle, choice);
|
||||
}
|
||||
return numberFormat;
|
||||
}
|
||||
|
||||
private static NumberFormat getInstance(LocaleProviderAdapter adapter,
|
||||
Locale locale, int choice) {
|
||||
Locale locale, Style formatStyle,
|
||||
int choice) {
|
||||
NumberFormatProvider provider = adapter.getNumberFormatProvider();
|
||||
NumberFormat numberFormat = null;
|
||||
switch (choice) {
|
||||
|
@ -929,6 +977,9 @@ public abstract class NumberFormat extends Format {
|
|||
case INTEGERSTYLE:
|
||||
numberFormat = provider.getIntegerInstance(locale);
|
||||
break;
|
||||
case COMPACTSTYLE:
|
||||
numberFormat = provider.getCompactNumberInstance(locale, formatStyle);
|
||||
break;
|
||||
}
|
||||
return numberFormat;
|
||||
}
|
||||
|
@ -1001,6 +1052,7 @@ public abstract class NumberFormat extends Format {
|
|||
private static final int PERCENTSTYLE = 2;
|
||||
private static final int SCIENTIFICSTYLE = 3;
|
||||
private static final int INTEGERSTYLE = 4;
|
||||
private static final int COMPACTSTYLE = 5;
|
||||
|
||||
/**
|
||||
* True if the grouping (i.e. thousands) separator is used when
|
||||
|
@ -1276,5 +1328,43 @@ public abstract class NumberFormat extends Format {
|
|||
* Constant identifying the exponent sign field.
|
||||
*/
|
||||
public static final Field EXPONENT_SIGN = new Field("exponent sign");
|
||||
|
||||
/**
|
||||
* Constant identifying the prefix field.
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public static final Field PREFIX = new Field("prefix");
|
||||
|
||||
/**
|
||||
* Constant identifying the suffix field.
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public static final Field SUFFIX = new Field("suffix");
|
||||
}
|
||||
|
||||
/**
|
||||
* A number format style.
|
||||
* <p>
|
||||
* {@code Style} is an enum which represents the style for formatting
|
||||
* a number within a given {@code NumberFormat} instance.
|
||||
*
|
||||
* @see CompactNumberFormat
|
||||
* @see NumberFormat#getCompactNumberInstance(Locale, Style)
|
||||
* @since 12
|
||||
*/
|
||||
public enum Style {
|
||||
|
||||
/**
|
||||
* The {@code SHORT} number format style.
|
||||
*/
|
||||
SHORT,
|
||||
|
||||
/**
|
||||
* The {@code LONG} number format style.
|
||||
*/
|
||||
LONG
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2018, 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
|
||||
|
@ -110,4 +110,37 @@ public abstract class NumberFormatProvider extends LocaleServiceProvider {
|
|||
* @see java.text.NumberFormat#getPercentInstance(java.util.Locale)
|
||||
*/
|
||||
public abstract NumberFormat getPercentInstance(Locale locale);
|
||||
|
||||
/**
|
||||
* Returns a new {@code NumberFormat} instance which formats
|
||||
* a number in its compact form for the specified
|
||||
* {@code locale} and {@code formatStyle}.
|
||||
*
|
||||
* @implSpec The default implementation of this method throws
|
||||
* {@code UnSupportedOperationException}. Overriding the implementation
|
||||
* of this method returns the compact number formatter instance
|
||||
* of the given {@code locale} with specified {@code formatStyle}.
|
||||
*
|
||||
* @param locale the desired locale
|
||||
* @param formatStyle the style for formatting a number
|
||||
* @throws NullPointerException if {@code locale} or {@code formatStyle}
|
||||
* is {@code null}
|
||||
* @throws IllegalArgumentException if {@code locale} is not
|
||||
* one of the locales returned from
|
||||
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
|
||||
* getAvailableLocales()}.
|
||||
* @return a compact number formatter
|
||||
*
|
||||
* @see java.text.NumberFormat#getCompactNumberInstance(Locale,
|
||||
* NumberFormat.Style)
|
||||
* @since 12
|
||||
*/
|
||||
public NumberFormat getCompactNumberInstance(Locale locale,
|
||||
NumberFormat.Style formatStyle) {
|
||||
throw new UnsupportedOperationException(
|
||||
"The " + this.getClass().getName() + " should override this"
|
||||
+ " method to return compact number format instance of "
|
||||
+ locale + " locale and " + formatStyle + " style.");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -463,7 +463,7 @@ public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
|
|||
|
||||
/**
|
||||
* Returns a
|
||||
* <a href="../../serialized-form.html#java.util.EnumSet.SerializationProxy">
|
||||
* <a href="{@docRoot}/serialized-form.html#java.util.EnumSet.SerializationProxy">
|
||||
* SerializationProxy</a>
|
||||
* representing the state of this instance.
|
||||
*
|
||||
|
|
|
@ -1091,9 +1091,9 @@ final class CollSer implements Serializable {
|
|||
* Creates and returns an immutable collection from this proxy class.
|
||||
* The instance returned is created as if by calling one of the
|
||||
* static factory methods for
|
||||
* <a href="List.html#immutable">List</a>,
|
||||
* <a href="Map.html#immutable">Map</a>, or
|
||||
* <a href="Set.html#immutable">Set</a>.
|
||||
* <a href="List.html#unmodifiable">List</a>,
|
||||
* <a href="Map.html#unmodifiable">Map</a>, or
|
||||
* <a href="Set.html#unmodifiable">Set</a>.
|
||||
* This proxy class is the serial form for all immutable collection instances,
|
||||
* regardless of implementation type. This is necessary to ensure that the
|
||||
* existence of any particular implementation type is kept out of the
|
||||
|
|
|
@ -2226,10 +2226,10 @@ public final class Locale implements Cloneable, Serializable {
|
|||
default:
|
||||
return Arrays.stream(stringList).reduce("",
|
||||
(s1, s2) -> {
|
||||
if (s1.equals("")) {
|
||||
if (s1.isEmpty()) {
|
||||
return s2;
|
||||
}
|
||||
if (s2.equals("")) {
|
||||
if (s2.isEmpty()) {
|
||||
return s1;
|
||||
}
|
||||
return MessageFormat.format(pattern, s1, s2);
|
||||
|
@ -3069,7 +3069,7 @@ public final class Locale implements Cloneable, Serializable {
|
|||
|
||||
private static boolean isSubtagIllFormed(String subtag,
|
||||
boolean isFirstSubtag) {
|
||||
if (subtag.equals("") || subtag.length() > 8) {
|
||||
if (subtag.isEmpty() || subtag.length() > 8) {
|
||||
return true;
|
||||
} else if (subtag.equals("*")) {
|
||||
return false;
|
||||
|
|
|
@ -704,7 +704,7 @@ public abstract class Pack200 {
|
|||
if (impl == null) {
|
||||
// The first time, we must decide which class to use.
|
||||
implName = GetPropertyAction.privilegedGetProperty(prop,"");
|
||||
if (implName != null && !implName.equals(""))
|
||||
if (implName != null && !implName.isEmpty())
|
||||
impl = Class.forName(implName);
|
||||
else if (PACK_PROVIDER.equals(prop))
|
||||
impl = com.sun.java.util.jar.pack.PackerImpl.class;
|
||||
|
|
|
@ -1290,7 +1290,7 @@ public final class Pattern
|
|||
// Construct result
|
||||
int resultSize = matchList.size();
|
||||
if (limit == 0)
|
||||
while (resultSize > 0 && matchList.get(resultSize-1).equals(""))
|
||||
while (resultSize > 0 && matchList.get(resultSize-1).isEmpty())
|
||||
resultSize--;
|
||||
String[] result = new String[resultSize];
|
||||
return matchList.subList(0, resultSize).toArray(result);
|
||||
|
|
|
@ -531,7 +531,7 @@ public class Cipher {
|
|||
public static final Cipher getInstance(String transformation)
|
||||
throws NoSuchAlgorithmException, NoSuchPaddingException
|
||||
{
|
||||
if ((transformation == null) || transformation.equals("")) {
|
||||
if ((transformation == null) || transformation.isEmpty()) {
|
||||
throw new NoSuchAlgorithmException("Null or empty transformation");
|
||||
}
|
||||
List<Transform> transforms = getTransforms(transformation);
|
||||
|
@ -631,7 +631,7 @@ public class Cipher {
|
|||
throws NoSuchAlgorithmException, NoSuchProviderException,
|
||||
NoSuchPaddingException
|
||||
{
|
||||
if ((transformation == null) || transformation.equals("")) {
|
||||
if ((transformation == null) || transformation.isEmpty()) {
|
||||
throw new NoSuchAlgorithmException("Null or empty transformation");
|
||||
}
|
||||
if ((provider == null) || (provider.length() == 0)) {
|
||||
|
@ -698,7 +698,7 @@ public class Cipher {
|
|||
Provider provider)
|
||||
throws NoSuchAlgorithmException, NoSuchPaddingException
|
||||
{
|
||||
if ((transformation == null) || transformation.equals("")) {
|
||||
if ((transformation == null) || transformation.isEmpty()) {
|
||||
throw new NoSuchAlgorithmException("Null or empty transformation");
|
||||
}
|
||||
if (provider == null) {
|
||||
|
@ -2840,4 +2840,4 @@ public class Cipher {
|
|||
sb.append(", algorithm from: ").append(getProviderName());
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -668,7 +668,7 @@ public class SSLParameters {
|
|||
String[] tempProtocols = protocols.clone();
|
||||
|
||||
for (String p : tempProtocols) {
|
||||
if (p == null || p.equals("")) {
|
||||
if (p == null || p.isEmpty()) {
|
||||
throw new IllegalArgumentException(
|
||||
"An element of protocols was null/empty");
|
||||
}
|
||||
|
|
|
@ -105,14 +105,6 @@ class JrtFileSystem extends FileSystem {
|
|||
cleanup();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
cleanup();
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileSystemProvider provider() {
|
||||
return provider;
|
||||
|
|
|
@ -97,10 +97,10 @@ public class URLClassPath {
|
|||
JAVA_VERSION = props.getProperty("java.version");
|
||||
DEBUG = (props.getProperty("sun.misc.URLClassPath.debug") != null);
|
||||
String p = props.getProperty("sun.misc.URLClassPath.disableJarChecking");
|
||||
DISABLE_JAR_CHECKING = p != null ? p.equals("true") || p.equals("") : false;
|
||||
DISABLE_JAR_CHECKING = p != null ? p.equals("true") || p.isEmpty() : false;
|
||||
|
||||
p = props.getProperty("jdk.net.URLClassPath.disableRestrictedPermissions");
|
||||
DISABLE_ACC_CHECKING = p != null ? p.equals("true") || p.equals("") : false;
|
||||
DISABLE_ACC_CHECKING = p != null ? p.equals("true") || p.isEmpty() : false;
|
||||
|
||||
// This property will be removed in a later release
|
||||
p = props.getProperty("jdk.net.URLClassPath.disableClassPathURLCheck", "true");
|
||||
|
@ -805,7 +805,7 @@ public class URLClassPath {
|
|||
private JarFile getJarFile(URL url) throws IOException {
|
||||
// Optimize case where url refers to a local jar file
|
||||
if (isOptimizable(url)) {
|
||||
FileURLMapper p = new FileURLMapper (url);
|
||||
FileURLMapper p = new FileURLMapper(url);
|
||||
if (!p.exists()) {
|
||||
throw new FileNotFoundException(p.getPath());
|
||||
}
|
||||
|
|
|
@ -27,32 +27,40 @@ package jdk.internal.module;
|
|||
|
||||
import java.lang.module.Configuration;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.internal.misc.VM;
|
||||
|
||||
/**
|
||||
* Used by ModuleBootstrap to obtain the archived system modules and finder.
|
||||
*/
|
||||
final class ArchivedModuleGraph {
|
||||
private static String archivedMainModule;
|
||||
private static SystemModules archivedSystemModules;
|
||||
private static ModuleFinder archivedModuleFinder;
|
||||
private static Configuration archivedConfiguration;
|
||||
private static ArchivedModuleGraph archivedModuleGraph;
|
||||
|
||||
private final SystemModules systemModules;
|
||||
private final String mainModule;
|
||||
private final boolean hasSplitPackages;
|
||||
private final boolean hasIncubatorModules;
|
||||
private final ModuleFinder finder;
|
||||
private final Configuration configuration;
|
||||
private final Map<String, Set<String>> concealedPackagesToOpen;
|
||||
private final Map<String, Set<String>> exportedPackagesToOpen;
|
||||
|
||||
private ArchivedModuleGraph(SystemModules modules,
|
||||
private ArchivedModuleGraph(String mainModule,
|
||||
boolean hasSplitPackages,
|
||||
boolean hasIncubatorModules,
|
||||
ModuleFinder finder,
|
||||
Configuration configuration) {
|
||||
this.systemModules = modules;
|
||||
Configuration configuration,
|
||||
Map<String, Set<String>> concealedPackagesToOpen,
|
||||
Map<String, Set<String>> exportedPackagesToOpen) {
|
||||
this.mainModule = mainModule;
|
||||
this.hasSplitPackages = hasSplitPackages;
|
||||
this.hasIncubatorModules = hasIncubatorModules;
|
||||
this.finder = finder;
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
SystemModules systemModules() {
|
||||
return systemModules;
|
||||
this.concealedPackagesToOpen = concealedPackagesToOpen;
|
||||
this.exportedPackagesToOpen = exportedPackagesToOpen;
|
||||
}
|
||||
|
||||
ModuleFinder finder() {
|
||||
|
@ -63,32 +71,54 @@ final class ArchivedModuleGraph {
|
|||
return configuration;
|
||||
}
|
||||
|
||||
// A factory method that ModuleBootstrap can use to obtain the
|
||||
// ArchivedModuleGraph.
|
||||
Map<String, Set<String>> concealedPackagesToOpen() {
|
||||
return concealedPackagesToOpen;
|
||||
}
|
||||
|
||||
Map<String, Set<String>> exportedPackagesToOpen() {
|
||||
return exportedPackagesToOpen;
|
||||
}
|
||||
|
||||
boolean hasSplitPackages() {
|
||||
return hasSplitPackages;
|
||||
}
|
||||
|
||||
boolean hasIncubatorModules() {
|
||||
return hasIncubatorModules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ArchivedModuleGraph for the given initial module.
|
||||
*/
|
||||
static ArchivedModuleGraph get(String mainModule) {
|
||||
if (Objects.equals(mainModule, archivedMainModule)
|
||||
&& archivedSystemModules != null
|
||||
&& archivedModuleFinder != null
|
||||
&& archivedConfiguration != null) {
|
||||
return new ArchivedModuleGraph(archivedSystemModules,
|
||||
archivedModuleFinder,
|
||||
archivedConfiguration);
|
||||
ArchivedModuleGraph graph = archivedModuleGraph;
|
||||
if (graph != null && Objects.equals(mainModule, graph.mainModule)) {
|
||||
return graph;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Used at CDS dump time
|
||||
/**
|
||||
* Archive the module graph for the given initial module.
|
||||
*/
|
||||
static void archive(String mainModule,
|
||||
SystemModules systemModules,
|
||||
boolean hasSplitPackages,
|
||||
boolean hasIncubatorModules,
|
||||
ModuleFinder finder,
|
||||
Configuration configuration) {
|
||||
if (archivedMainModule != null)
|
||||
Configuration configuration,
|
||||
Map<String, Set<String>> concealedPackagesToOpen,
|
||||
Map<String, Set<String>> exportedPackagesToOpen) {
|
||||
if (mainModule != null) {
|
||||
throw new UnsupportedOperationException();
|
||||
archivedMainModule = mainModule;
|
||||
archivedSystemModules = systemModules;
|
||||
archivedModuleFinder = finder;
|
||||
archivedConfiguration = configuration;
|
||||
}
|
||||
archivedModuleGraph = new ArchivedModuleGraph(mainModule,
|
||||
hasSplitPackages,
|
||||
hasIncubatorModules,
|
||||
finder,
|
||||
configuration,
|
||||
concealedPackagesToOpen,
|
||||
exportedPackagesToOpen);
|
||||
}
|
||||
|
||||
static {
|
||||
|
|
|
@ -172,6 +172,8 @@ public final class ModuleBootstrap {
|
|||
boolean haveModulePath = (appModulePath != null || upgradeModulePath != null);
|
||||
boolean needResolution = true;
|
||||
boolean canArchive = false;
|
||||
boolean hasSplitPackages;
|
||||
boolean hasIncubatorModules;
|
||||
|
||||
// If the java heap was archived at CDS dump time and the environment
|
||||
// at dump time matches the current environment then use the archived
|
||||
|
@ -182,8 +184,9 @@ public final class ModuleBootstrap {
|
|||
&& addModules.isEmpty()
|
||||
&& limitModules.isEmpty()
|
||||
&& !isPatched) {
|
||||
systemModules = archivedModuleGraph.systemModules();
|
||||
systemModuleFinder = archivedModuleGraph.finder();
|
||||
hasSplitPackages = archivedModuleGraph.hasSplitPackages();
|
||||
hasIncubatorModules = archivedModuleGraph.hasIncubatorModules();
|
||||
needResolution = (traceOutput != null);
|
||||
} else {
|
||||
if (!haveModulePath && addModules.isEmpty() && limitModules.isEmpty()) {
|
||||
|
@ -205,6 +208,11 @@ public final class ModuleBootstrap {
|
|||
systemModules = new ExplodedSystemModules();
|
||||
systemModuleFinder = SystemModuleFinders.ofSystem();
|
||||
}
|
||||
|
||||
hasSplitPackages = systemModules.hasSplitPackages();
|
||||
hasIncubatorModules = systemModules.hasIncubatorModules();
|
||||
// not using the archived module graph - avoid accidental use
|
||||
archivedModuleGraph = null;
|
||||
}
|
||||
|
||||
Counters.add("jdk.module.boot.1.systemModulesTime", t1);
|
||||
|
@ -395,7 +403,7 @@ public final class ModuleBootstrap {
|
|||
}
|
||||
|
||||
// check for split packages in the modules mapped to the built-in loaders
|
||||
if (systemModules.hasSplitPackages() || isPatched || haveModulePath) {
|
||||
if (hasSplitPackages || isPatched || haveModulePath) {
|
||||
checkSplitPackages(cf, clf);
|
||||
}
|
||||
|
||||
|
@ -415,7 +423,7 @@ public final class ModuleBootstrap {
|
|||
// Step 7: Miscellaneous
|
||||
|
||||
// check incubating status
|
||||
if (systemModules.hasIncubatorModules() || haveModulePath) {
|
||||
if (hasIncubatorModules || haveModulePath) {
|
||||
checkIncubatingStatus(cf);
|
||||
}
|
||||
|
||||
|
@ -423,7 +431,21 @@ public final class ModuleBootstrap {
|
|||
long t7 = System.nanoTime();
|
||||
addExtraReads(bootLayer);
|
||||
boolean extraExportsOrOpens = addExtraExportsAndOpens(bootLayer);
|
||||
addIllegalAccess(upgradeModulePath, systemModules, bootLayer, extraExportsOrOpens);
|
||||
|
||||
Map<String, Set<String>> concealedPackagesToOpen;
|
||||
Map<String, Set<String>> exportedPackagesToOpen;
|
||||
if (archivedModuleGraph != null) {
|
||||
concealedPackagesToOpen = archivedModuleGraph.concealedPackagesToOpen();
|
||||
exportedPackagesToOpen = archivedModuleGraph.exportedPackagesToOpen();
|
||||
} else {
|
||||
concealedPackagesToOpen = systemModules.concealedPackagesToOpen();
|
||||
exportedPackagesToOpen = systemModules.exportedPackagesToOpen();
|
||||
}
|
||||
addIllegalAccess(upgradeModulePath,
|
||||
concealedPackagesToOpen,
|
||||
exportedPackagesToOpen,
|
||||
bootLayer,
|
||||
extraExportsOrOpens);
|
||||
Counters.add("jdk.module.boot.7.adjustModulesTime", t7);
|
||||
|
||||
// save module finders for later use
|
||||
|
@ -436,8 +458,13 @@ public final class ModuleBootstrap {
|
|||
// Module graph can be archived at CDS dump time. Only allow the
|
||||
// unnamed module case for now.
|
||||
if (canArchive && (mainModule == null)) {
|
||||
ArchivedModuleGraph.archive(mainModule, systemModules,
|
||||
systemModuleFinder, cf);
|
||||
ArchivedModuleGraph.archive(mainModule,
|
||||
hasSplitPackages,
|
||||
hasIncubatorModules,
|
||||
systemModuleFinder,
|
||||
cf,
|
||||
concealedPackagesToOpen,
|
||||
exportedPackagesToOpen);
|
||||
}
|
||||
|
||||
// total time to initialize
|
||||
|
@ -738,7 +765,8 @@ public final class ModuleBootstrap {
|
|||
* of system modules in the boot layer to code in unnamed modules.
|
||||
*/
|
||||
private static void addIllegalAccess(ModuleFinder upgradeModulePath,
|
||||
SystemModules systemModules,
|
||||
Map<String, Set<String>> concealedPackagesToOpen,
|
||||
Map<String, Set<String>> exportedPackagesToOpen,
|
||||
ModuleLayer bootLayer,
|
||||
boolean extraExportsOrOpens) {
|
||||
String value = getAndRemoveProperty("jdk.module.illegalAccess");
|
||||
|
@ -764,13 +792,11 @@ public final class ModuleBootstrap {
|
|||
IllegalAccessLogger.Builder builder
|
||||
= new IllegalAccessLogger.Builder(mode, System.err);
|
||||
|
||||
Map<String, Set<String>> map1 = systemModules.concealedPackagesToOpen();
|
||||
Map<String, Set<String>> map2 = systemModules.exportedPackagesToOpen();
|
||||
if (map1.isEmpty() && map2.isEmpty()) {
|
||||
if (concealedPackagesToOpen.isEmpty() && exportedPackagesToOpen.isEmpty()) {
|
||||
// need to generate (exploded build)
|
||||
IllegalAccessMaps maps = IllegalAccessMaps.generate(limitedFinder());
|
||||
map1 = maps.concealedPackagesToOpen();
|
||||
map2 = maps.exportedPackagesToOpen();
|
||||
concealedPackagesToOpen = maps.concealedPackagesToOpen();
|
||||
exportedPackagesToOpen = maps.exportedPackagesToOpen();
|
||||
}
|
||||
|
||||
// open specific packages in the system modules
|
||||
|
@ -789,8 +815,8 @@ public final class ModuleBootstrap {
|
|||
continue;
|
||||
}
|
||||
|
||||
Set<String> concealedPackages = map1.getOrDefault(name, Set.of());
|
||||
Set<String> exportedPackages = map2.getOrDefault(name, Set.of());
|
||||
Set<String> concealedPackages = concealedPackagesToOpen.getOrDefault(name, Set.of());
|
||||
Set<String> exportedPackages = exportedPackagesToOpen.getOrDefault(name, Set.of());
|
||||
|
||||
// refresh the set of concealed and exported packages if needed
|
||||
if (extraExportsOrOpens) {
|
||||
|
|
|
@ -151,16 +151,18 @@ public final class SystemProps {
|
|||
String format) {
|
||||
// Do not override command line setting
|
||||
String baseValue = cmdProps.getProperty(base);
|
||||
if (baseValue == null) {
|
||||
// Not overridden on the command line; define the properties if there are platform defined values
|
||||
baseValue = display;
|
||||
}
|
||||
if (baseValue != null) {
|
||||
cmdProps.put(base, baseValue);
|
||||
return; // Do not override value from the command line
|
||||
}
|
||||
|
||||
// Not overridden on the command line; define the properties if there are platform defined values
|
||||
if (display != null) {
|
||||
cmdProps.put(base, display);
|
||||
baseValue = display;
|
||||
}
|
||||
|
||||
/* user.xxx.display property */
|
||||
String disp = base + ".display";
|
||||
String disp = base.concat(".display");
|
||||
String dispValue = cmdProps.getProperty(disp);
|
||||
if (dispValue == null && display != null && !display.equals(baseValue)) {
|
||||
// Create the property only if different from the base property
|
||||
|
@ -168,7 +170,7 @@ public final class SystemProps {
|
|||
}
|
||||
|
||||
/* user.xxx.format property */
|
||||
String fmt = base + ".format";
|
||||
String fmt = base.concat(".format");
|
||||
String fmtValue = cmdProps.getProperty(fmt);
|
||||
if (fmtValue == null && format != null && !format.equals(baseValue)) {
|
||||
// Create the property only if different than the base property
|
||||
|
|
|
@ -79,6 +79,7 @@ module java.base {
|
|||
exports java.io;
|
||||
exports java.lang;
|
||||
exports java.lang.annotation;
|
||||
exports java.lang.constant;
|
||||
exports java.lang.invoke;
|
||||
exports java.lang.module;
|
||||
exports java.lang.ref;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2018, 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
|
||||
|
@ -47,6 +47,7 @@ public enum Wrapper {
|
|||
private final Class<?> wrapperType;
|
||||
private final Class<?> primitiveType;
|
||||
private final char basicTypeChar;
|
||||
private final String basicTypeString;
|
||||
private final Object emptyArray;
|
||||
private final int format;
|
||||
private final String wrapperSimpleName;
|
||||
|
@ -56,6 +57,7 @@ public enum Wrapper {
|
|||
this.wrapperType = wtype;
|
||||
this.primitiveType = ptype;
|
||||
this.basicTypeChar = tchar;
|
||||
this.basicTypeString = new String(new char[] {this.basicTypeChar});
|
||||
this.emptyArray = emptyArray;
|
||||
this.format = format;
|
||||
this.wrapperSimpleName = wtypeName;
|
||||
|
@ -459,6 +461,11 @@ public enum Wrapper {
|
|||
*/
|
||||
public char basicTypeChar() { return basicTypeChar; }
|
||||
|
||||
/** What is the bytecode signature string for this wrapper's
|
||||
* primitive type?
|
||||
*/
|
||||
public String basicTypeString() { return basicTypeString; }
|
||||
|
||||
/** What is the simple name of the wrapper type?
|
||||
*/
|
||||
public String wrapperSimpleName() { return wrapperSimpleName; }
|
||||
|
@ -581,9 +588,8 @@ public enum Wrapper {
|
|||
* Returns null for {@code VOID}.
|
||||
*/
|
||||
public Object wrap(int x) {
|
||||
if (basicTypeChar == 'L') return (Integer)x;
|
||||
switch (basicTypeChar) {
|
||||
case 'L': throw newIllegalArgumentException("cannot wrap to object type");
|
||||
case 'L': return (Integer)x;
|
||||
case 'V': return null;
|
||||
case 'I': return Integer.valueOf(x);
|
||||
case 'J': return Long.valueOf(x);
|
||||
|
|
|
@ -111,7 +111,7 @@ public class URLJarFile extends JarFile {
|
|||
* 'file:' URLs can be accessible through ftp.
|
||||
*/
|
||||
String host = url.getHost();
|
||||
if (host == null || host.equals("") || host.equals("~") ||
|
||||
if (host == null || host.isEmpty() || host.equals("~") ||
|
||||
host.equalsIgnoreCase("localhost"))
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ public class Handler extends URLStreamHandler {
|
|||
* Let's just make sure we DO have an Email address in the URL.
|
||||
*/
|
||||
boolean nogood = false;
|
||||
if (file == null || file.equals(""))
|
||||
if (file == null || file.isEmpty())
|
||||
nogood = true;
|
||||
else {
|
||||
boolean allwhites = true;
|
||||
|
|
|
@ -1608,7 +1608,7 @@ public class PolicyFile extends java.security.Policy {
|
|||
if (u.getProtocol().equals("file")) {
|
||||
boolean isLocalFile = false;
|
||||
String host = u.getHost();
|
||||
isLocalFile = (host == null || host.equals("") ||
|
||||
isLocalFile = (host == null || host.isEmpty() ||
|
||||
host.equals("~") || host.equalsIgnoreCase("localhost"));
|
||||
|
||||
if (isLocalFile) {
|
||||
|
|
|
@ -518,10 +518,10 @@ final class HandshakeHash {
|
|||
JsseJce.getMessageDigest(cipherSuite.hashAlg.name);
|
||||
if (md instanceof Cloneable) {
|
||||
transcriptHash = new CloneableHash(md);
|
||||
this.baos = null;
|
||||
this.baos = new ByteArrayOutputStream();
|
||||
} else {
|
||||
transcriptHash = new NonCloneableHash(md);
|
||||
this.baos = new ByteArrayOutputStream();
|
||||
this.baos = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -550,26 +550,20 @@ final class HandshakeHash {
|
|||
|
||||
static final class T13HandshakeHash implements TranscriptHash {
|
||||
private final TranscriptHash transcriptHash;
|
||||
private final ByteArrayOutputStream baos;
|
||||
|
||||
T13HandshakeHash(CipherSuite cipherSuite) {
|
||||
MessageDigest md =
|
||||
JsseJce.getMessageDigest(cipherSuite.hashAlg.name);
|
||||
if (md instanceof Cloneable) {
|
||||
transcriptHash = new CloneableHash(md);
|
||||
this.baos = null;
|
||||
} else {
|
||||
transcriptHash = new NonCloneableHash(md);
|
||||
this.baos = new ByteArrayOutputStream();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(byte[] input, int offset, int length) {
|
||||
transcriptHash.update(input, offset, length);
|
||||
if (baos != null) {
|
||||
baos.write(input, offset, length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -579,13 +573,9 @@ final class HandshakeHash {
|
|||
|
||||
@Override
|
||||
public byte[] archived() {
|
||||
if (baos != null) {
|
||||
return baos.toByteArray();
|
||||
} else {
|
||||
return transcriptHash.archived();
|
||||
}
|
||||
|
||||
// throw new UnsupportedOperationException("Not supported yet.");
|
||||
// This method is not necessary in T13
|
||||
throw new UnsupportedOperationException(
|
||||
"TLS 1.3 does not require archived.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -176,7 +176,11 @@ final class SSLSessionImpl extends ExtendedSSLSession {
|
|||
|
||||
/*
|
||||
* Record a new session, using a given cipher spec, session ID,
|
||||
* and creation time
|
||||
* and creation time.
|
||||
* Note: For the unmodifiable collections and lists we are creating new
|
||||
* collections as inputs to avoid potential deep nesting of
|
||||
* unmodifiable collections that can cause StackOverflowErrors
|
||||
* (see JDK-6323374).
|
||||
*/
|
||||
SSLSessionImpl(HandshakeContext hc,
|
||||
CipherSuite cipherSuite, SessionId id, long creationTime) {
|
||||
|
@ -187,10 +191,11 @@ final class SSLSessionImpl extends ExtendedSSLSession {
|
|||
this.port = hc.conContext.transport.getPeerPort();
|
||||
this.localSupportedSignAlgs = hc.localSupportedSignAlgs == null ?
|
||||
Collections.emptySet() :
|
||||
Collections.unmodifiableCollection(hc.localSupportedSignAlgs);
|
||||
Collections.unmodifiableCollection(
|
||||
new ArrayList<>(hc.localSupportedSignAlgs));
|
||||
this.serverNameIndication = hc.negotiatedServerName;
|
||||
this.requestedServerNames = Collections.<SNIServerName>unmodifiableList(
|
||||
hc.getRequestedServerNames());
|
||||
this.requestedServerNames = Collections.unmodifiableList(
|
||||
new ArrayList<>(hc.getRequestedServerNames()));
|
||||
if (hc.sslConfig.isClientMode) {
|
||||
this.useExtendedMasterSecret =
|
||||
(hc.handshakeExtensions.get(
|
||||
|
@ -219,10 +224,8 @@ final class SSLSessionImpl extends ExtendedSSLSession {
|
|||
this.host = baseSession.getPeerHost();
|
||||
this.port = baseSession.getPeerPort();
|
||||
this.localSupportedSignAlgs =
|
||||
baseSession.localSupportedSignAlgs == null ?
|
||||
Collections.emptySet() :
|
||||
Collections.unmodifiableCollection(
|
||||
baseSession.localSupportedSignAlgs);
|
||||
baseSession.localSupportedSignAlgs == null ?
|
||||
Collections.emptySet() : baseSession.localSupportedSignAlgs;
|
||||
this.peerSupportedSignAlgs =
|
||||
baseSession.getPeerSupportedSignatureAlgorithms();
|
||||
this.serverNameIndication = baseSession.serverNameIndication;
|
||||
|
|
|
@ -82,9 +82,15 @@ final class ServerNameExtension {
|
|||
// +2: Name length
|
||||
final List<SNIServerName> serverNames;
|
||||
|
||||
/*
|
||||
* Note: For the unmodifiable collection we are creating new
|
||||
* collections as inputs to avoid potential deep nesting of
|
||||
* unmodifiable collections that can cause StackOverflowErrors
|
||||
* (see JDK-6323374).
|
||||
*/
|
||||
private CHServerNamesSpec(List<SNIServerName> serverNames) {
|
||||
this.serverNames =
|
||||
Collections.<SNIServerName>unmodifiableList(serverNames);
|
||||
this.serverNames = Collections.<SNIServerName>unmodifiableList(
|
||||
new ArrayList<>(serverNames));
|
||||
}
|
||||
|
||||
private CHServerNamesSpec(ByteBuffer buffer) throws IOException {
|
||||
|
|
|
@ -103,7 +103,7 @@ public class ConsoleCallbackHandler implements CallbackHandler {
|
|||
System.err.flush();
|
||||
|
||||
String result = readLine();
|
||||
if (result.equals("")) {
|
||||
if (result.isEmpty()) {
|
||||
result = nc.getDefaultName();
|
||||
}
|
||||
|
||||
|
@ -212,7 +212,7 @@ public class ConsoleCallbackHandler implements CallbackHandler {
|
|||
prompt = "";
|
||||
}
|
||||
prompt = prefix + prompt;
|
||||
if (!prompt.equals("")) {
|
||||
if (!prompt.isEmpty()) {
|
||||
System.err.println(prompt);
|
||||
}
|
||||
|
||||
|
|
|
@ -363,7 +363,7 @@ class DomainName {
|
|||
}
|
||||
|
||||
private static int numLabels(String rule) {
|
||||
if (rule.equals("")) {
|
||||
if (rule.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
int len = rule.length();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -34,16 +34,17 @@ import sun.security.util.*;
|
|||
* This class implements the DNSName as required by the GeneralNames
|
||||
* ASN.1 object.
|
||||
* <p>
|
||||
* [RFC2459] When the subjectAltName extension contains a domain name service
|
||||
* [RFC5280] When the subjectAltName extension contains a domain name system
|
||||
* label, the domain name MUST be stored in the dNSName (an IA5String).
|
||||
* The name MUST be in the "preferred name syntax," as specified by RFC
|
||||
* 1034 [RFC 1034]. Note that while upper and lower case letters are
|
||||
* allowed in domain names, no signifigance is attached to the case. In
|
||||
* The name MUST be in the "preferred name syntax", as specified by
|
||||
* Section 3.5 of [RFC1034] and as modified by Section 2.1 of
|
||||
* [RFC1123]. Note that while uppercase and lowercase letters are
|
||||
* allowed in domain names, no significance is attached to the case. In
|
||||
* addition, while the string " " is a legal domain name, subjectAltName
|
||||
* extensions with a dNSName " " are not permitted. Finally, the use of
|
||||
* the DNS representation for Internet mail addresses (wpolk.nist.gov
|
||||
* instead of wpolk@nist.gov) is not permitted; such identities are to
|
||||
* be encoded as rfc822Name.
|
||||
* extensions with a dNSName of " " MUST NOT be used. Finally, the use
|
||||
* of the DNS representation for Internet mail addresses
|
||||
* (subscriber.example.com instead of subscriber@example.com) MUST NOT
|
||||
* be used; such identities are to be encoded as rfc822Name.
|
||||
*
|
||||
* @author Amit Kapoor
|
||||
* @author Hemma Prafullchandra
|
||||
|
@ -51,9 +52,8 @@ import sun.security.util.*;
|
|||
public class DNSName implements GeneralNameInterface {
|
||||
private String name;
|
||||
|
||||
private static final String alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
private static final String digitsAndHyphen = "0123456789-";
|
||||
private static final String alphaDigitsAndHyphen = alpha + digitsAndHyphen;
|
||||
private static final String alphaDigits =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
|
||||
/**
|
||||
* Create the DNSName object from the passed encoded Der value.
|
||||
|
@ -73,35 +73,38 @@ public class DNSName implements GeneralNameInterface {
|
|||
*/
|
||||
public DNSName(String name) throws IOException {
|
||||
if (name == null || name.length() == 0)
|
||||
throw new IOException("DNS name must not be null");
|
||||
if (name.indexOf(' ') != -1)
|
||||
throw new IOException("DNS names or NameConstraints with blank components are not permitted");
|
||||
if (name.charAt(0) == '.' || name.charAt(name.length() -1) == '.')
|
||||
throw new IOException("DNS names or NameConstraints may not begin or end with a .");
|
||||
//Name will consist of label components separated by "."
|
||||
//startIndex is the index of the first character of a component
|
||||
//endIndex is the index of the last character of a component plus 1
|
||||
for (int endIndex,startIndex=0; startIndex < name.length(); startIndex = endIndex+1) {
|
||||
throw new IOException("DNSName must not be null or empty");
|
||||
if (name.contains(" "))
|
||||
throw new IOException("DNSName with blank components is not permitted");
|
||||
if (name.startsWith(".") || name.endsWith("."))
|
||||
throw new IOException("DNSName may not begin or end with a .");
|
||||
/*
|
||||
* Name will consist of label components separated by "."
|
||||
* startIndex is the index of the first character of a component
|
||||
* endIndex is the index of the last character of a component plus 1
|
||||
*/
|
||||
for (int endIndex,startIndex = 0; startIndex < name.length(); startIndex = endIndex+1) {
|
||||
endIndex = name.indexOf('.', startIndex);
|
||||
if (endIndex < 0) {
|
||||
endIndex = name.length();
|
||||
}
|
||||
if ((endIndex-startIndex) < 1)
|
||||
throw new IOException("DNSName SubjectAltNames with empty components are not permitted");
|
||||
if (endIndex - startIndex < 1)
|
||||
throw new IOException("DNSName with empty components are not permitted");
|
||||
|
||||
//DNSName components must begin with a letter A-Z or a-z
|
||||
if (alpha.indexOf(name.charAt(startIndex)) < 0)
|
||||
throw new IOException("DNSName components must begin with a letter");
|
||||
// RFC 1123: DNSName components must begin with a letter or digit
|
||||
if (alphaDigits.indexOf(name.charAt(startIndex)) < 0)
|
||||
throw new IOException("DNSName components must begin with a letter or digit");
|
||||
//nonStartIndex: index for characters in the component beyond the first one
|
||||
for (int nonStartIndex=startIndex+1; nonStartIndex < endIndex; nonStartIndex++) {
|
||||
char x = name.charAt(nonStartIndex);
|
||||
if ((alphaDigitsAndHyphen).indexOf(x) < 0)
|
||||
if ((alphaDigits).indexOf(x) < 0 && x != '-')
|
||||
throw new IOException("DNSName components must consist of letters, digits, and hyphens");
|
||||
}
|
||||
}
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the type of the GeneralName.
|
||||
*/
|
||||
|
@ -117,7 +120,7 @@ public class DNSName implements GeneralNameInterface {
|
|||
}
|
||||
|
||||
/**
|
||||
* Encode the DNS name into the DerOutputStream.
|
||||
* Encode the DNSName into the DerOutputStream.
|
||||
*
|
||||
* @param out the DER stream to encode the DNSName to.
|
||||
* @exception IOException on encoding errors.
|
||||
|
@ -137,7 +140,7 @@ public class DNSName implements GeneralNameInterface {
|
|||
* Compares this name with another, for equality.
|
||||
*
|
||||
* @return true iff the names are equivalent
|
||||
* according to RFC2459.
|
||||
* according to RFC5280.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
|
@ -148,7 +151,7 @@ public class DNSName implements GeneralNameInterface {
|
|||
|
||||
DNSName other = (DNSName)obj;
|
||||
|
||||
// RFC2459 mandates that these names are
|
||||
// RFC5280 mandates that these names are
|
||||
// not case-sensitive
|
||||
return name.equalsIgnoreCase(other.name);
|
||||
}
|
||||
|
@ -172,12 +175,14 @@ public class DNSName implements GeneralNameInterface {
|
|||
* </ul>. These results are used in checking NameConstraints during
|
||||
* certification path verification.
|
||||
* <p>
|
||||
* RFC2459: DNS name restrictions are expressed as foo.bar.com. Any subdomain
|
||||
* satisfies the name constraint. For example, www.foo.bar.com would
|
||||
* satisfy the constraint but bigfoo.bar.com would not.
|
||||
* RFC5280: DNS name restrictions are expressed as host.example.com.
|
||||
* Any DNS name that can be constructed by simply adding zero or more
|
||||
* labels to the left-hand side of the name satisfies the name constraint.
|
||||
* For example, www.host.example.com would satisfy the constraint but
|
||||
* host1.example.com would not.
|
||||
* <p>
|
||||
* draft-ietf-pkix-new-part1-00.txt: DNS name restrictions are expressed as foo.bar.com.
|
||||
* Any DNS name that
|
||||
* draft-ietf-pkix-new-part1-00.txt: DNSName restrictions are expressed as foo.bar.com.
|
||||
* Any DNSName that
|
||||
* can be constructed by simply adding to the left hand side of the name
|
||||
* satisfies the name constraint. For example, www.foo.bar.com would
|
||||
* satisfy the constraint but foo1.bar.com would not.
|
||||
|
|
|
@ -112,7 +112,7 @@ public class GeneralName {
|
|||
encName.resetTag(DerValue.tag_IA5String);
|
||||
name = new DNSName(encName);
|
||||
} else {
|
||||
throw new IOException("Invalid encoding of DNS name");
|
||||
throw new IOException("Invalid encoding of DNSName");
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -246,7 +246,7 @@ public class RFC822Name implements GeneralNameInterface
|
|||
subtree=subtree.substring(atNdx+1);
|
||||
}
|
||||
|
||||
/* count dots in dnsname, adding one if dnsname preceded by @ */
|
||||
/* count dots in DNSName, adding one if DNSName preceded by @ */
|
||||
for (; subtree.lastIndexOf('.') >= 0; i++) {
|
||||
subtree=subtree.substring(0,subtree.lastIndexOf('.'));
|
||||
}
|
||||
|
|
|
@ -131,13 +131,13 @@ public class URIName implements GeneralNameInterface {
|
|||
try {
|
||||
hostDNS = new DNSName(host);
|
||||
} catch (IOException ioe) {
|
||||
// Not a valid DNS Name; see if it is a valid IPv4
|
||||
// Not a valid DNSName; see if it is a valid IPv4
|
||||
// IPAddressName
|
||||
try {
|
||||
hostIP = new IPAddressName(host);
|
||||
} catch (Exception ioe2) {
|
||||
throw new IOException("invalid URI name (host " +
|
||||
"portion is not a valid DNS name, IPv4 address," +
|
||||
"portion is not a valid DNSName, IPv4 address," +
|
||||
" or IPv6 address):" + name);
|
||||
}
|
||||
}
|
||||
|
@ -339,7 +339,7 @@ public class URIName implements GeneralNameInterface {
|
|||
// If one (or both) is an IP address, only same type
|
||||
constraintType = NAME_SAME_TYPE;
|
||||
} else {
|
||||
// Both host portions are DNS names. Are they domains?
|
||||
// Both host portions are DNSNames. Are they domains?
|
||||
boolean thisDomain = (host.charAt(0) == '.');
|
||||
boolean otherDomain = (otherHost.charAt(0) == '.');
|
||||
DNSName otherDNS = (DNSName) otherHostObject;
|
||||
|
|
|
@ -1213,7 +1213,7 @@ public class X500Name implements GeneralNameInterface, Principal {
|
|||
*/
|
||||
|
||||
/*
|
||||
* OID for "DC=" domain component attributes, used with DNS names in DN
|
||||
* OID for "DC=" domain component attributes, used with DNSNames in DN
|
||||
* format
|
||||
*/
|
||||
DOMAIN_COMPONENT_OID =
|
||||
|
|
|
@ -796,6 +796,44 @@ public class FormatData extends ParallelListResourceBundle {
|
|||
"NaN",
|
||||
}
|
||||
},
|
||||
{ "short.CompactNumberPatterns",
|
||||
new String[] {
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"0K",
|
||||
"00K",
|
||||
"000K",
|
||||
"0M",
|
||||
"00M",
|
||||
"000M",
|
||||
"0B",
|
||||
"00B",
|
||||
"000B",
|
||||
"0T",
|
||||
"00T",
|
||||
"000T",
|
||||
}
|
||||
},
|
||||
{ "long.CompactNumberPatterns",
|
||||
new String[] {
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"0 thousand",
|
||||
"00 thousand",
|
||||
"000 thousand",
|
||||
"0 million",
|
||||
"00 million",
|
||||
"000 million",
|
||||
"0 billion",
|
||||
"00 billion",
|
||||
"000 billion",
|
||||
"0 trillion",
|
||||
"00 trillion",
|
||||
"000 trillion",
|
||||
}
|
||||
},
|
||||
{ "TimePatterns",
|
||||
new String[] {
|
||||
"h:mm:ss a z", // full time pattern
|
||||
|
|
|
@ -43,6 +43,7 @@ package sun.util.locale.provider;
|
|||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.text.MessageFormat;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
|
@ -88,6 +89,7 @@ public class LocaleResources {
|
|||
private static final String ZONE_IDS_CACHEKEY = "ZID";
|
||||
private static final String CALENDAR_NAMES = "CALN.";
|
||||
private static final String NUMBER_PATTERNS_CACHEKEY = "NP";
|
||||
private static final String COMPACT_NUMBER_PATTERNS_CACHEKEY = "CNP";
|
||||
private static final String DATE_TIME_PATTERN = "DTP.";
|
||||
|
||||
// TimeZoneNamesBundle exemplar city prefix
|
||||
|
@ -478,6 +480,32 @@ public class LocaleResources {
|
|||
return numberPatterns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the compact number format patterns.
|
||||
* @param formatStyle the style for formatting a number
|
||||
* @return an array of compact number patterns
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public String[] getCNPatterns(NumberFormat.Style formatStyle) {
|
||||
|
||||
Objects.requireNonNull(formatStyle);
|
||||
String[] compactNumberPatterns = null;
|
||||
removeEmptyReferences();
|
||||
String width = (formatStyle == NumberFormat.Style.LONG) ? "long" : "short";
|
||||
String cacheKey = width + "." + COMPACT_NUMBER_PATTERNS_CACHEKEY;
|
||||
ResourceReference data = cache.get(cacheKey);
|
||||
if (data == null || ((compactNumberPatterns
|
||||
= (String[]) data.get()) == null)) {
|
||||
ResourceBundle resource = localeData.getNumberFormatData(locale);
|
||||
compactNumberPatterns = (String[]) resource
|
||||
.getObject(width + ".CompactNumberPatterns");
|
||||
cache.put(cacheKey, new ResourceReference(cacheKey,
|
||||
(Object) compactNumberPatterns, referenceQueue));
|
||||
}
|
||||
return compactNumberPatterns;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the FormatData resource bundle of this LocaleResources.
|
||||
* The FormatData should be used only for accessing extra
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2018, 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
|
||||
|
@ -40,12 +40,14 @@
|
|||
|
||||
package sun.util.locale.provider;
|
||||
|
||||
import java.text.CompactNumberFormat;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.spi.NumberFormatProvider;
|
||||
import java.util.Currency;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
@ -225,6 +227,49 @@ public class NumberFormatProviderImpl extends NumberFormatProvider implements Av
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@code NumberFormat} instance which formats
|
||||
* a number in its compact form for the specified
|
||||
* {@code locale} and {@code formatStyle}.
|
||||
*
|
||||
* @param locale the desired locale
|
||||
* @param formatStyle the style for formatting a number
|
||||
* @throws NullPointerException if {@code locale} or {@code formatStyle}
|
||||
* is {@code null}
|
||||
* @throws IllegalArgumentException if {@code locale} isn't
|
||||
* one of the locales returned from
|
||||
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
|
||||
* getAvailableLocales()}.
|
||||
* @return a compact number formatter
|
||||
*
|
||||
* @see java.text.NumberFormat#getCompactNumberInstance(Locale,
|
||||
* NumberFormat.Style)
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public NumberFormat getCompactNumberInstance(Locale locale,
|
||||
NumberFormat.Style formatStyle) {
|
||||
|
||||
Objects.requireNonNull(locale);
|
||||
Objects.requireNonNull(formatStyle);
|
||||
|
||||
// Check for region override
|
||||
Locale override = locale.getUnicodeLocaleType("nu") == null
|
||||
? CalendarDataUtility.findRegionOverride(locale)
|
||||
: locale;
|
||||
|
||||
LocaleProviderAdapter adapter = LocaleProviderAdapter.forType(type);
|
||||
LocaleResources resource = adapter.getLocaleResources(override);
|
||||
|
||||
String[] numberPatterns = resource.getNumberPatterns();
|
||||
DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(override);
|
||||
String[] cnPatterns = resource.getCNPatterns(formatStyle);
|
||||
|
||||
CompactNumberFormat format = new CompactNumberFormat(numberPatterns[0],
|
||||
symbols, cnPatterns);
|
||||
return format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getAvailableLanguageTags() {
|
||||
return langtags;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue