This commit is contained in:
Jesper Wilhelmsson 2021-07-08 23:21:00 +00:00
commit dfd6b2be7d
22 changed files with 602 additions and 157 deletions

View File

@ -11539,7 +11539,7 @@ instruct rep_stos(eCXRegI cnt, eDIRegP base, regD tmp, eAXRegI zero, Universe du
%}
// Small ClearArray AVX512 non-constant length.
instruct rep_stos_evex(eCXRegI cnt, eDIRegP base, regD tmp, kReg ktmp, eAXRegI zero, Universe dummy, eFlagsReg cr) %{
instruct rep_stos_evex(eCXRegI cnt, eDIRegP base, legRegD tmp, kReg ktmp, eAXRegI zero, Universe dummy, eFlagsReg cr) %{
predicate(!((ClearArrayNode*)n)->is_large() && (UseAVX > 2));
match(Set dummy (ClearArray cnt base));
ins_cost(125);
@ -11650,7 +11650,7 @@ instruct rep_stos_large(eCXRegI cnt, eDIRegP base, regD tmp, eAXRegI zero, Unive
%}
// Large ClearArray AVX512.
instruct rep_stos_large_evex(eCXRegI cnt, eDIRegP base, regD tmp, kReg ktmp, eAXRegI zero, Universe dummy, eFlagsReg cr) %{
instruct rep_stos_large_evex(eCXRegI cnt, eDIRegP base, legRegD tmp, kReg ktmp, eAXRegI zero, Universe dummy, eFlagsReg cr) %{
predicate((UseAVX > 2) && ((ClearArrayNode*)n)->is_large());
match(Set dummy (ClearArray cnt base));
effect(USE_KILL cnt, USE_KILL base, TEMP tmp, TEMP ktmp, KILL zero, KILL cr);

View File

@ -11100,7 +11100,7 @@ instruct rep_stos(rcx_RegL cnt, rdi_RegP base, regD tmp, rax_RegI zero,
%}
// Small ClearArray AVX512 non-constant length.
instruct rep_stos_evex(rcx_RegL cnt, rdi_RegP base, regD tmp, kReg ktmp, rax_RegI zero,
instruct rep_stos_evex(rcx_RegL cnt, rdi_RegP base, legRegD tmp, kReg ktmp, rax_RegI zero,
Universe dummy, rFlagsReg cr)
%{
predicate(!((ClearArrayNode*)n)->is_large() && (UseAVX > 2));
@ -11212,7 +11212,7 @@ instruct rep_stos_large(rcx_RegL cnt, rdi_RegP base, regD tmp, rax_RegI zero,
%}
// Large ClearArray AVX512.
instruct rep_stos_large_evex(rcx_RegL cnt, rdi_RegP base, regD tmp, kReg ktmp, rax_RegI zero,
instruct rep_stos_large_evex(rcx_RegL cnt, rdi_RegP base, legRegD tmp, kReg ktmp, rax_RegI zero,
Universe dummy, rFlagsReg cr)
%{
predicate((UseAVX > 2) && ((ClearArrayNode*)n)->is_large());

View File

@ -1411,8 +1411,14 @@ Node *SafePointNode::Ideal(PhaseGVN *phase, bool can_reshape) {
Node* SafePointNode::Identity(PhaseGVN* phase) {
// If you have back to back safepoints, remove one
if( in(TypeFunc::Control)->is_SafePoint() )
return in(TypeFunc::Control);
if (in(TypeFunc::Control)->is_SafePoint()) {
Node* out_c = unique_ctrl_out();
// This can be the safepoint of an outer strip mined loop if the inner loop's backedge was removed. Replacing the
// outer loop's safepoint could confuse removal of the outer loop.
if (out_c != NULL && !out_c->is_OuterStripMinedLoopEnd()) {
return in(TypeFunc::Control);
}
}
// Transforming long counted loops requires a safepoint node. Do not
// eliminate a safepoint until loop opts are over.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 2021, 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
@ -156,6 +156,10 @@ public class ByteArrayInputStream extends InputStream {
* {@code b[off+k-1]} in the manner performed by {@code System.arraycopy}.
* The value {@code k} is added into {@code pos} and {@code k} is returned.
* <p>
* Unlike the {@link InputStream#read(byte[],int,int) overridden method}
* of {@code InputStream}, this method returns {@code -1} instead of zero
* if the end of the stream has been reached and {@code len == 0}.
* <p>
* This {@code read} method cannot block.
*
* @param b the buffer into which the data is read.

View File

@ -26,12 +26,11 @@
package java.lang.runtime;
import java.lang.invoke.CallSite;
import java.lang.invoke.ConstantBootstraps;
import java.lang.invoke.ConstantCallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Stream;
import jdk.internal.javac.PreviewFeature;
@ -53,12 +52,15 @@ public class SwitchBootstraps {
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
private static final MethodHandle DO_SWITCH;
private static final MethodHandle DO_TYPE_SWITCH;
private static final MethodHandle DO_ENUM_SWITCH;
static {
try {
DO_SWITCH = LOOKUP.findStatic(SwitchBootstraps.class, "doSwitch",
DO_TYPE_SWITCH = LOOKUP.findStatic(SwitchBootstraps.class, "doTypeSwitch",
MethodType.methodType(int.class, Object.class, int.class, Object[].class));
DO_ENUM_SWITCH = LOOKUP.findStatic(SwitchBootstraps.class, "doEnumSwitch",
MethodType.methodType(int.class, Enum.class, int.class, Object[].class));
}
catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
@ -108,14 +110,13 @@ public class SwitchBootstraps {
* second parameter of type {@code int} and with {@code int} as its return type,
* or if {@code labels} contains an element that is not of type {@code String},
* {@code Integer} or {@code Class}.
* @throws Throwable if there is any error linking the call site
* @jvms 4.4.6 The CONSTANT_NameAndType_info Structure
* @jvms 4.4.10 The CONSTANT_Dynamic_info and CONSTANT_InvokeDynamic_info Structures
*/
public static CallSite typeSwitch(MethodHandles.Lookup lookup,
String invocationName,
MethodType invocationType,
Object... labels) throws Throwable {
Object... labels) {
if (invocationType.parameterCount() != 2
|| (!invocationType.returnType().equals(int.class))
|| invocationType.parameterType(0).isPrimitive()
@ -126,7 +127,7 @@ public class SwitchBootstraps {
labels = labels.clone();
Stream.of(labels).forEach(SwitchBootstraps::verifyLabel);
MethodHandle target = MethodHandles.insertArguments(DO_SWITCH, 2, (Object) labels);
MethodHandle target = MethodHandles.insertArguments(DO_TYPE_SWITCH, 2, (Object) labels);
return new ConstantCallSite(target);
}
@ -142,7 +143,7 @@ public class SwitchBootstraps {
}
}
private static int doSwitch(Object target, int startIndex, Object[] labels) {
private static int doTypeSwitch(Object target, int startIndex, Object[] labels) {
if (target == null)
return -1;
@ -167,4 +168,124 @@ public class SwitchBootstraps {
return labels.length;
}
/**
* Bootstrap method for linking an {@code invokedynamic} call site that
* implements a {@code switch} on a target of an enum type. The static
* arguments are used to encode the case labels associated to the switch
* construct, where each label can be encoded in two ways:
* <ul>
* <li>as a {@code String} value, which represents the name of
* the enum constant associated with the label</li>
* <li>as a {@code Class} value, which represents the enum type
* associated with a type test pattern</li>
* </ul>
* <p>
* The returned {@code CallSite}'s method handle will have
* a return type of {@code int} and accepts two parameters: the first argument
* will be an {@code Enum} instance ({@code target}) and the second
* will be {@code int} ({@code restart}).
* <p>
* If the {@code target} is {@code null}, then the method of the call site
* returns {@literal -1}.
* <p>
* If the {@code target} is not {@code null}, then the method of the call site
* returns the index of the first element in the {@code labels} array starting from
* the {@code restart} index matching one of the following conditions:
* <ul>
* <li>the element is of type {@code Class} that is assignable
* from the target's class; or</li>
* <li>the element is of type {@code String} and equals to the target
* enum constant's {@link Enum#name()}.</li>
* </ul>
* <p>
* If no element in the {@code labels} array matches the target, then
* the method of the call site return the length of the {@code labels} array.
*
* @param lookup Represents a lookup context with the accessibility
* privileges of the caller. When used with {@code invokedynamic},
* this is stacked automatically by the VM.
* @param invocationName unused
* @param invocationType The invocation type of the {@code CallSite} with two parameters,
* an enum type, an {@code int}, and {@code int} as a return type.
* @param labels case labels - {@code String} constants and {@code Class} instances,
* in any combination
* @return a {@code CallSite} returning the first matching element as described above
*
* @throws NullPointerException if any argument is {@code null}
* @throws IllegalArgumentException if any element in the labels array is null, if the
* invocation type is not a method type whose first parameter type is an enum type,
* second parameter of type {@code int} and whose return type is {@code int},
* or if {@code labels} contains an element that is not of type {@code String} or
* {@code Class} of the target enum type.
* @jvms 4.4.6 The CONSTANT_NameAndType_info Structure
* @jvms 4.4.10 The CONSTANT_Dynamic_info and CONSTANT_InvokeDynamic_info Structures
*/
public static CallSite enumSwitch(MethodHandles.Lookup lookup,
String invocationName,
MethodType invocationType,
Object... labels) {
if (invocationType.parameterCount() != 2
|| (!invocationType.returnType().equals(int.class))
|| invocationType.parameterType(0).isPrimitive()
|| !invocationType.parameterType(0).isEnum()
|| !invocationType.parameterType(1).equals(int.class))
throw new IllegalArgumentException("Illegal invocation type " + invocationType);
requireNonNull(labels);
labels = labels.clone();
Class<?> enumClass = invocationType.parameterType(0);
labels = Stream.of(labels).map(l -> convertEnumConstants(lookup, enumClass, l)).toArray();
MethodHandle target =
MethodHandles.insertArguments(DO_ENUM_SWITCH, 2, (Object) labels);
target = target.asType(invocationType);
return new ConstantCallSite(target);
}
private static <E extends Enum<E>> Object convertEnumConstants(MethodHandles.Lookup lookup, Class<?> enumClassTemplate, Object label) {
if (label == null) {
throw new IllegalArgumentException("null label found");
}
Class<?> labelClass = label.getClass();
if (labelClass == Class.class) {
if (label != enumClassTemplate) {
throw new IllegalArgumentException("the Class label: " + label +
", expected the provided enum class: " + enumClassTemplate);
}
return label;
} else if (labelClass == String.class) {
@SuppressWarnings("unchecked")
Class<E> enumClass = (Class<E>) enumClassTemplate;
try {
return ConstantBootstraps.enumConstant(lookup, (String) label, enumClass);
} catch (IllegalArgumentException ex) {
return null;
}
} else {
throw new IllegalArgumentException("label with illegal type found: " + labelClass +
", expected label of type either String or Class");
}
}
private static int doEnumSwitch(Enum<?> target, int startIndex, Object[] labels) {
if (target == null)
return -1;
// Dumbest possible strategy
Class<?> targetClass = target.getClass();
for (int i = startIndex; i < labels.length; i++) {
Object label = labels[i];
if (label instanceof Class<?> c) {
if (c.isAssignableFrom(targetClass))
return i;
} else if (label == target) {
return i;
}
}
return labels.length;
}
}

View File

@ -664,7 +664,11 @@ public class Flow {
ListBuffer<PendingExit> prevPendingExits = pendingExits;
pendingExits = new ListBuffer<>();
scan(tree.selector);
Set<Symbol> constants = tree.patternSwitch ? new HashSet<>() : null;
boolean exhaustiveSwitch = tree.patternSwitch ||
tree.cases.stream()
.flatMap(c -> c.labels.stream())
.anyMatch(l -> TreeInfo.isNull(l));
Set<Symbol> constants = exhaustiveSwitch ? new HashSet<>() : null;
for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
alive = Liveness.ALIVE;
JCCase c = l.head;
@ -686,7 +690,7 @@ public class Flow {
l.tail.head.pos(),
Warnings.PossibleFallThroughIntoCase);
}
if (!tree.hasTotalPattern && tree.patternSwitch &&
if (!tree.hasTotalPattern && exhaustiveSwitch &&
!TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases) &&
(constants == null || !isExhaustive(tree.selector.type, constants))) {
log.error(tree, Errors.NotExhaustiveStatement);

View File

@ -35,6 +35,7 @@ import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.BindingSymbol;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
import com.sun.tools.javac.code.Symbol.DynamicVarSymbol;
import com.sun.tools.javac.code.Symbol.VarSymbol;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Type;
@ -58,6 +59,7 @@ import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Names;
import com.sun.tools.javac.util.Options;
@ -93,6 +95,7 @@ import com.sun.tools.javac.tree.JCTree.LetExpr;
import com.sun.tools.javac.tree.TreeInfo;
import com.sun.tools.javac.util.Assert;
import com.sun.tools.javac.util.List;
import java.util.Iterator;
/**
* This pass translates pattern-matching constructs, such as instanceof <pattern>.
@ -275,7 +278,6 @@ public class TransPatterns extends TreeTranslator {
boolean hasTotalPattern,
boolean patternSwitch) {
Type seltype = selector.type;
boolean enumSwitch = (seltype.tsym.flags() & Flags.ENUM) != 0;
if (patternSwitch) {
Assert.check(preview.isEnabled());
@ -315,27 +317,6 @@ public class TransPatterns extends TreeTranslator {
//-case null is always desugared to case -1, as the typeSwitch bootstrap method will
// return -1 when the input is null
//
//a special case for switches over enums with pattern case
//with only a single unguarded (type) pattern case, which is equivalent
//to a default with additional binding variable assignment:
//switch ($enum) {
// case $constant1: $stats$
// case $constant2: $stats$
// case typeof($enum) e: $stats$
//}
//=>
//switch ($enum) {
// case $constant1: $stats$
// case $constant2: $stats$
// default: typeof($enum) e = $enum; $stats$
//}
//constant labels in switches over enums with one or more pattern cases
//with guards are desugared into guards:
//case $constant1: $stats$
//=>
//case typeof($enum) e && e == $constant1: $stats$
//and handled as a normal pattern matching switch
//
//note the selector is evaluated only once and stored in a temporary variable
ListBuffer<JCCase> newCases = new ListBuffer<>();
for (List<JCCase> c = cases; c.nonEmpty(); c = c.tail) {
@ -345,27 +326,6 @@ public class TransPatterns extends TreeTranslator {
newCases.add(c.head);
}
}
if (enumSwitch && hasGuards(newCases)) {
for (JCCase c : newCases) {
for (List<JCCaseLabel> l = c.labels; l.nonEmpty(); l = l.tail) {
if (l.head.isExpression() && !TreeInfo.isNull(l.head)) {
BindingSymbol temp = new BindingSymbol(Flags.SYNTHETIC,
names.fromString("enumGuard" + c.pos +
target.syntheticNameChar() + "temp"),
seltype,
currentMethodSym);
JCBindingPattern binding =
make.at(l.head.pos()).BindingPattern(make.VarDef(temp, null));
binding.setType(seltype);
l.head = make.GuardPattern(binding,
makeBinary(Tag.EQ,
make.Ident(temp),
(JCExpression) l.head));
}
}
}
enumSwitch = false;
}
cases = newCases.toList();
ListBuffer<JCStatement> statements = new ListBuffer<>();
VarSymbol temp = new VarSymbol(Flags.SYNTHETIC,
@ -395,46 +355,44 @@ public class TransPatterns extends TreeTranslator {
currentMethodSym);
statements.append(make.at(tree.pos).VarDef(index, makeLit(syms.intType, 0)));
if (enumSwitch) {
selector = make.Ident(temp);
} else {
List<Type> staticArgTypes = List.of(syms.methodHandleLookupType,
syms.stringType,
syms.methodTypeType,
types.makeArrayType(new ClassType(syms.classType.getEnclosingType(),
List.of(new WildcardType(syms.objectType, BoundKind.UNBOUND,
syms.boundClass)),
syms.classType.tsym)));
LoadableConstant[] staticArgValues =
cases.stream()
.flatMap(c -> c.labels.stream())
.map(l -> toLoadableConstant(l))
.filter(c -> c != null)
.toArray(s -> new LoadableConstant[s]);
List<Type> staticArgTypes = List.of(syms.methodHandleLookupType,
syms.stringType,
syms.methodTypeType,
types.makeArrayType(new ClassType(syms.classType.getEnclosingType(),
List.of(new WildcardType(syms.objectType, BoundKind.UNBOUND,
syms.boundClass)),
syms.classType.tsym)));
LoadableConstant[] staticArgValues =
cases.stream()
.flatMap(c -> c.labels.stream())
.map(l -> toLoadableConstant(l, seltype))
.filter(c -> c != null)
.toArray(s -> new LoadableConstant[s]);
Symbol bsm = rs.resolveInternalMethod(tree.pos(), env, syms.switchBootstrapsType,
names.fromString("typeSwitch"), staticArgTypes, List.nil());
boolean enumSelector = seltype.tsym.isEnum();
Name bootstrapName = enumSelector ? names.enumSwitch : names.typeSwitch;
Symbol bsm = rs.resolveInternalMethod(tree.pos(), env, syms.switchBootstrapsType,
bootstrapName, staticArgTypes, List.nil());
MethodType indyType = new MethodType(
List.of(syms.objectType, syms.intType),
syms.intType,
List.nil(),
syms.methodClass
);
DynamicMethodSymbol dynSym = new DynamicMethodSymbol(names.fromString("typeSwitch"),
syms.noSymbol,
((MethodSymbol)bsm).asHandle(),
indyType,
staticArgValues);
MethodType indyType = new MethodType(
List.of(enumSelector ? seltype : syms.objectType, syms.intType),
syms.intType,
List.nil(),
syms.methodClass
);
DynamicMethodSymbol dynSym = new DynamicMethodSymbol(bootstrapName,
syms.noSymbol,
((MethodSymbol)bsm).asHandle(),
indyType,
staticArgValues);
JCFieldAccess qualifier = make.Select(make.QualIdent(bsm.owner), dynSym.name);
qualifier.sym = dynSym;
qualifier.type = syms.intType;
selector = make.Apply(List.nil(),
qualifier,
List.of(make.Ident(temp), make.Ident(index)))
.setType(syms.intType);
}
JCFieldAccess qualifier = make.Select(make.QualIdent(bsm.owner), dynSym.name);
qualifier.sym = dynSym;
qualifier.type = syms.intType;
selector = make.Apply(List.nil(),
qualifier,
List.of(make.Ident(temp), make.Ident(index)))
.setType(syms.intType);
int i = 0;
boolean previousCompletesNormally = false;
@ -473,38 +431,27 @@ public class TransPatterns extends TreeTranslator {
} else {
c.stats = translate(c.stats);
}
if (enumSwitch) {
var labels = c.labels;
while (labels.nonEmpty()) {
if (labels.head.isPattern()) {
labels.head = make.DefaultCaseLabel();
}
labels = labels.tail;
}
} else {
ListBuffer<JCCaseLabel> translatedLabels = new ListBuffer<>();
for (var p : c.labels) {
if (p.hasTag(Tag.DEFAULTCASELABEL)) {
translatedLabels.add(p);
hasDefault = true;
} else if (hasTotalPattern && !hasDefault &&
c == lastCase && p.isPattern()) {
//If the switch has total pattern, the last case will contain it.
//Convert the total pattern to default:
translatedLabels.add(make.DefaultCaseLabel());
ListBuffer<JCCaseLabel> translatedLabels = new ListBuffer<>();
for (var p : c.labels) {
if (p.hasTag(Tag.DEFAULTCASELABEL)) {
translatedLabels.add(p);
hasDefault = true;
} else if (hasTotalPattern && !hasDefault &&
c == lastCase && p.isPattern()) {
//If the switch has total pattern, the last case will contain it.
//Convert the total pattern to default:
translatedLabels.add(make.DefaultCaseLabel());
} else {
int value;
if (p.isNullPattern()) {
value = -1;
} else {
int value;
if (p.isNullPattern()) {
value = -1;
} else {
value = i++;
}
translatedLabels.add(make.Literal(value));
value = i++;
}
translatedLabels.add(make.Literal(value));
}
c.labels = translatedLabels.toList();
}
c.labels = translatedLabels.toList();
if (c.caseKind == CaseTree.CaseKind.STATEMENT) {
previousCompletesNormally = c.completesNormally;
} else {
@ -538,29 +485,31 @@ public class TransPatterns extends TreeTranslator {
}
}
private boolean hasGuards(Collection<JCCase> cases) {
return cases.stream()
.flatMap(c -> c.labels.stream())
.filter(JCCaseLabel::isPattern)
.anyMatch(l -> !TreeInfo.primaryPatternType((JCPattern) l).unconditional());
}
private Type principalType(JCPattern p) {
return types.boxedTypeOrType(types.erasure(TreeInfo.primaryPatternType(p).type()));
}
private LoadableConstant toLoadableConstant(JCCaseLabel l) {
private LoadableConstant toLoadableConstant(JCCaseLabel l, Type selector) {
if (l.isPattern()) {
return (LoadableConstant) principalType((JCPattern) l);
Type principalType = principalType((JCPattern) l);
if (types.isSubtype(selector, principalType)) {
return (LoadableConstant) selector;
} else {
return (LoadableConstant) principalType;
}
} else if (l.isExpression() && !TreeInfo.isNull((JCExpression) l)) {
Assert.checkNonNull(l.type.constValue());
if ((l.type.tsym.flags_field & Flags.ENUM) != 0) {
return LoadableConstant.String(((JCIdent) l).name.toString());
} else {
Assert.checkNonNull(l.type.constValue());
return switch (l.type.getTag()) {
case BYTE, CHAR,
SHORT, INT -> LoadableConstant.Int((Integer) l.type.constValue());
case CLASS -> LoadableConstant.String((String) l.type.constValue());
default -> throw new AssertionError();
};
return switch (l.type.getTag()) {
case BYTE, CHAR,
SHORT, INT -> LoadableConstant.Int((Integer) l.type.constValue());
case CLASS -> LoadableConstant.String((String) l.type.constValue());
default -> throw new AssertionError();
};
}
} else {
return null;
}
@ -819,7 +768,7 @@ public class TransPatterns extends TreeTranslator {
VarSymbol bindingDeclared(BindingSymbol varSymbol) {
VarSymbol res = parent.bindingDeclared(varSymbol);
if (res == null) {
res = new VarSymbol(varSymbol.flags(), varSymbol.name, varSymbol.type, varSymbol.owner);
res = new VarSymbol(varSymbol.flags(), varSymbol.name, varSymbol.type, currentMethodSym);
res.setTypeAttributes(varSymbol.getRawTypeAttributes());
hoistedVarMap.put(varSymbol, res);
}

View File

@ -215,6 +215,10 @@ public class Names {
public final Name permits;
public final Name sealed;
// pattern switches
public final Name typeSwitch;
public final Name enumSwitch;
public final Name.Table table;
public Names(Context context) {
@ -384,6 +388,10 @@ public class Names {
// sealed types
permits = fromString("permits");
sealed = fromString("sealed");
// pattern switches
typeSwitch = fromString("typeSwitch");
enumSwitch = fromString("enumSwitch");
}
protected Name.Table createTable(Options options) {

View File

@ -75,6 +75,7 @@ import com.sun.source.doctree.StartElementTree;
import com.sun.source.doctree.SummaryTree;
import com.sun.source.doctree.SystemPropertyTree;
import com.sun.source.doctree.TextTree;
import com.sun.source.util.DocTreePath;
import com.sun.source.util.SimpleDocTreeVisitor;
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
@ -1515,9 +1516,16 @@ public class HtmlDocletWriter {
@Override
public Boolean visitErroneous(ErroneousTree node, Content c) {
messages.warning(ch.getDocTreePath(node),
"doclet.tag.invalid_usage", node);
result.add(new RawHtml(node.toString()));
DocTreePath dtp = ch.getDocTreePath(node);
if (dtp != null) {
String body = node.getBody();
if (body.matches("(?i)\\{@[a-z]+.*")) {
messages.warning(dtp,"doclet.tag.invalid_usage", body);
} else {
messages.warning(dtp, "doclet.tag.invalid_input", body);
}
}
result.add(Text.of(node.toString()));
return false;
}
@ -1542,7 +1550,10 @@ public class HtmlDocletWriter {
public Boolean visitLink(LinkTree node, Content c) {
var inTags = context.inTags;
if (inTags.contains(LINK) || inTags.contains(LINK_PLAIN) || inTags.contains(SEE)) {
messages.warning(ch.getDocTreePath(node), "doclet.see.nested_link", "{@" + node.getTagName() + "}");
DocTreePath dtp = ch.getDocTreePath(node);
if (dtp != null) {
messages.warning(dtp, "doclet.see.nested_link", "{@" + node.getTagName() + "}");
}
Content label = commentTagsToContent(node, element, node.getLabel(), context);
if (label.isEmpty()) {
label = Text.of(node.getReference().getSignature());

View File

@ -104,6 +104,7 @@ doclet.see.class_or_package_not_found=Tag {0}: reference not found: {1}
doclet.see.class_or_package_not_accessible=Tag {0}: reference not accessible: {1}
doclet.see.nested_link=Tag {0}: nested link
doclet.tag.invalid_usage=invalid usage of tag {0}
doclet.tag.invalid_input=invalid input: ''{0}''
doclet.Deprecated_API=Deprecated API
doclet.Deprecated_Elements=Deprecated {0}
doclet.Deprecated_In_Release=Deprecated in {0}

View File

@ -114,6 +114,11 @@ serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorStatArrayCorrectnessTest.j
serviceability/jvmti/ModuleAwareAgents/ThreadStart/MAAThreadStart.java 8225354 windows-all
serviceability/dcmd/gc/RunFinalizationTest.java 8227120 linux-all,windows-x64
serviceability/sa/ClhsdbCDSCore.java 8269982 macosx-aarch64
serviceability/sa/ClhsdbFindPC.java#id1 8269982 macosx-aarch64
serviceability/sa/ClhsdbFindPC.java#id3 8269982 macosx-aarch64
serviceability/sa/ClhsdbPstack.java#id1 8269982 macosx-aarch64
#############################################################################
# :hotspot_misc

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
@ -33,7 +33,7 @@ import jdk.test.lib.RandomFactory;
* @library /test/lib
* @build jdk.test.lib.RandomFactory
* @run main ReadAllReadNTransferTo
* @bug 8180451
* @bug 6766844 8180451
* @summary Verify ByteArrayInputStream readAllBytes, readNBytes, and transferTo
* @key randomness
*/
@ -48,8 +48,16 @@ public class ReadAllReadNTransferTo {
int position = random.nextInt(SIZE/2);
int size = random.nextInt(SIZE - position);
ByteArrayInputStream bais =
new ByteArrayInputStream(buf, position, size);
ByteArrayInputStream bais = new ByteArrayInputStream(buf);
bais.readAllBytes();
if (bais.read(new byte[0]) != -1) {
throw new RuntimeException("read(byte[]) did not return -1");
}
if (bais.read(new byte[1], 0, 0) != -1) {
throw new RuntimeException("read(byte[],int,int) did not return -1");
}
bais = new ByteArrayInputStream(buf, position, size);
int off = size < 2 ? 0 : random.nextInt(size / 2);
int len = size - off < 1 ? 0 : random.nextInt(size - off);
@ -72,7 +80,6 @@ public class ReadAllReadNTransferTo {
throw new RuntimeException("readAllBytes content");
}
// XXX transferTo()
bais = new ByteArrayInputStream(buf);
ByteArrayOutputStream baos = new ByteArrayOutputStream(buf.length);
if (bais.transferTo(baos) != buf.length) {

View File

@ -44,11 +44,14 @@ import static org.testng.Assert.fail;
public class SwitchBootstrapsTest {
public static final MethodHandle BSM_TYPE_SWITCH;
public static final MethodHandle BSM_ENUM_SWITCH;
static {
try {
BSM_TYPE_SWITCH = MethodHandles.lookup().findStatic(SwitchBootstraps.class, "typeSwitch",
MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, Object[].class));
BSM_ENUM_SWITCH = MethodHandles.lookup().findStatic(SwitchBootstraps.class, "enumSwitch",
MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, Object[].class));
}
catch (ReflectiveOperationException e) {
throw new AssertionError("Should not happen", e);
@ -62,8 +65,16 @@ public class SwitchBootstrapsTest {
assertEquals(-1, (int) indy.invoke(null, start));
}
private void testEnum(Enum<?> target, int start, int result, Object... labels) throws Throwable {
MethodType switchType = MethodType.methodType(int.class, target.getClass(), int.class);
MethodHandle indy = ((CallSite) BSM_ENUM_SWITCH.invoke(MethodHandles.lookup(), "", switchType, labels)).dynamicInvoker();
assertEquals((int) indy.invoke(target, start), result);
assertEquals(-1, (int) indy.invoke(null, start));
}
public enum E1 {
A;
A,
B;
}
public enum E2 {
@ -98,6 +109,24 @@ public class SwitchBootstrapsTest {
testType("", 2, 2, String.class, String.class, String.class);
}
public void testEnums() throws Throwable {
testEnum(E1.A, 0, 2, "B", "C", "A", E1.class);
testEnum(E1.B, 0, 0, "B", "C", "A", E1.class);
testEnum(E1.B, 1, 3, "B", "C", "A", E1.class);
try {
testEnum(E1.B, 1, 3, "B", "C", "A", E2.class);
fail("Didn't get the expected exception.");
} catch (IllegalArgumentException ex) {
//OK
}
try {
testEnum(E1.B, 1, 3, "B", "C", "A", String.class);
fail("Didn't get the expected exception.");
} catch (IllegalArgumentException ex) {
//OK
}
}
public void testWrongSwitchTypes() throws Throwable {
MethodType[] switchTypes = new MethodType[] {
MethodType.methodType(int.class, Object.class),
@ -112,6 +141,20 @@ public class SwitchBootstrapsTest {
//OK, expected
}
}
MethodType[] enumSwitchTypes = new MethodType[] {
MethodType.methodType(int.class, Enum.class),
MethodType.methodType(int.class, Object.class, int.class),
MethodType.methodType(int.class, double.class, int.class),
MethodType.methodType(int.class, Enum.class, Integer.class)
};
for (MethodType enumSwitchType : enumSwitchTypes) {
try {
BSM_ENUM_SWITCH.invoke(MethodHandles.lookup(), "", enumSwitchType);
fail("Didn't get the expected exception.");
} catch (IllegalArgumentException ex) {
//OK, expected
}
}
}
public void testNullLabels() throws Throwable {
@ -129,5 +172,19 @@ public class SwitchBootstrapsTest {
} catch (IllegalArgumentException ex) {
//OK
}
MethodType enumSwitchType = MethodType.methodType(int.class, E1.class, int.class);
try {
BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", enumSwitchType, (Object[]) null);
fail("Didn't get the expected exception.");
} catch (NullPointerException ex) {
//OK
}
try {
BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", enumSwitchType,
new Object[] {1, null, String.class});
fail("Didn't get the expected exception.");
} catch (IllegalArgumentException ex) {
//OK
}
}
}

View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2021, 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.
*
* 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.
*/
/*
* @test
* @bug 8269722
* @summary NPE in HtmlDocletWriter, reporting errors on inherited tags
* @library /tools/lib ../../lib
* @modules jdk.javadoc/jdk.javadoc.internal.tool
* @build toolbox.ToolBox javadoc.tester.*
* @run main TestInherited
*/
import java.nio.file.Path;
import javadoc.tester.JavadocTester;
import toolbox.ToolBox;
public class TestInherited extends JavadocTester {
public static void main(String... args) throws Exception {
TestInherited tester = new TestInherited();
tester.runTests(m -> new Object[] { Path.of(m.getName())});
}
private final ToolBox tb = new ToolBox();
@Test
public void testBadInheritedParam(Path base) throws Exception {
Path src = base.resolve("src");
tb.writeJavaFiles(src, """
public class BadParam {
public static class Base {
/**
* @param i a < b
*/
public void m(int i) { }
}
public static class Sub extends Base {
public void m(int i) { }
}
}
""");
javadoc("-d", base.resolve("out").toString(),
"-Xdoclint:-missing", "-XDdoe",
src.resolve("BadParam.java").toString());
checkExit(Exit.OK);
}
@Test
public void testBadInheritedReturn(Path base) throws Exception {
Path src = base.resolve("src");
tb.writeJavaFiles(src, """
public class BadReturn {
public static class Base {
/**
* @return a < b
*/
public int m() { }
}
public static class Sub extends Base {
public int m() { }
}
}
""");
javadoc("-d", base.resolve("out").toString(),
"-Xdoclint:-missing",
src.resolve("BadReturn.java").toString());
checkExit(Exit.OK);
}
}

View File

@ -374,7 +374,7 @@ public class TestJavaFX extends JavadocTester {
checkExit(Exit.OK);
// make sure the doclet indeed emits the warning
checkOutput(Output.OUT, true, "C.java:31: warning: invalid usage of tag <");
checkOutput(Output.OUT, true, "C.java:31: warning: invalid input: '<'");
}
/*

View File

@ -85,6 +85,6 @@ public class TestNonInlineHtmlTagRemoval extends JavadocTester {
checkOutput("Negative.html", true,
"""
<div class="block">case1: A hanging &lt; : xx<</div>""");
<div class="block">case1: A hanging &lt; : xx&lt;</div>""");
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2021, 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.
*
* 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.
*/
/*
* @test
* @bug 8262891
* @summary Verify pattern switches work properly when the set of enum constant changes.
* @compile --enable-preview -source ${jdk.version} EnumTypeChanges.java
* @compile --enable-preview -source ${jdk.version} EnumTypeChanges2.java
* @run main/othervm --enable-preview EnumTypeChanges
*/
import java.util.function.Function;
import java.util.Objects;
public class EnumTypeChanges {
public static void main(String... args) throws Exception {
new EnumTypeChanges().run();
}
void run() throws Exception {
doRun(this::statementEnum);
doRun(this::expressionEnum);
}
void doRun(Function<EnumTypeChangesEnum, String> c) throws Exception {
assertEquals("A", c.apply(EnumTypeChangesEnum.A));
assertEquals("D", c.apply(EnumTypeChangesEnum.valueOf("C")));
}
String statementEnum(EnumTypeChangesEnum e) {
switch (e) {
case A -> { return "A"; }
case EnumTypeChangesEnum e1 && false -> throw new AssertionError();
case B -> { return "B"; }
default -> { return "D"; }
}
}
String expressionEnum(EnumTypeChangesEnum e) {
return switch (e) {
case A -> "A";
case EnumTypeChangesEnum e1 && false -> throw new AssertionError();
case B -> "B";
default -> "D";
};
}
private static void assertEquals(Object o1, Object o2) {
if (!Objects.equals(o1, o2)) {
throw new AssertionError();
}
}
}
enum EnumTypeChangesEnum {
A,
B;
}

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2021, 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.
*
* 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.
*/
enum EnumTypeChangesEnum {
A,
C;
}

View File

@ -23,7 +23,7 @@
/*
* @test
* @bug 8267610
* @bug 8267610 8269738
* @summary LambdaToMethod cannot capture pattern variables. So the TransPatterns should
* transform the pattern variables and symbols to normal variables and symbols.
* @compile --enable-preview -source ${jdk.version} LambdaCannotCapturePatternVariables.java
@ -34,11 +34,24 @@ import java.util.function.Supplier;
public class LambdaCannotCapturePatternVariables {
static Number num1 = 1;
static Number num2 = null;
static Number staticNum1 = (num1 instanceof Integer i) ? ((Supplier<Integer>) () -> i).get() : null;
static Number staticNum2 = (num2 instanceof Integer i) ? ((Supplier<Integer>) () -> i).get() : null;
Number instanceNum1 = (num1 instanceof Integer i) ? ((Supplier<Integer>) () -> i).get() : null;
Number instanceNum2 = (num2 instanceof Integer i) ? ((Supplier<Integer>) () -> i).get() : null;
public static void main(String[] args) {
var testVar = new LambdaCannotCapturePatternVariables();
testVar.testInstanceOfPatternVariable(Integer.valueOf(1));
testVar.testSwitchPatternVariable(Integer.valueOf(1));
testVar.test(Integer.valueOf(1));
assertTrue(staticNum1 != null, "staticNum1 is null unexpectedly");
assertTrue(staticNum2 == null, "staticNum1 is not null unexpectedly");
assertTrue(testVar.instanceNum1 != null, "instanceNum1 is null unexpectedly");
assertTrue(testVar.instanceNum2 == null, "instanceNum2 is not null unexpectedly");
assertTrue(staticNum1.intValue() == 1, "staticNum1.intValue() is not equal to 1");
assertTrue(testVar.instanceNum1.intValue() == 1, "instanceNum1.intValue() is not equal to 1");
}
public Integer testInstanceOfPatternVariable(Object x) {
@ -69,4 +82,9 @@ public class LambdaCannotCapturePatternVariables {
return ((y instanceof Integer z) ? z : bar);
})).get() : bar);
}
static void assertTrue(boolean cond, String info) {
if (!cond)
throw new AssertionError(info);
}
}

View File

@ -185,4 +185,9 @@ public class SwitchErrors {
default -> null;
};
}
void exhaustiveAndNull(String s) {
switch (s) {
case null: break;
}
}
}

View File

@ -42,6 +42,7 @@ SwitchErrors.java:91:9: compiler.err.not.exhaustive.statement
SwitchErrors.java:97:9: compiler.err.not.exhaustive.statement
SwitchErrors.java:104:9: compiler.err.not.exhaustive.statement
SwitchErrors.java:164:9: compiler.err.not.exhaustive.statement
SwitchErrors.java:189:9: compiler.err.not.exhaustive.statement
- compiler.note.preview.filename: SwitchErrors.java, DEFAULT
- compiler.note.preview.recompile
44 errors
45 errors

View File

@ -53,8 +53,12 @@ public class Switches {
runEnumTest(this::testEnumExpression2);
runEnumTest(this::testEnumWithGuards1);
runEnumTest(this::testEnumWithGuards2);
runEnumTest(this::testEnumWithGuards3);
runEnumTest(this::testEnumWithGuards4);
runEnumTest(this::testEnumWithGuardsExpression1);
runEnumTest(this::testEnumWithGuardsExpression2);
runEnumTest(this::testEnumWithGuardsExpression3);
runEnumTest(this::testEnumWithGuardsExpression4);
runEnumTest(this::testStringWithGuards1);
runEnumTest(this::testStringWithGuardsExpression1);
runEnumTest(this::testIntegerWithGuards1);
@ -288,6 +292,46 @@ public class Switches {
};
}
String testEnumWithGuards3(E e) {
switch (e) {
case A: return "a";
case B: return "b";
case Object x && "C".equals(x.toString()): return "C";
case C: return "broken";
case null, E x: return String.valueOf(x);
}
}
String testEnumWithGuardsExpression3(E e) {
return switch (e) {
case A -> "a";
case B -> "b";
case Object x && "C".equals(x.toString()) -> "C";
case C -> "broken";
case null, E x -> String.valueOf(x);
};
}
String testEnumWithGuards4(E e) {
switch (e) {
case A: return "a";
case B: return "b";
case Runnable x && "C".equals(x.toString()): return "C";
case C: return "broken";
case null, E x: return String.valueOf(x);
}
}
String testEnumWithGuardsExpression4(E e) {
return switch (e) {
case A -> "a";
case B -> "b";
case Runnable x && "C".equals(x.toString()) -> "C";
case C -> "broken";
case null, E x -> String.valueOf(x);
};
}
String testStringWithGuards1(E e) {
switch (e != null ? e.name() : null) {
case "A": return "a";
@ -520,7 +564,9 @@ public class Switches {
}
}
public enum E {
public enum E implements Runnable {
A, B, C;
@Override public void run() {}
}
}