1 /* 2 * Copyright (c) 2012, 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.replacements.test; 26 27 import org.junit.Test; 28 29 import org.graalvm.compiler.core.test.GraalCompilerTest; 30 import org.graalvm.compiler.nodes.ValueNode; 31 import org.graalvm.compiler.replacements.BoxingSnippets; 32 import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; 33 34 public class MonitorTest extends GraalCompilerTest { 35 36 @Test test0()37 public void test0() { 38 test("lockObjectSimple", new Object(), new Object()); 39 test("lockObjectSimple", new Object(), null); 40 test("lockObjectSimple", null, null); 41 } 42 43 @Test test01()44 public void test01() { 45 test("lockThisSimple", "test1", new Object()); 46 test("lockThisSimple", "test1", null); 47 } 48 49 @Test test02()50 public void test02() { 51 test("lockObjectSimple", null, "test1"); 52 } 53 54 @Test test101()55 public void test101() { 56 test("lockObject", new Object(), "test1", new String[1]); 57 } 58 59 @Test test102()60 public void test102() { 61 test("lockObject", null, "test1_1", new String[1]); 62 } 63 64 @Test test2()65 public void test2() { 66 test("lockThis", "test2", new String[1]); 67 } 68 69 /** 70 * Tests monitor operations on {@link PartialEscapePhase virtual objects}. 71 */ 72 @Test test3()73 public void test3() { 74 test("lockLocalObject", "test3", new String[1]); 75 } 76 77 /** 78 * Tests recursive locking of objects which should be biasable. 79 */ 80 @Test test4()81 public void test4() { 82 Chars src = new Chars("1234567890".toCharArray()); 83 Chars dst = new Chars(src.data.length); 84 test("copyObj", src, dst, 100); 85 } 86 87 /** 88 * Tests recursive locking of objects which do not appear to be biasable. 89 */ 90 @Test test5()91 public void test5() { 92 char[] src = "1234567890".toCharArray(); 93 char[] dst = new char[src.length]; 94 test("copyArr", src, dst, 100); 95 } 96 97 /** 98 * Extends {@link #test4()} with contention. 99 */ 100 @Test test6()101 public void test6() { 102 Chars src = new Chars("1234567890".toCharArray()); 103 Chars dst = new Chars(src.data.length); 104 int n = Runtime.getRuntime().availableProcessors(); 105 testN(n, "copyObj", src, dst, 100); 106 } 107 108 /** 109 * Extends {@link #test5()} with contention. 110 */ 111 @Test test7()112 public void test7() { 113 char[] src = "1234567890".toCharArray(); 114 char[] dst = new char[src.length]; 115 int n = Math.min(32, Runtime.getRuntime().availableProcessors()); 116 testN(n, "copyArr", src, dst, 100); 117 } 118 setAndGet(String[] box, String value)119 private static String setAndGet(String[] box, String value) { 120 synchronized (box) { 121 box[0] = null; 122 } 123 124 // Do a GC while a object is locked (by the caller) 125 System.gc(); 126 127 synchronized (box) { 128 box[0] = value; 129 } 130 return box[0]; 131 } 132 lockObjectSimple(Object o, Object value)133 public static Object lockObjectSimple(Object o, Object value) { 134 synchronized (o) { 135 value.hashCode(); 136 return value; 137 } 138 } 139 lockThisSimple(String value, Object o)140 public String lockThisSimple(String value, Object o) { 141 synchronized (this) { 142 synchronized (value) { 143 o.hashCode(); 144 return value; 145 } 146 } 147 } 148 lockObject(Object o, String value, String[] box)149 public static String lockObject(Object o, String value, String[] box) { 150 synchronized (o) { 151 return setAndGet(box, value); 152 } 153 } 154 lockThis(String value, String[] box)155 public String lockThis(String value, String[] box) { 156 synchronized (this) { 157 return setAndGet(box, value); 158 } 159 } 160 lockLocalObject(String value, String[] box)161 public static String lockLocalObject(String value, String[] box) { 162 Object o = new Object(); 163 synchronized (o) { 164 return setAndGet(box, value); 165 } 166 } 167 168 static class Chars { 169 170 final char[] data; 171 Chars(int size)172 Chars(int size) { 173 this.data = new char[size]; 174 } 175 Chars(char[] data)176 Chars(char[] data) { 177 this.data = data; 178 } 179 } 180 copyObj(Chars src, Chars dst, int n)181 public static String copyObj(Chars src, Chars dst, int n) { 182 for (int j = 0; j < n; j++) { 183 for (int i = 0; i < src.data.length; i++) { 184 synchronized (src) { 185 synchronized (dst) { 186 synchronized (src) { 187 synchronized (dst) { 188 dst.data[i] = src.data[i]; 189 } 190 } 191 } 192 } 193 } 194 } 195 return new String(dst.data); 196 } 197 copyArr(char[] src, char[] dst, int n)198 public static String copyArr(char[] src, char[] dst, int n) { 199 for (int j = 0; j < n; j++) { 200 for (int i = 0; i < src.length; i++) { 201 synchronized (src) { 202 synchronized (dst) { 203 synchronized (src) { 204 synchronized (dst) { 205 dst[i] = src[i]; 206 } 207 } 208 } 209 } 210 } 211 } 212 return new String(dst); 213 } 214 lockBoxedLong(long value)215 public static String lockBoxedLong(long value) { 216 Long lock = value; 217 synchronized (lock) { 218 return lock.toString(); 219 } 220 } 221 222 /** 223 * Reproduces issue reported in https://github.com/graalvm/graal-core/issues/201. The stamp in 224 * the PiNode returned by {@link BoxingSnippets#longValueOf} was overwritten when the node was 225 * subsequently canonicalized because {@code PiNode.computeValue()} ignored the 226 * {@link ValueNode#stamp(org.graalvm.compiler.nodes.NodeView)} field and used the 227 * {@code PiNode.piStamp} field. 228 */ 229 @Test test8()230 public void test8() { 231 test("lockBoxedLong", 5L); 232 test("lockBoxedLong", Long.MAX_VALUE - 1); 233 test("lockBoxedLong", Long.MIN_VALUE + 1); 234 } 235 } 236