Skip to content

Commit

Permalink
Merge
Browse files Browse the repository at this point in the history
  • Loading branch information
JesperIRL committed Jul 8, 2021
2 parents 5832882 + 6401633 commit dfd6b2b
Show file tree
Hide file tree
Showing 22 changed files with 606 additions and 161 deletions.
4 changes: 2 additions & 2 deletions src/hotspot/cpu/x86/x86_32.ad
Original file line number Diff line number Diff line change
Expand Up @@ -11539,7 +11539,7 @@ instruct rep_stos(eCXRegI cnt, eDIRegP base, regD tmp, eAXRegI zero, Universe du
%}

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

// Large ClearArray AVX512.
instruct rep_stos_large_evex(eCXRegI cnt, eDIRegP base, regD tmp, kReg ktmp, eAXRegI zero, Universe dummy, eFlagsReg cr) %{
instruct rep_stos_large_evex(eCXRegI cnt, eDIRegP base, legRegD tmp, kReg ktmp, eAXRegI zero, Universe dummy, eFlagsReg cr) %{
predicate((UseAVX > 2) && ((ClearArrayNode*)n)->is_large());
match(Set dummy (ClearArray cnt base));
effect(USE_KILL cnt, USE_KILL base, TEMP tmp, TEMP ktmp, KILL zero, KILL cr);
Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/cpu/x86/x86_64.ad
Original file line number Diff line number Diff line change
Expand Up @@ -11100,7 +11100,7 @@ instruct rep_stos(rcx_RegL cnt, rdi_RegP base, regD tmp, rax_RegI zero,
%}

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

// Large ClearArray AVX512.
instruct rep_stos_large_evex(rcx_RegL cnt, rdi_RegP base, regD tmp, kReg ktmp, rax_RegI zero,
instruct rep_stos_large_evex(rcx_RegL cnt, rdi_RegP base, legRegD tmp, kReg ktmp, rax_RegI zero,
Universe dummy, rFlagsReg cr)
%{
predicate((UseAVX > 2) && ((ClearArrayNode*)n)->is_large());
Expand Down
10 changes: 8 additions & 2 deletions src/hotspot/share/opto/callnode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1411,8 +1411,14 @@ Node *SafePointNode::Ideal(PhaseGVN *phase, bool can_reshape) {
Node* SafePointNode::Identity(PhaseGVN* phase) {

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

// Transforming long counted loops requires a safepoint node. Do not
// eliminate a safepoint until loop opts are over.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -156,6 +156,10 @@ public synchronized int read() {
* {@code b[off+k-1]} in the manner performed by {@code System.arraycopy}.
* The value {@code k} is added into {@code pos} and {@code k} is returned.
* <p>
* Unlike the {@link InputStream#read(byte[],int,int) overridden method}
* of {@code InputStream}, this method returns {@code -1} instead of zero
* if the end of the stream has been reached and {@code len == 0}.
* <p>
* This {@code read} method cannot block.
*
* @param b the buffer into which the data is read.
Expand Down
137 changes: 129 additions & 8 deletions src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,11 @@
package java.lang.runtime;

import java.lang.invoke.CallSite;
import java.lang.invoke.ConstantBootstraps;
import java.lang.invoke.ConstantCallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Stream;

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

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

private static final MethodHandle DO_SWITCH;
private static final MethodHandle DO_TYPE_SWITCH;
private static final MethodHandle DO_ENUM_SWITCH;

static {
try {
DO_SWITCH = LOOKUP.findStatic(SwitchBootstraps.class, "doSwitch",
DO_TYPE_SWITCH = LOOKUP.findStatic(SwitchBootstraps.class, "doTypeSwitch",
MethodType.methodType(int.class, Object.class, int.class, Object[].class));
DO_ENUM_SWITCH = LOOKUP.findStatic(SwitchBootstraps.class, "doEnumSwitch",
MethodType.methodType(int.class, Enum.class, int.class, Object[].class));
}
catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
Expand Down Expand Up @@ -108,14 +110,13 @@ private SwitchBootstraps() {}
* second parameter of type {@code int} and with {@code int} as its return type,
* or if {@code labels} contains an element that is not of type {@code String},
* {@code Integer} or {@code Class}.
* @throws Throwable if there is any error linking the call site
* @jvms 4.4.6 The CONSTANT_NameAndType_info Structure
* @jvms 4.4.10 The CONSTANT_Dynamic_info and CONSTANT_InvokeDynamic_info Structures
*/
public static CallSite typeSwitch(MethodHandles.Lookup lookup,
String invocationName,
MethodType invocationType,
Object... labels) throws Throwable {
Object... labels) {
if (invocationType.parameterCount() != 2
|| (!invocationType.returnType().equals(int.class))
|| invocationType.parameterType(0).isPrimitive()
Expand All @@ -126,7 +127,7 @@ public static CallSite typeSwitch(MethodHandles.Lookup lookup,
labels = labels.clone();
Stream.of(labels).forEach(SwitchBootstraps::verifyLabel);

MethodHandle target = MethodHandles.insertArguments(DO_SWITCH, 2, (Object) labels);
MethodHandle target = MethodHandles.insertArguments(DO_TYPE_SWITCH, 2, (Object) labels);
return new ConstantCallSite(target);
}

Expand All @@ -142,7 +143,7 @@ private static void verifyLabel(Object label) {
}
}

private static int doSwitch(Object target, int startIndex, Object[] labels) {
private static int doTypeSwitch(Object target, int startIndex, Object[] labels) {
if (target == null)
return -1;

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

/**
* Bootstrap method for linking an {@code invokedynamic} call site that
* implements a {@code switch} on a target of an enum type. The static
* arguments are used to encode the case labels associated to the switch
* construct, where each label can be encoded in two ways:
* <ul>
* <li>as a {@code String} value, which represents the name of
* the enum constant associated with the label</li>
* <li>as a {@code Class} value, which represents the enum type
* associated with a type test pattern</li>
* </ul>
* <p>
* The returned {@code CallSite}'s method handle will have
* a return type of {@code int} and accepts two parameters: the first argument
* will be an {@code Enum} instance ({@code target}) and the second
* will be {@code int} ({@code restart}).
* <p>
* If the {@code target} is {@code null}, then the method of the call site
* returns {@literal -1}.
* <p>
* If the {@code target} is not {@code null}, then the method of the call site
* returns the index of the first element in the {@code labels} array starting from
* the {@code restart} index matching one of the following conditions:
* <ul>
* <li>the element is of type {@code Class} that is assignable
* from the target's class; or</li>
* <li>the element is of type {@code String} and equals to the target
* enum constant's {@link Enum#name()}.</li>
* </ul>
* <p>
* If no element in the {@code labels} array matches the target, then
* the method of the call site return the length of the {@code labels} array.
*
* @param lookup Represents a lookup context with the accessibility
* privileges of the caller. When used with {@code invokedynamic},
* this is stacked automatically by the VM.
* @param invocationName unused
* @param invocationType The invocation type of the {@code CallSite} with two parameters,
* an enum type, an {@code int}, and {@code int} as a return type.
* @param labels case labels - {@code String} constants and {@code Class} instances,
* in any combination
* @return a {@code CallSite} returning the first matching element as described above
*
* @throws NullPointerException if any argument is {@code null}
* @throws IllegalArgumentException if any element in the labels array is null, if the
* invocation type is not a method type whose first parameter type is an enum type,
* second parameter of type {@code int} and whose return type is {@code int},
* or if {@code labels} contains an element that is not of type {@code String} or
* {@code Class} of the target enum type.
* @jvms 4.4.6 The CONSTANT_NameAndType_info Structure
* @jvms 4.4.10 The CONSTANT_Dynamic_info and CONSTANT_InvokeDynamic_info Structures
*/
public static CallSite enumSwitch(MethodHandles.Lookup lookup,
String invocationName,
MethodType invocationType,
Object... labels) {
if (invocationType.parameterCount() != 2
|| (!invocationType.returnType().equals(int.class))
|| invocationType.parameterType(0).isPrimitive()
|| !invocationType.parameterType(0).isEnum()
|| !invocationType.parameterType(1).equals(int.class))
throw new IllegalArgumentException("Illegal invocation type " + invocationType);
requireNonNull(labels);

labels = labels.clone();

Class<?> enumClass = invocationType.parameterType(0);
labels = Stream.of(labels).map(l -> convertEnumConstants(lookup, enumClass, l)).toArray();

MethodHandle target =
MethodHandles.insertArguments(DO_ENUM_SWITCH, 2, (Object) labels);
target = target.asType(invocationType);

return new ConstantCallSite(target);
}

private static <E extends Enum<E>> Object convertEnumConstants(MethodHandles.Lookup lookup, Class<?> enumClassTemplate, Object label) {
if (label == null) {
throw new IllegalArgumentException("null label found");
}
Class<?> labelClass = label.getClass();
if (labelClass == Class.class) {
if (label != enumClassTemplate) {
throw new IllegalArgumentException("the Class label: " + label +
", expected the provided enum class: " + enumClassTemplate);
}
return label;
} else if (labelClass == String.class) {
@SuppressWarnings("unchecked")
Class<E> enumClass = (Class<E>) enumClassTemplate;
try {
return ConstantBootstraps.enumConstant(lookup, (String) label, enumClass);
} catch (IllegalArgumentException ex) {
return null;
}
} else {
throw new IllegalArgumentException("label with illegal type found: " + labelClass +
", expected label of type either String or Class");
}
}

private static int doEnumSwitch(Enum<?> target, int startIndex, Object[] labels) {
if (target == null)
return -1;

// Dumbest possible strategy
Class<?> targetClass = target.getClass();
for (int i = startIndex; i < labels.length; i++) {
Object label = labels[i];
if (label instanceof Class<?> c) {
if (c.isAssignableFrom(targetClass))
return i;
} else if (label == target) {
return i;
}
}

return labels.length;
}

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

0 comments on commit dfd6b2b

Please sign in to comment.