Skip to content

Commit dfd6b2b

Browse files
committed
Merge
2 parents 5832882 + 6401633 commit dfd6b2b

22 files changed

Lines changed: 606 additions & 161 deletions

File tree

src/hotspot/cpu/x86/x86_32.ad

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11539,7 +11539,7 @@ instruct rep_stos(eCXRegI cnt, eDIRegP base, regD tmp, eAXRegI zero, Universe du
1153911539
%}
1154011540

1154111541
// Small ClearArray AVX512 non-constant length.
11542-
instruct rep_stos_evex(eCXRegI cnt, eDIRegP base, regD tmp, kReg ktmp, eAXRegI zero, Universe dummy, eFlagsReg cr) %{
11542+
instruct rep_stos_evex(eCXRegI cnt, eDIRegP base, legRegD tmp, kReg ktmp, eAXRegI zero, Universe dummy, eFlagsReg cr) %{
1154311543
predicate(!((ClearArrayNode*)n)->is_large() && (UseAVX > 2));
1154411544
match(Set dummy (ClearArray cnt base));
1154511545
ins_cost(125);
@@ -11650,7 +11650,7 @@ instruct rep_stos_large(eCXRegI cnt, eDIRegP base, regD tmp, eAXRegI zero, Unive
1165011650
%}
1165111651

1165211652
// Large ClearArray AVX512.
11653-
instruct rep_stos_large_evex(eCXRegI cnt, eDIRegP base, regD tmp, kReg ktmp, eAXRegI zero, Universe dummy, eFlagsReg cr) %{
11653+
instruct rep_stos_large_evex(eCXRegI cnt, eDIRegP base, legRegD tmp, kReg ktmp, eAXRegI zero, Universe dummy, eFlagsReg cr) %{
1165411654
predicate((UseAVX > 2) && ((ClearArrayNode*)n)->is_large());
1165511655
match(Set dummy (ClearArray cnt base));
1165611656
effect(USE_KILL cnt, USE_KILL base, TEMP tmp, TEMP ktmp, KILL zero, KILL cr);

src/hotspot/cpu/x86/x86_64.ad

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11100,7 +11100,7 @@ instruct rep_stos(rcx_RegL cnt, rdi_RegP base, regD tmp, rax_RegI zero,
1110011100
%}
1110111101

1110211102
// Small ClearArray AVX512 non-constant length.
11103-
instruct rep_stos_evex(rcx_RegL cnt, rdi_RegP base, regD tmp, kReg ktmp, rax_RegI zero,
11103+
instruct rep_stos_evex(rcx_RegL cnt, rdi_RegP base, legRegD tmp, kReg ktmp, rax_RegI zero,
1110411104
Universe dummy, rFlagsReg cr)
1110511105
%{
1110611106
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,
1121211212
%}
1121311213

1121411214
// Large ClearArray AVX512.
11215-
instruct rep_stos_large_evex(rcx_RegL cnt, rdi_RegP base, regD tmp, kReg ktmp, rax_RegI zero,
11215+
instruct rep_stos_large_evex(rcx_RegL cnt, rdi_RegP base, legRegD tmp, kReg ktmp, rax_RegI zero,
1121611216
Universe dummy, rFlagsReg cr)
1121711217
%{
1121811218
predicate((UseAVX > 2) && ((ClearArrayNode*)n)->is_large());

src/hotspot/share/opto/callnode.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1411,8 +1411,14 @@ Node *SafePointNode::Ideal(PhaseGVN *phase, bool can_reshape) {
14111411
Node* SafePointNode::Identity(PhaseGVN* phase) {
14121412

14131413
// If you have back to back safepoints, remove one
1414-
if( in(TypeFunc::Control)->is_SafePoint() )
1415-
return in(TypeFunc::Control);
1414+
if (in(TypeFunc::Control)->is_SafePoint()) {
1415+
Node* out_c = unique_ctrl_out();
1416+
// This can be the safepoint of an outer strip mined loop if the inner loop's backedge was removed. Replacing the
1417+
// outer loop's safepoint could confuse removal of the outer loop.
1418+
if (out_c != NULL && !out_c->is_OuterStripMinedLoopEnd()) {
1419+
return in(TypeFunc::Control);
1420+
}
1421+
}
14161422

14171423
// Transforming long counted loops requires a safepoint node. Do not
14181424
// eliminate a safepoint until loop opts are over.

src/java.base/share/classes/java/io/ByteArrayInputStream.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -156,6 +156,10 @@ public synchronized int read() {
156156
* {@code b[off+k-1]} in the manner performed by {@code System.arraycopy}.
157157
* The value {@code k} is added into {@code pos} and {@code k} is returned.
158158
* <p>
159+
* Unlike the {@link InputStream#read(byte[],int,int) overridden method}
160+
* of {@code InputStream}, this method returns {@code -1} instead of zero
161+
* if the end of the stream has been reached and {@code len == 0}.
162+
* <p>
159163
* This {@code read} method cannot block.
160164
*
161165
* @param b the buffer into which the data is read.

src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java

Lines changed: 129 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,11 @@
2626
package java.lang.runtime;
2727

2828
import java.lang.invoke.CallSite;
29+
import java.lang.invoke.ConstantBootstraps;
2930
import java.lang.invoke.ConstantCallSite;
3031
import java.lang.invoke.MethodHandle;
3132
import java.lang.invoke.MethodHandles;
3233
import java.lang.invoke.MethodType;
33-
import java.util.Arrays;
34-
import java.util.Objects;
3534
import java.util.stream.Stream;
3635

3736
import jdk.internal.javac.PreviewFeature;
@@ -53,12 +52,15 @@ private SwitchBootstraps() {}
5352

5453
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
5554

56-
private static final MethodHandle DO_SWITCH;
55+
private static final MethodHandle DO_TYPE_SWITCH;
56+
private static final MethodHandle DO_ENUM_SWITCH;
5757

5858
static {
5959
try {
60-
DO_SWITCH = LOOKUP.findStatic(SwitchBootstraps.class, "doSwitch",
60+
DO_TYPE_SWITCH = LOOKUP.findStatic(SwitchBootstraps.class, "doTypeSwitch",
6161
MethodType.methodType(int.class, Object.class, int.class, Object[].class));
62+
DO_ENUM_SWITCH = LOOKUP.findStatic(SwitchBootstraps.class, "doEnumSwitch",
63+
MethodType.methodType(int.class, Enum.class, int.class, Object[].class));
6264
}
6365
catch (ReflectiveOperationException e) {
6466
throw new ExceptionInInitializerError(e);
@@ -108,14 +110,13 @@ private SwitchBootstraps() {}
108110
* second parameter of type {@code int} and with {@code int} as its return type,
109111
* or if {@code labels} contains an element that is not of type {@code String},
110112
* {@code Integer} or {@code Class}.
111-
* @throws Throwable if there is any error linking the call site
112113
* @jvms 4.4.6 The CONSTANT_NameAndType_info Structure
113114
* @jvms 4.4.10 The CONSTANT_Dynamic_info and CONSTANT_InvokeDynamic_info Structures
114115
*/
115116
public static CallSite typeSwitch(MethodHandles.Lookup lookup,
116117
String invocationName,
117118
MethodType invocationType,
118-
Object... labels) throws Throwable {
119+
Object... labels) {
119120
if (invocationType.parameterCount() != 2
120121
|| (!invocationType.returnType().equals(int.class))
121122
|| invocationType.parameterType(0).isPrimitive()
@@ -126,7 +127,7 @@ public static CallSite typeSwitch(MethodHandles.Lookup lookup,
126127
labels = labels.clone();
127128
Stream.of(labels).forEach(SwitchBootstraps::verifyLabel);
128129

129-
MethodHandle target = MethodHandles.insertArguments(DO_SWITCH, 2, (Object) labels);
130+
MethodHandle target = MethodHandles.insertArguments(DO_TYPE_SWITCH, 2, (Object) labels);
130131
return new ConstantCallSite(target);
131132
}
132133

@@ -142,7 +143,7 @@ private static void verifyLabel(Object label) {
142143
}
143144
}
144145

145-
private static int doSwitch(Object target, int startIndex, Object[] labels) {
146+
private static int doTypeSwitch(Object target, int startIndex, Object[] labels) {
146147
if (target == null)
147148
return -1;
148149

@@ -167,4 +168,124 @@ private static int doSwitch(Object target, int startIndex, Object[] labels) {
167168
return labels.length;
168169
}
169170

171+
/**
172+
* Bootstrap method for linking an {@code invokedynamic} call site that
173+
* implements a {@code switch} on a target of an enum type. The static
174+
* arguments are used to encode the case labels associated to the switch
175+
* construct, where each label can be encoded in two ways:
176+
* <ul>
177+
* <li>as a {@code String} value, which represents the name of
178+
* the enum constant associated with the label</li>
179+
* <li>as a {@code Class} value, which represents the enum type
180+
* associated with a type test pattern</li>
181+
* </ul>
182+
* <p>
183+
* The returned {@code CallSite}'s method handle will have
184+
* a return type of {@code int} and accepts two parameters: the first argument
185+
* will be an {@code Enum} instance ({@code target}) and the second
186+
* will be {@code int} ({@code restart}).
187+
* <p>
188+
* If the {@code target} is {@code null}, then the method of the call site
189+
* returns {@literal -1}.
190+
* <p>
191+
* If the {@code target} is not {@code null}, then the method of the call site
192+
* returns the index of the first element in the {@code labels} array starting from
193+
* the {@code restart} index matching one of the following conditions:
194+
* <ul>
195+
* <li>the element is of type {@code Class} that is assignable
196+
* from the target's class; or</li>
197+
* <li>the element is of type {@code String} and equals to the target
198+
* enum constant's {@link Enum#name()}.</li>
199+
* </ul>
200+
* <p>
201+
* If no element in the {@code labels} array matches the target, then
202+
* the method of the call site return the length of the {@code labels} array.
203+
*
204+
* @param lookup Represents a lookup context with the accessibility
205+
* privileges of the caller. When used with {@code invokedynamic},
206+
* this is stacked automatically by the VM.
207+
* @param invocationName unused
208+
* @param invocationType The invocation type of the {@code CallSite} with two parameters,
209+
* an enum type, an {@code int}, and {@code int} as a return type.
210+
* @param labels case labels - {@code String} constants and {@code Class} instances,
211+
* in any combination
212+
* @return a {@code CallSite} returning the first matching element as described above
213+
*
214+
* @throws NullPointerException if any argument is {@code null}
215+
* @throws IllegalArgumentException if any element in the labels array is null, if the
216+
* invocation type is not a method type whose first parameter type is an enum type,
217+
* second parameter of type {@code int} and whose return type is {@code int},
218+
* or if {@code labels} contains an element that is not of type {@code String} or
219+
* {@code Class} of the target enum type.
220+
* @jvms 4.4.6 The CONSTANT_NameAndType_info Structure
221+
* @jvms 4.4.10 The CONSTANT_Dynamic_info and CONSTANT_InvokeDynamic_info Structures
222+
*/
223+
public static CallSite enumSwitch(MethodHandles.Lookup lookup,
224+
String invocationName,
225+
MethodType invocationType,
226+
Object... labels) {
227+
if (invocationType.parameterCount() != 2
228+
|| (!invocationType.returnType().equals(int.class))
229+
|| invocationType.parameterType(0).isPrimitive()
230+
|| !invocationType.parameterType(0).isEnum()
231+
|| !invocationType.parameterType(1).equals(int.class))
232+
throw new IllegalArgumentException("Illegal invocation type " + invocationType);
233+
requireNonNull(labels);
234+
235+
labels = labels.clone();
236+
237+
Class<?> enumClass = invocationType.parameterType(0);
238+
labels = Stream.of(labels).map(l -> convertEnumConstants(lookup, enumClass, l)).toArray();
239+
240+
MethodHandle target =
241+
MethodHandles.insertArguments(DO_ENUM_SWITCH, 2, (Object) labels);
242+
target = target.asType(invocationType);
243+
244+
return new ConstantCallSite(target);
245+
}
246+
247+
private static <E extends Enum<E>> Object convertEnumConstants(MethodHandles.Lookup lookup, Class<?> enumClassTemplate, Object label) {
248+
if (label == null) {
249+
throw new IllegalArgumentException("null label found");
250+
}
251+
Class<?> labelClass = label.getClass();
252+
if (labelClass == Class.class) {
253+
if (label != enumClassTemplate) {
254+
throw new IllegalArgumentException("the Class label: " + label +
255+
", expected the provided enum class: " + enumClassTemplate);
256+
}
257+
return label;
258+
} else if (labelClass == String.class) {
259+
@SuppressWarnings("unchecked")
260+
Class<E> enumClass = (Class<E>) enumClassTemplate;
261+
try {
262+
return ConstantBootstraps.enumConstant(lookup, (String) label, enumClass);
263+
} catch (IllegalArgumentException ex) {
264+
return null;
265+
}
266+
} else {
267+
throw new IllegalArgumentException("label with illegal type found: " + labelClass +
268+
", expected label of type either String or Class");
269+
}
270+
}
271+
272+
private static int doEnumSwitch(Enum<?> target, int startIndex, Object[] labels) {
273+
if (target == null)
274+
return -1;
275+
276+
// Dumbest possible strategy
277+
Class<?> targetClass = target.getClass();
278+
for (int i = startIndex; i < labels.length; i++) {
279+
Object label = labels[i];
280+
if (label instanceof Class<?> c) {
281+
if (c.isAssignableFrom(targetClass))
282+
return i;
283+
} else if (label == target) {
284+
return i;
285+
}
286+
}
287+
288+
return labels.length;
289+
}
290+
170291
}

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -664,7 +664,11 @@ public void visitSwitch(JCSwitch tree) {
664664
ListBuffer<PendingExit> prevPendingExits = pendingExits;
665665
pendingExits = new ListBuffer<>();
666666
scan(tree.selector);
667-
Set<Symbol> constants = tree.patternSwitch ? new HashSet<>() : null;
667+
boolean exhaustiveSwitch = tree.patternSwitch ||
668+
tree.cases.stream()
669+
.flatMap(c -> c.labels.stream())
670+
.anyMatch(l -> TreeInfo.isNull(l));
671+
Set<Symbol> constants = exhaustiveSwitch ? new HashSet<>() : null;
668672
for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
669673
alive = Liveness.ALIVE;
670674
JCCase c = l.head;
@@ -686,7 +690,7 @@ public void visitSwitch(JCSwitch tree) {
686690
l.tail.head.pos(),
687691
Warnings.PossibleFallThroughIntoCase);
688692
}
689-
if (!tree.hasTotalPattern && tree.patternSwitch &&
693+
if (!tree.hasTotalPattern && exhaustiveSwitch &&
690694
!TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases) &&
691695
(constants == null || !isExhaustive(tree.selector.type, constants))) {
692696
log.error(tree, Errors.NotExhaustiveStatement);

0 commit comments

Comments
 (0)