001/* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013package org.jikesrvm.scheduler; 014 015import org.jikesrvm.VM; 016import org.jikesrvm.mm.mminterface.Barriers; 017import org.jikesrvm.runtime.Magic; 018import org.vmmagic.pragma.Inline; 019import org.vmmagic.pragma.Uninterruptible; 020import org.vmmagic.unboxed.Address; 021import org.vmmagic.unboxed.Word; 022import org.vmmagic.unboxed.Offset; 023 024/** 025 * Class to provide synchronization methods where java language 026 * synchronization is insufficient and Magic.prepare and Magic.attempt 027 * are at too low a level. 028 */ 029@Uninterruptible 030public class Synchronization { 031 032 /** 033 * Atomically swap test value to new value in the specified object and the specified field 034 * @param base object containing field 035 * @param offset position of field 036 * @param testValue expected value of field 037 * @param newValue new value of field 038 * @return {@code true}=> successful swap, {@code false}=> field not equal to testValue 039 */ 040 @Inline 041 public static boolean tryCompareAndSwap(Object base, Offset offset, int testValue, int newValue) { 042 if (Barriers.NEEDS_INT_PUTFIELD_BARRIER || Barriers.NEEDS_INT_GETFIELD_BARRIER) { 043 return Barriers.intTryCompareAndSwap(base, offset, testValue, newValue); 044 } else { 045 if (VM.BuildForIA32) { 046 return Magic.attemptInt(base, offset, testValue, newValue); 047 } else { 048 int oldValue; 049 do { 050 oldValue = Magic.prepareInt(base, offset); 051 if (oldValue != testValue) return false; 052 } while (!Magic.attemptInt(base, offset, oldValue, newValue)); 053 return true; 054 } 055 } 056 } 057 058 /** 059 * Atomically swap test value to new value in the specified object and the specified field 060 * @param base object containing field 061 * @param offset position of field 062 * @param testValue expected value of field 063 * @param newValue new value of field 064 * @return {@code true}=> successful swap, {@code false}=> field not equal to testValue 065 */ 066 @Inline 067 public static boolean tryCompareAndSwap(Object base, Offset offset, long testValue, long newValue) { 068 if (Barriers.NEEDS_LONG_PUTFIELD_BARRIER || Barriers.NEEDS_LONG_GETFIELD_BARRIER) { 069 return Barriers.longTryCompareAndSwap(base, offset, testValue, newValue); 070 } else { 071 if (VM.BuildForIA32) { 072 return Magic.attemptLong(base, offset, testValue, newValue); 073 } else { 074 long oldValue; 075 do { 076 oldValue = Magic.prepareLong(base, offset); 077 if (oldValue != testValue) return false; 078 } while (!Magic.attemptLong(base, offset, oldValue, newValue)); 079 return true; 080 } 081 } 082 } 083 084 /** 085 * Atomically swap test value to new value in the specified object and the specified field 086 * @param base object containing field 087 * @param offset position of field 088 * @param testValue expected value of field 089 * @param newValue new value of field 090 * @return {@code true}=> successful swap, {@code false}=> field not equal to testValue 091 */ 092 @Inline 093 public static boolean tryCompareAndSwap(Object base, Offset offset, Word testValue, Word newValue) { 094 if (Barriers.NEEDS_WORD_PUTFIELD_BARRIER || Barriers.NEEDS_WORD_GETFIELD_BARRIER) { 095 return Barriers.wordTryCompareAndSwap(base, offset, testValue, newValue); 096 } else { 097 if (VM.BuildForIA32) { 098 return Magic.attemptWord(base, offset, testValue, newValue); 099 } else { 100 Word oldValue; 101 do { 102 oldValue = Magic.prepareWord(base, offset); 103 if (oldValue.NE(testValue)) return false; 104 } while (!Magic.attemptWord(base, offset, oldValue, newValue)); 105 return true; 106 } 107 } 108 } 109 110 /** 111 * Atomically swap test value to new value in the specified object and the specified field 112 * @param base object containing field 113 * @param offset position of field 114 * @param testValue expected value of field 115 * @param newValue new value of field 116 * @return {@code true}=> successful swap, {@code false}=> field not equal to testValue 117 */ 118 @Inline 119 public static boolean tryCompareAndSwap(Object base, Offset offset, Address testValue, Address newValue) { 120 if (Barriers.NEEDS_ADDRESS_PUTFIELD_BARRIER || Barriers.NEEDS_ADDRESS_GETFIELD_BARRIER) { 121 return Barriers.addressTryCompareAndSwap(base, offset, testValue, newValue); 122 } else { 123 if (VM.BuildForIA32) { 124 return Magic.attemptAddress(base, offset, testValue, newValue); 125 } else { 126 Address oldValue; 127 do { 128 oldValue = Magic.prepareAddress(base, offset); 129 if (oldValue.NE(testValue)) 130 return false; 131 } while (!Magic.attemptAddress(base, offset, oldValue, newValue)); 132 return true; 133 } 134 } 135 } 136 137 /** 138 * Atomically swap test value to new value in the specified object and the specified field 139 * @param base object containing field 140 * @param offset position of field 141 * @param testValue expected value of field 142 * @param newValue new value of field 143 * @return {@code true}=> successful swap, {@code false}=> field not equal to testValue 144 */ 145 @Inline 146 public static boolean tryCompareAndSwap(Object base, Offset offset, Object testValue, Object newValue) { 147 if (Barriers.NEEDS_OBJECT_PUTFIELD_BARRIER || Barriers.NEEDS_OBJECT_GETFIELD_BARRIER) { 148 return Barriers.objectTryCompareAndSwap(base, offset, testValue, newValue); 149 } else { 150 if (VM.BuildForIA32) { 151 return Magic.attemptObject(base, offset, testValue, newValue); 152 } else { 153 Object oldValue; 154 do { 155 oldValue = Magic.prepareObject(base, offset); 156 if (oldValue != testValue) return false; 157 } while (!Magic.attemptObject(base, offset, oldValue, newValue)); 158 return true; 159 } 160 } 161 } 162 163 @Inline 164 public static boolean testAndSet(Object base, Offset offset, int newValue) { 165 return tryCompareAndSwap(base, offset, 0, newValue); 166 } 167 168 @Inline 169 public static int fetchAndStore(Object base, Offset offset, int newValue) { 170 int oldValue; 171 do { 172 if (Barriers.NEEDS_INT_GETFIELD_BARRIER) { 173 oldValue = Barriers.intFieldRead(base, offset, 0); 174 } else { 175 oldValue = Magic.getIntAtOffset(base, offset); 176 } 177 } while (!tryCompareAndSwap(base, offset, oldValue, newValue)); 178 return oldValue; 179 } 180 181 @Inline 182 public static Address fetchAndStoreAddress(Object base, Offset offset, Address newValue) { 183 Address oldValue; 184 do { 185 if (Barriers.NEEDS_ADDRESS_GETFIELD_BARRIER) { 186 oldValue = Barriers.addressFieldRead(base, offset, 0); 187 } else { 188 oldValue = Magic.getAddressAtOffset(base, offset); 189 } 190 } while (!tryCompareAndSwap(base, offset, oldValue, newValue)); 191 return oldValue; 192 } 193 194 @Inline 195 public static int fetchAndAdd(Object base, Offset offset, int increment) { 196 int oldValue; 197 do { 198 if (Barriers.NEEDS_INT_GETFIELD_BARRIER) { 199 oldValue = Barriers.intFieldRead(base, offset, 0); 200 } else { 201 oldValue = Magic.getIntAtOffset(base, offset); 202 } 203 } while (!tryCompareAndSwap(base, offset, oldValue, oldValue + increment)); 204 return oldValue; 205 } 206 207 @Inline 208 public static int fetchAndDecrement(Object base, Offset offset, int decrement) { 209 int oldValue; 210 do { 211 if (Barriers.NEEDS_INT_GETFIELD_BARRIER) { 212 oldValue = Barriers.intFieldRead(base, offset, 0); 213 } else { 214 oldValue = Magic.getIntAtOffset(base, offset); 215 } 216 } while (!tryCompareAndSwap(base, offset, oldValue, oldValue - decrement)); 217 return oldValue; 218 } 219 220 @Inline 221 public static Address fetchAndAddAddressWithBound(Object base, Offset offset, int increment, Address bound) { 222 Address oldValue, newValue; 223 if (VM.VerifyAssertions) VM._assert(increment > 0); 224 do { 225 if (Barriers.NEEDS_ADDRESS_GETFIELD_BARRIER) { 226 oldValue = Barriers.addressFieldRead(base, offset, 0); 227 } else { 228 oldValue = Magic.getAddressAtOffset(base, offset); 229 } 230 newValue = oldValue.plus(increment); 231 if (newValue.GT(bound)) return Address.max(); 232 } while (!tryCompareAndSwap(base, offset, oldValue, newValue)); 233 return oldValue; 234 } 235 236 @Inline 237 public static Address fetchAndSubAddressWithBound(Object base, Offset offset, int decrement, Address bound) { 238 Address oldValue, newValue; 239 if (VM.VerifyAssertions) VM._assert(decrement > 0); 240 do { 241 if (Barriers.NEEDS_ADDRESS_GETFIELD_BARRIER) { 242 oldValue = Barriers.addressFieldRead(base, offset, 0); 243 } else { 244 oldValue = Magic.getAddressAtOffset(base, offset); 245 } 246 newValue = oldValue.minus(decrement); 247 if (newValue.LT(bound)) return Address.max(); 248 } while (!tryCompareAndSwap(base, offset, oldValue, newValue)); 249 return oldValue; 250 } 251}