1 /* 2 * Copyright (c) 2018, 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 package org.graalvm.compiler.core.test; 26 27 import java.util.ArrayList; 28 import java.util.List; 29 30 import org.graalvm.compiler.debug.GraalError; 31 import org.junit.Test; 32 import org.junit.runner.RunWith; 33 import org.junit.runners.Parameterized; 34 import org.objectweb.asm.ClassWriter; 35 import org.objectweb.asm.FieldVisitor; 36 import org.objectweb.asm.MethodVisitor; 37 38 import jdk.vm.ci.meta.JavaKind; 39 40 @RunWith(Parameterized.class) 41 public class SubWordArrayStoreTest extends CustomizedBytecodePatternTest { 42 43 @Parameterized.Parameters(name = "{0}, {1}, {2}, {3}") data()44 public static List<Object[]> data() { 45 ArrayList<Object[]> ret = new ArrayList<>(); 46 for (int i : new int[]{0xFFFF0000, 0xFFFF0001, 0x0000FFFF, 0x01020304}) { 47 for (boolean unsafeStore : new boolean[]{false, true}) { 48 for (boolean unsafeLoad : new boolean[]{false, true}) { 49 ret.add(new Object[]{JavaKind.Boolean, i, unsafeStore, unsafeLoad}); 50 ret.add(new Object[]{JavaKind.Byte, i, unsafeStore, unsafeLoad}); 51 ret.add(new Object[]{JavaKind.Short, i, unsafeStore, unsafeLoad}); 52 ret.add(new Object[]{JavaKind.Char, i, unsafeStore, unsafeLoad}); 53 } 54 } 55 } 56 return ret; 57 } 58 59 private static final String SNIPPET = "snippet"; 60 61 private final JavaKind kind; 62 private final int value; 63 private final boolean unsafeStore; 64 private final boolean unsafeLoad; 65 SubWordArrayStoreTest(JavaKind kind, int value, boolean unsafeStore, boolean unsafeLoad)66 public SubWordArrayStoreTest(JavaKind kind, int value, boolean unsafeStore, boolean unsafeLoad) { 67 this.kind = kind; 68 this.value = value; 69 this.unsafeStore = unsafeStore; 70 this.unsafeLoad = unsafeLoad; 71 } 72 73 @Test testArrayStore()74 public void testArrayStore() throws ClassNotFoundException { 75 Class<?> testClass = getClass(SubWordArrayStoreTest.class.getName() + "$" + kind.toString() + "Getter"); 76 test(getResolvedJavaMethod(testClass, SNIPPET), null); 77 } 78 arrayBaseOffset(JavaKind kind)79 private static long arrayBaseOffset(JavaKind kind) { 80 switch (kind) { 81 case Boolean: 82 return UNSAFE.arrayBaseOffset(boolean[].class); 83 case Byte: 84 return UNSAFE.arrayBaseOffset(byte[].class); 85 case Short: 86 return UNSAFE.arrayBaseOffset(short[].class); 87 case Char: 88 return UNSAFE.arrayBaseOffset(char[].class); 89 default: 90 throw GraalError.shouldNotReachHere(); 91 } 92 } 93 toASMType(JavaKind kind)94 static int toASMType(JavaKind kind) { 95 switch (kind) { 96 case Boolean: 97 return T_BOOLEAN; 98 case Byte: 99 return T_BYTE; 100 case Short: 101 return T_SHORT; 102 case Char: 103 return T_CHAR; 104 default: 105 throw GraalError.shouldNotReachHere(); 106 } 107 } 108 toArrayStoreOpcode(JavaKind kind)109 private static int toArrayStoreOpcode(JavaKind kind) { 110 switch (kind) { 111 case Boolean: 112 case Byte: 113 return BASTORE; 114 case Short: 115 return SASTORE; 116 case Char: 117 return CASTORE; 118 default: 119 throw GraalError.shouldNotReachHere(); 120 } 121 } 122 toArrayLoadOpcode(JavaKind kind)123 private static int toArrayLoadOpcode(JavaKind kind) { 124 switch (kind) { 125 case Boolean: 126 case Byte: 127 return BALOAD; 128 case Short: 129 return SALOAD; 130 case Char: 131 return CALOAD; 132 default: 133 throw GraalError.shouldNotReachHere(); 134 } 135 } 136 137 @Override generateClass(String internalClassName)138 protected byte[] generateClass(String internalClassName) { 139 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 140 cw.visit(52, ACC_SUPER | ACC_PUBLIC, internalClassName, null, "java/lang/Object", null); 141 142 final String fieldName = "array"; 143 final String fieldDescriptor = "[" + kind.getTypeChar(); 144 145 FieldVisitor field = cw.visitField(ACC_PUBLIC | ACC_STATIC, fieldName, fieldDescriptor, null, null); 146 field.visitEnd(); 147 148 MethodVisitor clinit = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null); 149 clinit.visitCode(); 150 clinit.visitIntInsn(BIPUSH, 16); 151 clinit.visitIntInsn(NEWARRAY, toASMType(kind)); 152 clinit.visitFieldInsn(PUTSTATIC, internalClassName, fieldName, fieldDescriptor); 153 clinit.visitInsn(RETURN); 154 clinit.visitMaxs(1, 0); 155 clinit.visitEnd(); 156 157 MethodVisitor snippet = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, SNIPPET, "()Z", null, null); 158 snippet.visitCode(); 159 160 if (unsafeStore) { 161 SubWordTestUtil.getUnsafe(snippet); 162 snippet.visitFieldInsn(GETSTATIC, internalClassName, fieldName, fieldDescriptor); 163 snippet.visitLdcInsn(arrayBaseOffset(kind)); 164 snippet.visitLdcInsn(value); 165 snippet.visitMethodInsn(INVOKEVIRTUAL, "sun/misc/Unsafe", "put" + SubWordTestUtil.getUnsafePutMethodName(kind), "(Ljava/lang/Object;J" + kind.getTypeChar() + ")V", false); 166 } else { 167 snippet.visitFieldInsn(GETSTATIC, internalClassName, fieldName, fieldDescriptor); 168 snippet.visitInsn(ICONST_0); 169 snippet.visitLdcInsn(value); 170 snippet.visitInsn(toArrayStoreOpcode(kind)); 171 } 172 173 if (unsafeLoad) { 174 SubWordTestUtil.getUnsafe(snippet); 175 snippet.visitFieldInsn(GETSTATIC, internalClassName, fieldName, fieldDescriptor); 176 snippet.visitLdcInsn(arrayBaseOffset(kind)); 177 snippet.visitMethodInsn(INVOKEVIRTUAL, "sun/misc/Unsafe", "get" + SubWordTestUtil.getUnsafePutMethodName(kind), "(Ljava/lang/Object;J)" + kind.getTypeChar(), false); 178 } else { 179 snippet.visitFieldInsn(GETSTATIC, internalClassName, fieldName, fieldDescriptor); 180 snippet.visitInsn(ICONST_0); 181 snippet.visitInsn(toArrayLoadOpcode(kind)); 182 } 183 184 snippet.visitLdcInsn(value); 185 SubWordTestUtil.convertToKind(snippet, kind); 186 SubWordTestUtil.testEqual(snippet); 187 188 snippet.visitMaxs(5, 0); 189 snippet.visitEnd(); 190 191 cw.visitEnd(); 192 return cw.toByteArray(); 193 } 194 } 195