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     */
013    package org.jikesrvm.scheduler;
014    
015    import org.jikesrvm.VM;
016    import org.jikesrvm.mm.mminterface.Barriers;
017    import org.jikesrvm.runtime.Magic;
018    import org.vmmagic.pragma.Inline;
019    import org.vmmagic.pragma.Uninterruptible;
020    import org.vmmagic.unboxed.Address;
021    import org.vmmagic.unboxed.Word;
022    import 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
030    public 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 != 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 != 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    }