}.
*
* A parameterized type is created the first time it is needed by a
* reflective method, as specified in this package. When a
@@ -42,6 +42,7 @@
* an equals() method that equates any two instances that share the
* same generic type declaration and have equal type parameters.
*
+ * @jls 4.5 Parameterized Types
* @since 1.5
*/
public interface ParameterizedType extends Type {
diff --git a/src/java.base/share/classes/java/lang/reflect/Proxy.java b/src/java.base/share/classes/java/lang/reflect/Proxy.java
index 1a2d7f668ab..2f2ec3bba34 100644
--- a/src/java.base/share/classes/java/lang/reflect/Proxy.java
+++ b/src/java.base/share/classes/java/lang/reflect/Proxy.java
@@ -674,12 +674,6 @@ private static void validateProxyInterfaces(ClassLoader loader,
{
Map, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.size());
for (Class> intf : interfaces) {
- /*
- * Verify that the class loader resolves the name of this
- * interface to the same Class object.
- */
- ensureVisible(loader, intf);
-
/*
* Verify that the Class object actually represents an
* interface.
@@ -688,6 +682,16 @@ private static void validateProxyInterfaces(ClassLoader loader,
throw new IllegalArgumentException(intf.getName() + " is not an interface");
}
+ if (intf.isHidden()) {
+ throw new IllegalArgumentException(intf.getName() + " is a hidden interface");
+ }
+
+ /*
+ * Verify that the class loader resolves the name of this
+ * interface to the same Class object.
+ */
+ ensureVisible(loader, intf);
+
/*
* Verify that this interface is not a duplicate.
*/
@@ -905,7 +909,8 @@ private static Module getDynamicModule(ClassLoader loader) {
* if any of the following restrictions is violated:
*
* - All of {@code Class} objects in the given {@code interfaces} array
- * must represent interfaces, not classes or primitive types.
+ * must represent {@linkplain Class#isHidden() non-hidden} interfaces,
+ * not classes or primitive types.
*
*
- No two elements in the {@code interfaces} array may
* refer to identical {@code Class} objects.
diff --git a/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java b/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java
index 14a8d4e6318..5974140763a 100644
--- a/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java
+++ b/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java
@@ -670,7 +670,10 @@ private ProxyMethod(Method method, String methodFieldName) {
private void generateMethod(ClassWriter cw, String className) {
MethodType mt = MethodType.methodType(returnType, parameterTypes);
String desc = mt.toMethodDescriptorString();
- MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_FINAL,
+ int accessFlags = ACC_PUBLIC | ACC_FINAL;
+ if (method.isVarArgs()) accessFlags |= ACC_VARARGS;
+
+ MethodVisitor mv = cw.visitMethod(accessFlags,
method.getName(), desc, null,
typeNames(Arrays.asList(exceptionTypes)));
diff --git a/src/java.base/share/classes/java/lang/reflect/Type.java b/src/java.base/share/classes/java/lang/reflect/Type.java
index eee74435880..1754784d97e 100644
--- a/src/java.base/share/classes/java/lang/reflect/Type.java
+++ b/src/java.base/share/classes/java/lang/reflect/Type.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2020, 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
@@ -30,6 +30,14 @@
* programming language. These include raw types, parameterized types,
* array types, type variables and primitive types.
*
+ * @jls 4.1 The Kinds of Types and Values
+ * @jls 4.2 Primitive Types and Values
+ * @jls 4.3 Reference Types and Values
+ * @jls 4.4 Type Variables
+ * @jls 4.5 Parameterized Types
+ * @jls 4.8 Raw Types
+ * @jls 4.9 Intersection Types
+ * @jls 10.1 Array Types
* @since 1.5
*/
public interface Type {
diff --git a/src/java.base/share/classes/java/lang/reflect/TypeVariable.java b/src/java.base/share/classes/java/lang/reflect/TypeVariable.java
index 6e4b105c3ba..0064aed2a22 100644
--- a/src/java.base/share/classes/java/lang/reflect/TypeVariable.java
+++ b/src/java.base/share/classes/java/lang/reflect/TypeVariable.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2020, 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
@@ -46,6 +46,7 @@
* @param the type of generic declaration that declared the
* underlying type variable.
*
+ * @jls 4.4 Type Variables
* @since 1.5
*/
public interface TypeVariable extends Type, AnnotatedElement {
diff --git a/src/java.base/share/classes/java/lang/reflect/WildcardType.java b/src/java.base/share/classes/java/lang/reflect/WildcardType.java
index 7b8f3962514..0ef18413ea4 100644
--- a/src/java.base/share/classes/java/lang/reflect/WildcardType.java
+++ b/src/java.base/share/classes/java/lang/reflect/WildcardType.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2020, 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
@@ -29,6 +29,7 @@
* WildcardType represents a wildcard type expression, such as
* {@code ?}, {@code ? extends Number}, or {@code ? super Integer}.
*
+ * @jls 4.5.1 Type Arguments of Parameterized Types
* @since 1.5
*/
public interface WildcardType extends Type {
diff --git a/src/java.base/share/classes/java/time/temporal/WeekFields.java b/src/java.base/share/classes/java/time/temporal/WeekFields.java
index d3a4f19951b..a831e8820f1 100644
--- a/src/java.base/share/classes/java/time/temporal/WeekFields.java
+++ b/src/java.base/share/classes/java/time/temporal/WeekFields.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2020, 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
@@ -210,7 +210,7 @@ public final class WeekFields implements Serializable {
* Note also that the first few days of a calendar year may be in the
* week-based-year corresponding to the previous calendar year.
*/
- public static final WeekFields ISO = new WeekFields(DayOfWeek.MONDAY, 4);
+ public static final WeekFields ISO = WeekFields.of(DayOfWeek.MONDAY, 4);
/**
* The common definition of a week that starts on Sunday and the first week
diff --git a/src/java.base/share/classes/java/util/regex/Pattern.java b/src/java.base/share/classes/java/util/regex/Pattern.java
index c0ccc531dbf..8304f05b1d7 100644
--- a/src/java.base/share/classes/java/util/regex/Pattern.java
+++ b/src/java.base/share/classes/java/util/regex/Pattern.java
@@ -1049,9 +1049,10 @@
private transient int patternLength;
/**
- * If the Start node might possibly match supplementary characters.
+ * If the Start node might possibly match supplementary or surrogate
+ * code points.
* It is set to true during compiling if
- * (1) There is supplementary char in pattern, or
+ * (1) There is supplementary or surrogate code point in pattern, or
* (2) There is complement node of a "family" CharProperty
*/
private transient boolean hasSupplementary;
@@ -2948,8 +2949,10 @@ private CharProperty newCharProperty(CharPredicate p) {
return null;
if (p instanceof BmpCharPredicate)
return new BmpCharProperty((BmpCharPredicate)p);
- else
+ else {
+ hasSupplementary = true;
return new CharProperty(p);
+ }
}
/**
@@ -5785,18 +5788,18 @@ private static boolean inRange(int lower, int ch, int upper) {
}
/**
- * Charactrs within a explicit value range
+ * Characters within a explicit value range
*/
static CharPredicate Range(int lower, int upper) {
if (upper < Character.MIN_HIGH_SURROGATE ||
- lower > Character.MAX_HIGH_SURROGATE &&
+ lower > Character.MAX_LOW_SURROGATE &&
upper < Character.MIN_SUPPLEMENTARY_CODE_POINT)
return (BmpCharPredicate)(ch -> inRange(lower, ch, upper));
return ch -> inRange(lower, ch, upper);
}
/**
- * Charactrs within a explicit value range in a case insensitive manner.
+ * Characters within a explicit value range in a case insensitive manner.
*/
static CharPredicate CIRange(int lower, int upper) {
return ch -> inRange(lower, ch, upper) ||
diff --git a/src/java.base/share/classes/sun/nio/ch/Net.java b/src/java.base/share/classes/sun/nio/ch/Net.java
index f820035686f..1a796dff453 100644
--- a/src/java.base/share/classes/sun/nio/ch/Net.java
+++ b/src/java.base/share/classes/sun/nio/ch/Net.java
@@ -185,8 +185,10 @@ else if (x instanceof NotYetBoundException)
nx = new SocketException("Socket is not bound yet");
else if (x instanceof UnsupportedAddressTypeException)
nx = new SocketException("Unsupported address type");
- else if (x instanceof UnresolvedAddressException) {
+ else if (x instanceof UnresolvedAddressException)
nx = new SocketException("Unresolved address");
+ else if (x instanceof IOException) {
+ nx = new SocketException(x.getMessage());
}
if (nx != x)
nx.initCause(x);
diff --git a/src/java.base/share/native/libfdlibm/k_standard.c b/src/java.base/share/native/libfdlibm/k_standard.c
index c0f8d936770..d6e18e2d72d 100644
--- a/src/java.base/share/native/libfdlibm/k_standard.c
+++ b/src/java.base/share/native/libfdlibm/k_standard.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2020, 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
@@ -739,6 +739,10 @@ static double zero = 0.0; /* used as const */
errno = EDOM;
}
break;
+ default:
+ exc.retval = zero / zero;
+ errno = EINVAL;
+ break;
}
return exc.retval;
}
diff --git a/src/java.base/unix/native/libnet/NetworkInterface.c b/src/java.base/unix/native/libnet/NetworkInterface.c
index fa145b5af41..0581b8e90ec 100644
--- a/src/java.base/unix/native/libnet/NetworkInterface.c
+++ b/src/java.base/unix/native/libnet/NetworkInterface.c
@@ -1296,7 +1296,8 @@ static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
static int getIndex(int sock, const char *name) {
struct ifreq if2;
memset((char *)&if2, 0, sizeof(if2));
- strncpy(if2.ifr_name, name, sizeof(if2.ifr_name) - 1);
+ strncpy(if2.ifr_name, name, sizeof(if2.ifr_name));
+ if2.ifr_name[sizeof(if2.ifr_name) - 1] = 0;
if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) < 0) {
return -1;
@@ -1359,7 +1360,8 @@ static int getMTU(JNIEnv *env, int sock, const char *ifname) {
static int getFlags(int sock, const char *ifname, int *flags) {
struct ifreq if2;
memset((char *)&if2, 0, sizeof(if2));
- strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
+ strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name));
+ if2.ifr_name[sizeof(if2.ifr_name) - 1] = 0;
if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {
return -1;
diff --git a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c
index a5d4d80c0ab..dc4abafcd68 100644
--- a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c
+++ b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c
@@ -48,6 +48,11 @@
#endif
#endif // __linux__
+#ifdef __APPLE__
+#define IPV4_SNDBUF_LIMIT 65507
+#define IPV6_SNDBUF_LIMIT 65527
+#endif // __APPLE__
+
#ifndef IPTOS_TOS_MASK
#define IPTOS_TOS_MASK 0x1e
#endif
@@ -895,7 +900,7 @@ Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env,
}
#ifdef __APPLE__
- arg = 65507;
+ arg = (domain == AF_INET6) ? IPV6_SNDBUF_LIMIT : IPV4_SNDBUF_LIMIT;
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
(char *)&arg, sizeof(arg)) < 0) {
getErrorString(errno, tmpbuf, sizeof(tmpbuf));
diff --git a/src/java.desktop/share/classes/sun/print/ServiceDialog.java b/src/java.desktop/share/classes/sun/print/ServiceDialog.java
index 016eb432372..0801caee1b8 100644
--- a/src/java.desktop/share/classes/sun/print/ServiceDialog.java
+++ b/src/java.desktop/share/classes/sun/print/ServiceDialog.java
@@ -961,7 +961,13 @@ public void updateInfo() {
if (info != null) {
lblInfo.setText(info.toString());
}
- btnProperties.setEnabled(uiFactory != null);
+ PrinterJob job = null;
+ PrinterJobWrapper wrapper = (PrinterJobWrapper)
+ asCurrent.get(PrinterJobWrapper.class);
+ if (wrapper != null) {
+ job = wrapper.getPrinterJob();
+ }
+ btnProperties.setEnabled(uiFactory != null && job != null);
}
}
diff --git a/src/java.xml/share/classes/org/xml/sax/HandlerBase.java b/src/java.xml/share/classes/org/xml/sax/HandlerBase.java
index b3140887935..23e1da1e18d 100644
--- a/src/java.xml/share/classes/org/xml/sax/HandlerBase.java
+++ b/src/java.xml/share/classes/org/xml/sax/HandlerBase.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2020, 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
@@ -58,7 +58,10 @@
public class HandlerBase
implements EntityResolver, DTDHandler, DocumentHandler, ErrorHandler
{
-
+ /**
+ * Constructs a {@code HandlerBase}.
+ */
+ public HandlerBase() {}
////////////////////////////////////////////////////////////////////
// Default implementation of the EntityResolver interface.
diff --git a/src/java.xml/share/classes/org/xml/sax/helpers/DefaultHandler.java b/src/java.xml/share/classes/org/xml/sax/helpers/DefaultHandler.java
index 205e392eb97..1ee6153baed 100644
--- a/src/java.xml/share/classes/org/xml/sax/helpers/DefaultHandler.java
+++ b/src/java.xml/share/classes/org/xml/sax/helpers/DefaultHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2020, 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
@@ -70,7 +70,10 @@
public class DefaultHandler
implements EntityResolver, DTDHandler, ContentHandler, ErrorHandler
{
-
+ /**
+ * Constructs a {@code DefaultHandler}.
+ */
+ public DefaultHandler() {}
////////////////////////////////////////////////////////////////////
// Default implementation of the EntityResolver interface.
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java
index f1d8a1d01c6..a76833251f1 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java
@@ -400,7 +400,7 @@ public static EnumSet asFlagSet(long flags) {
public static final int
AccessFlags = PUBLIC | PROTECTED | PRIVATE,
LocalClassFlags = FINAL | ABSTRACT | STRICTFP | ENUM | SYNTHETIC | VALUE,
- StaticLocalFlags = LocalClassFlags | STATIC | INTERFACE | ANNOTATION,
+ StaticLocalFlags = LocalClassFlags | STATIC | INTERFACE,
MemberClassFlags = LocalClassFlags | INTERFACE | AccessFlags,
MemberRecordFlags = MemberClassFlags | STATIC,
ClassFlags = LocalClassFlags | INTERFACE | PUBLIC | ANNOTATION,
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
index 8b7a30a222e..c5bce2c8c9e 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
@@ -1389,7 +1389,7 @@ else if ((sym.owner.flags_field & INTERFACE) != 0)
boolean implicitlyStatic = !sym.isAnonymous() &&
((flags & RECORD) != 0 || (flags & ENUM) != 0 || (flags & INTERFACE) != 0);
boolean staticOrImplicitlyStatic = (flags & STATIC) != 0 || implicitlyStatic;
- mask = staticOrImplicitlyStatic && allowRecords ? StaticLocalFlags : LocalClassFlags;
+ mask = staticOrImplicitlyStatic && allowRecords && (flags & ANNOTATION) == 0 ? StaticLocalFlags : LocalClassFlags;
implicit = implicitlyStatic ? STATIC : implicit;
if (staticOrImplicitlyStatic) {
if (sym.owner.kind == TYP) {
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java
index 8a14f738664..66ed1834179 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java
@@ -918,6 +918,13 @@ public void visitApply(JCMethodInvocation tree) {
//do nothing
}
+ @Override
+ public void visitConditional(JCTree.JCConditional tree) {
+ //skip tree.cond
+ scan(tree.truepart);
+ scan(tree.falsepart);
+ }
+
@Override
public void visitReference(JCMemberReference tree) {
Assert.checkNonNull(tree.getOverloadKind());
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
index 0a4d4ac12a1..bf4c367782c 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
@@ -3505,10 +3505,10 @@ Source restrictedTypeNameStartingAtSource(Name name, int pos, boolean shouldWarn
/** VariableDeclaratorId = Ident BracketsOpt
*/
JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type) {
- return variableDeclaratorId(mods, type, false);
+ return variableDeclaratorId(mods, type, false, false);
}
//where
- JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type, boolean lambdaParameter) {
+ JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type, boolean lambdaParameter, boolean recordComponent) {
int pos = token.pos;
Name name;
if (lambdaParameter && token.kind == UNDERSCORE) {
@@ -3553,6 +3553,9 @@ JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type, boolean
token.kind == LBRACKET) {
log.error(token.pos, Errors.VarargsAndOldArraySyntax);
}
+ if (recordComponent && token.kind == LBRACKET) {
+ log.error(token.pos, Errors.RecordComponentAndOldArraySyntax);
+ }
type = bracketsOpt(type);
return toP(F.at(pos).VarDef(mods, name, type, null));
@@ -4698,12 +4701,12 @@ protected JCVariableDecl formalParameter(boolean lambdaParameter, boolean record
}
typeAnnotationsPushedBack = List.nil();
}
- return variableDeclaratorId(mods, type, lambdaParameter);
+ return variableDeclaratorId(mods, type, lambdaParameter, recordComponent);
}
protected JCVariableDecl implicitParameter() {
JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
- return variableDeclaratorId(mods, null, true);
+ return variableDeclaratorId(mods, null, true, false);
}
/* ---------- auxiliary methods -------------- */
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
index cf1dbe32c00..cef4c8cc046 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
@@ -3515,6 +3515,9 @@ compiler.err.record.cant.declare.field.modifiers=\
compiler.err.illegal.record.component.name=\
illegal record component name {0}
+compiler.err.record.component.and.old.array.syntax=\
+ legacy array notation not allowed on record components
+
# accessor methods
# 0: symbol, 1: fragment
compiler.err.invalid.accessor.method.in.record=\
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java
index 0980995f1e9..7dcf0145ff0 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java
@@ -154,7 +154,13 @@ public JCTree visitCase(CaseTree node, P p) {
JCCase t = (JCCase) node;
List pats = copy(t.pats, p);
List stats = copy(t.stats, p);
- JCTree body = copy(t.body, p);
+ JCTree body;
+ if (node.getCaseKind() == CaseTree.CaseKind.RULE) {
+ body = t.body instanceof JCExpression && t.stats.head.hasTag(Tag.YIELD)
+ ? ((JCYield) t.stats.head).value : t.stats.head;
+ } else {
+ body = null;
+ }
return M.at(t.pos).Case(t.caseKind, pats, stats, body);
}
diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h
index 9144a3d1cee..9463aa67c93 100644
--- a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h
+++ b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h
@@ -67,6 +67,7 @@ typedef struct map_info {
off_t offset; // file offset of this mapping
uintptr_t vaddr; // starting virtual address
size_t memsz; // size of the mapping
+ uint32_t flags; // acces flags
struct map_info* next;
} map_info;
diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c b/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c
index 0bc009a6c5f..4087d1c0f71 100644
--- a/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c
+++ b/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c
@@ -351,7 +351,7 @@ static bool read_core_segments(struct ps_prochandle* ph, ELF_EHDR* core_ehdr) {
case PT_LOAD: {
if (core_php->p_filesz != 0) {
if (add_map_info(ph, ph->core->core_fd, core_php->p_offset,
- core_php->p_vaddr, core_php->p_filesz) == NULL) goto err;
+ core_php->p_vaddr, core_php->p_filesz, core_php->p_flags) == NULL) goto err;
}
break;
}
@@ -390,10 +390,21 @@ static bool read_lib_segments(struct ps_prochandle* ph, int lib_fd, ELF_EHDR* li
if (existing_map == NULL){
if (add_map_info(ph, lib_fd, lib_php->p_offset,
- target_vaddr, lib_php->p_memsz) == NULL) {
+ target_vaddr, lib_php->p_memsz, lib_php->p_flags) == NULL) {
goto err;
}
+ } else if (lib_php->p_flags != existing_map->flags) {
+ // Access flags for this memory region are different between the library
+ // and coredump. It might be caused by mprotect() call at runtime.
+ // We should respect the coredump.
+ continue;
} else {
+ // Read only segments in ELF should not be any different from PT_LOAD segments
+ // in the coredump.
+ // Also the first page of the ELF header might be included
+ // in the coredump (See JDK-7133122).
+ // Thus we need to replace the PT_LOAD segment with the library version.
+ //
// Coredump stores value of p_memsz elf field
// rounded up to page boundary.
@@ -460,7 +471,7 @@ static bool read_exec_segments(struct ps_prochandle* ph, ELF_EHDR* exec_ehdr) {
case PT_LOAD: {
// add only non-writable segments of non-zero filesz
if (!(exec_php->p_flags & PF_W) && exec_php->p_filesz != 0) {
- if (add_map_info(ph, ph->core->exec_fd, exec_php->p_offset, exec_php->p_vaddr, exec_php->p_filesz) == NULL) goto err;
+ if (add_map_info(ph, ph->core->exec_fd, exec_php->p_offset, exec_php->p_vaddr, exec_php->p_filesz, exec_php->p_flags) == NULL) goto err;
}
break;
}
diff --git a/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.c b/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.c
index ed61b6d1cac..9c902c6450f 100644
--- a/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.c
+++ b/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.c
@@ -208,12 +208,12 @@ void Prelease(struct ps_prochandle* ph) {
free(ph);
}
-lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base, size_t memsz) {
- return add_lib_info_fd(ph, libname, -1, base, memsz);
+lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base) {
+ return add_lib_info_fd(ph, libname, -1, base);
}
-lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base, size_t memsz) {
- lib_info* newlib;
+lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base) {
+ lib_info* newlib;
print_debug("add_lib_info_fd %s\n", libname);
if ( (newlib = (lib_info*) calloc(1, sizeof(struct lib_info))) == NULL) {
@@ -229,7 +229,6 @@ lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd,
strcpy(newlib->name, libname);
newlib->base = base;
- newlib->memsz = memsz;
if (fd == -1) {
if ( (newlib->fd = pathmap_open(newlib->name)) < 0) {
@@ -259,11 +258,11 @@ lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd,
}
#endif // __APPLE__
- newlib->symtab = build_symtab(newlib->fd);
+ newlib->symtab = build_symtab(newlib->fd, &newlib->memsz);
if (newlib->symtab == NULL) {
print_debug("symbol table build failed for %s\n", newlib->name);
} else {
- print_debug("built symbol table for 0x%lx %s\n", newlib, newlib->name);
+ print_debug("built symbol table for 0x%lx memsz=0x%lx %s\n", newlib, newlib->memsz, newlib->name);
}
// even if symbol table building fails, we add the lib_info.
diff --git a/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.h b/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.h
index 51694673fe0..3084a5283c7 100644
--- a/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.h
+++ b/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.h
@@ -36,6 +36,7 @@
#include
#include
#include
+#include
#ifndef register_t
#define register_t uint64_t
@@ -112,6 +113,7 @@ typedef struct map_info {
uint64_t offset; // file offset of this mapping
uint64_t vaddr; // starting virtual address
size_t memsz; // size of the mapping
+ uint32_t flags; // access flags
struct map_info* next;
} map_info;
@@ -171,11 +173,10 @@ typedef bool (*thread_info_callback)(struct ps_prochandle* ph, pthread_t pid, lw
bool read_thread_info(struct ps_prochandle* ph, thread_info_callback cb);
// adds a new shared object to lib list, returns NULL on failure
-lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base, size_t memsz);
+lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base);
// adds a new shared object to lib list, supply open lib file descriptor as well
-lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd,
- uintptr_t base, size_t memsz);
+lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base);
sa_thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id);
// a test for ELF signature without using libelf
diff --git a/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c b/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c
index 336124f67c8..229abedadad 100644
--- a/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c
+++ b/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c
@@ -248,7 +248,7 @@ static bool read_core_segments(struct ps_prochandle* ph) {
print_debug("failed to read LC_SEGMENT_64 i = %d!\n", i);
goto err;
}
- if (add_map_info(ph, fd, segcmd.fileoff, segcmd.vmaddr, segcmd.vmsize) == NULL) {
+ if (add_map_info(ph, fd, segcmd.fileoff, segcmd.vmaddr, segcmd.vmsize, segcmd.flags) == NULL) {
print_debug("Failed to add map_info at i = %d\n", i);
goto err;
}
@@ -507,7 +507,7 @@ static bool read_shared_lib_info(struct ps_prochandle* ph) {
} else {
break; // Ignore non-relative paths, which are system libs. See JDK-8249779.
}
- add_lib_info(ph, name, iter->vaddr, iter->memsz);
+ add_lib_info(ph, name, iter->vaddr);
break;
}
}
@@ -788,7 +788,7 @@ static bool read_core_segments(struct ps_prochandle* ph, ELF_EHDR* core_ehdr) {
case PT_LOAD: {
if (core_php->p_filesz != 0) {
if (add_map_info(ph, ph->core->core_fd, core_php->p_offset,
- core_php->p_vaddr, core_php->p_filesz) == NULL) goto err;
+ core_php->p_vaddr, core_php->p_filesz, core_php->p_flags) == NULL) goto err;
}
break;
}
@@ -827,7 +827,7 @@ static bool read_lib_segments(struct ps_prochandle* ph, int lib_fd, ELF_EHDR* li
if (existing_map == NULL){
if (add_map_info(ph, lib_fd, lib_php->p_offset,
- target_vaddr, lib_php->p_filesz) == NULL) {
+ target_vaddr, lib_php->p_filesz, lib_php->p_flags) == NULL) {
goto err;
}
} else {
@@ -893,7 +893,7 @@ static bool read_exec_segments(struct ps_prochandle* ph, ELF_EHDR* exec_ehdr) {
case PT_LOAD: {
// add only non-writable segments of non-zero filesz
if (!(exec_php->p_flags & PF_W) && exec_php->p_filesz != 0) {
- if (add_map_info(ph, ph->core->exec_fd, exec_php->p_offset, exec_php->p_vaddr, exec_php->p_filesz) == NULL) goto err;
+ if (add_map_info(ph, ph->core->exec_fd, exec_php->p_offset, exec_php->p_vaddr, exec_php->p_filesz, exec_php->p_flags) == NULL) goto err;
}
break;
}
diff --git a/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.c b/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.c
index df70737392c..52fd791117d 100644
--- a/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.c
+++ b/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.c
@@ -93,11 +93,12 @@ void build_search_table(symtab_t *symtab) {
}
// read symbol table from given fd.
-struct symtab* build_symtab(int fd) {
+struct symtab* build_symtab(int fd, size_t *p_max_offset) {
symtab_t* symtab = NULL;
int i, j;
mach_header_64 header;
off_t image_start;
+ size_t max_offset = 0;
print_debug("build_symtab\n");
if (!get_arch_off(fd, CPU_TYPE_X86_64, &image_start)) {
@@ -187,6 +188,11 @@ struct symtab* build_symtab(int fd) {
if (stridx == 0 || offset == 0) {
continue; // Skip this entry. It's not a reference to code or data
}
+ if (lentry.n_type == N_OSO) {
+ // This is an object file name/path. These entries have something other than
+ // an offset in lentry.n_value, so we need to ignore them.
+ continue;
+ }
symtab->symbols[i].offset = offset;
symtab->symbols[i].name = symtab->strs + stridx;
symtab->symbols[i].size = strlen(symtab->symbols[i].name);
@@ -195,6 +201,11 @@ struct symtab* build_symtab(int fd) {
continue; // Skip this entry. It points to an empty string.
}
+ // Track the maximum offset we've seen. This is used to determine the address range
+ // that the library covers.
+ if (offset > max_offset) {
+ max_offset = (offset + 4096) & ~0xfff; // Round up to next page boundary
+ }
print_debug("symbol read: %d %d n_type=0x%x n_sect=0x%x n_desc=0x%x n_strx=0x%lx offset=0x%lx %s\n",
j, i, lentry.n_type, lentry.n_sect, lentry.n_desc, stridx, offset, symtab->symbols[i].name);
i++;
@@ -212,6 +223,7 @@ struct symtab* build_symtab(int fd) {
// build a hashtable for fast query
build_search_table(symtab);
+ *p_max_offset = max_offset;
return symtab;
quit:
if (symtab) destroy_symtab(symtab);
diff --git a/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.h b/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.h
index f5f8645dabc..a55fbaa1467 100644
--- a/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.h
+++ b/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2020, 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
@@ -32,7 +32,7 @@
struct symtab;
// build symbol table for a given ELF or MachO file escriptor
-struct symtab* build_symtab(int fd);
+struct symtab* build_symtab(int fd, size_t *p_max_offset);
// destroy the symbol table
void destroy_symtab(struct symtab* symtab);
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/SharedObject.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/SharedObject.java
index 2f72f7d5d46..a21c2c21a74 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/SharedObject.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/SharedObject.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2020, 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
@@ -44,5 +44,9 @@ protected long getAddressValue(Address addr) {
return dbg.getAddressValue(addr);
}
+ public ClosestSymbol closestSymbolToPC(Address pcAsAddr) throws DebuggerException {
+ return dbg.lookup(dbg.getAddressValue(pcAsAddr));
+ }
+
private BsdDebugger dbg;
}
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/SharedObject.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/SharedObject.java
index 2c3f7b56614..00be154ad39 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/SharedObject.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/SharedObject.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2020, 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
@@ -44,5 +44,9 @@ protected long getAddressValue(Address addr) {
return dbg.getAddressValue(addr);
}
+ public ClosestSymbol closestSymbolToPC(Address pcAsAddr) throws DebuggerException {
+ return dbg.lookup(dbg.getAddressValue(pcAsAddr));
+ }
+
private LinuxDebugger dbg;
}
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/DSO.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/DSO.java
index 9ad1996547c..01c4821e0cb 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/DSO.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/DSO.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,48 +25,20 @@
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.debugger.cdbg.*;
-import sun.jvm.hotspot.debugger.posix.elf.*;
import sun.jvm.hotspot.utilities.memo.*;
/** Provides a simple wrapper around the ELF library which handles
relocation. */
public abstract class DSO implements LoadObject {
- private MemoizedObject file; // contains ELFFile
private String filename;
private Address addr;
private long size;
- private IsDSO dso = new IsDSO();
- class IsDSO extends MemoizedBoolean {
- protected boolean computeValue() {
- return getFile().getHeader().getFileType() == ELFHeader.FT_DYN;
- }
- };
-
- class ELFFileByName extends MemoizedObject {
- protected Object computeValue() {
- return ELFFileParser.getParser().parse(DSO.this.filename);
- }
- };
-
- class ELFFileByAddress extends MemoizedObject {
- protected Object computeValue() {
- return ELFFileParser.getParser().parse(new AddressDataSource(DSO.this.addr));
- }
- };
-
- public DSO(String filename, long size, Address relocation) throws ELFException {
+ public DSO(String filename, long size, Address relocation) {
this.filename = filename;
this.size = size;
this.addr = relocation;
- this.file = new ELFFileByName();
- }
-
- public DSO(long size, Address relocation) throws ELFException {
- this.addr = relocation;
- this.size = size;
- this.file = new ELFFileByAddress();
}
public String getName() {
@@ -77,17 +49,6 @@ public Address getBase() {
return addr;
}
- /** if this .so is unloaded and re-loaded in the same process at a different
- base, change the base by calling this to avoid re-parsing the ELF. */
- public void setBase(Address newBase) {
- addr = newBase;
- if (filename == null) {
- // ELFFile was created by address. we have to re-parse it.
- file = new ELFFileByAddress();
- dso = new IsDSO();
- }
- }
-
public long getSize() {
return size;
}
@@ -102,39 +63,11 @@ public BlockSym debugInfoForPC(Address pc) throws DebuggerException {
return null;
}
- public ClosestSymbol closestSymbolToPC(Address pcAsAddr) throws DebuggerException {
- boolean dso = isDSO();
- long offset = dso? pcAsAddr.minus(addr) : getAddressValue(pcAsAddr);
- ELFSymbol sym = getFile().getHeader().getELFSymbol(offset);
- return (sym != null)? createClosestSymbol(sym.getName(), offset - sym.getValue()) : null;
- }
-
public LineNumberInfo lineNumberForPC(Address pc) throws DebuggerException {
// FIXME: after stabs parser
return null;
}
- /** return true if file is a .so */
- public boolean isDSO() {
- return dso.getValue();
- }
-
- /** Look up a symbol; returns absolute address or null if symbol was
- not found. */
- public Address lookupSymbol(String symbol) throws ELFException {
- ELFSymbol sym = getFile().getHeader().getELFSymbol(symbol);
- if (sym == null) {
- return null;
- }
-
- long value = sym.getValue();
- if (isDSO()) {
- return addr.addOffsetTo(value);
- } else {
- return newAddress(value);
- }
- }
-
public boolean equals(Object o) {
if (o == null || !(o instanceof DSO)) {
return false;
@@ -147,14 +80,6 @@ public int hashCode() {
return getBase().hashCode();
}
- protected ELFFile getFile() {
- return (ELFFile) file.getValue();
- }
-
protected abstract Address newAddress(long addr);
protected abstract long getAddressValue(Address addr);
-
- protected ClosestSymbol createClosestSymbol(String name, long diff) {
- return new ClosestSymbol(name, diff);
- }
}
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/SharedObject.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/SharedObject.java
index c6a5262824d..95aa7e2e550 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/SharedObject.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/SharedObject.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2020, 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
@@ -44,5 +44,9 @@ protected long getAddressValue(Address addr) {
return dbg.getAddressValue(addr);
}
+ public ClosestSymbol closestSymbolToPC(Address pcAsAddr) throws DebuggerException {
+ return dbg.lookup(dbg.getAddressValue(pcAsAddr));
+ }
+
private ProcDebugger dbg;
}
diff --git a/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c b/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c
index 57eb2f2e175..09526beedc2 100644
--- a/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c
+++ b/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c
@@ -41,6 +41,13 @@
#include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h"
#endif
+// Define a segment permission flag allowing read if there is a read flag. Otherwise use 0.
+#ifdef PF_R
+#define MAP_R_FLAG PF_R
+#else
+#define MAP_R_FLAG 0
+#endif
+
#ifdef LINUX
// I have no idea why this function is called ps_pread() on macos but ps_pdread on linux.
#define ps_pread ps_pdread
@@ -113,7 +120,7 @@ void core_release(struct ps_prochandle* ph) {
}
}
-static map_info* allocate_init_map(int fd, off_t offset, uintptr_t vaddr, size_t memsz) {
+static map_info* allocate_init_map(int fd, off_t offset, uintptr_t vaddr, size_t memsz, uint32_t flags) {
map_info* map;
if ( (map = (map_info*) calloc(1, sizeof(map_info))) == NULL) {
print_debug("can't allocate memory for map_info\n");
@@ -125,14 +132,15 @@ static map_info* allocate_init_map(int fd, off_t offset, uintptr_t vaddr, size_t
map->offset = offset;
map->vaddr = vaddr;
map->memsz = memsz;
+ map->flags = flags;
return map;
}
// add map info with given fd, offset, vaddr and memsz
map_info* add_map_info(struct ps_prochandle* ph, int fd, off_t offset,
- uintptr_t vaddr, size_t memsz) {
+ uintptr_t vaddr, size_t memsz, uint32_t flags) {
map_info* map;
- if ((map = allocate_init_map(fd, offset, vaddr, memsz)) == NULL) {
+ if ((map = allocate_init_map(fd, offset, vaddr, memsz, flags)) == NULL) {
return NULL;
}
@@ -149,7 +157,7 @@ static map_info* add_class_share_map_info(struct ps_prochandle* ph, off_t offset
uintptr_t vaddr, size_t memsz) {
map_info* map;
if ((map = allocate_init_map(ph->core->classes_jsa_fd,
- offset, vaddr, memsz)) == NULL) {
+ offset, vaddr, memsz, MAP_R_FLAG)) == NULL) {
return NULL;
}
diff --git a/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.h b/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.h
index 87155b26559..8531c6545ef 100644
--- a/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.h
+++ b/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,7 @@
map_info* core_lookup(struct ps_prochandle *ph, uintptr_t addr);
map_info* add_map_info(struct ps_prochandle* ph, int fd, off_t offset,
- uintptr_t vaddr, size_t memsz);
+ uintptr_t vaddr, size_t memsz, uint32_t flags);
void core_release(struct ps_prochandle* ph);
bool read_string(struct ps_prochandle* ph, uintptr_t addr, char* buf, size_t size);
bool init_classsharing_workaround(struct ps_prochandle* ph);
diff --git a/src/jdk.incubator.jpackage/macosx/classes/jdk/incubator/jpackage/internal/MacDmgBundler.java b/src/jdk.incubator.jpackage/macosx/classes/jdk/incubator/jpackage/internal/MacDmgBundler.java
index eeaf30b5f01..c599bc1e040 100644
--- a/src/jdk.incubator.jpackage/macosx/classes/jdk/incubator/jpackage/internal/MacDmgBundler.java
+++ b/src/jdk.incubator.jpackage/macosx/classes/jdk/incubator/jpackage/internal/MacDmgBundler.java
@@ -446,9 +446,22 @@ private Path buildDMG( Map params,
// "hdiutil detach" might not work right away due to resource busy error, so
// repeat detach several times.
RetryExecutor retryExecutor = new RetryExecutor();
- // 10 times with 3 second delays.
- retryExecutor.setMaxAttemptsCount(10).setAttemptTimeoutMillis(3000)
- .execute(pb);
+ // Image can get detach even if we got resource busy error, so stop
+ // trying to detach it if it is no longer attached.
+ retryExecutor.setExecutorInitializer(exec -> {
+ if (!Files.exists(mountedRoot)) {
+ retryExecutor.abort();
+ }
+ });
+ try {
+ // 10 times with 3 second delays.
+ retryExecutor.setMaxAttemptsCount(10).setAttemptTimeoutMillis(3000)
+ .execute(pb);
+ } catch (IOException ex) {
+ if (!retryExecutor.isAborted()) {
+ throw ex;
+ }
+ }
}
// Compress it to a new image
diff --git a/src/jdk.incubator.jpackage/share/classes/jdk/incubator/jpackage/internal/RetryExecutor.java b/src/jdk.incubator.jpackage/share/classes/jdk/incubator/jpackage/internal/RetryExecutor.java
index 586477abb27..2370389d52b 100644
--- a/src/jdk.incubator.jpackage/share/classes/jdk/incubator/jpackage/internal/RetryExecutor.java
+++ b/src/jdk.incubator.jpackage/share/classes/jdk/incubator/jpackage/internal/RetryExecutor.java
@@ -53,6 +53,10 @@ void abort() {
aborted = true;
}
+ boolean isAborted() {
+ return aborted;
+ }
+
static RetryExecutor retryOnKnownErrorMessage(String v) {
RetryExecutor result = new RetryExecutor();
return result.setExecutorInitializer(exec -> {
@@ -75,6 +79,10 @@ void execute(ProcessBuilder pb) throws IOException {
private void executeLoop(Supplier execSupplier) throws IOException {
aborted = false;
for (;;) {
+ if (aborted) {
+ break;
+ }
+
try {
Executor exec = execSupplier.get();
if (executorInitializer != null) {
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalNodeTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalNodeTest.java
index 88191e683ec..fc1cde8cf5b 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalNodeTest.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalNodeTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2020, 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
@@ -24,7 +24,9 @@
package org.graalvm.compiler.core.test;
+import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
import org.junit.Test;
public class ConditionalNodeTest extends GraalCompilerTest {
@@ -126,4 +128,73 @@ public static int conditionalTest4(ConditionalNodeTest node, int a) {
node.a = a;
return a;
}
+
+ @SuppressWarnings("all")
+ static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,
+ char[] target, int targetOffset, int targetCount,
+ int fromIndex) {
+ /*
+ * Check arguments; return immediately where possible. For consistency, don't check for null
+ * str.
+ */
+ int rightIndex = sourceCount - targetCount;
+ if (fromIndex < 0) {
+ return -1;
+ }
+ if (fromIndex > rightIndex) {
+ fromIndex = rightIndex;
+ }
+ /* Empty string always matches. */
+ if (targetCount == 0) {
+ return fromIndex;
+ }
+
+ int strLastIndex = targetOffset + targetCount - 1;
+ char strLastChar = target[strLastIndex];
+ int min = sourceOffset + targetCount - 1;
+ int i = min + fromIndex;
+
+ startSearchForLastChar: while (true) {
+ while (i >= min && source[i] != strLastChar) {
+ i--;
+ }
+ if (i < min) {
+ return -1;
+ }
+ int j = i - 1;
+ int start = j - (targetCount - 1);
+ int k = strLastIndex - 1;
+
+ while (j > start) {
+ if (source[j--] != target[k--]) {
+ i--;
+ continue startSearchForLastChar;
+ }
+ }
+ return start - sourceOffset + 1;
+ }
+ }
+
+ public static String simple(String simpleName) {
+ char[] value = simpleName.toCharArray();
+ char[] target = ".".toCharArray();
+ int lastDotIndex = lastIndexOf(value, 0, value.length,
+ target, 0, target.length, value.length);
+ if (lastDotIndex < 0) {
+ return null;
+ }
+ GraalDirectives.deoptimize();
+ return simpleName.substring(0, lastDotIndex);
+ }
+
+ @Override
+ protected OptimisticOptimizations getOptimisticOptimizations() {
+ // Disable profile based optimizations
+ return OptimisticOptimizations.NONE;
+ }
+
+ @Test
+ public void testConditionalExit() {
+ test("simple", Object.class.getName());
+ }
}
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java
index 204bc55a3d5..3d0cf6bea55 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java
@@ -549,6 +549,10 @@ private boolean conditionalNodeOptimization(SimplifierTool tool) {
return false;
}
+ if (falseSuccessor instanceof LoopExitNode && ((LoopExitNode) falseSuccessor).stateAfter != null) {
+ return false;
+ }
+
PhiNode phi = merge.phis().first();
ValueNode falseValue = phi.valueAt(falseEnd);
ValueNode trueValue = phi.valueAt(trueEnd);
@@ -868,6 +872,11 @@ private boolean removeOrMaterializeIf(SimplifierTool tool) {
AbstractEndNode trueEnd = (AbstractEndNode) trueSuccessor().next();
AbstractEndNode falseEnd = (AbstractEndNode) falseSuccessor().next();
AbstractMergeNode merge = trueEnd.merge();
+
+ if (falseSuccessor instanceof LoopExitNode && ((LoopExitNode) falseSuccessor).stateAfter != null) {
+ return false;
+ }
+
if (merge == falseEnd.merge() && trueSuccessor().anchored().isEmpty() && falseSuccessor().anchored().isEmpty()) {
PhiNode singlePhi = null;
int distinct = 0;
@@ -986,6 +995,11 @@ private ValueNode proxyReplacement(ValueNode replacement) {
}
protected void removeThroughFalseBranch(SimplifierTool tool, AbstractMergeNode merge) {
+ // If the LoopExitNode and the Merge still have states then it's incorrect to arbitrarily
+ // pick one side of the branch the represent the control flow. The state on the merge is the
+ // real after state but it would need to be adjusted to represent the effects of the
+ // conditional conversion.
+ assert !(falseSuccessor instanceof LoopExitNode) || ((LoopExitNode) falseSuccessor).stateAfter == null;
AbstractBeginNode trueBegin = trueSuccessor();
LogicNode conditionNode = condition();
graph().removeSplitPropagate(this, trueBegin);
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java
index a3b900d4f4f..1759c0c7263 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java
@@ -177,14 +177,11 @@ protected void addReceiverAnnotations(ExecutableElement member, TypeMirror rcvrT
*/
protected void addParameters(ExecutableElement member, Content htmltree) {
Content paramTree = getParameters(member, false);
- if (paramTree.isEmpty()) {
- htmltree.add("()");
- } else {
+ if (paramTree.charCount() > 2) {
+ // only add zero-width-space for non-empty parameters
htmltree.add(Entity.ZERO_WIDTH_SPACE);
- htmltree.add("(");
- htmltree.add(paramTree);
- paramTree.add(")");
}
+ htmltree.add(paramTree);
}
/**
@@ -196,13 +193,14 @@ protected void addParameters(ExecutableElement member, Content htmltree) {
*/
protected Content getParameters(ExecutableElement member, boolean includeAnnotations) {
Content paramTree = new ContentBuilder();
+ paramTree.add("(");
String sep = "";
List extends VariableElement> parameters = member.getParameters();
TypeMirror rcvrType = member.getReceiverType();
if (includeAnnotations && rcvrType != null && utils.isAnnotated(rcvrType)) {
List extends AnnotationMirror> annotationMirrors = rcvrType.getAnnotationMirrors();
addReceiverAnnotations(member, rcvrType, annotationMirrors, paramTree);
- sep = "," + DocletConstants.NL;
+ sep = "," + DocletConstants.NL + " ";
}
int paramstart;
ExecutableType instMeth = utils.asInstantiatedMethodType(typeElement, member);
@@ -217,6 +215,7 @@ protected Content getParameters(ExecutableElement member, boolean includeAnnotat
writer.addAnnotationInfo(param, paramTree);
if (foundAnnotations) {
paramTree.add(DocletConstants.NL);
+ paramTree.add(" ");
}
}
addParam(member, param, paramType,
@@ -228,19 +227,22 @@ protected Content getParameters(ExecutableElement member, boolean includeAnnotat
for (int i = paramstart + 1; i < parameters.size(); i++) {
paramTree.add(",");
paramTree.add(DocletConstants.NL);
+ paramTree.add(" ");
+
if (includeAnnotations) {
boolean foundAnnotations =
writer.addAnnotationInfo(parameters.get(i),
paramTree);
if (foundAnnotations) {
paramTree.add(DocletConstants.NL);
+ paramTree.add(" ");
}
}
addParam(member, parameters.get(i), instMeth.getParameterTypes().get(i),
(i == parameters.size() - 1) && member.isVarArgs(),
paramTree);
}
-
+ paramTree.add(")");
return paramTree;
}
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java
index e2b2aae691f..f5c140bd5ac 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java
@@ -686,12 +686,11 @@ private void appendParametersAndExceptions(Content htmltree, int lastLineSeparat
// Record current position for indentation of exceptions
int indentSize = htmltree.charCount() - lastLineSeparator;
- if (parameters.isEmpty()) {
- htmltree.add("()");
+ if (parameters.charCount() == 2) {
+ // empty parameters are added without packing
+ htmltree.add(parameters);
} else {
- parameters.add(")");
htmltree.add(Entity.ZERO_WIDTH_SPACE);
- htmltree.add("(");
htmltree.add(HtmlTree.SPAN(HtmlStyle.parameters, parameters));
}
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/script.js b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/script.js
index 85087d3d767..47139324f83 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/script.js
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/script.js
@@ -103,17 +103,17 @@ function indexFilesLoaded() {
}
// Workaround for scroll position not being included in browser history (8249133)
-document.addEventListener("DOMContentLoaded", function() {
+document.addEventListener("DOMContentLoaded", function(e) {
var contentDiv = document.querySelector("div.flex-content");
- window.onpopstate = function(e) {
+ window.addEventListener("popstate", function(e) {
if (e.state !== null) {
contentDiv.scrollTop = e.state;
}
- }
- window.onhashchange = function(e) {
+ });
+ window.addEventListener("hashchange", function(e) {
history.replaceState(contentDiv.scrollTop, document.title);
- }
- contentDiv.onscroll = function(e) {
+ });
+ contentDiv.addEventListener("scroll", function(e) {
var timeoutID;
if (!timeoutID) {
timeoutID = setTimeout(function() {
@@ -121,6 +121,8 @@ document.addEventListener("DOMContentLoaded", function() {
timeoutID = null;
}, 100);
}
+ });
+ if (!location.hash) {
+ history.replaceState(contentDiv.scrollTop, document.title);
}
- history.replaceState(contentDiv.scrollTop, document.title);
});
diff --git a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java
index 1fa09dfae5c..60a14bddf09 100644
--- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java
@@ -25,34 +25,28 @@
package jdk.internal.jshell.tool;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
+import java.util.*;
import java.util.Map.Entry;
-import java.util.Objects;
-import java.util.Set;
-import java.util.StringJoiner;
-import java.util.function.BiConsumer;
-import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
-import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import java.util.stream.Collector;
-import static java.util.stream.Collectors.joining;
-import static java.util.stream.Collectors.toMap;
-import static jdk.internal.jshell.tool.ContinuousCompletionProvider.PERFECT_MATCHER;
+
import jdk.internal.jshell.tool.JShellTool.CompletionProvider;
+
+import static java.util.stream.Collectors.*;
+import static jdk.internal.jshell.tool.ContinuousCompletionProvider.PERFECT_MATCHER;
import static jdk.internal.jshell.tool.JShellTool.EMPTY_COMPLETION_PROVIDER;
+import static jdk.internal.jshell.tool.Selector.SelectorKind;
+import static jdk.internal.jshell.tool.Selector.SelectorInstanceWithDoc;
+import static jdk.internal.jshell.tool.Selector.SelectorBuilder;
+import static jdk.internal.jshell.tool.Selector.FormatAction;
+import static jdk.internal.jshell.tool.Selector.FormatCase;
+import static jdk.internal.jshell.tool.Selector.FormatErrors;
+import static jdk.internal.jshell.tool.Selector.FormatResolve;
+import static jdk.internal.jshell.tool.Selector.FormatUnresolved;
+import static jdk.internal.jshell.tool.Selector.FormatWhen;
+
/**
* Feedback customization support
@@ -70,6 +64,24 @@ class Feedback {
// For encoding to Properties String
private static final String RECORD_SEPARATOR = "\u241E";
+ // Selector for truncation of var value
+ private static final Selector VAR_VALUE_ADD_SELECTOR = new Selector(
+ FormatCase.VARVALUE,
+ FormatAction.ADDED,
+ FormatWhen.PRIMARY,
+ FormatResolve.OK,
+ FormatUnresolved.UNRESOLVED0,
+ FormatErrors.ERROR0);
+
+ // Selector for typeKind record
+ private static final Selector RECORD_TYPEKIND_SELECTOR = new Selector(
+ EnumSet.of(FormatCase.RECORD),
+ EnumSet.noneOf(FormatAction.class),
+ EnumSet.noneOf(FormatWhen.class),
+ EnumSet.noneOf(FormatResolve.class),
+ EnumSet.noneOf(FormatUnresolved.class),
+ EnumSet.noneOf(FormatErrors.class));
+
// Current mode -- initial value is placeholder during start-up
private Mode mode = new Mode("");
@@ -82,43 +94,36 @@ class Feedback {
// Mapping of mode names to encoded retained mode
private final Map retainedMap = new HashMap<>();
- // Mapping selector enum names to enums
- private final Map> selectorMap = new HashMap<>();
-
- private static final long ALWAYS = bits(FormatCase.all, FormatAction.all, FormatWhen.all,
- FormatResolve.all, FormatUnresolved.all, FormatErrors.all);
- private static final long ANY = 0L;
-
public boolean shouldDisplayCommandFluff() {
return mode.commandFluff;
}
public String getPre() {
- return mode.format("pre", ANY);
+ return mode.format("pre", Selector.ANY);
}
public String getPost() {
- return mode.format("post", ANY);
+ return mode.format("post", Selector.ANY);
}
public String getErrorPre() {
- return mode.format("errorpre", ANY);
+ return mode.format("errorpre", Selector.ANY);
}
public String getErrorPost() {
- return mode.format("errorpost", ANY);
+ return mode.format("errorpost", Selector.ANY);
}
public String format(FormatCase fc, FormatAction fa, FormatWhen fw,
- FormatResolve fr, FormatUnresolved fu, FormatErrors fe,
- String name, String type, String value, String unresolved, List errorLines) {
+ FormatResolve fr, FormatUnresolved fu, FormatErrors fe,
+ String name, String type, String value, String unresolved, List errorLines) {
return mode.format(fc, fa, fw, fr, fu, fe,
name, type, value, unresolved, errorLines);
}
public String format(String field, FormatCase fc, FormatAction fa, FormatWhen fw,
- FormatResolve fr, FormatUnresolved fu, FormatErrors fe,
- String name, String type, String value, String unresolved, List errorLines) {
+ FormatResolve fr, FormatUnresolved fu, FormatErrors fe,
+ String name, String type, String value, String unresolved, List errorLines) {
return mode.format(field, fc, fa, fw, fr, fu, fe,
name, type, value, unresolved, errorLines);
}
@@ -175,30 +180,6 @@ JShellTool.CompletionProvider modeCompletions(CompletionProvider successor) {
PERFECT_MATCHER);
}
- {
- for (FormatCase e : FormatCase.all)
- selectorMap.put(e.name().toLowerCase(Locale.US), e);
- for (FormatAction e : FormatAction.all)
- selectorMap.put(e.name().toLowerCase(Locale.US), e);
- for (FormatResolve e : FormatResolve.all)
- selectorMap.put(e.name().toLowerCase(Locale.US), e);
- for (FormatUnresolved e : FormatUnresolved.all)
- selectorMap.put(e.name().toLowerCase(Locale.US), e);
- for (FormatErrors e : FormatErrors.all)
- selectorMap.put(e.name().toLowerCase(Locale.US), e);
- for (FormatWhen e : FormatWhen.all)
- selectorMap.put(e.name().toLowerCase(Locale.US), e);
- }
-
- private static class SelectorSets {
- Set cc;
- Set ca;
- Set cw;
- Set cr;
- Set cu;
- Set ce;
- }
-
/**
* Holds all the context of a mode mode
*/
@@ -210,8 +191,8 @@ private static class Mode {
// Display command verification/information
boolean commandFluff;
- // Event cases: class, method, expression, ...
- final Map> cases;
+ // Setting (including format) by field
+ final Map> byField;
boolean readOnly = false;
@@ -220,19 +201,20 @@ private static class Mode {
static class Setting {
- final long enumBits;
final String format;
+ final Selector selector;
- Setting(long enumBits, String format) {
- this.enumBits = enumBits;
+ Setting(String format, Selector selector) {
this.format = format;
+ this.selector = selector;
}
@Override
public boolean equals(Object o) {
if (o instanceof Setting) {
Setting ing = (Setting) o;
- return enumBits == ing.enumBits && format.equals(ing.format);
+ return format.equals(ing.format)
+ && selector.equals(ing.selector);
} else {
return false;
}
@@ -241,81 +223,61 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
int hash = 7;
- hash = 67 * hash + (int) (this.enumBits ^ (this.enumBits >>> 32));
+ hash = 67 * hash + Objects.hashCode(this.selector);
hash = 67 * hash + Objects.hashCode(this.format);
return hash;
}
+
+ @Override
+ public String toString() {
+ return "Setting(" + format + "," + selector.toString() + ")";
+ }
}
/**
* Set up an empty mode.
*
* @param name
- * @param commandFluff True if should display command fluff messages
*/
Mode(String name) {
this.name = name;
- this.cases = new HashMap<>();
- add("name", new Setting(ALWAYS, "%1$s"));
- add("type", new Setting(ALWAYS, "%2$s"));
- add("value", new Setting(ALWAYS, "%3$s"));
- add("unresolved", new Setting(ALWAYS, "%4$s"));
- add("errors", new Setting(ALWAYS, "%5$s"));
- add("err", new Setting(ALWAYS, "%6$s"));
-
- add("errorline", new Setting(ALWAYS, " {err}%n"));
-
- add("pre", new Setting(ALWAYS, "| "));
- add("post", new Setting(ALWAYS, "%n"));
- add("errorpre", new Setting(ALWAYS, "| "));
- add("errorpost", new Setting(ALWAYS, "%n"));
+ this.byField = new HashMap<>();
+ set("name", "%1$s", Selector.ALWAYS);
+ set("type", "%2$s", Selector.ALWAYS);
+ set("value", "%3$s", Selector.ALWAYS);
+ set("unresolved", "%4$s", Selector.ALWAYS);
+ set("errors", "%5$s", Selector.ALWAYS);
+ set("err", "%6$s", Selector.ALWAYS);
+
+ set("errorline", " {err}%n", Selector.ALWAYS);
+
+ set("pre", "| ", Selector.ALWAYS);
+ set("post", "%n", Selector.ALWAYS);
+ set("errorpre", "| ", Selector.ALWAYS);
+ set("errorpost", "%n", Selector.ALWAYS);
+ }
+
+ private Mode(String name, boolean commandFluff, String prompt, String continuationPrompt) {
+ this.name = name;
+ this.commandFluff = commandFluff;
+ this.prompt = prompt;
+ this.continuationPrompt = continuationPrompt;
+ this.byField = new HashMap<>();
}
/**
* Set up a copied mode.
*
* @param name
- * @param m Mode to copy, or null for no fresh
+ * @param m Mode to copy, or null for no fresh
*/
Mode(String name, Mode m) {
- this.name = name;
- this.commandFluff = m.commandFluff;
- this.prompt = m.prompt;
- this.continuationPrompt = m.continuationPrompt;
- this.cases = new HashMap<>();
- m.cases.entrySet().stream()
- .forEach(fes -> fes.getValue()
- .forEach(ing -> add(fes.getKey(), ing)));
+ this(name, m.commandFluff, m.prompt, m.continuationPrompt);
+ m.byField.forEach((fieldName, settingList) ->
+ settingList.forEach(setting -> set(fieldName, setting.format, setting.selector)));
}
- /**
- * Set up a mode reconstituted from a preferences string.
- *
- * @param it the encoded Mode broken into String chunks, may contain
- * subsequent encoded modes
- */
- Mode(Iterator it) {
- this.name = it.next();
- this.commandFluff = Boolean.parseBoolean(it.next());
- this.prompt = it.next();
- this.continuationPrompt = it.next();
- cases = new HashMap<>();
- String field;
- while (!(field = it.next()).equals("***")) {
- String open = it.next();
- assert open.equals("(");
- List settings = new ArrayList<>();
- String bits;
- while (!(bits = it.next()).equals(")")) {
- String format = it.next();
- Setting ing = new Setting(Long.parseLong(bits), format);
- settings.add(ing);
- }
- cases.put(field, settings);
- }
- }
-
@Override
public boolean equals(Object o) {
if (o instanceof Mode) {
@@ -324,7 +286,7 @@ public boolean equals(Object o) {
&& commandFluff == m.commandFluff
&& prompt.equals((m.prompt))
&& continuationPrompt.equals((m.continuationPrompt))
- && cases.equals((m.cases));
+ && byField.equals((m.byField));
} else {
return false;
}
@@ -356,11 +318,11 @@ String encode() {
el.add(String.valueOf(commandFluff));
el.add(prompt);
el.add(continuationPrompt);
- for (Entry> es : cases.entrySet()) {
+ for (Entry> es : byField.entrySet()) {
el.add(es.getKey());
el.add("(");
for (Setting ing : es.getValue()) {
- el.add(String.valueOf(ing.enumBits));
+ el.add(ing.selector.toString());
el.add(ing.format);
}
el.add(")");
@@ -370,28 +332,21 @@ String encode() {
}
private void add(String field, Setting ing) {
- List settings = cases.get(field);
+ List settings = byField.get(field);
if (settings == null) {
settings = new ArrayList<>();
- cases.put(field, settings);
+ byField.put(field, settings);
} else {
- // remove obscured settings
- long mask = ~ing.enumBits;
- settings.removeIf(t -> (t.enumBits & mask) == 0);
+ // remove completely obscured settings.
+ // transformation of partially obscured would be confusing to user and complex
+ Selector addedSelector = ing.selector;
+ settings.removeIf(t -> t.selector.includedIn(addedSelector));
}
settings.add(ing);
}
- void set(String field,
- Collection cc, Collection ca, Collection cw,
- Collection cr, Collection cu, Collection ce,
- String format) {
- long bits = bits(cc, ca, cw, cr, cu, ce);
- set(field, bits, format);
- }
-
- void set(String field, long bits, String format) {
- add(field, new Setting(bits, format));
+ void set(String field, String format, Selector selector) {
+ add(field, new Setting(format, selector));
}
/**
@@ -399,16 +354,16 @@ void set(String field, long bits, String format) {
*
* @return format string
*/
- String format(String field, long bits) {
- List settings = cases.get(field);
+ String format(String field, Selector selector) {
+ List settings = byField.get(field);
if (settings == null) {
return ""; //TODO error?
}
String format = null;
+ // Iterate backward, as most recent setting that covers the case is used
for (int i = settings.size() - 1; i >= 0; --i) {
Setting ing = settings.get(i);
- long mask = ing.enumBits;
- if ((bits & mask) == bits) {
+ if (ing.selector.covers(selector)) {
format = ing.format;
break;
}
@@ -420,7 +375,7 @@ String format(String field, long bits) {
StringBuffer sb = new StringBuffer(format.length());
while (m.find()) {
String fieldName = m.group(1);
- String sub = format(fieldName, bits);
+ String sub = format(fieldName, selector);
m.appendReplacement(sb, Matcher.quoteReplacement(sub));
}
m.appendTail(sb);
@@ -428,18 +383,15 @@ String format(String field, long bits) {
}
String truncateVarValue(String value) {
- return truncateValue(value,
- bits(FormatCase.VARVALUE, FormatAction.ADDED,
- FormatWhen.PRIMARY, FormatResolve.OK,
- FormatUnresolved.UNRESOLVED0, FormatErrors.ERROR0));
+ return truncateValue(value, VAR_VALUE_ADD_SELECTOR);
}
- String truncateValue(String value, long bits) {
+ String truncateValue(String value, Selector selector) {
if (value==null) {
return "";
} else {
// Retrieve the truncation length
- String truncField = format(TRUNCATION_FIELD, bits);
+ String truncField = format(TRUNCATION_FIELD, selector);
if (truncField.isEmpty()) {
// No truncation set, use whole value
return value;
@@ -468,30 +420,30 @@ String truncateValue(String value, long bits) {
// Compute the display output given full context and values
String format(FormatCase fc, FormatAction fa, FormatWhen fw,
- FormatResolve fr, FormatUnresolved fu, FormatErrors fe,
- String name, String type, String value, String unresolved, List errorLines) {
+ FormatResolve fr, FormatUnresolved fu, FormatErrors fe,
+ String name, String type, String value, String unresolved, List errorLines) {
return format("display", fc, fa, fw, fr, fu, fe,
name, type, value, unresolved, errorLines);
}
// Compute the display output given full context and values
String format(String field, FormatCase fc, FormatAction fa, FormatWhen fw,
- FormatResolve fr, FormatUnresolved fu, FormatErrors fe,
- String name, String type, String value, String unresolved, List errorLines) {
+ FormatResolve fr, FormatUnresolved fu, FormatErrors fe,
+ String name, String type, String value, String unresolved, List errorLines) {
// Convert the context into a bit representation used as selectors for store field formats
- long bits = bits(fc, fa, fw, fr, fu, fe);
+ Selector selector = new Selector(fc, fa, fw, fr, fu, fe);
String fname = name==null? "" : name;
String ftype = type==null? "" : type;
// Compute the representation of value
- String fvalue = truncateValue(value, bits);
+ String fvalue = truncateValue(value, selector);
String funresolved = unresolved==null? "" : unresolved;
String errors = errorLines.stream()
.map(el -> String.format(
- format("errorline", bits),
+ format("errorline", selector),
fname, ftype, fvalue, funresolved, "*cannot-use-errors-here*", el))
.collect(joining());
return String.format(
- format(field, bits),
+ format(field, selector),
fname, ftype, fvalue, funresolved, errors, "*cannot-use-err-here*");
}
@@ -509,279 +461,6 @@ String getContinuationPrompt(String nextId) {
}
}
- // Representation of one instance of all the enum values as bits in a long
- private static long bits(FormatCase fc, FormatAction fa, FormatWhen fw,
- FormatResolve fr, FormatUnresolved fu, FormatErrors fe) {
- long res = 0L;
- res |= 1 << fc.ordinal();
- res <<= FormatAction.count;
- res |= 1 << fa.ordinal();
- res <<= FormatWhen.count;
- res |= 1 << fw.ordinal();
- res <<= FormatResolve.count;
- res |= 1 << fr.ordinal();
- res <<= FormatUnresolved.count;
- res |= 1 << fu.ordinal();
- res <<= FormatErrors.count;
- res |= 1 << fe.ordinal();
- return res;
- }
-
- // Representation of a space of enum values as or'edbits in a long
- private static long bits(Collection cc, Collection ca, Collection cw,
- Collection cr, Collection cu, Collection ce) {
- long res = 0L;
- for (FormatCase fc : cc)
- res |= 1 << fc.ordinal();
- res <<= FormatAction.count;
- for (FormatAction fa : ca)
- res |= 1 << fa.ordinal();
- res <<= FormatWhen.count;
- for (FormatWhen fw : cw)
- res |= 1 << fw.ordinal();
- res <<= FormatResolve.count;
- for (FormatResolve fr : cr)
- res |= 1 << fr.ordinal();
- res <<= FormatUnresolved.count;
- for (FormatUnresolved fu : cu)
- res |= 1 << fu.ordinal();
- res <<= FormatErrors.count;
- for (FormatErrors fe : ce)
- res |= 1 << fe.ordinal();
- return res;
- }
-
- private static SelectorSets unpackEnumbits(long enumBits) {
- class Unpacker {
-
- SelectorSets u = new SelectorSets();
- long b = enumBits;
-
- > Set unpackEnumbits(E[] values) {
- Set c = new HashSet<>();
- for (int i = 0; i < values.length; ++i) {
- if ((b & (1 << i)) != 0) {
- c.add(values[i]);
- }
- }
- b >>>= values.length;
- return c;
- }
-
- SelectorSets unpack() {
- // inverseof the order they were packed
- u.ce = unpackEnumbits(FormatErrors.values());
- u.cu = unpackEnumbits(FormatUnresolved.values());
- u.cr = unpackEnumbits(FormatResolve.values());
- u.cw = unpackEnumbits(FormatWhen.values());
- u.ca = unpackEnumbits(FormatAction.values());
- u.cc = unpackEnumbits(FormatCase.values());
- return u;
- }
- }
- return new Unpacker().unpack();
- }
-
- interface Selector & Selector> {
- SelectorCollector collector(Setter.SelectorList sl);
- String doc();
- }
-
- /**
- * The event cases
- */
- public enum FormatCase implements Selector {
- IMPORT("import declaration"),
- CLASS("class declaration"),
- INTERFACE("interface declaration"),
- ENUM("enum declaration"),
- ANNOTATION("annotation interface declaration"),
- RECORD("record declaration"),
- METHOD("method declaration -- note: {type}==parameter-types"),
- VARDECL("variable declaration without init"),
- VARINIT("variable declaration with init"),
- EXPRESSION("expression -- note: {name}==scratch-variable-name"),
- VARVALUE("variable value expression"),
- ASSIGNMENT("assign variable"),
- STATEMENT("statement");
- String doc;
- static final EnumSet all = EnumSet.allOf(FormatCase.class);
- static final int count = all.size();
-
- @Override
- public SelectorCollector collector(Setter.SelectorList sl) {
- return sl.cases;
- }
-
- @Override
- public String doc() {
- return doc;
- }
-
- private FormatCase(String doc) {
- this.doc = doc;
- }
- }
-
- /**
- * The event actions
- */
- public enum FormatAction implements Selector {
- ADDED("snippet has been added"),
- MODIFIED("an existing snippet has been modified"),
- REPLACED("an existing snippet has been replaced with a new snippet"),
- OVERWROTE("an existing snippet has been overwritten"),
- DROPPED("snippet has been dropped"),
- USED("snippet was used when it cannot be");
- String doc;
- static final EnumSet all = EnumSet.allOf(FormatAction.class);
- static final int count = all.size();
-
- @Override
- public SelectorCollector collector(Setter.SelectorList sl) {
- return sl.actions;
- }
-
- @Override
- public String doc() {
- return doc;
- }
-
- private FormatAction(String doc) {
- this.doc = doc;
- }
- }
-
- /**
- * When the event occurs: primary or update
- */
- public enum FormatWhen implements Selector {
- PRIMARY("the entered snippet"),
- UPDATE("an update to a dependent snippet");
- String doc;
- static final EnumSet all = EnumSet.allOf(FormatWhen.class);
- static final int count = all.size();
-
- @Override
- public SelectorCollector collector(Setter.SelectorList sl) {
- return sl.whens;
- }
-
- @Override
- public String doc() {
- return doc;
- }
-
- private FormatWhen(String doc) {
- this.doc = doc;
- }
- }
-
- /**
- * Resolution problems
- */
- public enum FormatResolve implements Selector {
- OK("resolved correctly"),
- DEFINED("defined despite recoverably unresolved references"),
- NOTDEFINED("not defined because of recoverably unresolved references");
- String doc;
- static final EnumSet all = EnumSet.allOf(FormatResolve.class);
- static final int count = all.size();
-
- @Override
- public SelectorCollector collector(Setter.SelectorList sl) {
- return sl.resolves;
- }
-
- @Override
- public String doc() {
- return doc;
- }
-
- private FormatResolve(String doc) {
- this.doc = doc;
- }
- }
-
- /**
- * Count of unresolved references
- */
- public enum FormatUnresolved implements Selector {
- UNRESOLVED0("no names are unresolved"),
- UNRESOLVED1("one name is unresolved"),
- UNRESOLVED2("two or more names are unresolved");
- String doc;
- static final EnumSet all = EnumSet.allOf(FormatUnresolved.class);
- static final int count = all.size();
-
- @Override
- public SelectorCollector collector(Setter.SelectorList sl) {
- return sl.unresolvedCounts;
- }
-
- @Override
- public String doc() {
- return doc;
- }
-
- private FormatUnresolved(String doc) {
- this.doc = doc;
- }
- }
-
- /**
- * Count of unresolved references
- */
- public enum FormatErrors implements Selector {
- ERROR0("no errors"),
- ERROR1("one error"),
- ERROR2("two or more errors");
- String doc;
- static final EnumSet all = EnumSet.allOf(FormatErrors.class);
- static final int count = all.size();
-
- @Override
- public SelectorCollector collector(Setter.SelectorList sl) {
- return sl.errorCounts;
- }
-
- @Override
- public String doc() {
- return doc;
- }
-
- private FormatErrors(String doc) {
- this.doc = doc;
- }
- }
-
- class SelectorCollector & Selector> {
- final EnumSet all;
- EnumSet set = null;
- SelectorCollector(EnumSet all) {
- this.all = all;
- }
- void add(Object o) {
- @SuppressWarnings("unchecked")
- E e = (E) o;
- if (set == null) {
- set = EnumSet.of(e);
- } else {
- set.add(e);
- }
- }
-
- boolean isEmpty() {
- return set == null;
- }
-
- EnumSet getSet() {
- return set == null
- ? all
- : set;
- }
- }
-
// Class used to set custom eval output formats
// For both /set format -- Parse arguments, setting custom format, or printing error
private class Setter {
@@ -827,52 +506,6 @@ void errorat(String messageKey, Object... args) {
messageHandler.errormsg(messageKey, a2);
}
- String selectorsToString(SelectorSets u) {
- StringBuilder sb = new StringBuilder();
- selectorToString(sb, u.cc, FormatCase.values());
- selectorToString(sb, u.ca, FormatAction.values());
- selectorToString(sb, u.cw, FormatWhen.values());
- selectorToString(sb, u.cr, FormatResolve.values());
- selectorToString(sb, u.cu, FormatUnresolved.values());
- selectorToString(sb, u.ce, FormatErrors.values());
- return sb.toString();
- }
-
- private > void selectorToString(StringBuilder sb, Set c, E[] values) {
- if (!c.containsAll(Arrays.asList(values))) {
- sb.append(c.stream()
- .sorted((x, y) -> x.ordinal() - y.ordinal())
- .map(v -> v.name().toLowerCase(Locale.US))
- .collect(new Collector() {
- @Override
- public BiConsumer accumulator() {
- return StringJoiner::add;
- }
-
- @Override
- public Supplier supplier() {
- return () -> new StringJoiner(",", (sb.length() == 0)? "" : "-", "")
- .setEmptyValue("");
- }
-
- @Override
- public BinaryOperator combiner() {
- return StringJoiner::merge;
- }
-
- @Override
- public Function finisher() {
- return StringJoiner::toString;
- }
-
- @Override
- public Set characteristics() {
- return Collections.emptySet();
- }
- }));
- }
- }
-
// Show format settings -- in a predictable order, for testing...
void showFormatSettings(Mode sm, String f) {
if (sm == null) {
@@ -880,7 +513,7 @@ void showFormatSettings(Mode sm, String f) {
.sorted((es1, es2) -> es1.getKey().compareTo(es2.getKey()))
.forEach(m -> showFormatSettings(m.getValue(), f));
} else {
- sm.cases.entrySet().stream()
+ sm.byField.entrySet().stream()
.filter(ec -> (f == null)
? !ec.getKey().equals(TRUNCATION_FIELD)
: ec.getKey().equals(f))
@@ -889,7 +522,7 @@ void showFormatSettings(Mode sm, String f) {
ec.getValue().forEach(s -> {
hard("/set format %s %s %s %s",
sm.name, ec.getKey(), toStringLiteral(s.format),
- selectorsToString(unpackEnumbits(s.enumBits)));
+ s.selector.toString());
});
});
@@ -900,12 +533,12 @@ void showTruncationSettings(Mode sm) {
if (sm == null) {
modeMap.values().forEach(this::showTruncationSettings);
} else {
- List trunc = sm.cases.get(TRUNCATION_FIELD);
+ List trunc = sm.byField.get(TRUNCATION_FIELD);
if (trunc != null) {
trunc.forEach(s -> {
hard("/set truncation %s %s %s",
sm.name, s.format,
- selectorsToString(unpackEnumbits(s.enumBits)));
+ s.selector.toString());
});
}
}
@@ -939,7 +572,7 @@ void showModeSettings(String umode, String msg) {
m = modeMap.get(umode);
}
if (retained != null) {
- Mode rm = new Mode(encodedModeIterator(retained));
+ Mode rm = buildMode(encodedModeIterator(retained));
showModeSettings(rm);
hard("/set mode -retain %s", umode);
if (m != null && !m.equals(rm)) {
@@ -994,7 +627,7 @@ boolean setPrompt() {
/**
* Set mode. Create, changed, or delete a feedback mode. For @{code /set
- * mode [] [-command|-quiet|-delete]}.
+ * mode [] [-command|-quiet|-delete|-retain]}.
*
* @return true if successful
*/
@@ -1134,7 +767,7 @@ boolean setFormat() {
String field = toIdentifier(next(), "jshell.err.field.name");
String format = nextFormat();
if (valid && format == null) {
- if (field != null && m != null && !m.cases.containsKey(field)) {
+ if (field != null && m != null && !m.byField.containsKey(field)) {
errorat("jshell.err.field.name", field);
} else {
showFormatSettings(m, field);
@@ -1206,9 +839,9 @@ boolean restoreEncodedModes(String allEncoded) {
Iterator itr = encodedModeIterator(allEncoded);
while (itr.hasNext()) {
// Reconstruct the encoded mode
- Mode m = new Mode(itr);
+ Mode m = buildMode(itr);
modeMap.put(m.name, m);
- // Continue to retain it a new retains occur
+ // Continue to retain if a new retains occur
retainedMap.put(m.name, m.encode());
}
return true;
@@ -1220,6 +853,78 @@ boolean restoreEncodedModes(String allEncoded) {
}
}
+
+ /**
+ * Set up a mode reconstituted from a preferences string.
+ *
+ * @param it the encoded Mode broken into String chunks, may contain
+ * subsequent encoded modes
+ */
+ private Mode buildMode(Iterator it) {
+ Mode newMode = new Mode(it.next(), Boolean.parseBoolean(it.next()), it.next(), it.next());
+ Map> fields = new HashMap<>();
+ long suspiciousBits = Selector.OLD_ALWAYS.asBits();
+ boolean suspicious = false;
+ String field;
+ while (!(field = it.next()).equals("***")) {
+ String open = it.next();
+ assert open.equals("(");
+ List settings = new ArrayList<>();
+ String selectorText;
+ while (!(selectorText = it.next()).equals(")")) {
+ String format = it.next();
+ Selector selector;
+ if (selectorText.isEmpty()) {
+ selector = Selector.ALWAYS;
+ } else if (Character.isDigit(selectorText.charAt(0))) {
+ // legacy format, bits
+ long bits = Long.parseLong(selectorText);
+ suspicious |= bits == suspiciousBits;
+ selector = new Selector(bits);
+ } else {
+ selector = parseSelector(selectorText);
+ }
+ Mode.Setting ing = new Mode.Setting(format, selector);
+ settings.add(ing);
+ }
+ fields.put(field, settings);
+ }
+ List tk;
+ List errf;
+ // If suspicious that this is a pre-JDK-14 settings, check deeper...
+ if (suspicious
+ // Super simple might not define typeKind, otherwise check for JDK-14 presence of record
+ && ((tk = fields.get("typeKind")) == null
+ || !tk.stream().anyMatch(tkc -> tkc.selector.equals(RECORD_TYPEKIND_SELECTOR)))
+ // no record typeKind, now check for corruption
+ && ((errf = fields.get("err")) == null
+ || errf.stream().anyMatch(tkc -> tkc.selector.equals(Selector.OLD_ALWAYS)))) {
+ // Pre-JDK-14 setting found, convert them
+
+ // start with solid base, ideally normal
+ Mode base = modeMap.get("normal");
+ if (base == null) {
+ base = mode;
+ }
+
+ // Make sure any current fields/selectors are covered: filling in with the base (normal)
+ base.byField.forEach((fieldName, settingList) ->
+ settingList.forEach(setting -> newMode.set(fieldName, setting.format, setting.selector)));
+
+ // Now, overlay with user's settings (position adjusted).
+ // Assume any setting for class applies to record, except for typeKind definition where base definition
+ // should fall through.
+ fields.forEach((fieldName, settingList) -> {
+ settingList.forEach(setting -> newMode.set(fieldName, setting.format,
+ Selector.fromPreJDK14(setting.selector, !fieldName.equals("typeKind"))));
+ });
+ } else {
+ fields.forEach((fieldName, settingList) ->
+ settingList.forEach(setting -> newMode.set(fieldName, setting.format, setting.selector)));
+ }
+ return newMode;
+ }
+
Iterator encodedModeIterator(String encoded) {
String[] ms = encoded.split(RECORD_SEPARATOR);
return Arrays.asList(ms).iterator();
@@ -1228,26 +933,20 @@ Iterator encodedModeIterator(String encoded) {
// install the format of a field under parsed selectors
void installFormat(Mode m, String field, String format, String help) {
String slRaw;
- List slList = new ArrayList<>();
+ List selectorList = new ArrayList<>();
while (valid && (slRaw = next()) != null) {
- SelectorList sl = new SelectorList();
- sl.parseSelectorList(slRaw);
- slList.add(sl);
+ selectorList.add(parseSelector(slRaw));
}
checkOptionsAndRemainingInput();
if (valid) {
if (m.readOnly) {
errorat("jshell.err.not.valid.with.predefined.mode", m.name);
- } else if (slList.isEmpty()) {
- // No selectors specified, then always the format
- m.set(field, ALWAYS, format);
+ } else if (selectorList.isEmpty()) {
+ // No selectors specified, then always use the format
+ m.set(field, format, Selector.ALWAYS);
} else {
// Set the format of the field for specified selector
- slList.stream()
- .forEach(sl -> m.set(field,
- sl.cases.getSet(), sl.actions.getSet(), sl.whens.getSet(),
- sl.resolves.getSet(), sl.unresolvedCounts.getSet(), sl.errorCounts.getSet(),
- format));
+ selectorList.forEach(sel -> m.set(field, format, sel));
}
} else {
fluffmsg("jshell.msg.see", help);
@@ -1281,7 +980,6 @@ String next() {
*
* @param id the string to check, MUST be the most recently retrieved
* token from 'at'.
- * @param missing null for no null error, otherwise the resource error to display if id is null
* @param err the resource error to display if not an identifier
* @return the identifier string, or null if null or not an identifier
*/
@@ -1425,41 +1123,35 @@ private String toStringLiteral(String s) {
return sb.toString();
}
- class SelectorList {
-
- SelectorCollector cases = new SelectorCollector<>(FormatCase.all);
- SelectorCollector actions = new SelectorCollector<>(FormatAction.all);
- SelectorCollector whens = new SelectorCollector<>(FormatWhen.all);
- SelectorCollector resolves = new SelectorCollector<>(FormatResolve.all);
- SelectorCollector unresolvedCounts = new SelectorCollector<>(FormatUnresolved.all);
- SelectorCollector errorCounts = new SelectorCollector<>(FormatErrors.all);
-
- final void parseSelectorList(String sl) {
- for (String s : sl.split("-")) {
- SelectorCollector> lastCollector = null;
- for (String as : s.split(",")) {
- if (!as.isEmpty()) {
- Selector> sel = selectorMap.get(as);
- if (sel == null) {
- errorat("jshell.err.feedback.not.a.valid.selector", as, s);
- return;
- }
- SelectorCollector> collector = sel.collector(this);
- if (lastCollector == null) {
- if (!collector.isEmpty()) {
- errorat("jshell.err.feedback.multiple.sections", as, s);
- return;
- }
- } else if (collector != lastCollector) {
- errorat("jshell.err.feedback.different.selector.kinds", as, s);
- return;
+ private Selector parseSelector(String selectorText) {
+ SelectorBuilder seb = new SelectorBuilder(selectorText);
+ EnumSet