8338532: Speed up the ClassFile API MethodTypeDesc#ofDescriptor
Reviewed-by: redestad, liach
This commit is contained in:
parent
918cf11454
commit
3aeb6733f9
@ -36,6 +36,7 @@ import static java.util.stream.Collectors.joining;
|
||||
import static jdk.internal.constant.ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS;
|
||||
import static jdk.internal.constant.ConstantUtils.arrayDepth;
|
||||
import static jdk.internal.constant.ConstantUtils.binaryToInternal;
|
||||
import static jdk.internal.constant.ConstantUtils.forPrimitiveType;
|
||||
import static jdk.internal.constant.ConstantUtils.internalToBinary;
|
||||
import static jdk.internal.constant.ConstantUtils.validateBinaryClassName;
|
||||
import static jdk.internal.constant.ConstantUtils.validateInternalClassName;
|
||||
@ -164,7 +165,7 @@ public sealed interface ClassDesc
|
||||
static ClassDesc ofDescriptor(String descriptor) {
|
||||
// implicit null-check
|
||||
return (descriptor.length() == 1)
|
||||
? Wrapper.forPrimitiveType(descriptor.charAt(0)).basicClassDescriptor()
|
||||
? forPrimitiveType(descriptor, 0)
|
||||
// will throw IAE on descriptor.length == 0 or if array dimensions too long
|
||||
: ReferenceClassDescImpl.of(descriptor);
|
||||
}
|
||||
|
@ -240,31 +240,31 @@ public final class ConstantDescs {
|
||||
CD_Object, CD_Object);
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code int} */
|
||||
public static final ClassDesc CD_int = new PrimitiveClassDescImpl("I");
|
||||
public static final ClassDesc CD_int = PrimitiveClassDescImpl.CD_int;
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code long} */
|
||||
public static final ClassDesc CD_long = new PrimitiveClassDescImpl("J");
|
||||
public static final ClassDesc CD_long = PrimitiveClassDescImpl.CD_long;
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code float} */
|
||||
public static final ClassDesc CD_float = new PrimitiveClassDescImpl("F");
|
||||
public static final ClassDesc CD_float = PrimitiveClassDescImpl.CD_float;
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code double} */
|
||||
public static final ClassDesc CD_double = new PrimitiveClassDescImpl("D");
|
||||
public static final ClassDesc CD_double = PrimitiveClassDescImpl.CD_double;
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code short} */
|
||||
public static final ClassDesc CD_short = new PrimitiveClassDescImpl("S");
|
||||
public static final ClassDesc CD_short = PrimitiveClassDescImpl.CD_short;
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code byte} */
|
||||
public static final ClassDesc CD_byte = new PrimitiveClassDescImpl("B");
|
||||
public static final ClassDesc CD_byte = PrimitiveClassDescImpl.CD_byte;
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code char} */
|
||||
public static final ClassDesc CD_char = new PrimitiveClassDescImpl("C");
|
||||
public static final ClassDesc CD_char = PrimitiveClassDescImpl.CD_char;
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code boolean} */
|
||||
public static final ClassDesc CD_boolean = new PrimitiveClassDescImpl("Z");
|
||||
public static final ClassDesc CD_boolean = PrimitiveClassDescImpl.CD_boolean;
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code void} */
|
||||
public static final ClassDesc CD_void = new PrimitiveClassDescImpl("V");
|
||||
public static final ClassDesc CD_void = PrimitiveClassDescImpl.CD_void;
|
||||
|
||||
/**
|
||||
* {@link MethodHandleDesc} representing {@link MethodHandles#classData(Lookup, String, Class) MethodHandles.classData}
|
||||
|
@ -25,6 +25,7 @@
|
||||
package java.lang.invoke;
|
||||
|
||||
import sun.invoke.util.Wrapper;
|
||||
import jdk.internal.constant.ConstantUtils;
|
||||
|
||||
import static java.lang.invoke.MethodHandleNatives.mapLookupExceptionToError;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
@ -112,7 +113,7 @@ public final class ConstantBootstraps {
|
||||
throw new IllegalArgumentException(String.format("not primitive: %s", name));
|
||||
}
|
||||
|
||||
return Wrapper.forPrimitiveType(name.charAt(0)).primitiveType();
|
||||
return ConstantUtils.forPrimitiveType(name, 0).resolveConstantDesc(lookup);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -35,6 +35,8 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static jdk.internal.constant.PrimitiveClassDescImpl.*;
|
||||
|
||||
/**
|
||||
* Helper methods for the implementation of {@code java.lang.constant}.
|
||||
*/
|
||||
@ -269,59 +271,40 @@ public final class ConstantUtils {
|
||||
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
|
||||
*/
|
||||
public static List<ClassDesc> parseMethodDescriptor(String descriptor) {
|
||||
int cur = 0, end = descriptor.length();
|
||||
ArrayList<ClassDesc> ptypes = new ArrayList<>();
|
||||
ptypes.add(null); // placeholder for return type
|
||||
|
||||
if (cur >= end || descriptor.charAt(cur) != '(')
|
||||
throw new IllegalArgumentException("Bad method descriptor: " + descriptor);
|
||||
|
||||
++cur; // skip '('
|
||||
while (cur < end && descriptor.charAt(cur) != ')') {
|
||||
int len = skipOverFieldSignature(descriptor, cur, end, false);
|
||||
if (len == 0)
|
||||
throw new IllegalArgumentException("Bad method descriptor: " + descriptor);
|
||||
ptypes.add(resolveClassDesc(descriptor, cur, len));
|
||||
cur += len;
|
||||
}
|
||||
if (cur >= end)
|
||||
throw new IllegalArgumentException("Bad method descriptor: " + descriptor);
|
||||
++cur; // skip ')'
|
||||
|
||||
int rLen = skipOverFieldSignature(descriptor, cur, end, true);
|
||||
if (rLen == 0 || cur + rLen != end)
|
||||
throw new IllegalArgumentException("Bad method descriptor: " + descriptor);
|
||||
ptypes.set(0, resolveClassDesc(descriptor, cur, rLen));
|
||||
return ptypes;
|
||||
public static PrimitiveClassDescImpl forPrimitiveType(String descriptor, int offset) {
|
||||
return switch (descriptor.charAt(offset)) {
|
||||
case JVM_SIGNATURE_BYTE -> CD_byte;
|
||||
case JVM_SIGNATURE_CHAR -> CD_char;
|
||||
case JVM_SIGNATURE_FLOAT -> CD_float;
|
||||
case JVM_SIGNATURE_DOUBLE -> CD_double;
|
||||
case JVM_SIGNATURE_INT -> CD_int;
|
||||
case JVM_SIGNATURE_LONG -> CD_long;
|
||||
case JVM_SIGNATURE_SHORT -> CD_short;
|
||||
case JVM_SIGNATURE_VOID -> CD_void;
|
||||
case JVM_SIGNATURE_BOOLEAN -> CD_boolean;
|
||||
default -> throw badMethodDescriptor(descriptor);
|
||||
};
|
||||
}
|
||||
|
||||
private static ClassDesc resolveClassDesc(String descriptor, int start, int len) {
|
||||
static ClassDesc resolveClassDesc(String descriptor, int start, int len) {
|
||||
if (len == 1) {
|
||||
return Wrapper.forPrimitiveType(descriptor.charAt(start)).basicClassDescriptor();
|
||||
return forPrimitiveType(descriptor, start);
|
||||
}
|
||||
// Pre-verified in parseMethodDescriptor; avoid redundant verification
|
||||
|
||||
// Pre-verified in MethodTypeDescImpl#ofDescriptor; avoid redundant verification
|
||||
return ReferenceClassDescImpl.ofValidated(descriptor.substring(start, start + len));
|
||||
}
|
||||
|
||||
static IllegalArgumentException badMethodDescriptor(String descriptor) {
|
||||
return new IllegalArgumentException("Bad method descriptor: " + descriptor);
|
||||
}
|
||||
|
||||
private static final char JVM_SIGNATURE_ARRAY = '[';
|
||||
private static final char JVM_SIGNATURE_BYTE = 'B';
|
||||
private static final char JVM_SIGNATURE_CHAR = 'C';
|
||||
private static final char JVM_SIGNATURE_CLASS = 'L';
|
||||
private static final char JVM_SIGNATURE_ENDCLASS = ';';
|
||||
private static final char JVM_SIGNATURE_ENUM = 'E';
|
||||
private static final char JVM_SIGNATURE_FLOAT = 'F';
|
||||
private static final char JVM_SIGNATURE_DOUBLE = 'D';
|
||||
private static final char JVM_SIGNATURE_FUNC = '(';
|
||||
private static final char JVM_SIGNATURE_ENDFUNC = ')';
|
||||
private static final char JVM_SIGNATURE_INT = 'I';
|
||||
private static final char JVM_SIGNATURE_LONG = 'J';
|
||||
private static final char JVM_SIGNATURE_SHORT = 'S';
|
||||
@ -334,17 +317,22 @@ public final class ConstantUtils {
|
||||
* @param descriptor the descriptor string
|
||||
* @param start the starting index into the string
|
||||
* @param end the ending index within the string
|
||||
* @param voidOK is void acceptable?
|
||||
* @return the length of the descriptor, or 0 if it is not a descriptor
|
||||
* @throws IllegalArgumentException if the descriptor string is not valid
|
||||
*/
|
||||
@SuppressWarnings("fallthrough")
|
||||
static int skipOverFieldSignature(String descriptor, int start, int end, boolean voidOK) {
|
||||
static int skipOverFieldSignature(String descriptor, int start, int end) {
|
||||
int arrayDim = 0;
|
||||
int index = start;
|
||||
while (index < end) {
|
||||
switch (descriptor.charAt(index)) {
|
||||
case JVM_SIGNATURE_VOID: if (!voidOK) { return 0; }
|
||||
if (index < end) {
|
||||
char ch;
|
||||
while ((ch = descriptor.charAt(index++)) == JVM_SIGNATURE_ARRAY) {
|
||||
arrayDim++;
|
||||
}
|
||||
if (arrayDim > MAX_ARRAY_TYPE_DESC_DIMENSIONS) {
|
||||
throw maxArrayTypeDescDimensions();
|
||||
}
|
||||
|
||||
switch (ch) {
|
||||
case JVM_SIGNATURE_BOOLEAN:
|
||||
case JVM_SIGNATURE_BYTE:
|
||||
case JVM_SIGNATURE_CHAR:
|
||||
@ -353,16 +341,16 @@ public final class ConstantUtils {
|
||||
case JVM_SIGNATURE_FLOAT:
|
||||
case JVM_SIGNATURE_LONG:
|
||||
case JVM_SIGNATURE_DOUBLE:
|
||||
return index - start + 1;
|
||||
return index - start;
|
||||
case JVM_SIGNATURE_CLASS:
|
||||
// state variable for detection of illegal states, such as:
|
||||
// empty unqualified name, '//', leading '/', or trailing '/'
|
||||
boolean legal = false;
|
||||
while (++index < end) {
|
||||
switch (descriptor.charAt(index)) {
|
||||
while (index < end) {
|
||||
switch (descriptor.charAt(index++)) {
|
||||
case ';' -> {
|
||||
// illegal state on parser exit indicates empty unqualified name or trailing '/'
|
||||
return legal ? index - start + 1 : 0;
|
||||
return legal ? index - start : 0;
|
||||
}
|
||||
case '.', '[' -> {
|
||||
// do not permit '.' or '['
|
||||
@ -377,21 +365,17 @@ public final class ConstantUtils {
|
||||
legal = true;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
case JVM_SIGNATURE_ARRAY:
|
||||
arrayDim++;
|
||||
if (arrayDim > MAX_ARRAY_TYPE_DESC_DIMENSIONS) {
|
||||
throw new IllegalArgumentException(String.format("Cannot create an array type descriptor with more than %d dimensions",
|
||||
ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS));
|
||||
}
|
||||
// The rest of what's there better be a legal descriptor
|
||||
index++;
|
||||
voidOK = false;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static IllegalArgumentException maxArrayTypeDescDimensions() {
|
||||
return new IllegalArgumentException(String.format(
|
||||
"Cannot create an array type descriptor with more than %d dimensions",
|
||||
ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS));
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2024, Alibaba Group Holding Limited. 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,17 +28,25 @@ package jdk.internal.constant;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.ConstantDescs;
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import static jdk.internal.constant.ConstantUtils.badMethodDescriptor;
|
||||
import static jdk.internal.constant.ConstantUtils.resolveClassDesc;
|
||||
import static jdk.internal.constant.ConstantUtils.skipOverFieldSignature;
|
||||
import static jdk.internal.constant.ConstantUtils.EMPTY_CLASSDESC;
|
||||
import static jdk.internal.constant.PrimitiveClassDescImpl.CD_void;
|
||||
|
||||
/**
|
||||
* A <a href="package-summary.html#nominal">nominal descriptor</a> for a
|
||||
* {@link MethodType}. A {@linkplain MethodTypeDescImpl} corresponds to a
|
||||
@ -91,7 +100,7 @@ public final class MethodTypeDescImpl implements MethodTypeDesc {
|
||||
*/
|
||||
public static MethodTypeDescImpl ofValidated(ClassDesc returnType, ClassDesc... trustedArgTypes) {
|
||||
if (trustedArgTypes.length == 0)
|
||||
return new MethodTypeDescImpl(returnType, ConstantUtils.EMPTY_CLASSDESC);
|
||||
return new MethodTypeDescImpl(returnType, EMPTY_CLASSDESC);
|
||||
return new MethodTypeDescImpl(returnType, trustedArgTypes);
|
||||
}
|
||||
|
||||
@ -105,18 +114,98 @@ public final class MethodTypeDescImpl implements MethodTypeDesc {
|
||||
* @jvms 4.3.3 Method Descriptors
|
||||
*/
|
||||
public static MethodTypeDescImpl ofDescriptor(String descriptor) {
|
||||
// Implicit null-check of descriptor
|
||||
List<ClassDesc> ptypes = ConstantUtils.parseMethodDescriptor(descriptor);
|
||||
int args = ptypes.size() - 1;
|
||||
ClassDesc[] paramTypes = args > 0
|
||||
? ptypes.subList(1, args + 1).toArray(ConstantUtils.EMPTY_CLASSDESC)
|
||||
: ConstantUtils.EMPTY_CLASSDESC;
|
||||
int length = descriptor.length();
|
||||
int rightBracket, retTypeLength;
|
||||
if (descriptor.charAt(0) != '('
|
||||
|| (rightBracket = (descriptor.charAt(1) == ')' ? 1 : descriptor.lastIndexOf(')'))) <= 0
|
||||
|| (retTypeLength = length - rightBracket - 1) == 0
|
||||
|| (retTypeLength != 1 // if retTypeLength == 1, check correctness in resolveClassDesc
|
||||
&& retTypeLength != skipOverFieldSignature(descriptor, rightBracket + 1, length))
|
||||
) {
|
||||
throw badMethodDescriptor(descriptor);
|
||||
}
|
||||
|
||||
MethodTypeDescImpl result = ofValidated(ptypes.get(0), paramTypes);
|
||||
var returnType = resolveClassDesc(descriptor, rightBracket + 1, retTypeLength);
|
||||
if (length == 3 && returnType == CD_void) {
|
||||
return (MethodTypeDescImpl) ConstantDescs.MTD_void;
|
||||
}
|
||||
var paramTypes = paramTypes(descriptor, 1, rightBracket);
|
||||
var result = new MethodTypeDescImpl(returnType, paramTypes);
|
||||
result.cachedDescriptorString = descriptor;
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ClassDesc[] paramTypes(String descriptor, int start, int end) {
|
||||
if (start == end) {
|
||||
return EMPTY_CLASSDESC;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the length of the first 8 parameters is < 256, save them in lengths to avoid ArrayList allocation
|
||||
* Stop storing for the last parameter (we can compute length), or if too many parameters or too long.
|
||||
*/
|
||||
// little endian storage - lowest byte is encoded length 0
|
||||
long packedLengths = 0;
|
||||
int packedCount = 0;
|
||||
int cur = start;
|
||||
while (cur < end) {
|
||||
int len = skipOverFieldSignature(descriptor, cur, end);
|
||||
if (len == 0) {
|
||||
throw badMethodDescriptor(descriptor);
|
||||
}
|
||||
cur += len;
|
||||
if (len > 0xFF || packedCount >= Long.SIZE / Byte.SIZE || cur == end) {
|
||||
// Cannot or do not have to pack this item, but is already scanned and valid
|
||||
break;
|
||||
}
|
||||
packedLengths = packedLengths | (((long) len) << (Byte.SIZE * packedCount++));
|
||||
}
|
||||
|
||||
// Invariant: packedCount parameters encoded in packedLengths,
|
||||
// And another valid parameter pointed by cur
|
||||
|
||||
// Recover encoded elements
|
||||
ClassDesc[] paramTypes = null;
|
||||
List<ClassDesc> paramTypeList = null;
|
||||
if (cur == end) {
|
||||
paramTypes = new ClassDesc[packedCount + 1];
|
||||
} else {
|
||||
paramTypeList = new ArrayList<>(32);
|
||||
}
|
||||
|
||||
int last = start;
|
||||
for (int i = 0; i < packedCount; i++) {
|
||||
int len = Byte.toUnsignedInt((byte) (packedLengths >> (Byte.SIZE * i)));
|
||||
var cd = resolveClassDesc(descriptor, last, len);
|
||||
if (paramTypes != null) {
|
||||
paramTypes[i] = cd;
|
||||
} else {
|
||||
paramTypeList.add(cd);
|
||||
}
|
||||
last += len;
|
||||
}
|
||||
var lastCd = resolveClassDesc(descriptor, last, cur - last);
|
||||
|
||||
if (paramTypes != null) {
|
||||
paramTypes[packedCount] = lastCd;
|
||||
return paramTypes;
|
||||
}
|
||||
paramTypeList.add(lastCd);
|
||||
return buildParamTypes(descriptor, cur, end, paramTypeList);
|
||||
}
|
||||
|
||||
// slow path
|
||||
private static ClassDesc[] buildParamTypes(String descriptor, int cur, int end, List<ClassDesc> list) {
|
||||
while (cur < end) {
|
||||
int len = skipOverFieldSignature(descriptor, cur, end);
|
||||
if (len == 0)
|
||||
throw badMethodDescriptor(descriptor);
|
||||
list.add(resolveClassDesc(descriptor, cur, len));
|
||||
cur += len;
|
||||
}
|
||||
|
||||
return list.toArray(EMPTY_CLASSDESC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassDesc returnType() {
|
||||
|
@ -29,6 +29,7 @@ import java.lang.constant.ConstantDescs;
|
||||
import java.lang.constant.DynamicConstantDesc;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
import sun.invoke.util.Wrapper;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
@ -40,7 +41,35 @@ import static java.util.Objects.requireNonNull;
|
||||
public final class PrimitiveClassDescImpl
|
||||
extends DynamicConstantDesc<Class<?>> implements ClassDesc {
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code int} */
|
||||
public static final PrimitiveClassDescImpl CD_int = new PrimitiveClassDescImpl("I");
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code long} */
|
||||
public static final PrimitiveClassDescImpl CD_long = new PrimitiveClassDescImpl("J");
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code float} */
|
||||
public static final PrimitiveClassDescImpl CD_float = new PrimitiveClassDescImpl("F");
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code double} */
|
||||
public static final PrimitiveClassDescImpl CD_double = new PrimitiveClassDescImpl("D");
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code short} */
|
||||
public static final PrimitiveClassDescImpl CD_short = new PrimitiveClassDescImpl("S");
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code byte} */
|
||||
public static final PrimitiveClassDescImpl CD_byte = new PrimitiveClassDescImpl("B");
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code char} */
|
||||
public static final PrimitiveClassDescImpl CD_char = new PrimitiveClassDescImpl("C");
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code boolean} */
|
||||
public static final PrimitiveClassDescImpl CD_boolean = new PrimitiveClassDescImpl("Z");
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code void} */
|
||||
public static final PrimitiveClassDescImpl CD_void = new PrimitiveClassDescImpl("V");
|
||||
|
||||
private final String descriptor;
|
||||
private @Stable Wrapper lazyWrapper; // initialized only after this
|
||||
|
||||
/**
|
||||
* Creates a {@linkplain ClassDesc} given a descriptor string for a primitive
|
||||
@ -52,14 +81,18 @@ public final class PrimitiveClassDescImpl
|
||||
* describe a valid primitive type
|
||||
* @jvms 4.3 Descriptors
|
||||
*/
|
||||
public PrimitiveClassDescImpl(String descriptor) {
|
||||
private 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;
|
||||
}
|
||||
|
||||
public Wrapper wrapper() {
|
||||
var wrapper = this.lazyWrapper;
|
||||
if (wrapper != null)
|
||||
return wrapper;
|
||||
return this.lazyWrapper = Wrapper.forBasicType(descriptorString().charAt(0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String descriptorString() {
|
||||
return descriptor;
|
||||
@ -67,7 +100,7 @@ public final class PrimitiveClassDescImpl
|
||||
|
||||
@Override
|
||||
public Class<?> resolveConstantDesc(MethodHandles.Lookup lookup) {
|
||||
return Wrapper.forBasicType(descriptorString().charAt(0)).primitiveType();
|
||||
return wrapper().primitiveType();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -52,7 +52,7 @@ public final class ReferenceClassDescImpl implements ClassDesc {
|
||||
*/
|
||||
public static ReferenceClassDescImpl of(String descriptor) {
|
||||
int dLen = descriptor.length();
|
||||
int len = ConstantUtils.skipOverFieldSignature(descriptor, 0, dLen, false);
|
||||
int len = ConstantUtils.skipOverFieldSignature(descriptor, 0, dLen);
|
||||
if (len <= 1 || len != dLen)
|
||||
throw new IllegalArgumentException(String.format("not a valid reference type descriptor: %s", descriptor));
|
||||
return new ReferenceClassDescImpl(descriptor);
|
||||
@ -66,7 +66,7 @@ public final class ReferenceClassDescImpl implements ClassDesc {
|
||||
* @jvms 4.3.2 Field Descriptors
|
||||
*/
|
||||
public static ReferenceClassDescImpl ofValidated(String descriptor) {
|
||||
assert ConstantUtils.skipOverFieldSignature(descriptor, 0, descriptor.length(), false)
|
||||
assert ConstantUtils.skipOverFieldSignature(descriptor, 0, descriptor.length())
|
||||
== descriptor.length() : descriptor;
|
||||
return new ReferenceClassDescImpl(descriptor);
|
||||
}
|
||||
|
@ -304,21 +304,6 @@ public enum Wrapper {
|
||||
throw newIllegalArgumentException("not primitive: " + type);
|
||||
}
|
||||
|
||||
/** Return the wrapper that corresponds to the provided basic type char.
|
||||
* The basic type char must be for one of the eight primitive types, or void.
|
||||
* @throws IllegalArgumentException for unexpected types
|
||||
*/
|
||||
public static Wrapper forPrimitiveType(char basicTypeChar) {
|
||||
Wrapper w = FROM_CHAR[(basicTypeChar + (basicTypeChar >> 1)) & 0xf];
|
||||
if (w == null || w.basicTypeChar != basicTypeChar) {
|
||||
throw basicTypeError(basicTypeChar);
|
||||
}
|
||||
if (w == OBJECT) {
|
||||
throw newIllegalArgumentException("not primitive: " + basicTypeChar);
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
/** Return the wrapper that wraps values into the given wrapper type.
|
||||
* If it is {@code Object}, return {@code OBJECT}.
|
||||
* Otherwise, it must be a wrapper type.
|
||||
|
@ -69,7 +69,7 @@ public class ConstantUtilsTest {
|
||||
}
|
||||
|
||||
public void testSkipOverFieldSignatureVoid() {
|
||||
int ret = ConstantUtils.skipOverFieldSignature("(V)V", 1, 4, false);
|
||||
int ret = ConstantUtils.skipOverFieldSignature("(V)V", 1, 4);
|
||||
assertEquals(ret, 0, "Descriptor of (V)V starting at index 1, void disallowed");
|
||||
}
|
||||
}
|
||||
|
@ -58,9 +58,14 @@ public class MethodTypeDescFactories {
|
||||
@Param({
|
||||
"(Ljava/lang/Object;Ljava/lang/String;)I",
|
||||
"()V",
|
||||
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
|
||||
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
|
||||
"(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;",
|
||||
"()Ljava/lang/Object;",
|
||||
"([IJLjava/lang/String;Z)Ljava/util/List;",
|
||||
"()[Ljava/lang/String;",
|
||||
"(..IIJ)V",
|
||||
"([III.Z[B..[.[B).",
|
||||
"(.....................)."
|
||||
})
|
||||
public String descString;
|
||||
|
@ -112,11 +112,4 @@ public class Wrappers {
|
||||
bh.consume(Wrapper.forBasicType(c));
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void forPrimitiveType(Blackhole bh) throws Throwable {
|
||||
for (char c : PRIM_TYPES) {
|
||||
bh.consume(Wrapper.forPrimitiveType(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user