8210031: implementation for JVM Constants API

Co-authored-by: Brian Goetz <brian.goetz@oracle.com>
Reviewed-by: jrose, mcimadamore, darcy, mchung, rriggs, dholmes, forax
This commit is contained in:
Vicente Romero 2018-12-09 12:36:24 -05:00
parent b80d335354
commit 9846588b31
72 changed files with 6719 additions and 103 deletions

View file

@ -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;
}
}
}