Skip to content

Commit

Permalink
Implement type pairs to exactnessMethod name
Browse files Browse the repository at this point in the history
  • Loading branch information
biboudis committed Oct 2, 2023
1 parent 1ae06ac commit 6ebae0d
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,46 +36,6 @@ public class ExactnessMethods {

private ExactnessMethods() { }

/** Exactness method from byte to char
*
* @param n value
* @return true if the passed value can be converted exactly to the target type
*
* */
public static boolean byte_char(byte n) {return n == (char) n;}

/** Exactness method from short to byte
*
* @param n value
* @return true if the passed value can be converted exactly to the target type
*
* */
public static boolean short_byte(short n) {return n == (short)(byte)(n);}

/** Exactness method from short to char
*
* @param n value
* @return true if the passed value can be converted exactly to the target type
*
* */
public static boolean short_char(short n) {return n == (char)(n);}

/** Exactness method from char to byte
*
* @param n value
* @return true if the passed value can be converted exactly to the target type
*
* */
public static boolean char_byte(char n) {return n == (byte)(n);}

/** Exactness method from char to short
*
* @param n value
* @return true if the passed value can be converted exactly to the target type
*
* */
public static boolean char_short(char n) {return n == (short)(n);}

/** Exactness method from int to byte
*
* @param n value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;
Expand Down Expand Up @@ -67,8 +68,10 @@ private SwitchBootstraps() {}
private static final MethodHandle IS_ZERO;
private static final MethodHandle CHECK_INDEX;
private static final MethodHandle MAPPED_ENUM_LOOKUP;
private static final HashMap<TypePairs, String> typePairToName;

static {
typePairToName = TypePairs.initialize();
try {
INSTANCEOF_CHECK = MethodHandles.permuteArguments(LOOKUP.findVirtual(Class.class, "isInstance",
MethodType.methodType(boolean.class, Object.class)),
Expand Down Expand Up @@ -243,9 +246,10 @@ private static MethodHandle createRepeatIndexSwitch(MethodHandles.Lookup lookup,
} else {
MethodHandle exactnessCheck;
try {
String methodName = selectorType.toString().substring(selectorType.toString().lastIndexOf(".") + 1) + "_" + currentLabelClass;
MethodType methodType = MethodType.methodType(boolean.class, selectorType);
exactnessCheck = lookup.findStatic(ExactnessMethods.class, methodName, methodType);
TypePairs typePair = TypePairs.of(selectorType, currentLabelClass);
String methodName = typePairToName.get(typePair);
MethodType methodType = MethodType.methodType(boolean.class, typePair.from);
exactnessCheck = lookup.findStatic(ExactnessMethods.class, methodName, methodType).asType(MethodType.methodType(boolean.class, selectorType));
}
catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
Expand Down Expand Up @@ -559,4 +563,68 @@ private static final class EnumMap {
@Stable
public int[] map;
}

static class TypePairs {
public Class<?> from, to;

public static TypePairs of(Class<?> from, Class<?> to) {
if (from == byte.class || from == short.class || from == char.class) {
from = int.class;
}
return new TypePairs(from, to);
}

private TypePairs(Class<?> from, Class<?> to) {
this.from = from;
this.to = to;
}

public static HashMap<TypePairs, String> initialize() {
HashMap<TypePairs, String> typePairToName = new HashMap<>();
typePairToName.put(new TypePairs(byte.class, char.class), "int_char"); // redirected
typePairToName.put(new TypePairs(short.class, byte.class), "int_byte"); // redirected
typePairToName.put(new TypePairs(short.class, char.class), "int_char"); // redirected
typePairToName.put(new TypePairs(char.class, byte.class), "int_byte"); // redirected
typePairToName.put(new TypePairs(char.class, short.class), "int_short"); // redirected
typePairToName.put(new TypePairs(int.class, byte.class), "int_byte");
typePairToName.put(new TypePairs(int.class, short.class), "int_short");
typePairToName.put(new TypePairs(int.class, char.class), "int_char");
typePairToName.put(new TypePairs(int.class, float.class), "int_float");
typePairToName.put(new TypePairs(long.class, byte.class), "long_byte");
typePairToName.put(new TypePairs(long.class, short.class), "long_short");
typePairToName.put(new TypePairs(long.class, char.class), "long_char");
typePairToName.put(new TypePairs(long.class, int.class), "long_int");
typePairToName.put(new TypePairs(long.class, float.class), "long_float");
typePairToName.put(new TypePairs(long.class, double.class), "long_double");
typePairToName.put(new TypePairs(float.class, byte.class), "float_byte");
typePairToName.put(new TypePairs(float.class, short.class), "float_short");
typePairToName.put(new TypePairs(float.class, char.class), "float_char");
typePairToName.put(new TypePairs(float.class, int.class), "float_int");
typePairToName.put(new TypePairs(float.class, long.class), "float_long");
typePairToName.put(new TypePairs(double.class, byte.class), "double_byte");
typePairToName.put(new TypePairs(double.class, short.class), "double_short");
typePairToName.put(new TypePairs(double.class, char.class), "double_char");
typePairToName.put(new TypePairs(double.class, int.class), "double_int");
typePairToName.put(new TypePairs(double.class, long.class), "double_long");
typePairToName.put(new TypePairs(double.class, float.class), "double_float");
return typePairToName;
}

@Override
public int hashCode() {
int code = 0;
code += from.hashCode();
code += to.hashCode();
return code;
}

@Override
public boolean equals(Object testName) {
if ((!(testName instanceof TypePairs testNameAsName))) return false;
else {
return this.from.equals(testNameAsName.from) &&
this.to.equals(testNameAsName.to);
}
}
}
}
72 changes: 70 additions & 2 deletions src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ public static Lower instance(Context context) {
private final PkgInfo pkginfoOpt;
private final boolean optimizeOuterThis;
private final boolean useMatchException;
private final HashMap<TypePairs, String> typePairToName;

@SuppressWarnings("this-escape")
protected Lower(Context context) {
Expand Down Expand Up @@ -134,6 +135,7 @@ protected Lower(Context context) {
Preview preview = Preview.instance(context);
useMatchException = Feature.PATTERN_SWITCH.allowedInSource(source) &&
(preview.isEnabled() || !preview.isPreview(Feature.PATTERN_SWITCH));
typePairToName = TypePairs.initialize(syms);
}

/** The currently enclosing class.
Expand Down Expand Up @@ -2996,15 +2998,81 @@ else if (!(tree.expr.type.isNullOrReference() && tree.pattern.type.isReference()
}
}

static class TypePairs {
public Type from, to;

public static TypePairs of(Symtab syms, Type from, Type to) {
if (from == syms.byteType || from == syms.shortType || from == syms.charType) {
from = syms.intType;
}
return new TypePairs(from, to);
}

private TypePairs(Type from, Type to) {
this.from = from;
this.to = to;
}

public static HashMap<TypePairs, String> initialize(Symtab syms) {
HashMap<TypePairs, String> typePairToName = new HashMap<>();
typePairToName.put(new TypePairs(syms.byteType, syms.charType), "int_char"); // redirected
typePairToName.put(new TypePairs(syms.shortType, syms.byteType), "int_byte"); // redirected
typePairToName.put(new TypePairs(syms.shortType, syms.charType), "int_char"); // redirected
typePairToName.put(new TypePairs(syms.charType, syms.byteType), "int_byte"); // redirected
typePairToName.put(new TypePairs(syms.charType, syms.shortType), "int_short"); // redirected
typePairToName.put(new TypePairs(syms.intType, syms.byteType), "int_byte");
typePairToName.put(new TypePairs(syms.intType, syms.shortType), "int_short");
typePairToName.put(new TypePairs(syms.intType, syms.charType), "int_char");
typePairToName.put(new TypePairs(syms.intType, syms.floatType), "int_float");
typePairToName.put(new TypePairs(syms.longType, syms.byteType), "long_byte");
typePairToName.put(new TypePairs(syms.longType, syms.shortType), "long_short");
typePairToName.put(new TypePairs(syms.longType, syms.charType), "long_char");
typePairToName.put(new TypePairs(syms.longType, syms.intType), "long_int");
typePairToName.put(new TypePairs(syms.longType, syms.floatType), "long_float");
typePairToName.put(new TypePairs(syms.longType, syms.doubleType), "long_double");
typePairToName.put(new TypePairs(syms.floatType, syms.byteType), "float_byte");
typePairToName.put(new TypePairs(syms.floatType, syms.shortType), "float_short");
typePairToName.put(new TypePairs(syms.floatType, syms.charType), "float_char");
typePairToName.put(new TypePairs(syms.floatType, syms.intType), "float_int");
typePairToName.put(new TypePairs(syms.floatType, syms.longType), "float_long");
typePairToName.put(new TypePairs(syms.doubleType, syms.byteType), "double_byte");
typePairToName.put(new TypePairs(syms.doubleType, syms.shortType), "double_short");
typePairToName.put(new TypePairs(syms.doubleType, syms.charType), "double_char");
typePairToName.put(new TypePairs(syms.doubleType, syms.intType), "double_int");
typePairToName.put(new TypePairs(syms.doubleType, syms.longType), "double_long");
typePairToName.put(new TypePairs(syms.doubleType, syms.floatType), "double_float");
return typePairToName;
}

@Override
public int hashCode() {
int code = 0;
code += from.tsym.hashCode();
code += to.tsym.hashCode();
return code;
}

@Override
public boolean equals(Object testName) {
if ((!(testName instanceof TypePairs testNameAsName))) return false;
else {
return this.from.tsym.equals(testNameAsName.from.tsym) &&
this.to.tsym.equals(testNameAsName.to.tsym);
}
}
}

private JCExpression getExactnessCheck(JCInstanceOf tree, JCExpression argument) {
Name exactnessFunction = names.fromString(types.unboxedTypeOrType(tree.expr.type).tsym.name.toString() + "_"+ tree.pattern.type.toString());
TypePairs pair = TypePairs.of(syms, types.unboxedTypeOrType(tree.expr.type), tree.pattern.type);

Name exactnessFunction = names.fromString(typePairToName.get(pair));

// Resolve the exactness method
Symbol ecsym = rs.resolveQualifiedMethod(null,
attrEnv,
syms.exactnessMethodsType,
exactnessFunction,
List.of(tree.expr.type),
List.of(pair.from),
List.nil());

// Generate the method call ExactnessChecks.<exactness method>(<argument>);
Expand Down
35 changes: 35 additions & 0 deletions test/langtools/tools/javac/patterns/PrimitivePatterns.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public static void main(String[] args) {
assertEquals(42, primitiveSwitch3());
assertEquals(1, primitiveSwitch4(0.0f));
assertEquals(2, primitiveSwitch4(1.0f));
assertEquals(1, primitiveSwitchUnconditionallyExact(Byte.MAX_VALUE));
assertEquals(42, exhaustive0());
assertEquals(1, exhaustive1WithDefault());
assertEquals(2, exhaustive2WithDefault());
Expand Down Expand Up @@ -82,6 +83,10 @@ public static void main(String[] args) {
assertEquals(2, switchOverPrimitiveFloat((float) Math.pow(0.0f/0.0f, 0)));
assertEquals(3, switchOverPrimitiveFloat(0.0f));
assertEquals(4, switchOverPrimitiveFloat(-0.0f));
assertEquals(1, switchRedirectedExactnessMethods1('a'));
assertEquals(-1, switchRedirectedExactnessMethods1('\u03A9'));
assertEquals(1, switchRedirectedExactnessMethods2('\u03A9'));
assertEquals(-1, switchRedirectedExactnessMethods2('\uFFFF'));
}

public static int primitivePattern() {
Expand Down Expand Up @@ -138,6 +143,12 @@ public static int primitiveSwitch4(float f) {
};
}

public static int primitiveSwitchUnconditionallyExact(byte c) {
return switch (c) {
case short _ -> 1;
};
}

public static int exhaustive0() {
Integer i = 42;
switch (i) {
Expand Down Expand Up @@ -378,6 +389,30 @@ public static int switchOverPrimitiveFloat(float f) {
};
}

// tests that Exactness.char_byte is properly redirected to int_byte
public static int switchRedirectedExactnessMethods1(char c) {
return switch (c) {
case byte _ -> 1;
default -> -1;
};
}

// tests that Exactness.char_short is properly redirected to int_short
public static int switchRedirectedExactnessMethods2(char c) {
return switch (c) {
case short _ -> 1;
default -> -1;
};
}

// tests that Exactness.short_byte is properly redirected to int_byte
public static int switchRedirectedExactnessMethods2(short c) {
return switch (c) {
case byte _ -> 1;
default -> -1;
};
}

record R_Integer(Integer x) {}
record R_int(int x) {}
record R_double(double x) {}
Expand Down

0 comments on commit 6ebae0d

Please sign in to comment.