1 /* 2 * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 6896617 27 * @summary Optimize sun.nio.cs.ISO_8859_1$Encode.encodeArrayLoop() with SSE instructions on x86 28 * @library /testlibrary 29 * @modules java.base/jdk.internal.misc 30 * java.base/sun.nio.cs 31 * java.management 32 * 33 * @run main/othervm/timeout=1200 -Xbatch -Xmx256m compiler.codegen.Test6896617 34 */ 35 36 package compiler.codegen; 37 38 import jdk.test.lib.Utils; 39 40 import java.nio.ByteBuffer; 41 import java.nio.CharBuffer; 42 import java.nio.charset.Charset; 43 import java.nio.charset.CharsetDecoder; 44 import java.nio.charset.CharsetEncoder; 45 import java.nio.charset.CodingErrorAction; 46 import java.util.Arrays; 47 import java.util.Random; 48 49 public class Test6896617 { 50 final static int SIZE = 256; 51 52 public static void main(String[] args) { 53 String csn = "ISO-8859-1"; 54 Charset cs = Charset.forName(csn); 55 CharsetEncoder enc = cs.newEncoder(); 56 enc.onMalformedInput(CodingErrorAction.REPLACE) 57 .onUnmappableCharacter(CodingErrorAction.REPLACE); 58 CharsetDecoder dec = cs.newDecoder(); 59 dec.onMalformedInput(CodingErrorAction.REPLACE) 60 .onUnmappableCharacter(CodingErrorAction.REPLACE); 61 62 byte repl = (byte)'?'; 63 enc.replaceWith(new byte[] { repl }); 64 65 // Use internal API for tests. 66 sun.nio.cs.ArrayEncoder arrenc = (sun.nio.cs.ArrayEncoder)enc; 67 sun.nio.cs.ArrayDecoder arrdec = (sun.nio.cs.ArrayDecoder)dec; 68 69 // Populate char[] with chars which can be encoded by ISO_8859_1 (<= 0xFF) 70 Random rnd = Utils.getRandomInstance(); 71 int maxchar = 0xFF; 72 char[] a = new char[SIZE]; 73 byte[] b = new byte[SIZE]; 74 char[] at = new char[SIZE]; 75 byte[] bt = new byte[SIZE]; 76 for (int i = 0; i < SIZE; i++) { 77 char c = (char) rnd.nextInt(maxchar); 78 if (!enc.canEncode(c)) { 79 System.out.printf("Something wrong: can't encode c=%03x\n", (int)c); 80 System.exit(97); 81 } 82 a[i] = c; 83 b[i] = (byte)c; 84 at[i] = (char)-1; 85 bt[i] = (byte)-1; 86 } 87 if (arrenc.encode(a, 0, SIZE, bt) != SIZE || !Arrays.equals(b, bt)) { 88 System.out.println("Something wrong: ArrayEncoder.encode failed"); 89 System.exit(97); 90 } 91 if (arrdec.decode(b, 0, SIZE, at) != SIZE || !Arrays.equals(a, at)) { 92 System.out.println("Something wrong: ArrayDecoder.decode failed"); 93 System.exit(97); 94 } 95 for (int i = 0; i < SIZE; i++) { 96 at[i] = (char)-1; 97 bt[i] = (byte)-1; 98 } 99 100 ByteBuffer bb = ByteBuffer.wrap(b); 101 CharBuffer ba = CharBuffer.wrap(a); 102 ByteBuffer bbt = ByteBuffer.wrap(bt); 103 CharBuffer bat = CharBuffer.wrap(at); 104 if (!enc.encode(ba, bbt, true).isUnderflow() || !Arrays.equals(b, bt)) { 105 System.out.println("Something wrong: Encoder.encode failed"); 106 System.exit(97); 107 } 108 if (!dec.decode(bb, bat, true).isUnderflow() || !Arrays.equals(a, at)) { 109 System.out.println("Something wrong: Decoder.decode failed"); 110 System.exit(97); 111 } 112 for (int i = 0; i < SIZE; i++) { 113 at[i] = (char)-1; 114 bt[i] = (byte)-1; 115 } 116 117 // Warm up 118 boolean failed = false; 119 int result = 0; 120 for (int i = 0; i < 10000; i++) { 121 result += arrenc.encode(a, 0, SIZE, bt); 122 result -= arrdec.decode(b, 0, SIZE, at); 123 } 124 for (int i = 0; i < 10000; i++) { 125 result += arrenc.encode(a, 0, SIZE, bt); 126 result -= arrdec.decode(b, 0, SIZE, at); 127 } 128 for (int i = 0; i < 10000; i++) { 129 result += arrenc.encode(a, 0, SIZE, bt); 130 result -= arrdec.decode(b, 0, SIZE, at); 131 } 132 if (result != 0 || !Arrays.equals(b, bt) || !Arrays.equals(a, at)) { 133 failed = true; 134 System.out.println("Failed: ArrayEncoder.encode char[" + SIZE + "] and ArrayDecoder.decode byte[" + SIZE + "]"); 135 } 136 for (int i = 0; i < SIZE; i++) { 137 at[i] = (char)-1; 138 bt[i] = (byte)-1; 139 } 140 141 boolean is_underflow = true; 142 for (int i = 0; i < 10000; i++) { 143 ba.clear(); bb.clear(); bat.clear(); bbt.clear(); 144 boolean enc_res = enc.encode(ba, bbt, true).isUnderflow(); 145 boolean dec_res = dec.decode(bb, bat, true).isUnderflow(); 146 is_underflow = is_underflow && enc_res && dec_res; 147 } 148 for (int i = 0; i < SIZE; i++) { 149 at[i] = (char)-1; 150 bt[i] = (byte)-1; 151 } 152 for (int i = 0; i < 10000; i++) { 153 ba.clear(); bb.clear(); bat.clear(); bbt.clear(); 154 boolean enc_res = enc.encode(ba, bbt, true).isUnderflow(); 155 boolean dec_res = dec.decode(bb, bat, true).isUnderflow(); 156 is_underflow = is_underflow && enc_res && dec_res; 157 } 158 for (int i = 0; i < SIZE; i++) { 159 at[i] = (char)-1; 160 bt[i] = (byte)-1; 161 } 162 for (int i = 0; i < 10000; i++) { 163 ba.clear(); bb.clear(); bat.clear(); bbt.clear(); 164 boolean enc_res = enc.encode(ba, bbt, true).isUnderflow(); 165 boolean dec_res = dec.decode(bb, bat, true).isUnderflow(); 166 is_underflow = is_underflow && enc_res && dec_res; 167 } 168 if (!is_underflow || !Arrays.equals(b, bt) || !Arrays.equals(a, at)) { 169 failed = true; 170 System.out.println("Failed: Encoder.encode char[" + SIZE + "] and Decoder.decode byte[" + SIZE + "]"); 171 } 172 173 // Test encoder with different source and destination sizes 174 System.out.println("Testing different source and destination sizes"); 175 for (int i = 1; i <= SIZE; i++) { 176 for (int j = 1; j <= SIZE; j++) { 177 bt = new byte[j]; 178 // very source's SIZE 179 result = arrenc.encode(a, 0, i, bt); 180 int l = Math.min(i, j); 181 if (result != l) { 182 failed = true; 183 System.out.println("Failed: encode char[" + i + "] to byte[" + j + "]: result = " + result + ", expected " + l); 184 } 185 for (int k = 0; k < l; k++) { 186 if (bt[k] != b[k]) { 187 failed = true; 188 System.out.println("Failed: encoded byte[" + k + "] (" + bt[k] + ") != " + b[k]); 189 } 190 } 191 // very source's offset 192 int sz = SIZE - i + 1; 193 result = arrenc.encode(a, i-1, sz, bt); 194 l = Math.min(sz, j); 195 if (result != l) { 196 failed = true; 197 System.out.println("Failed: encode char[" + sz + "] to byte[" + j + "]: result = " + result + ", expected " + l); 198 } 199 for (int k = 0; k < l; k++) { 200 if (bt[k] != b[i+k-1]) { 201 failed = true; 202 System.out.println("Failed: encoded byte[" + k + "] (" + bt[k] + ") != " + b[i+k-1]); 203 } 204 } 205 } 206 } 207 208 // Test encoder with char > 0xFF 209 System.out.println("Testing big char"); 210 211 byte orig = (byte)'A'; 212 bt = new byte[SIZE]; 213 for (int i = 1; i <= SIZE; i++) { 214 for (int j = 0; j < i; j++) { 215 a[j] += 0x100; 216 // make sure to replace a different byte 217 bt[j] = orig; 218 result = arrenc.encode(a, 0, i, bt); 219 if (result != i) { 220 failed = true; 221 System.out.println("Failed: encode char[" + i + "] to byte[" + i + "]: result = " + result + ", expected " + i); 222 } 223 if (bt[j] != repl) { 224 failed = true; 225 System.out.println("Failed: encoded replace byte[" + j + "] (" + bt[j] + ") != " + repl); 226 } 227 bt[j] = b[j]; // Restore to compare whole array 228 for (int k = 0; k < i; k++) { 229 if (bt[k] != b[k]) { 230 failed = true; 231 System.out.println("Failed: encoded byte[" + k + "] (" + bt[k] + ") != " + b[k]); 232 } 233 } 234 a[j] -= 0x100; // Restore 235 } 236 } 237 238 // Test sun.nio.cs.ISO_8859_1$Encode.encodeArrayLoop() performance. 239 240 int itrs = Integer.getInteger("iterations", 1000000); 241 int size = Integer.getInteger("size", 256); 242 a = new char[size]; 243 b = new byte[size]; 244 bt = new byte[size]; 245 for (int i = 0; i < size; i++) { 246 char c = (char) rnd.nextInt(maxchar); 247 if (!enc.canEncode(c)) { 248 System.out.printf("Something wrong: can't encode c=%03x\n", (int)c); 249 System.exit(97); 250 } 251 a[i] = c; 252 b[i] = (byte)-1; 253 bt[i] = (byte)c; 254 } 255 ba = CharBuffer.wrap(a); 256 bb = ByteBuffer.wrap(b); 257 boolean enc_res = enc.encode(ba, bb, true).isUnderflow(); 258 if (!enc_res || !Arrays.equals(b, bt)) { 259 failed = true; 260 System.out.println("Failed 1: Encoder.encode char[" + size + "]"); 261 } 262 for (int i = 0; i < size; i++) { 263 b[i] = (byte)-1; 264 } 265 266 // Make sure to recompile method if needed before performance run. 267 for (int i = 0; i < 10000; i++) { 268 ba.clear(); bb.clear(); 269 enc_res = enc_res && enc.encode(ba, bb, true).isUnderflow(); 270 } 271 for (int i = 0; i < size; i++) { 272 b[i] = (byte)-1; 273 } 274 for (int i = 0; i < 10000; i++) { 275 ba.clear(); bb.clear(); 276 enc_res = enc_res && enc.encode(ba, bb, true).isUnderflow(); 277 } 278 if (!enc_res || !Arrays.equals(b, bt)) { 279 failed = true; 280 System.out.println("Failed 2: Encoder.encode char[" + size + "]"); 281 } 282 for (int i = 0; i < size; i++) { 283 b[i] = (byte)-1; 284 } 285 286 System.out.println("Testing ISO_8859_1$Encode.encodeArrayLoop() performance"); 287 long start = System.currentTimeMillis(); 288 for (int i = 0; i < itrs; i++) { 289 ba.clear(); bb.clear(); 290 enc_res = enc_res && enc.encode(ba, bb, true).isUnderflow(); 291 } 292 long end = System.currentTimeMillis(); 293 if (!enc_res || !Arrays.equals(b, bt)) { 294 failed = true; 295 System.out.println("Failed 3: Encoder.encode char[" + size + "]"); 296 } else { 297 System.out.println("size: " + size + " time: " + (end - start)); 298 } 299 300 // Test sun.nio.cs.ISO_8859_1$Encode.encode() performance. 301 302 // Make sure to recompile method if needed before performance run. 303 result = 0; 304 for (int i = 0; i < size; i++) { 305 b[i] = (byte)-1; 306 } 307 for (int i = 0; i < 10000; i++) { 308 result += arrenc.encode(a, 0, size, b); 309 } 310 for (int i = 0; i < size; i++) { 311 b[i] = (byte)-1; 312 } 313 for (int i = 0; i < 10000; i++) { 314 result += arrenc.encode(a, 0, size, b); 315 } 316 if (result != size*20000 || !Arrays.equals(b, bt)) { 317 failed = true; 318 System.out.println("Failed 1: ArrayEncoder.encode char[" + SIZE + "]"); 319 } 320 for (int i = 0; i < size; i++) { 321 b[i] = (byte)-1; 322 } 323 324 System.out.println("Testing ISO_8859_1$Encode.encode() performance"); 325 result = 0; 326 start = System.currentTimeMillis(); 327 for (int i = 0; i < itrs; i++) { 328 result += arrenc.encode(a, 0, size, b); 329 } 330 end = System.currentTimeMillis(); 331 if (!Arrays.equals(b, bt)) { 332 failed = true; 333 System.out.println("Failed 2: ArrayEncoder.encode char[" + size + "]"); 334 } else { 335 System.out.println("size: " + size + " time: " + (end - start)); 336 } 337 338 if (failed) { 339 System.out.println("FAILED"); 340 System.exit(97); 341 } 342 System.out.println("PASSED"); 343 } 344 }