8338532: Speed up the ClassFile API MethodTypeDesc#ofDescriptor

Reviewed-by: redestad, liach
This commit is contained in:
Shaojin Wen 2024-08-21 14:56:30 +00:00 committed by Chen Liang
parent 918cf11454
commit 3aeb6733f9
11 changed files with 201 additions and 110 deletions

View file

@ -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.MAX_ARRAY_TYPE_DESC_DIMENSIONS;
import static jdk.internal.constant.ConstantUtils.arrayDepth; import static jdk.internal.constant.ConstantUtils.arrayDepth;
import static jdk.internal.constant.ConstantUtils.binaryToInternal; 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.internalToBinary;
import static jdk.internal.constant.ConstantUtils.validateBinaryClassName; import static jdk.internal.constant.ConstantUtils.validateBinaryClassName;
import static jdk.internal.constant.ConstantUtils.validateInternalClassName; import static jdk.internal.constant.ConstantUtils.validateInternalClassName;
@ -164,7 +165,7 @@ public sealed interface ClassDesc
static ClassDesc ofDescriptor(String descriptor) { static ClassDesc ofDescriptor(String descriptor) {
// implicit null-check // implicit null-check
return (descriptor.length() == 1) 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 // will throw IAE on descriptor.length == 0 or if array dimensions too long
: ReferenceClassDescImpl.of(descriptor); : ReferenceClassDescImpl.of(descriptor);
} }

View file

@ -240,31 +240,31 @@ public final class ConstantDescs {
CD_Object, CD_Object); CD_Object, CD_Object);
/** {@link ClassDesc} representing the primitive type {@code int} */ /** {@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} */ /** {@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} */ /** {@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} */ /** {@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} */ /** {@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} */ /** {@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} */ /** {@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} */ /** {@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} */ /** {@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} * {@link MethodHandleDesc} representing {@link MethodHandles#classData(Lookup, String, Class) MethodHandles.classData}

View file

@ -25,6 +25,7 @@
package java.lang.invoke; package java.lang.invoke;
import sun.invoke.util.Wrapper; import sun.invoke.util.Wrapper;
import jdk.internal.constant.ConstantUtils;
import static java.lang.invoke.MethodHandleNatives.mapLookupExceptionToError; import static java.lang.invoke.MethodHandleNatives.mapLookupExceptionToError;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
@ -112,7 +113,7 @@ public final class ConstantBootstraps {
throw new IllegalArgumentException(String.format("not primitive: %s", name)); throw new IllegalArgumentException(String.format("not primitive: %s", name));
} }
return Wrapper.forPrimitiveType(name.charAt(0)).primitiveType(); return ConstantUtils.forPrimitiveType(name, 0).resolveConstantDesc(lookup);
} }
/** /**

View file

@ -35,6 +35,8 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import static jdk.internal.constant.PrimitiveClassDescImpl.*;
/** /**
* Helper methods for the implementation of {@code java.lang.constant}. * 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); return s.substring(1, s.length() - 1);
} }
/** public static PrimitiveClassDescImpl forPrimitiveType(String descriptor, int offset) {
* Parses a method descriptor string, and return a list of field descriptor return switch (descriptor.charAt(offset)) {
* strings, return type first, then parameter types case JVM_SIGNATURE_BYTE -> CD_byte;
* case JVM_SIGNATURE_CHAR -> CD_char;
* @param descriptor the descriptor string case JVM_SIGNATURE_FLOAT -> CD_float;
* @return the list of types case JVM_SIGNATURE_DOUBLE -> CD_double;
* @throws IllegalArgumentException if the descriptor string is not valid case JVM_SIGNATURE_INT -> CD_int;
*/ case JVM_SIGNATURE_LONG -> CD_long;
public static List<ClassDesc> parseMethodDescriptor(String descriptor) { case JVM_SIGNATURE_SHORT -> CD_short;
int cur = 0, end = descriptor.length(); case JVM_SIGNATURE_VOID -> CD_void;
ArrayList<ClassDesc> ptypes = new ArrayList<>(); case JVM_SIGNATURE_BOOLEAN -> CD_boolean;
ptypes.add(null); // placeholder for return type default -> throw badMethodDescriptor(descriptor);
};
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;
} }
private static ClassDesc resolveClassDesc(String descriptor, int start, int len) { static ClassDesc resolveClassDesc(String descriptor, int start, int len) {
if (len == 1) { 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)); 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_ARRAY = '[';
private static final char JVM_SIGNATURE_BYTE = 'B'; private static final char JVM_SIGNATURE_BYTE = 'B';
private static final char JVM_SIGNATURE_CHAR = 'C'; private static final char JVM_SIGNATURE_CHAR = 'C';
private static final char JVM_SIGNATURE_CLASS = 'L'; 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_FLOAT = 'F';
private static final char JVM_SIGNATURE_DOUBLE = 'D'; 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_INT = 'I';
private static final char JVM_SIGNATURE_LONG = 'J'; private static final char JVM_SIGNATURE_LONG = 'J';
private static final char JVM_SIGNATURE_SHORT = 'S'; private static final char JVM_SIGNATURE_SHORT = 'S';
@ -334,17 +317,22 @@ public final class ConstantUtils {
* @param descriptor the descriptor string * @param descriptor the descriptor string
* @param start the starting index into the string * @param start the starting index into the string
* @param end the ending index within 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 * @return the length of the descriptor, or 0 if it is not a descriptor
* @throws IllegalArgumentException if the descriptor string is not valid * @throws IllegalArgumentException if the descriptor string is not valid
*/ */
@SuppressWarnings("fallthrough") static int skipOverFieldSignature(String descriptor, int start, int end) {
static int skipOverFieldSignature(String descriptor, int start, int end, boolean voidOK) {
int arrayDim = 0; int arrayDim = 0;
int index = start; int index = start;
while (index < end) { if (index < end) {
switch (descriptor.charAt(index)) { char ch;
case JVM_SIGNATURE_VOID: if (!voidOK) { return 0; } 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_BOOLEAN:
case JVM_SIGNATURE_BYTE: case JVM_SIGNATURE_BYTE:
case JVM_SIGNATURE_CHAR: case JVM_SIGNATURE_CHAR:
@ -353,16 +341,16 @@ public final class ConstantUtils {
case JVM_SIGNATURE_FLOAT: case JVM_SIGNATURE_FLOAT:
case JVM_SIGNATURE_LONG: case JVM_SIGNATURE_LONG:
case JVM_SIGNATURE_DOUBLE: case JVM_SIGNATURE_DOUBLE:
return index - start + 1; return index - start;
case JVM_SIGNATURE_CLASS: case JVM_SIGNATURE_CLASS:
// state variable for detection of illegal states, such as: // state variable for detection of illegal states, such as:
// empty unqualified name, '//', leading '/', or trailing '/' // empty unqualified name, '//', leading '/', or trailing '/'
boolean legal = false; boolean legal = false;
while (++index < end) { while (index < end) {
switch (descriptor.charAt(index)) { switch (descriptor.charAt(index++)) {
case ';' -> { case ';' -> {
// illegal state on parser exit indicates empty unqualified name or trailing '/' // illegal state on parser exit indicates empty unqualified name or trailing '/'
return legal ? index - start + 1 : 0; return legal ? index - start : 0;
} }
case '.', '[' -> { case '.', '[' -> {
// do not permit '.' or '[' // do not permit '.' or '['
@ -377,21 +365,17 @@ public final class ConstantUtils {
legal = true; 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; break;
default: default:
return 0; break;
} }
} }
return 0; 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));
}
} }

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 jdk.internal.vm.annotation.Stable;
import java.lang.constant.ClassDesc; import java.lang.constant.ClassDesc;
import java.lang.constant.ConstantDescs;
import java.lang.constant.MethodTypeDesc; import java.lang.constant.MethodTypeDesc;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import static java.util.Objects.requireNonNull; 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 * A <a href="package-summary.html#nominal">nominal descriptor</a> for a
* {@link MethodType}. A {@linkplain MethodTypeDescImpl} corresponds to 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) { public static MethodTypeDescImpl ofValidated(ClassDesc returnType, ClassDesc... trustedArgTypes) {
if (trustedArgTypes.length == 0) if (trustedArgTypes.length == 0)
return new MethodTypeDescImpl(returnType, ConstantUtils.EMPTY_CLASSDESC); return new MethodTypeDescImpl(returnType, EMPTY_CLASSDESC);
return new MethodTypeDescImpl(returnType, trustedArgTypes); return new MethodTypeDescImpl(returnType, trustedArgTypes);
} }
@ -105,18 +114,98 @@ public final class MethodTypeDescImpl implements MethodTypeDesc {
* @jvms 4.3.3 Method Descriptors * @jvms 4.3.3 Method Descriptors
*/ */
public static MethodTypeDescImpl ofDescriptor(String descriptor) { public static MethodTypeDescImpl ofDescriptor(String descriptor) {
// Implicit null-check of descriptor int length = descriptor.length();
List<ClassDesc> ptypes = ConstantUtils.parseMethodDescriptor(descriptor); int rightBracket, retTypeLength;
int args = ptypes.size() - 1; if (descriptor.charAt(0) != '('
ClassDesc[] paramTypes = args > 0 || (rightBracket = (descriptor.charAt(1) == ')' ? 1 : descriptor.lastIndexOf(')'))) <= 0
? ptypes.subList(1, args + 1).toArray(ConstantUtils.EMPTY_CLASSDESC) || (retTypeLength = length - rightBracket - 1) == 0
: ConstantUtils.EMPTY_CLASSDESC; || (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; result.cachedDescriptorString = descriptor;
return result; 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 @Override
public ClassDesc returnType() { public ClassDesc returnType() {

View file

@ -29,6 +29,7 @@ import java.lang.constant.ConstantDescs;
import java.lang.constant.DynamicConstantDesc; import java.lang.constant.DynamicConstantDesc;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import jdk.internal.vm.annotation.Stable;
import sun.invoke.util.Wrapper; import sun.invoke.util.Wrapper;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
@ -40,7 +41,35 @@ import static java.util.Objects.requireNonNull;
public final class PrimitiveClassDescImpl public final class PrimitiveClassDescImpl
extends DynamicConstantDesc<Class<?>> implements ClassDesc { 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 final String descriptor;
private @Stable Wrapper lazyWrapper; // initialized only after this
/** /**
* Creates a {@linkplain ClassDesc} given a descriptor string for a primitive * Creates a {@linkplain ClassDesc} given a descriptor string for a primitive
@ -52,14 +81,18 @@ public final class PrimitiveClassDescImpl
* describe a valid primitive type * describe a valid primitive type
* @jvms 4.3 Descriptors * @jvms 4.3 Descriptors
*/ */
public PrimitiveClassDescImpl(String descriptor) { private PrimitiveClassDescImpl(String descriptor) {
super(ConstantDescs.BSM_PRIMITIVE_CLASS, requireNonNull(descriptor), ConstantDescs.CD_Class); 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; this.descriptor = descriptor;
} }
public Wrapper wrapper() {
var wrapper = this.lazyWrapper;
if (wrapper != null)
return wrapper;
return this.lazyWrapper = Wrapper.forBasicType(descriptorString().charAt(0));
}
@Override @Override
public String descriptorString() { public String descriptorString() {
return descriptor; return descriptor;
@ -67,7 +100,7 @@ public final class PrimitiveClassDescImpl
@Override @Override
public Class<?> resolveConstantDesc(MethodHandles.Lookup lookup) { public Class<?> resolveConstantDesc(MethodHandles.Lookup lookup) {
return Wrapper.forBasicType(descriptorString().charAt(0)).primitiveType(); return wrapper().primitiveType();
} }
@Override @Override

View file

@ -52,7 +52,7 @@ public final class ReferenceClassDescImpl implements ClassDesc {
*/ */
public static ReferenceClassDescImpl of(String descriptor) { public static ReferenceClassDescImpl of(String descriptor) {
int dLen = descriptor.length(); int dLen = descriptor.length();
int len = ConstantUtils.skipOverFieldSignature(descriptor, 0, dLen, false); int len = ConstantUtils.skipOverFieldSignature(descriptor, 0, dLen);
if (len <= 1 || len != dLen) if (len <= 1 || len != dLen)
throw new IllegalArgumentException(String.format("not a valid reference type descriptor: %s", descriptor)); throw new IllegalArgumentException(String.format("not a valid reference type descriptor: %s", descriptor));
return new ReferenceClassDescImpl(descriptor); return new ReferenceClassDescImpl(descriptor);
@ -66,7 +66,7 @@ public final class ReferenceClassDescImpl implements ClassDesc {
* @jvms 4.3.2 Field Descriptors * @jvms 4.3.2 Field Descriptors
*/ */
public static ReferenceClassDescImpl ofValidated(String descriptor) { public static ReferenceClassDescImpl ofValidated(String descriptor) {
assert ConstantUtils.skipOverFieldSignature(descriptor, 0, descriptor.length(), false) assert ConstantUtils.skipOverFieldSignature(descriptor, 0, descriptor.length())
== descriptor.length() : descriptor; == descriptor.length() : descriptor;
return new ReferenceClassDescImpl(descriptor); return new ReferenceClassDescImpl(descriptor);
} }

View file

@ -304,21 +304,6 @@ public enum Wrapper {
throw newIllegalArgumentException("not primitive: " + type); 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. /** Return the wrapper that wraps values into the given wrapper type.
* If it is {@code Object}, return {@code OBJECT}. * If it is {@code Object}, return {@code OBJECT}.
* Otherwise, it must be a wrapper type. * Otherwise, it must be a wrapper type.

View file

@ -69,7 +69,7 @@ public class ConstantUtilsTest {
} }
public void testSkipOverFieldSignatureVoid() { 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"); assertEquals(ret, 0, "Descriptor of (V)V starting at index 1, void disallowed");
} }
} }

View file

@ -58,9 +58,14 @@ public class MethodTypeDescFactories {
@Param({ @Param({
"(Ljava/lang/Object;Ljava/lang/String;)I", "(Ljava/lang/Object;Ljava/lang/String;)I",
"()V", "()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;", "([IJLjava/lang/String;Z)Ljava/util/List;",
"()[Ljava/lang/String;", "()[Ljava/lang/String;",
"(..IIJ)V", "(..IIJ)V",
"([III.Z[B..[.[B).",
"(.....................)." "(.....................)."
}) })
public String descString; public String descString;

View file

@ -112,11 +112,4 @@ public class Wrappers {
bh.consume(Wrapper.forBasicType(c)); bh.consume(Wrapper.forBasicType(c));
} }
} }
@Benchmark
public void forPrimitiveType(Blackhole bh) throws Throwable {
for (char c : PRIM_TYPES) {
bh.consume(Wrapper.forPrimitiveType(c));
}
}
} }