|
1 | 1 | /* |
2 | | - * Copyright (c) 2018, Red Hat Inc. All rights reserved. |
| 2 | + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. |
3 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | 4 | * |
5 | 5 | * This code is free software; you can redistribute it and/or modify it |
|
23 | 23 |
|
24 | 24 | /* |
25 | 25 | * @test |
26 | | - * @bug 8204479 |
27 | | - * @summary Bitwise AND on byte value sometimes produces wrong result |
| 26 | + * @bug 8204479 8253191 |
28 | 27 | * |
29 | | - * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation |
30 | | - * -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -Xcomp -XX:-Inline |
31 | | - * compiler.c2.TestUnsignedByteCompare |
| 28 | + * @library /test/lib |
| 29 | + * @modules java.base/jdk.internal.vm.annotation |
| 30 | + * |
| 31 | + * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation compiler.c2.TestUnsignedByteCompare |
32 | 32 | */ |
33 | | - |
34 | 33 | package compiler.c2; |
35 | 34 |
|
| 35 | +import java.lang.invoke.*; |
| 36 | +import jdk.internal.vm.annotation.DontInline; |
| 37 | +import jdk.test.lib.Asserts; |
| 38 | + |
36 | 39 | public class TestUnsignedByteCompare { |
37 | 40 |
|
38 | | - static int p, n; |
| 41 | + @DontInline static boolean testByteGT0(byte[] val) { return (val[0] & mask()) > 0; } |
| 42 | + @DontInline static boolean testByteGE0(byte[] val) { return (val[0] & mask()) >= 0; } |
| 43 | + @DontInline static boolean testByteEQ0(byte[] val) { return (val[0] & mask()) == 0; } |
| 44 | + @DontInline static boolean testByteNE0(byte[] val) { return (val[0] & mask()) != 0; } |
| 45 | + @DontInline static boolean testByteLE0(byte[] val) { return (val[0] & mask()) <= 0; } |
| 46 | + @DontInline static boolean testByteLT0(byte[] val) { return (val[0] & mask()) < 0; } |
39 | 47 |
|
40 | | - static void report(byte[] ba, int i, boolean failed) { |
41 | | - // Enable for debugging: |
42 | | - // System.out.println((failed ? "Failed" : "Passed") + " with: " + ba[i] + " at " + i); |
| 48 | + static void testValue(byte b) { |
| 49 | + byte[] bs = new byte[] { b }; |
| 50 | + Asserts.assertEquals(((b & mask()) > 0), testByteGT0(bs), errorMessage(b, "GT0")); |
| 51 | + Asserts.assertEquals(((b & mask()) >= 0), testByteGE0(bs), errorMessage(b, "GE0")); |
| 52 | + Asserts.assertEquals(((b & mask()) == 0), testByteEQ0(bs), errorMessage(b, "EQ0")); |
| 53 | + Asserts.assertEquals(((b & mask()) != 0), testByteNE0(bs), errorMessage(b, "NE0")); |
| 54 | + Asserts.assertEquals(((b & mask()) <= 0), testByteLE0(bs), errorMessage(b, "LE0")); |
| 55 | + Asserts.assertEquals(((b & mask()) < 0), testByteLT0(bs), errorMessage(b, "LT0")); |
43 | 56 | } |
44 | 57 |
|
45 | | - static void m1(byte[] ba) { |
46 | | - for (int i = 0; i < ba.length; i++) { |
47 | | - if ((ba[i] & 0xFF) < 0x10) { |
48 | | - p++; |
49 | | - report(ba, i, true); |
50 | | - } else { |
51 | | - n++; |
52 | | - report(ba, i, false); |
| 58 | + public static void main(String[] args) { |
| 59 | + for (int mask = 0; mask <= 0xFF; mask++) { |
| 60 | + setMask(mask); |
| 61 | + for (int i = 0; i < 20_000; i++) { |
| 62 | + testValue((byte) i); |
53 | 63 | } |
54 | 64 | } |
| 65 | + System.out.println("TEST PASSED"); |
55 | 66 | } |
56 | 67 |
|
57 | | - static void m2(byte[] ba) { |
58 | | - for (int i = 0; i < ba.length; i++) { |
59 | | - if (((ba[i] & 0xFF) & 0x80) < 0) { |
60 | | - p++; |
61 | | - report(ba, i, true); |
62 | | - } else { |
63 | | - n++; |
64 | | - report(ba, i, false); |
65 | | - } |
66 | | - } |
| 68 | + static String errorMessage(byte b, String type) { |
| 69 | + return String.format("%s: val=0x%x mask=0x%x", type, b, mask()); |
67 | 70 | } |
68 | 71 |
|
69 | | - static public void main(String[] args) { |
70 | | - final int tries = 1_000; |
71 | | - final int count = 1_000; |
| 72 | + // Mutable mask as a compile-time constant. |
72 | 73 |
|
73 | | - byte[] ba = new byte[count]; |
| 74 | + private static final CallSite MASK_CS = new MutableCallSite(MethodType.methodType(int.class)); |
| 75 | + private static final MethodHandle MASK_MH = MASK_CS.dynamicInvoker(); |
74 | 76 |
|
75 | | - for (int i = 0; i < count; i++) { |
76 | | - int v = -(i % 126 + 1); |
77 | | - ba[i] = (byte)v; |
78 | | - } |
79 | | - |
80 | | - for (int t = 0; t < tries; t++) { |
81 | | - m1(ba); |
82 | | - if (p != 0) { |
83 | | - throw new IllegalStateException("m1 error: p = " + p + ", n = " + n); |
84 | | - } |
| 77 | + static int mask() { |
| 78 | + try { |
| 79 | + return (int) MASK_MH.invokeExact(); |
| 80 | + } catch (Throwable t) { |
| 81 | + throw new InternalError(t); // should NOT happen |
85 | 82 | } |
| 83 | + } |
86 | 84 |
|
87 | | - for (int t = 0; t < tries; t++) { |
88 | | - m2(ba); |
89 | | - if (p != 0) { |
90 | | - throw new IllegalStateException("m2 error: p = " + p + ", n = " + n); |
91 | | - } |
92 | | - } |
| 85 | + static void setMask(int mask) { |
| 86 | + MethodHandle constant = MethodHandles.constant(int.class, mask); |
| 87 | + MASK_CS.setTarget(constant); |
93 | 88 | } |
94 | 89 | } |
0 commit comments