001    package edu.rice.cs.cunit;
002    
003    import edu.rice.cs.cunit.instrumentors.DoNotInstrument;
004    import edu.rice.cs.cunit.record.syncPoints.ISyncPoint;
005    
006    /**
007     * Class that records synchronization points.
008     *
009     * NOTE: This class may not be instrumented with a strategy affecting synchronized methods or blocks!
010     * Do not instrument with SynchronizedMethodToBlockStrategy, SynchronizedBlockStrategy,
011     * CompactSynchronizedBlockStrategy, CompactSynchronizedBlockDebugStrategy, or
012     * CompactSynchronizedBlockReplayStrategy.
013     *
014     * @author Mathias Ricken
015     */
016    @DoNotInstrument(instrumentors = "***.*Synchronized*;***.ObjectCallStrategy;***.AssignObjectIDStrategy")
017    public class SyncPointBuffer {
018        /**
019         * A method to retrieve the .class field; this is required for pre-1.5 compatibility where
020         * simple field access to the .class field is not allowed.
021         */
022        public static final Class<?> _class() {
023            return SyncPointBuffer.class;
024        }; 
025      
026        /**
027         * Size of array.
028         */
029        public static final int SIZE = 1 << 9;
030    
031        /**
032         * Array of synchronization points.
033         */
034        private static volatile ISyncPoint[] _syncPoints = new ISyncPoint[SIZE];
035    
036        /**
037         * Index to be used next.
038         */
039        private static volatile int _index = 0;
040    
041        /**
042         * Size of a record in the compact array.
043         */
044        public static final int COMPACT_RECORD_SIZE = 2;
045    
046        /**
047         * Size of a record in the compact array with debug info.
048         */
049        public static final int COMPACT_DEBUG_RECORD_SIZE = 5;
050    
051        /**
052         * Size of compact array.
053         */
054        public static final int COMPACT_SIZE = 1 << 9;
055    
056        /**
057         * Enumeration of sync point codes.
058         */
059        public static enum SP {
060            /**
061             * Code for entering a synchronized block.
062             */
063            MONITORENTER(1),
064    
065            /**
066             * Code for leaving a synchronized block.
067             */
068            MONITOREXIT(2),
069    
070            /**
071             * Code for trying to enter a synchronized block.
072             */
073            TRYMONITORENTER(3),
074    
075            /**
076             * Code for the start of a thread.
077             */
078            THREADSTART(4),
079    
080            /**
081             * Code for the end of a thread.
082             */
083            THREADEXIT(5),
084    
085            /**
086             * Code for entering a synchronized block to assign an object ID. This synchronized block did not exist
087             * in the original program and is an artifact of the instrumentation.
088             * Object ID is 0; since SyncPointBuffer.class is used as lock, the value is meaningless.
089             */
090            OBJID_MONITORENTER(6),
091    
092            /**
093             * Code for leaving a synchronized block to assign an object ID. This synchronized block did not exist
094             * in the original program and is an artifact of the instrumentation.
095             * Object ID is set to the newly assigned object ID. SyncPointBuffer.class is used as lock, but its object ID
096             * is rather meaningless.
097             */
098            OBJID_MONITOREXIT(7),
099    
100            /**
101             * Code for trying to enter a synchronized block to assign an object ID. This synchronized block did not exist
102             * in the original program and is an artifact of the instrumentation.
103             * Object ID is 0; since SyncPointBuffer.class is used as lock, the value is meaningless.
104             */
105            OBJID_TRYMONITORENTER(8),
106    
107            /**
108             * Code for entering a synchronized block to assign a thread ID. This synchronized block did not exist
109             * in the original program and is an artifact of the instrumentation.
110             * Object ID is 0; since SyncPointBuffer.class is used as lock, the value is meaningless.
111             */
112            THREADID_MONITORENTER(9),
113    
114            /**
115             * Code for leaving a synchronized block to assign a thread ID. This synchronized block did not exist
116             * in the original program and is an artifact of the instrumentation.
117             * Object ID is set to the newly assigned thread ID. SyncPointBuffer.class is used as lock, but its object ID
118             * is rather meaningless.
119             */
120            THREADID_MONITOREXIT(10),
121    
122            /**
123             * Code for trying to enter a synchronized block to assign a thread ID. This synchronized block did not exist
124             * in the original program and is an artifact of the instrumentation.
125             * Object ID is 0; since SyncPointBuffer.class is used as lock, the value is meaningless.
126             */
127            THREADID_TRYMONITORENTER(11),
128    
129            /**
130             * Code for the end of the trace.
131             */
132            END(12),
133    
134            /**
135             * Last code used.
136             */
137            LAST_VALID_CODE(12);
138    
139            /**
140             * Integer value of the enum.
141             */
142            private int _value;
143    
144            /**
145             * Constructor.
146             * @param value integer value
147             */
148            SP(int value) { _value = value; }
149    
150            /**
151             * Return the integer value of the enum.
152             * @return integer value, ranging from 1 to SP_LAST_VALID_CODE.value() (inclusive)
153             */
154            public int intValue() { return _value; }
155        }
156    
157        /**
158         * Compact array of synchronization points.
159         */
160        private static volatile long[] _compactSyncPoints = new long[COMPACT_SIZE];
161    
162        /**
163         * Index to be used next for the compact array.
164         */
165        private static volatile int _compactIndex = 0;
166    
167        /**
168         * Size of replay array.
169         */
170        public static final int REPLAY_SIZE = 1 << 9;
171    
172        /**
173         * Record array of synchronization points.
174         */
175        private static volatile long[] _replaySyncPoints = new long[REPLAY_SIZE];
176    
177        /**
178         * Object array with objects that threads may wait for.
179         */
180        private static volatile Object[] _replayWaitArray = new Object[REPLAY_SIZE/COMPACT_RECORD_SIZE];
181    
182        /**
183         * Object that threads can wait for if they need to enter the algorithm.
184         */
185        private static final Object _waitAlgoObj = new Object();
186    
187        /**
188         * Object that threads can wait for if they need to wait for a new buffer.
189         */
190        private static final Object _newBufferWaitObj = new Object();
191    
192        /**
193         * Index to be used next for the replay array.
194         */
195        private static volatile int _replayIndex = 0;
196    
197        /**
198         * Index to be used next for the replay wait array.
199         */
200        private static volatile int _replayWaitIndex = 0;
201    
202        /**
203         * True if points should be recorded.
204         */
205        private static volatile boolean _recording = false;
206    
207        /**
208         * True if points should be recorded immediately.
209         */
210        private static volatile boolean _transferImmediately = false;
211    
212        /**
213         * Array for immediate transfer.
214         */
215        private static volatile long[] _immediateTransfer = new long[COMPACT_DEBUG_RECORD_SIZE];
216    
217        /**
218         * True if scheduled replay has begun.
219         */
220        private static volatile boolean _replaying = false;
221    
222        /**
223         * True if the initial buffer for replay has been loaded. Since this starts out as false, the buffer will
224         * be loaded.
225         */
226        private static volatile boolean _replayBufferLoaded = false;
227    
228        /**
229         * Next object ID to be assigned.
230         */
231        public static volatile long _nextObjectID = 0;
232    
233        /**
234         * Next thread ID to be assigned.
235         */
236        public static volatile long _nextThreadID = 0;
237    
238        /**
239         * Message description.
240         */
241        public static volatile String _message = null;
242    
243        /**
244         * Number of running threads.
245         */
246        public static volatile long _runningThreads = 0;
247    
248        /**
249         * Adds a synchronization point to the list.
250         * NOTE: This method has to be synchronized, but it may NOT be instrumented as such! An infinite recursion would
251         * be the result.
252         * The monitor application has to check that no thread is currently holding the lock on SyncPointBuffer.class.
253         * Only then may it clear the list.
254         * @param sp synchronization point to add.
255         */
256        public static synchronized void add(ISyncPoint sp) {
257            if (!_recording) {
258                return;
259            }
260    
261            _syncPoints[_index] = sp;
262            _index = _index + 1;
263            if (SIZE==_index) {
264                transfer();
265            }
266        }
267    
268        /**
269         * Transfer and empty array.
270         * NOTE: The master should set a "method entry event" at the beginning of this method and transfer the array.
271         */
272        public static void transfer() {
273            for (int i=0; i<SIZE; ++i) {
274                _syncPoints[i] = null;
275            }
276            _index = 0;
277        }
278    
279        /**
280         * Adds a synchronization point to the compact list.
281         * NOTE: This method has to be synchronized, but it may NOT be instrumented as such! An infinite recursion would
282         * be the result.
283         * The monitor application has to check that no thread is currently holding the lock on SyncPointBuffer.class.
284         * Only then may it clear the list.
285         * @param code code for this event
286         * @param tid thread id
287         */
288        public static synchronized void compactAdd(long code, long tid) {
289            if (!_recording) {
290                return;
291            }
292    
293            if (_transferImmediately) {
294                _immediateTransfer[0] = tid;
295                _immediateTransfer[1] = code;
296                compactImmediateTransfer();
297            }
298            else {
299                _compactSyncPoints[_compactIndex++] = tid;
300                _compactSyncPoints[_compactIndex++] = code;
301                if (COMPACT_SIZE<=_compactIndex) {
302                    compactTransfer();
303                }
304            }
305        }
306    
307        /**
308         * Adds a synchronization point to the compact list.
309         * NOTE: This method has to be synchronized, but it may NOT be instrumented as such! An infinite recursion would
310         * be the result.
311         * The monitor application has to check that no thread is currently holding the lock on SyncPointBuffer.class.
312         * Only then may it clear the list.
313         * @param oid object id
314         * @param code code for this event
315         * @param tid thread id
316         * @param classIndex index of the class in the method database
317         * @param methodAndPC method index and PC
318         */
319        public static synchronized void compactDebugAdd(long oid, long code, long tid, long classIndex, long methodAndPC) {
320            if (!_recording) {
321                return;
322            }
323    
324            if (_transferImmediately) {
325                _immediateTransfer[0] = tid;
326                _immediateTransfer[1] = code;
327                _immediateTransfer[2] = classIndex;
328                _immediateTransfer[3] = methodAndPC;
329                _immediateTransfer[4] = oid;
330                compactImmediateTransfer();
331            }
332            else {
333                _compactSyncPoints[_compactIndex++] = tid;
334                _compactSyncPoints[_compactIndex++] = code;
335                _compactSyncPoints[_compactIndex++] = classIndex;
336                _compactSyncPoints[_compactIndex++] = methodAndPC;
337                _compactSyncPoints[_compactIndex++] = oid;
338                if (COMPACT_SIZE-(COMPACT_SIZE%COMPACT_DEBUG_RECORD_SIZE)<=_compactIndex) {
339                    compactTransfer();
340                }
341            }
342        }
343    
344        /**
345         * Transfer and empty compact array.
346         * NOTE: The master should set a "method entry event" at the beginning of this method and transfer the array.
347         */
348        public static void compactTransfer() {
349            for (int i=0; i<COMPACT_SIZE; ++i) {
350                _compactSyncPoints[i] = 0;
351            }
352        }
353    
354        /**
355         * Transfer immediately and empty compact array.
356         * NOTE: The master should set a "method entry event" at the beginning of this method and transfer the array.
357         */
358        public static void compactImmediateTransfer() {
359            for (int i=0; i<COMPACT_DEBUG_RECORD_SIZE; ++i) {
360                _immediateTransfer[i] = 0;
361            }
362        }
363    
364        /**
365         * Wait for this synchronization point in the compact list.
366         * NOTE: This method has to be synchronized, but it may NOT be instrumented as such! An infinite recursion would
367         * be the result.
368         * @param code code for this event
369         * @param tid thread id
370         */
371        public static synchronized void compactWait(long code, long tid) {
372            compactWait(code, tid, -1, -1);
373        }
374    
375        /**
376         * Notify the wait algorithm that a thread has ended and check if the next thread has to be woken up.
377         * <p/>
378         * NOTE: This method has to be synchronized, but it may NOT be instrumented as such! An infinite recursion would be the
379         * result.
380         *
381         * @param tid thread id
382         */
383        public static synchronized void compactThreadExit(long tid) {
384            compactThreadExit(tid, -1, -1);
385        }
386    
387    
388        /**
389         * Wait for this synchronization point in the compact list.
390         * <p/>
391         * NOTE: This method has to be synchronized, but it may NOT be instrumented as such! An infinite recursion would be
392         * the result.
393         *
394         * @param code code for this event
395         * @param tid thread id
396         * @param classIndex  index of the class in the method database
397         * @param methodAndPC method index and PC
398         */
399        public static synchronized void compactWait(long code, long tid, long classIndex, long methodAndPC) {
400            if (!_replaying) {
401                return;
402            }
403    
404            boolean oldReplaying = _replaying;
405            try {
406                _replaying = false;
407    
408                monitorEnter(_waitAlgoObj);
409                setMessage(tid+" "+code+" - compactWait class="+Long.toHexString(classIndex)+" method="+
410                           Long.toHexString(methodAndPC >>> 32)+", PC="+Long.toHexString(methodAndPC & 0xFFFF));
411    
412                // If this is NOT the first sync point for this thread...
413                if (isOldThread()) {
414                    // Advance the indices.
415                    _replayIndex += 2;
416                    ++_replayWaitIndex;
417    
418                    setMessage("\told thread");
419                }
420                // Otherwise, if it was the first time...
421                else {
422                    // Do not advance the indices.
423    
424                    // Set flag.
425                    setOldThread();
426    
427                    setMessage("\tnew thread, oldThread = "+isOldThread());
428                }
429    
430                // If the buffer has never been loaded, or if the index is at the end of the buffer...
431                if ((!_replayBufferLoaded) || (_replayIndex>=REPLAY_SIZE)) {
432                    // Load the buffer and reset the indices.
433                    replayTransfer();
434    
435                    // Wake up all threads waiting for a buffer update.
436                    synchronized(_newBufferWaitObj) {
437                        _newBufferWaitObj.notifyAll();
438                    }
439                }
440    
441                _replayIndex += 2;
442                ++_replayWaitIndex;
443    
444                monitorExit(_waitAlgoObj);
445            /*
446                // If scheduled replay is enabled...
447    
448                // monitorenter _waitAlgoObj (beginning of main synchronized block)
449                monitorEnter(_waitAlgoObj);
450    
451                // If this is NOT the first sync point for this thread...
452                if (isOldThread()) {
453                    // Advance the indices.
454                    _replayIndex += 2;
455                    ++_replayWaitIndex;
456                }
457                // Otherwise, if it was the first time...
458                else {
459                    // Do not advance the indices.
460    
461                    // Set flag.
462                    setOldThread();
463                }
464    
465                boolean exitMethod = false;
466                Object waitObject = null;
467    
468                // Repeat this... ("RETRY" loop)
469                do {
470                    // If the buffer has never been loaded, or if the index is at the end of the buffer...
471                    if ((!_replayBufferLoaded) || (_replayIndex>=REPLAY_SIZE)) {
472                        // Load the buffer and reset the indices.
473                        replayTransfer();
474    
475                        // Wake up all threads waiting for a buffer update.
476                        synchronized(_newBufferWaitObj) {
477                            _newBufferWaitObj.notifyAll();
478                        }
479                    }
480    
481                    // If the current sync point marks the end of the schedule...
482                    if (_replaySyncPoints[_replayIndex] == SP_END) {
483                        // Disable scheduled replay.
484                        _replaying = false;
485    
486                        // Wake up all threads waiting for a buffer update.
487                        synchronized(_newBufferWaitObj) {
488                            _newBufferWaitObj.notifyAll();
489                        }
490    
491                        // monitorexit _waitAlgoObj
492                        monitorExit(_waitAlgoObj);
493    
494                        // Break out of the "RETRY" loop.
495                        break;
496                    }
497    
498                    boolean scan = false;
499    
500                    // If there's a thread waiting for this wait array entry...
501                    if (_replayWaitArray[_replayWaitIndex] != null) {
502                        // Notify it
503                        Object o = _replayWaitArray[_replayWaitIndex];
504                        synchronized(o) {
505                            o.notify();
506                        }
507    
508                        // Clear this entry in the wait array
509                        _replayWaitArray[_replayWaitIndex] = null;
510    
511                        // Set a flag to scan ahead for the current sync point ("SCAN").
512                        scan = true;
513    
514                        // Do not advance indices.
515                    }
516                    else {
517                        // If the current sync point in the array is the right one...
518                        if (_replaySyncPoints[_replayIndex+1] == tid) { // right tid
519                            if (_replaySyncPoints[_replayIndex] == code) { // right code {
520                                // Do not advance indices.
521    
522                                // Allow the thread to exit the "RETRY" loop.
523                                exitMethod = true;
524                            }
525                            else {
526                                // Right tid, but wrong code
527                                // oldReplaying = _replaying;
528                                // _replaying = false;
529                                // String msg = "Scanned ahead, found sync point " + _replaySyncPoints[_replayIndex] +
530                                //              " " + _replaySyncPoints[_replayIndex + 1] + " (wait array entry=" +
531                                //              _replayWaitArray[_replayWaitIndex] + ") at index " +
532                                //              (_replayIndex / 2)
533                                //              + ". Same thread, but different code or filled wait array entry!";
534                                // setMessage(msg);
535                                // _replaying = oldReplaying;
536                            }
537                        }
538                        // Otherwise...
539                        else {
540                            // Set a flag to scan ahead ("SCAN").
541                            scan = true;
542                        }
543                    }
544                    // If the "SCAN" flag is set (i.e. either a thread was woken up
545                    // or the current sync point did not match)...
546                    if (scan) {
547                        // Look for the sync points in the remaining part of the array.
548                        int index = _replayIndex + COMPACT_RECORD_SIZE;
549                        int waitIndex = _replayWaitIndex + 1;
550                        while(index < REPLAY_SIZE) {
551                            // If it could be found...
552                            if (_replaySyncPoints[index + 1] == tid) { // right tid
553                                if ((_replaySyncPoints[index] == code) && // right code
554                                    (_replayWaitArray[waitIndex] == null)) { // no one waiting for this one yet
555                                    // Insert a new object into corresponding slot of the wait array
556                                    // and set as "wait object" for this method.
557                                    waitObject = _replayWaitArray[waitIndex] = new Object();
558    
559                                    // Allow the thread to exit the "RETRY" loop.
560                                    exitMethod = true;
561                                    break;
562                                }
563                                else {
564                                    // right tid, but wrong code or someone already waiting for it
565                                    // oldReplaying = _replaying;
566                                    // _replaying = false;
567                                    // msg = "Scanned ahead, found sync point " + _replaySyncPoints[index] +
568                                    //       " " + _replaySyncPoints[index + 1] + " (wait array entry=" +
569                                    //       _replayWaitArray[waitIndex] + ") at index " +
570                                    //       (index / 2) + ". Same thread, but different code or filled wait array entry!";
571                                    // setMessage(msg);
572                                    // _replaying = oldReplaying;
573                                }
574                            }
575                            index += COMPACT_RECORD_SIZE;
576                            ++waitIndex;
577                        }
578    
579                        // Otherwise, if it could not be found...
580                        if (!exitMethod) {
581                            // Set the new buffer wait object as "wait object" for this method.
582                            waitObject = _newBufferWaitObj;
583    
584                            // Do not allow the thread to exit the "RETRY" loop.
585                        }
586    
587                        // monitorenter waitObj (beginning of wait object synchronized block)
588                        monitorEnter(waitObject);
589                    }
590    
591                    // monitorexit _waitAlgoObj (end of main synchronized block)
592                    monitorExit(_waitAlgoObj);
593    
594                    // If a "wait object" has been set for this method...
595                    if (waitObject!=null) {
596                        // Call wait() on that object (make sure to continue waiting if interrupted).
597                        boolean stillWaiting = true;
598                        do {
599                            try {
600                                waitObject.wait();
601                                stillWaiting = false;
602                            }
603                            catch(InterruptedException e) {
604                                // do nothing, continue to wait
605                            }
606                        } while(stillWaiting);
607    
608                        // monitorexit waitObj (end of wait object synchronized block)
609                        monitorExit(waitObject);
610    
611                        // Do not advance indices.
612    
613                        // If the thread is NOT allowed to exit the loop
614                        // (i.e. it was waiting for a new buffer) AND scheduled replay is enabled...
615                        if ((!exitMethod) && _replaying) {
616                            // monitorenter _waitAlgoObj (beginning of main synchronized block for next iteration)
617                            monitorEnter(_waitAlgoObj);
618                        }
619                    }
620                } while((!exitMethod) && _replaying);
621                // ...while the thread is not allowed to exit the loop and scheduled replay is enabled (end "RETRY" loop).
622                */
623            }
624            finally {
625                _replaying = oldReplaying;
626            }
627        }
628    
629        /**
630         * Notify the wait algorithm that a thread has ended and check if the next thread has to be woken up.
631         * NOTE: This method has to be synchronized, but it may NOT be instrumented as such! An infinite recursion would be
632         * the result.
633         *
634         * @param tid         thread id
635         * @param classIndex  index of the class in the method database
636         * @param methodAndPC method index and PC
637         */
638        public static synchronized void compactThreadExit(long tid, long classIndex, long methodAndPC) {
639            if (!_replaying) {
640                return;
641            }
642    
643            boolean oldReplaying = _replaying;
644            try {
645                _replaying = false;
646                setMessage(tid+" "+SP.THREADEXIT.intValue()+" - compactWait class="+Long.toHexString(classIndex)+
647                           " method="+Long.toHexString(methodAndPC >>> 32)+", PC="+Long.toHexString(methodAndPC & 0xFFFF));
648    
649                /*
650                // If scheduled replay is enabled...
651    
652                // monitorenter _waitAlgoObj (beginning of main synchronized block)
653                monitorEnter(_waitAlgoObj);
654    
655                // Advance the indices.
656                _replayIndex += 2;
657                ++_replayWaitIndex;
658    
659                // If the index is at the end of the buffer...
660                if (_replayIndex>=REPLAY_SIZE) {
661                    // Load the buffer and reset the indices.
662                    replayTransfer();
663    
664                    // Wake up all threads waiting for a buffer update.
665                    synchronized(_newBufferWaitObj) {
666                        _newBufferWaitObj.notifyAll();
667                    }
668                }
669                // Otherwise...
670                else {
671                    Object o = _replayWaitArray[_replayWaitIndex];
672    
673                    // If there's a thread waiting for this wait array entry...
674                    if (o != null) {
675                        // monitorenter _waitArray[index] (beginning of wait object synchronized block)
676                        synchronized(o) {
677                            // Notify it.
678                            o.notify();
679                        }
680                    }
681                    // Otherwise, if the current sync point marks the end of the schedule...
682                    else if (_replaySyncPoints[_replayIndex] == SP_END) {
683                        // Disable scheduled replay.
684                        _replaying = false;
685    
686                        // Wake up all threads waiting for a buffer update.
687                        synchronized(_newBufferWaitObj) {
688                            _newBufferWaitObj.notifyAll();
689                        }
690                    }
691                    // Otherwise...
692                    else {
693                        // Do nothing, because there's still a thread awake that will reach this sync point.
694                    }
695                }
696    
697                // monitorexit _waitAlgoObj (end of main synchronized block)
698                monitorExit(_waitAlgoObj);
699                */
700            }
701            finally{
702                _replaying = oldReplaying;
703            }
704        }
705    
706        /**
707         * Transfer and and reset replay array. NOTE: The master should set a "method entry event" at the beginning of this
708         * method and transfer the array.
709         */
710        public static void replayTransfer() {
711            _replayIndex = 0;
712            _replayWaitIndex = 0;
713            _replayBufferLoaded = true;
714            synchronized(_newBufferWaitObj) {
715                _newBufferWaitObj.notifyAll();
716            }
717        }
718    
719    /**
720     * Accessor for the recording flag.
721         * NOTE: This method has to be synchronized, but should not be instrumented.
722         * @return true if recording
723         */
724        public static synchronized boolean isRecording() {
725            return _recording;
726        }
727    
728        /**
729         * Mutator for the recording flag.
730         * NOTE: This method has to be synchronized, but should not be instrumented.
731         * @param recording true if recording should be enabled
732         */
733        public static synchronized void setRecording(boolean recording) {
734            _recording = recording;
735        }
736    
737        /**
738         * Notify the monitor application of a message.
739         * NOTE: The master should set a "method exit event" at the end of this method and process the error.
740         * @param message message string
741         */
742        public static void setMessage(String message) {
743            _message = message;
744        }
745    
746        /**
747         * Marker for monitorenter instructions. The invokestatic instruction should get replaced with a monitorenter.
748         * @param o object whose lock should be acquired
749         */
750        public static void monitorEnter(Object o) {
751            // nothing to do
752        }
753    
754        /**
755         * Marker for monitorexit instructions. The invokestatic instruction should get replaced with a monitorexit.
756         * @param o object whose lock should be released
757         */
758        public static void monitorExit(Object o) {
759            // nothing to do
760        }
761    
762        /**
763         * Marker for getting the value of the $$$oldThread$$$ field. The invokestatic instruction should get replaced with
764         * invokestatic java/lang/Thread.currentThread()Ljava/lang/Thread;
765         * getfield java/lang/Thread.$$$oldThread$$$
766         * @return value of the $$$oldThread$$$ field of the current thread (theoretically)
767         */
768        public static boolean isOldThread() {
769            // nothing to do
770            return true;
771        }
772    
773        /**
774         * Marker for setting $$$oldThread$$$ field. The invokestatic instruction should get replaced with
775         * iconst_1
776         * invokestatic java/lang/Thread.currentThread()Ljava/lang/Thread;
777         * setfield java/lang/Thread.$$$oldThread$$$
778         */
779        public static void setOldThread() {
780            // nothing to do
781        }
782    
783    
784        //
785        // Execution with random delays.
786        //
787        /**
788         * Length of the shortest delay in milliseconds.
789         * RANDOM_DELAY_MIN <= t < (RANDOM_DELAY_MIN + RANDOM_DELAY_MAGNITUDE)
790         */
791        public static final int RANDOM_DELAY_MIN = 0;
792    
793        /**
794         * Length of time in milliseconds between the shorted and the longest delay.
795         * RANDOM_DELAY_MIN <= t < (RANDOM_DELAY_MIN + RANDOM_DELAY_MAGNITUDE)
796         */
797        public static final int RANDOM_DELAY_MAGNITUDE = 50;
798    
799        /**
800         * Enable delay on thread start?
801         */
802        public static boolean RANDOM_DELAY_THREAD_START = true;
803        
804        /**
805         * Enable delay on thread exit?
806         */
807        public static boolean RANDOM_DELAY_THREAD_EXIT = true;
808        
809        /**
810         * Enable delay on thread run?
811         */
812        public static boolean RANDOM_DELAY_THREAD_RUN = true;
813    
814        /**
815         * Enable delay on thread join?
816         */
817        public static boolean RANDOM_DELAY_THREAD_JOIN = true;
818    
819        /**
820         * Enable delay before notify?
821         */
822        public static boolean RANDOM_DELAY_PRE_NOTIFY = true;
823    
824        /**
825         * Enable delay after notify?
826         */
827        public static boolean RANDOM_DELAY_POST_NOTIFY = true;
828    
829        /**
830         * Enable delay before wait?
831         */
832        public static boolean RANDOM_DELAY_PRE_WAIT = true;
833    
834        /**
835         * Enable delay after wait?
836         */
837        public static boolean RANDOM_DELAY_POST_WAIT = true;
838        
839        /**
840         * Enable delay before monitorenter/exit??
841         */
842        public static boolean RANDOM_DELAY_PRE_MONITOR = true;
843    
844        /**
845         * Enable delay after monitorenter/exit?
846         */
847        public static boolean RANDOM_DELAY_POST_MONITOR = true;
848        /**
849         * Sleep for a random amount of time, up to RANDOM_DELAY_MAGNITUDE milliseconds, if there is concurrency.
850         * @param delay true if delay is enabled
851         */
852        public static void randomDelay(boolean delay) {
853            if (delay && (_runningThreads>1)) {
854                try {
855                    Thread.sleep(((long)(RANDOM_DELAY_MIN + Math.random() * RANDOM_DELAY_MAGNITUDE)));
856                }
857                catch(InterruptedException e) { /* ignore */ }
858            }
859        }
860    
861        /**
862         * Increment the number of running thread, and then sleep for a while if there is concurrency.
863         * @param delay true if delay is enabled
864         */
865        public static void delayThreadStart(boolean delay) {
866            synchronized(SyncPointBuffer.class) { ++_runningThreads; }
867            randomDelay(delay);
868        }
869    
870        /**
871         * Sleep for a while if there is concurrency, and then decrement the number of running threads.
872         * @param delay true if delay is enabled
873         */
874        public static void delayThreadExit(boolean delay) {
875            randomDelay(delay);
876            synchronized(SyncPointBuffer.class) { --_runningThreads; }
877        }
878    
879        /**
880         * Throw an exception if no other thread is alive anymore, otherwise sleep for a while.
881         * @param delay true if delay is enabled
882         */
883        public static void delayObjectWait(boolean delay) {
884            synchronized(SyncPointBuffer.class) {
885                if (_runningThreads<=2) {
886                    throw new AssertionError("Call to Object.wait with only one user thread alive (_runningThreads=="+_runningThreads+")");
887                };
888            }
889            randomDelay(delay);
890        }
891    
892    
893        //
894        // Execution with random yields.
895        //
896        /**
897         * Probability of a yield.
898         */
899        public static float RANDOM_YIELD_PROB = 0.5f;
900        
901        /**
902         * Enable yield on thread start?
903         */
904        public static boolean RANDOM_YIELD_THREAD_START = true;
905        
906        /**
907         * Enable yield on thread exit?
908         */
909        public static boolean RANDOM_YIELD_THREAD_EXIT = true;
910        
911        /**
912         * Enable yield on thread run?
913         */
914        public static boolean RANDOM_YIELD_THREAD_RUN = true;
915    
916        /**
917         * Enable yield on thread join?
918         */
919        public static boolean RANDOM_YIELD_THREAD_JOIN = true;
920    
921        /**
922         * Enable yield before notify?
923         */
924        public static boolean RANDOM_YIELD_PRE_NOTIFY = true;
925    
926        /**
927         * Enable yield after notify?
928         */
929        public static boolean RANDOM_YIELD_POST_NOTIFY = true;
930    
931        /**
932         * Enable yield before wait?
933         */
934        public static boolean RANDOM_YIELD_PRE_WAIT = true;
935    
936        /**
937         * Enable yield after wait?
938         */
939        public static boolean RANDOM_YIELD_POST_WAIT = true;
940        
941        /**
942         * Enable yield before monitorenter/exit??
943         */
944        public static boolean RANDOM_YIELD_PRE_MONITOR = true;
945    
946        /**
947         * Enable yield after monitorenter/exit?
948         */
949        public static boolean RANDOM_YIELD_POST_MONITOR = true;
950        
951        /**
952         * Yield if random number < RANDOM_YIELD_PROB, but only if there is concurrency.
953         * @param yield true if yield is enabled
954         */
955        public static void randomYield(boolean yield) {
956            if (yield && (_runningThreads>1)) {
957                // Math.random
958                if ((RANDOM_YIELD_PROB>=1) || ((RANDOM_YIELD_PROB>0) && (Math.random()<RANDOM_YIELD_PROB))) {
959                    Thread.yield();
960                }
961            }
962        }
963    
964        /**
965         * Increment the number of running thread, and then do a random yield.
966         * @param yield true if yield is enabled
967         */
968        public static void yieldThreadStart(boolean yield) {
969            synchronized(SyncPointBuffer.class) { ++_runningThreads; }
970            randomYield(yield);
971        }
972    
973        /**
974         * Do a random yield, and then decrement the number of running threads.
975         * @param yield true if yield is enabled
976         */
977        public static void yieldThreadExit(boolean yield) {
978            randomYield(yield);
979            synchronized(SyncPointBuffer.class) { --_runningThreads; }
980        }
981    
982        /**
983         * Throw an exception if no other thread is alive anymore, otherwise do a random yield.
984         * @param yield true if yield is enabled
985         */
986        public static void yieldObjectWait(boolean yield) {
987            synchronized(SyncPointBuffer.class) {
988                if (_runningThreads<=2) {
989                    throw new AssertionError("Call to Object.wait with only one user thread alive (_runningThreads=="+_runningThreads+")");
990                };
991            }
992            randomYield(yield);
993        }
994    }